Stardew valley: Fix Queen of Sauce Cookbook conditions (#3651)

* - Extracted walnut logic to a Mixin so it can be used in content pack requirements

* - Add 100 walnut requirements to the Queen of Sauce Cookbook

* - Woops a file wasn't added to previous commits

* - Make the queen of sauce cookbook a ginger island only thing, due to the walnut requirement

* - Moved the book in the correct content pack

* - Removed an empty class that I'm not sure where it came from
This commit is contained in:
agilbert1412 2024-07-23 01:36:42 +03:00 committed by GitHub
parent f7989780fa
commit c12d3dd6ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 171 additions and 133 deletions

View File

@ -255,7 +255,7 @@ class StardewValleyWorld(World):
Event.victory) Event.victory)
elif self.options.goal == Goal.option_greatest_walnut_hunter: elif self.options.goal == Goal.option_greatest_walnut_hunter:
self.create_event_location(location_table[GoalName.greatest_walnut_hunter], self.create_event_location(location_table[GoalName.greatest_walnut_hunter],
self.logic.has_walnut(130), self.logic.walnut.has_walnut(130),
Event.victory) Event.victory)
elif self.options.goal == 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.create_event_location(location_table[GoalName.protector_of_the_valley],

View File

@ -3,6 +3,7 @@ from ..game_content import ContentPack, StardewContent
from ...data import villagers_data, fish_data from ...data import villagers_data, fish_data
from ...data.game_item import ItemTag, Tag from ...data.game_item import ItemTag, Tag
from ...data.harvest import ForagingSource, HarvestFruitTreeSource, HarvestCropSource from ...data.harvest import ForagingSource, HarvestFruitTreeSource, HarvestCropSource
from ...data.requirement import WalnutRequirement
from ...data.shop import ShopSource from ...data.shop import ShopSource
from ...strings.book_names import Book from ...strings.book_names import Book
from ...strings.crop_names import Fruit, Vegetable from ...strings.crop_names import Fruit, Vegetable
@ -10,7 +11,7 @@ from ...strings.fish_names import Fish
from ...strings.forageable_names import Forageable, Mushroom from ...strings.forageable_names import Forageable, Mushroom
from ...strings.fruit_tree_names import Sapling from ...strings.fruit_tree_names import Sapling
from ...strings.metal_names import Fossil, Mineral from ...strings.metal_names import Fossil, Mineral
from ...strings.region_names import Region from ...strings.region_names import Region, LogicRegion
from ...strings.season_names import Season from ...strings.season_names import Season
from ...strings.seed_names import Seed from ...strings.seed_names import Seed
@ -62,6 +63,9 @@ ginger_island_content_pack = GingerIslandContentPack(
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER), Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
ShopSource(items_price=((10, Mineral.diamond),), shop_region=Region.volcano_dwarf_shop), ShopSource(items_price=((10, Mineral.diamond),), shop_region=Region.volcano_dwarf_shop),
), ),
Book.queen_of_sauce_cookbook: (
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2, other_requirements=(WalnutRequirement(100),)),), # Worst book ever
}, },
fishes=( fishes=(

View File

@ -290,9 +290,6 @@ pelican_town = ContentPack(
Book.woodcutters_weekly: ( Book.woodcutters_weekly: (
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL), Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),), ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
Book.queen_of_sauce_cookbook: (
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2),), # Worst book ever
}, },
fishes=( fishes=(
fish_data.albacore, fish_data.albacore,

View File

@ -2252,7 +2252,7 @@ id,region,name,tags,mod_name
3848,Shipping,Shipsanity: Way Of The Wind pt. 1,"SHIPSANITY", 3848,Shipping,Shipsanity: Way Of The Wind pt. 1,"SHIPSANITY",
3849,Shipping,Shipsanity: Mapping Cave Systems,"SHIPSANITY", 3849,Shipping,Shipsanity: Mapping Cave Systems,"SHIPSANITY",
3850,Shipping,Shipsanity: Price Catalogue,"SHIPSANITY", 3850,Shipping,Shipsanity: Price Catalogue,"SHIPSANITY",
3851,Shipping,Shipsanity: Queen Of Sauce Cookbook,"SHIPSANITY", 3851,Shipping,Shipsanity: Queen Of Sauce Cookbook,"SHIPSANITY,GINGER_ISLAND",
3852,Shipping,Shipsanity: The Diamond Hunter,"SHIPSANITY,GINGER_ISLAND", 3852,Shipping,Shipsanity: The Diamond Hunter,"SHIPSANITY,GINGER_ISLAND",
3853,Shipping,Shipsanity: Book of Mysteries,"SHIPSANITY", 3853,Shipping,Shipsanity: Book of Mysteries,"SHIPSANITY",
3854,Shipping,Shipsanity: Animal Catalogue,"SHIPSANITY", 3854,Shipping,Shipsanity: Animal Catalogue,"SHIPSANITY",
@ -2292,7 +2292,7 @@ id,region,name,tags,mod_name
4032,Farm,Read Book Of Stars,"BOOKSANITY,BOOKSANITY_SKILL", 4032,Farm,Read Book Of Stars,"BOOKSANITY,BOOKSANITY_SKILL",
4033,Farm,Read Combat Quarterly,"BOOKSANITY,BOOKSANITY_SKILL", 4033,Farm,Read Combat Quarterly,"BOOKSANITY,BOOKSANITY_SKILL",
4034,Farm,Read Mining Monthly,"BOOKSANITY,BOOKSANITY_SKILL", 4034,Farm,Read Mining Monthly,"BOOKSANITY,BOOKSANITY_SKILL",
4035,Farm,Read Queen Of Sauce Cookbook,"BOOKSANITY,BOOKSANITY_SKILL", 4035,Farm,Read Queen Of Sauce Cookbook,"BOOKSANITY,BOOKSANITY_SKILL,GINGER_ISLAND",
4036,Farm,Read Stardew Valley Almanac,"BOOKSANITY,BOOKSANITY_SKILL", 4036,Farm,Read Stardew Valley Almanac,"BOOKSANITY,BOOKSANITY_SKILL",
4037,Farm,Read Woodcutter's Weekly,"BOOKSANITY,BOOKSANITY_SKILL", 4037,Farm,Read Woodcutter's Weekly,"BOOKSANITY,BOOKSANITY_SKILL",
4051,Museum,Read Tips on Farming,"BOOKSANITY,BOOKSANITY_LOST", 4051,Museum,Read Tips on Farming,"BOOKSANITY,BOOKSANITY_LOST",

1 id region name tags mod_name
2252 3848 Shipping Shipsanity: Way Of The Wind pt. 1 SHIPSANITY
2253 3849 Shipping Shipsanity: Mapping Cave Systems SHIPSANITY
2254 3850 Shipping Shipsanity: Price Catalogue SHIPSANITY
2255 3851 Shipping Shipsanity: Queen Of Sauce Cookbook SHIPSANITY SHIPSANITY,GINGER_ISLAND
2256 3852 Shipping Shipsanity: The Diamond Hunter SHIPSANITY,GINGER_ISLAND
2257 3853 Shipping Shipsanity: Book of Mysteries SHIPSANITY
2258 3854 Shipping Shipsanity: Animal Catalogue SHIPSANITY
2292 4032 Farm Read Book Of Stars BOOKSANITY,BOOKSANITY_SKILL
2293 4033 Farm Read Combat Quarterly BOOKSANITY,BOOKSANITY_SKILL
2294 4034 Farm Read Mining Monthly BOOKSANITY,BOOKSANITY_SKILL
2295 4035 Farm Read Queen Of Sauce Cookbook BOOKSANITY,BOOKSANITY_SKILL BOOKSANITY,BOOKSANITY_SKILL,GINGER_ISLAND
2296 4036 Farm Read Stardew Valley Almanac BOOKSANITY,BOOKSANITY_SKILL
2297 4037 Farm Read Woodcutter's Weekly BOOKSANITY,BOOKSANITY_SKILL
2298 4051 Museum Read Tips on Farming BOOKSANITY,BOOKSANITY_LOST

View File

@ -29,3 +29,8 @@ class SeasonRequirement(Requirement):
@dataclass(frozen=True) @dataclass(frozen=True)
class YearRequirement(Requirement): class YearRequirement(Requirement):
year: int year: int
@dataclass(frozen=True)
class WalnutRequirement(Requirement):
amount: int

View File

@ -1,7 +1,6 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from functools import cached_property
from typing import Collection, Callable from typing import Collection, Callable
from .ability_logic import AbilityLogicMixin from .ability_logic import AbilityLogicMixin
@ -43,6 +42,7 @@ from .time_logic import TimeLogicMixin
from .tool_logic import ToolLogicMixin from .tool_logic import ToolLogicMixin
from .traveling_merchant_logic import TravelingMerchantLogicMixin from .traveling_merchant_logic import TravelingMerchantLogicMixin
from .wallet_logic import WalletLogicMixin from .wallet_logic import WalletLogicMixin
from .walnut_logic import WalnutLogicMixin
from ..content.game_content import StardewContent from ..content.game_content import StardewContent
from ..data.craftable_data import all_crafting_recipes from ..data.craftable_data import all_crafting_recipes
from ..data.museum_data import all_museum_items from ..data.museum_data import all_museum_items
@ -50,16 +50,14 @@ from ..data.recipe_data import all_cooking_recipes
from ..mods.logic.magic_logic import MagicLogicMixin from ..mods.logic.magic_logic import MagicLogicMixin
from ..mods.logic.mod_logic import ModLogicMixin from ..mods.logic.mod_logic import ModLogicMixin
from ..mods.mod_data import ModNames from ..mods.mod_data import ModNames
from ..options import SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Walnutsanity from ..options import ExcludeGingerIsland, FestivalLocations, StardewValleyOptions
from ..stardew_rule import False_, True_, StardewRule from ..stardew_rule import False_, True_, StardewRule
from ..strings.animal_names import Animal from ..strings.animal_names import Animal
from ..strings.animal_product_names import AnimalProduct from ..strings.animal_product_names import AnimalProduct
from ..strings.ap_names.ap_option_names import OptionName
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade from ..strings.ap_names.community_upgrade_names import CommunityUpgrade
from ..strings.ap_names.event_names import Event
from ..strings.artisan_good_names import ArtisanGood from ..strings.artisan_good_names import ArtisanGood
from ..strings.building_names import Building from ..strings.building_names import Building
from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting, WildSeeds from ..strings.craftable_names import Consumable, Ring, Fishing, Lighting, WildSeeds
from ..strings.crop_names import Fruit, Vegetable from ..strings.crop_names import Fruit, Vegetable
from ..strings.currency_names import Currency from ..strings.currency_names import Currency
from ..strings.decoration_names import Decoration from ..strings.decoration_names import Decoration
@ -96,7 +94,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin, CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin,
SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin, SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin,
SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin, SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin,
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin): RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, WalnutLogicMixin):
player: int player: int
options: StardewValleyOptions options: StardewValleyOptions
content: StardewContent content: StardewContent
@ -461,32 +459,6 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
def can_smelt(self, item: str) -> StardewRule: def can_smelt(self, item: str) -> StardewRule:
return self.has(Machine.furnace) & self.has(item) return self.has(Machine.furnace) & self.has(item)
@cached_property
def can_start_field_office(self) -> StardewRule:
field_office = self.region.can_reach(Region.field_office)
professor_snail = self.received("Open Professor Snail Cave")
return field_office & professor_snail
def can_complete_large_animal_collection(self) -> StardewRule:
fossils = self.has_all(Fossil.fossilized_leg, Fossil.fossilized_ribs, Fossil.fossilized_skull, Fossil.fossilized_spine, Fossil.fossilized_tail)
return self.can_start_field_office & fossils
def can_complete_snake_collection(self) -> StardewRule:
fossils = self.has_all(Fossil.snake_skull, Fossil.snake_vertebrae)
return self.can_start_field_office & fossils
def can_complete_frog_collection(self) -> StardewRule:
fossils = self.has_all(Fossil.mummified_frog)
return self.can_start_field_office & fossils
def can_complete_bat_collection(self) -> StardewRule:
fossils = self.has_all(Fossil.mummified_bat)
return self.can_start_field_office & fossils
def can_complete_field_office(self) -> StardewRule:
return self.can_complete_large_animal_collection() & self.can_complete_snake_collection() & \
self.can_complete_frog_collection() & self.can_complete_bat_collection()
def can_finish_grandpa_evaluation(self) -> StardewRule: def can_finish_grandpa_evaluation(self) -> StardewRule:
# https://stardewvalleywiki.com/Grandpa # https://stardewvalleywiki.com/Grandpa
rules_worth_a_point = [ rules_worth_a_point = [
@ -566,86 +538,6 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
return False_() return False_()
return self.region.can_reach(Region.island_trader) return self.region.can_reach(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_()
if self.options.walnutsanity == Walnutsanity.preset_none:
return self.can_get_walnuts(number)
if self.options.walnutsanity == Walnutsanity.preset_all:
return self.has_received_walnuts(number)
puzzle_walnuts = 61
bush_walnuts = 25
dig_walnuts = 18
repeatable_walnuts = 33
total_walnuts = puzzle_walnuts + bush_walnuts + dig_walnuts + repeatable_walnuts
walnuts_to_receive = 0
walnuts_to_collect = number
if OptionName.walnutsanity_puzzles in self.options.walnutsanity:
puzzle_walnut_rate = puzzle_walnuts / total_walnuts
puzzle_walnuts_required = round(puzzle_walnut_rate * number)
walnuts_to_receive += puzzle_walnuts_required
walnuts_to_collect -= puzzle_walnuts_required
if OptionName.walnutsanity_bushes in self.options.walnutsanity:
bush_walnuts_rate = bush_walnuts / total_walnuts
bush_walnuts_required = round(bush_walnuts_rate * number)
walnuts_to_receive += bush_walnuts_required
walnuts_to_collect -= bush_walnuts_required
if OptionName.walnutsanity_dig_spots in self.options.walnutsanity:
dig_walnuts_rate = dig_walnuts / total_walnuts
dig_walnuts_required = round(dig_walnuts_rate * number)
walnuts_to_receive += dig_walnuts_required
walnuts_to_collect -= dig_walnuts_required
if OptionName.walnutsanity_repeatables in self.options.walnutsanity:
repeatable_walnuts_rate = repeatable_walnuts / total_walnuts
repeatable_walnuts_required = round(repeatable_walnuts_rate * number)
walnuts_to_receive += repeatable_walnuts_required
walnuts_to_collect -= repeatable_walnuts_required
return self.has_received_walnuts(walnuts_to_receive) & self.can_get_walnuts(walnuts_to_collect)
def has_received_walnuts(self, number: int) -> StardewRule:
return self.received(Event.received_walnuts, number)
def can_get_walnuts(self, number: int) -> StardewRule:
# 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_field_office = self.region.can_reach(Region.field_office)
reach_pirate_cove = self.region.can_reach(Region.pirate_cove)
reach_outside_areas = self.logic.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 = self.logic.or_(*reach_volcano_regions)
reach_all_volcano = self.logic.and_(*reach_volcano_regions)
reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office]
reach_caves = self.logic.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.combat.has_slingshot)
reach_entire_island = self.logic.and_(reach_outside_areas, reach_all_volcano,
reach_caves, reach_southeast, reach_field_office, reach_pirate_cove)
if number <= 5:
return self.logic.or_(reach_south, reach_north, reach_west, reach_volcano)
if number <= 10:
return self.count(2, *reach_walnut_regions)
if number <= 15:
return self.count(3, *reach_walnut_regions)
if number <= 20:
return self.logic.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_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()
def has_all_stardrops(self) -> StardewRule: def has_all_stardrops(self) -> StardewRule:
other_rules = [] other_rules = []
number_of_stardrops_to_receive = 0 number_of_stardrops_to_receive = 0

View File

@ -9,8 +9,9 @@ from .season_logic import SeasonLogicMixin
from .skill_logic import SkillLogicMixin from .skill_logic import SkillLogicMixin
from .time_logic import TimeLogicMixin from .time_logic import TimeLogicMixin
from .tool_logic import ToolLogicMixin from .tool_logic import ToolLogicMixin
from .walnut_logic import WalnutLogicMixin
from ..data.game_item import Requirement from ..data.game_item import Requirement
from ..data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement, YearRequirement from ..data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement, YearRequirement, WalnutRequirement
class RequirementLogicMixin(BaseLogicMixin): class RequirementLogicMixin(BaseLogicMixin):
@ -20,7 +21,7 @@ class RequirementLogicMixin(BaseLogicMixin):
class RequirementLogic(BaseLogic[Union[RequirementLogicMixin, HasLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, BookLogicMixin, class RequirementLogic(BaseLogic[Union[RequirementLogicMixin, HasLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, BookLogicMixin,
SeasonLogicMixin, TimeLogicMixin]]): SeasonLogicMixin, TimeLogicMixin, WalnutLogicMixin]]):
def meet_all_requirements(self, requirements: Iterable[Requirement]): def meet_all_requirements(self, requirements: Iterable[Requirement]):
if not requirements: if not requirements:
@ -50,3 +51,7 @@ SeasonLogicMixin, TimeLogicMixin]]):
@meet_requirement.register @meet_requirement.register
def _(self, requirement: YearRequirement): def _(self, requirement: YearRequirement):
return self.logic.time.has_year(requirement.year) return self.logic.time.has_year(requirement.year)
@meet_requirement.register
def _(self, requirement: WalnutRequirement):
return self.logic.walnut.has_walnut(requirement.amount)

View File

@ -0,0 +1,135 @@
from functools import cached_property
from typing import Union
from .ability_logic import AbilityLogicMixin
from .base_logic import BaseLogic, BaseLogicMixin
from .combat_logic import CombatLogicMixin
from .has_logic import HasLogicMixin
from .received_logic import ReceivedLogicMixin
from .region_logic import RegionLogicMixin
from ..strings.ap_names.event_names import Event
from ..options import ExcludeGingerIsland, Walnutsanity
from ..stardew_rule import StardewRule, False_, True_
from ..strings.ap_names.ap_option_names import OptionName
from ..strings.craftable_names import Furniture
from ..strings.crop_names import Fruit
from ..strings.metal_names import Mineral, Fossil
from ..strings.region_names import Region
from ..strings.seed_names import Seed
class WalnutLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.walnut = WalnutLogic(*args, **kwargs)
class WalnutLogic(BaseLogic[Union[WalnutLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, CombatLogicMixin,
AbilityLogicMixin]]):
def has_walnut(self, number: int) -> StardewRule:
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
return False_()
if number <= 0:
return True_()
if self.options.walnutsanity == Walnutsanity.preset_none:
return self.can_get_walnuts(number)
if self.options.walnutsanity == Walnutsanity.preset_all:
return self.has_received_walnuts(number)
puzzle_walnuts = 61
bush_walnuts = 25
dig_walnuts = 18
repeatable_walnuts = 33
total_walnuts = puzzle_walnuts + bush_walnuts + dig_walnuts + repeatable_walnuts
walnuts_to_receive = 0
walnuts_to_collect = number
if OptionName.walnutsanity_puzzles in self.options.walnutsanity:
puzzle_walnut_rate = puzzle_walnuts / total_walnuts
puzzle_walnuts_required = round(puzzle_walnut_rate * number)
walnuts_to_receive += puzzle_walnuts_required
walnuts_to_collect -= puzzle_walnuts_required
if OptionName.walnutsanity_bushes in self.options.walnutsanity:
bush_walnuts_rate = bush_walnuts / total_walnuts
bush_walnuts_required = round(bush_walnuts_rate * number)
walnuts_to_receive += bush_walnuts_required
walnuts_to_collect -= bush_walnuts_required
if OptionName.walnutsanity_dig_spots in self.options.walnutsanity:
dig_walnuts_rate = dig_walnuts / total_walnuts
dig_walnuts_required = round(dig_walnuts_rate * number)
walnuts_to_receive += dig_walnuts_required
walnuts_to_collect -= dig_walnuts_required
if OptionName.walnutsanity_repeatables in self.options.walnutsanity:
repeatable_walnuts_rate = repeatable_walnuts / total_walnuts
repeatable_walnuts_required = round(repeatable_walnuts_rate * number)
walnuts_to_receive += repeatable_walnuts_required
walnuts_to_collect -= repeatable_walnuts_required
return self.has_received_walnuts(walnuts_to_receive) & self.can_get_walnuts(walnuts_to_collect)
def has_received_walnuts(self, number: int) -> StardewRule:
return self.logic.received(Event.received_walnuts, number)
def can_get_walnuts(self, number: int) -> StardewRule:
# https://stardewcommunitywiki.com/Golden_Walnut#Walnut_Locations
reach_south = self.logic.region.can_reach(Region.island_south)
reach_north = self.logic.region.can_reach(Region.island_north)
reach_west = self.logic.region.can_reach(Region.island_west)
reach_hut = self.logic.region.can_reach(Region.leo_hut)
reach_southeast = self.logic.region.can_reach(Region.island_south_east)
reach_field_office = self.logic.region.can_reach(Region.field_office)
reach_pirate_cove = self.logic.region.can_reach(Region.pirate_cove)
reach_outside_areas = self.logic.and_(reach_south, reach_north, reach_west, reach_hut)
reach_volcano_regions = [self.logic.region.can_reach(Region.volcano),
self.logic.region.can_reach(Region.volcano_secret_beach),
self.logic.region.can_reach(Region.volcano_floor_5),
self.logic.region.can_reach(Region.volcano_floor_10)]
reach_volcano = self.logic.or_(*reach_volcano_regions)
reach_all_volcano = self.logic.and_(*reach_volcano_regions)
reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office]
reach_caves = self.logic.and_(self.logic.region.can_reach(Region.qi_walnut_room), self.logic.region.can_reach(Region.dig_site),
self.logic.region.can_reach(Region.gourmand_frog_cave),
self.logic.region.can_reach(Region.colored_crystals_cave),
self.logic.region.can_reach(Region.shipwreck), self.logic.combat.has_slingshot)
reach_entire_island = self.logic.and_(reach_outside_areas, reach_all_volcano,
reach_caves, reach_southeast, reach_field_office, reach_pirate_cove)
if number <= 5:
return self.logic.or_(reach_south, reach_north, reach_west, reach_volcano)
if number <= 10:
return self.logic.count(2, *reach_walnut_regions)
if number <= 15:
return self.logic.count(3, *reach_walnut_regions)
if number <= 20:
return self.logic.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.logic.has(Fruit.banana) & self.logic.has_all(*gems) & \
self.logic.ability.can_mine_perfectly() & self.logic.ability.can_fish_perfectly() & \
self.logic.has(Furniture.flute_block) & self.logic.has(Seed.melon) & self.logic.has(Seed.wheat) & \
self.logic.has(Seed.garlic) & self.can_complete_field_office()
@cached_property
def can_start_field_office(self) -> StardewRule:
field_office = self.logic.region.can_reach(Region.field_office)
professor_snail = self.logic.received("Open Professor Snail Cave")
return field_office & professor_snail
def can_complete_large_animal_collection(self) -> StardewRule:
fossils = self.logic.has_all(Fossil.fossilized_leg, Fossil.fossilized_ribs, Fossil.fossilized_skull, Fossil.fossilized_spine, Fossil.fossilized_tail)
return self.can_start_field_office & fossils
def can_complete_snake_collection(self) -> StardewRule:
fossils = self.logic.has_all(Fossil.snake_skull, Fossil.snake_vertebrae)
return self.can_start_field_office & fossils
def can_complete_frog_collection(self) -> StardewRule:
fossils = self.logic.has_all(Fossil.mummified_frog)
return self.can_start_field_office & fossils
def can_complete_bat_collection(self) -> StardewRule:
fossils = self.logic.has_all(Fossil.mummified_bat)
return self.can_start_field_office & fossils
def can_complete_field_office(self) -> StardewRule:
return self.can_complete_large_animal_collection() & self.can_complete_snake_collection() & \
self.can_complete_frog_collection() & self.can_complete_bat_collection()

View File

@ -375,7 +375,7 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio
MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player), MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player),
logic.has(Bomb.cherry_bomb)) logic.has(Bomb.cherry_bomb))
MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player), MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player),
logic.can_complete_field_office()) logic.walnut.can_complete_field_office())
set_walnut_rules(logic, multiworld, player, world_options) set_walnut_rules(logic, multiworld, player, world_options)
@ -432,10 +432,10 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player, world_op
def set_island_parrot_rules(logic: StardewLogic, multiworld, player): def set_island_parrot_rules(logic: StardewLogic, multiworld, player):
# Logic rules require more walnuts than in reality, to allow the player to spend them "wrong" # Logic rules require more walnuts than in reality, to allow the player to spend them "wrong"
has_walnut = logic.has_walnut(5) has_walnut = logic.walnut.has_walnut(5)
has_5_walnut = logic.has_walnut(15) has_5_walnut = logic.walnut.has_walnut(15)
has_10_walnut = logic.has_walnut(40) has_10_walnut = logic.walnut.has_walnut(40)
has_20_walnut = logic.has_walnut(60) has_20_walnut = logic.walnut.has_walnut(60)
MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player), MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player),
has_walnut) has_walnut)
MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player), MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player),
@ -471,7 +471,7 @@ def set_walnut_rules(logic: StardewLogic, multiworld, player, world_options: Sta
set_walnut_repeatable_rules(logic, multiworld, player, world_options) set_walnut_repeatable_rules(logic, multiworld, player, world_options)
def set_walnut_puzzle_rules(logic, multiworld, player, world_options): def set_walnut_puzzle_rules(logic: StardewLogic, multiworld, player, world_options):
if OptionName.walnutsanity_puzzles not in world_options.walnutsanity: if OptionName.walnutsanity_puzzles not in world_options.walnutsanity:
return return
@ -487,12 +487,12 @@ def set_walnut_puzzle_rules(logic, multiworld, player, world_options):
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Garlic", player), logic.has(Vegetable.garlic) & MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Garlic", player), logic.has(Vegetable.garlic) &
logic.region.can_reach(Region.island_west) & logic.region.can_reach_location("Gourmand Frog Wheat")) logic.region.can_reach(Region.island_west) & logic.region.can_reach_location("Gourmand Frog Wheat"))
MultiWorldRules.add_rule(multiworld.get_location("Whack A Mole", player), logic.tool.has_tool(Tool.watering_can, ToolMaterial.iridium)) MultiWorldRules.add_rule(multiworld.get_location("Whack A Mole", player), logic.tool.has_tool(Tool.watering_can, ToolMaterial.iridium))
MultiWorldRules.add_rule(multiworld.get_location("Complete Large Animal Collection", player), logic.can_complete_large_animal_collection()) MultiWorldRules.add_rule(multiworld.get_location("Complete Large Animal Collection", player), logic.walnut.can_complete_large_animal_collection())
MultiWorldRules.add_rule(multiworld.get_location("Complete Snake Collection", player), logic.can_complete_snake_collection()) MultiWorldRules.add_rule(multiworld.get_location("Complete Snake Collection", player), logic.walnut.can_complete_snake_collection())
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Frog Collection", player), logic.can_complete_frog_collection()) MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Frog Collection", player), logic.walnut.can_complete_frog_collection())
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Bat Collection", player), logic.can_complete_bat_collection()) MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Bat Collection", player), logic.walnut.can_complete_bat_collection())
MultiWorldRules.add_rule(multiworld.get_location("Purple Flowers Island Survey", player), logic.can_start_field_office) MultiWorldRules.add_rule(multiworld.get_location("Purple Flowers Island Survey", player), logic.walnut.can_start_field_office)
MultiWorldRules.add_rule(multiworld.get_location("Purple Starfish Island Survey", player), logic.can_start_field_office) MultiWorldRules.add_rule(multiworld.get_location("Purple Starfish Island Survey", player), logic.walnut.can_start_field_office)
MultiWorldRules.add_rule(multiworld.get_location("Protruding Tree Walnut", player), logic.combat.has_slingshot) MultiWorldRules.add_rule(multiworld.get_location("Protruding Tree Walnut", player), logic.combat.has_slingshot)
MultiWorldRules.add_rule(multiworld.get_location("Starfish Tide Pool", player), logic.tool.has_fishing_rod(1)) MultiWorldRules.add_rule(multiworld.get_location("Starfish Tide Pool", player), logic.tool.has_fishing_rod(1))
MultiWorldRules.add_rule(multiworld.get_location("Mermaid Song", player), logic.has(Furniture.flute_block)) MultiWorldRules.add_rule(multiworld.get_location("Mermaid Song", player), logic.has(Furniture.flute_block))