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:
parent
f7989780fa
commit
c12d3dd6ad
|
@ -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],
|
||||||
|
|
|
@ -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=(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue