 c12d3dd6ad
			
		
	
	c12d3dd6ad
	
	
	
		
			
			* - 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
		
			
				
	
	
		
			591 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			591 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import annotations
 | |
| 
 | |
| import logging
 | |
| from typing import Collection, Callable
 | |
| 
 | |
| 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
 | |
| from .book_logic import BookLogicMixin
 | |
| from .building_logic import BuildingLogicMixin
 | |
| from .bundle_logic import BundleLogicMixin
 | |
| from .combat_logic import CombatLogicMixin
 | |
| from .cooking_logic import CookingLogicMixin
 | |
| from .crafting_logic import CraftingLogicMixin
 | |
| from .farming_logic import FarmingLogicMixin
 | |
| from .fishing_logic import FishingLogicMixin
 | |
| from .gift_logic import GiftLogicMixin
 | |
| from .grind_logic import GrindLogicMixin
 | |
| from .harvesting_logic import HarvestingLogicMixin
 | |
| from .has_logic import HasLogicMixin
 | |
| from .logic_event import all_logic_events
 | |
| from .mine_logic import MineLogicMixin
 | |
| from .money_logic import MoneyLogicMixin
 | |
| from .monster_logic import MonsterLogicMixin
 | |
| from .museum_logic import MuseumLogicMixin
 | |
| from .pet_logic import PetLogicMixin
 | |
| from .quality_logic import QualityLogicMixin
 | |
| from .quest_logic import QuestLogicMixin
 | |
| from .received_logic import ReceivedLogicMixin
 | |
| from .region_logic import RegionLogicMixin
 | |
| from .relationship_logic import RelationshipLogicMixin
 | |
| from .requirement_logic import RequirementLogicMixin
 | |
| from .season_logic import SeasonLogicMixin
 | |
| from .shipping_logic import ShippingLogicMixin
 | |
| from .skill_logic import SkillLogicMixin
 | |
| from .source_logic import SourceLogicMixin
 | |
| from .special_order_logic import SpecialOrderLogicMixin
 | |
| from .time_logic import TimeLogicMixin
 | |
| from .tool_logic import ToolLogicMixin
 | |
| from .traveling_merchant_logic import TravelingMerchantLogicMixin
 | |
| from .wallet_logic import WalletLogicMixin
 | |
| from .walnut_logic import WalnutLogicMixin
 | |
| from ..content.game_content import StardewContent
 | |
| from ..data.craftable_data import all_crafting_recipes
 | |
| 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 ModLogicMixin
 | |
| from ..mods.mod_data import ModNames
 | |
| from ..options import ExcludeGingerIsland, FestivalLocations, StardewValleyOptions
 | |
| from ..stardew_rule import False_, True_, StardewRule
 | |
| from ..strings.animal_names import Animal
 | |
| from ..strings.animal_product_names import AnimalProduct
 | |
| 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, 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, SpeedGro, RetainingSoil
 | |
| 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.machine_names import Machine
 | |
| from ..strings.material_names import Material
 | |
| from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil, Artifact
 | |
| from ..strings.monster_drop_names import Loot
 | |
| from ..strings.monster_names import Monster
 | |
| from ..strings.region_names import Region, LogicRegion
 | |
| from ..strings.season_names import Season
 | |
| 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
 | |
| 
 | |
| logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, TravelingMerchantLogicMixin, TimeLogicMixin,
 | |
|                    SeasonLogicMixin, MoneyLogicMixin, ActionLogicMixin, ArcadeLogicMixin, ArtisanLogicMixin, GiftLogicMixin,
 | |
|                    BuildingLogicMixin, ShippingLogicMixin, RelationshipLogicMixin, MuseumLogicMixin, WalletLogicMixin, AnimalLogicMixin,
 | |
|                    CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin,
 | |
|                    SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin,
 | |
|                    SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin,
 | |
|                    RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, WalnutLogicMixin):
 | |
|     player: int
 | |
|     options: StardewValleyOptions
 | |
|     content: StardewContent
 | |
|     regions: Collection[str]
 | |
| 
 | |
|     def __init__(self, player: int, options: StardewValleyOptions, content: StardewContent, regions: Collection[str]):
 | |
|         self.registry = LogicRegistry()
 | |
|         super().__init__(player, self.registry, options, content, regions, self)
 | |
| 
 | |
|         self.registry.fish_rules.update({fish.name: self.fishing.can_catch_fish(fish) for fish in content.fishes.values()})
 | |
|         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:
 | |
|                 continue
 | |
|             can_cook_rule = self.cooking.can_cook(recipe)
 | |
|             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 self.options.mods:
 | |
|                 continue
 | |
|             can_craft_rule = self.crafting.can_craft(recipe)
 | |
|             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.registry.crop_rules.update({
 | |
|             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.registry.item_rules.update({
 | |
|             "Energy Tonic": self.money.can_spend_at(Region.hospital, 1000),
 | |
|             WaterChest.fishing_chest: self.fishing.can_fish_chests(),
 | |
|             WaterChest.golden_fishing_chest: self.fishing.can_fish_chests() & self.skill.has_mastery(Skill.fishing),
 | |
|             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),
 | |
|             "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.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.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.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.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.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.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) & self.has(Forageable.journal_scrap) & self.region.can_reach(Region.volcano_floor_5),
 | |
|             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.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.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),
 | |
|             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.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),
 | |
|             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.honey: self.money.can_spend_at(Region.oasis, 200) | (self.has(Machine.bee_house) & self.season.has_any_not_winter()),
 | |
|             ArtisanGood.maple_syrup: self.has(Machine.tapper),
 | |
|             ArtisanGood.mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.chicken_egg),
 | |
|             ArtisanGood.mystic_syrup: self.has(Machine.tapper) & self.has(TreeSeed.mystic),
 | |
|             ArtisanGood.oak_resin: self.has(Machine.tapper),
 | |
|             ArtisanGood.pine_tar: self.has(Machine.tapper),
 | |
|             ArtisanGood.smoked_fish: self.artisan.has_smoked_fish(),
 | |
|             ArtisanGood.targeted_bait: self.artisan.has_targeted_bait(),
 | |
|             ArtisanGood.stardrop_tea: self.has(WaterChest.golden_fishing_chest),
 | |
|             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)),
 | |
|             Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600),
 | |
|             Beverage.triple_shot_espresso: self.has("Hot Java Ring"),
 | |
|             Consumable.butterfly_powder: self.money.can_spend_at(Region.sewer, 20000),
 | |
|             Consumable.far_away_stone: self.region.can_reach(Region.mines_floor_100) & self.has(Artifact.ancient_doll),
 | |
|             Consumable.fireworks_red: self.region.can_reach(Region.casino),
 | |
|             Consumable.fireworks_purple: self.region.can_reach(Region.casino),
 | |
|             Consumable.fireworks_green: self.region.can_reach(Region.casino),
 | |
|             Consumable.golden_animal_cracker: self.skill.has_mastery(Skill.farming),
 | |
|             Consumable.mystery_box: self.received(CommunityUpgrade.mr_qi_plane_ride),
 | |
|             Consumable.gold_mystery_box: self.received(CommunityUpgrade.mr_qi_plane_ride) & self.skill.has_mastery(Skill.foraging),
 | |
|             Currency.calico_egg: self.region.can_reach(LogicRegion.desert_festival),
 | |
|             Currency.golden_tag: self.region.can_reach(LogicRegion.trout_derby),
 | |
|             Currency.prize_ticket: self.time.has_lived_months(2),  # Time to do a few help wanted quests
 | |
|             Decoration.rotten_plant: self.has(Lighting.jack_o_lantern) & self.season.has(Season.winter),
 | |
|             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: self.logic.or_(*(self.fishing.can_catch_fish(fish) for fish in content.fishes.values())),
 | |
|             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_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(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.hay: self.building.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), #
 | |
|             Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & (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()), #
 | |
|             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),
 | |
|             Fossil.fossilized_spine: self.skill.can_fish(Region.dig_site),
 | |
|             Fossil.fossilized_tail: self.action.can_pan_at(Region.dig_site, ToolMaterial.copper),
 | |
|             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.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.tool.has_tool(Tool.pan, ToolMaterial.iron) | 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_with_any_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_with_any_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.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) & 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),
 | |
|             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) | self.artisan.can_keg(Ingredient.rice),
 | |
|             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.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),
 | |
|             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.tool.has_tool(Tool.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.moss: True_(),
 | |
|             Material.sap: self.ability.can_chop_trees(),
 | |
|             Material.stone: self.tool.has_tool(Tool.pickaxe),
 | |
|             Material.wood: self.tool.has_tool(Tool.axe),
 | |
|             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.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(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.tool.has_tool(Tool.pan, ToolMaterial.copper),
 | |
|             Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_tool(Tool.pan, ToolMaterial.iron),
 | |
|             Ore.iridium: self.mine.can_mine_in_the_skull_cavern() | self.can_fish_pond(Fish.super_cucumber) | self.tool.has_tool(Tool.pan, ToolMaterial.gold),
 | |
|             Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_tool(Tool.pan, ToolMaterial.copper),
 | |
|             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),
 | |
|             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,
 | |
|             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(),
 | |
|             TreeSeed.mossy: self.ability.can_chop_trees() & self.season.has(Season.summer),
 | |
|             Fish.clam: self.tool.can_forage(Generic.any, Region.beach),
 | |
|             Fish.cockle: self.tool.can_forage(Generic.any, Region.beach),
 | |
|             WaterItem.green_algae: self.fishing.can_fish_in_freshwater(),
 | |
|             WaterItem.cave_jelly: self.fishing.can_fish_at(Region.mines_floor_100) & self.tool.has_fishing_rod(2),
 | |
|             WaterItem.river_jelly: self.fishing.can_fish_at(Region.town) & self.tool.has_fishing_rod(2),
 | |
|             WaterItem.sea_jelly: self.fishing.can_fish_at(Region.beach) & self.tool.has_fishing_rod(2),
 | |
|             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),
 | |
|         })
 | |
|         # @formatter:on
 | |
| 
 | |
|         content_rules = {
 | |
|             item_name: self.source.has_access_to_item(game_item)
 | |
|             for item_name, game_item in self.content.game_items.items()
 | |
|         }
 | |
| 
 | |
|         for item in set(content_rules.keys()).intersection(self.registry.item_rules.keys()):
 | |
|             logger.warning(f"Rule for {item} already exists in the registry, overwriting it.")
 | |
| 
 | |
|         self.registry.item_rules.update(content_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.crop_rules)
 | |
|         self.artisan.initialize_rules()
 | |
|         self.registry.item_rules.update(self.registry.artisan_good_rules)
 | |
| 
 | |
|         self.registry.item_rules.update(self.mod.item.get_modded_item_rules())
 | |
|         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:
 | |
|             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.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.building.get_modded_building_rules())
 | |
| 
 | |
|         self.quest.initialize_rules()
 | |
|         self.quest.update_rules(self.mod.quest.get_modded_quest_rules())
 | |
| 
 | |
|         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_with_any_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),
 | |
|             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.rarecrow_3: True_(),
 | |
|             FestivalCheck.all_rarecrows: self.region.can_reach(Region.farm) & self.has_all_rarecrows(),
 | |
|             FestivalCheck.calico_race: True_(),
 | |
|             FestivalCheck.mummy_mask: True_(),
 | |
|             FestivalCheck.calico_statue: True_(),
 | |
|             FestivalCheck.emily_outfit_service: True_(),
 | |
|             FestivalCheck.earthy_mousse: True_(),
 | |
|             FestivalCheck.sweet_bean_cake: True_(),
 | |
|             FestivalCheck.skull_cave_casserole: True_(),
 | |
|             FestivalCheck.spicy_tacos: True_(),
 | |
|             FestivalCheck.mountain_chili: True_(),
 | |
|             FestivalCheck.crystal_cake: True_(),
 | |
|             FestivalCheck.cave_kebab: True_(),
 | |
|             FestivalCheck.hot_log: True_(),
 | |
|             FestivalCheck.sour_salad: True_(),
 | |
|             FestivalCheck.superfood_cake: True_(),
 | |
|             FestivalCheck.warrior_smoothie: True_(),
 | |
|             FestivalCheck.rumpled_fruit_skin: True_(),
 | |
|             FestivalCheck.calico_pizza: True_(),
 | |
|             FestivalCheck.stuffed_mushrooms: True_(),
 | |
|             FestivalCheck.elf_quesadilla: True_(),
 | |
|             FestivalCheck.nachos_of_the_desert: True_(),
 | |
|             FestivalCheck.cloppino: True_(),
 | |
|             FestivalCheck.rainforest_shrimp: True_(),
 | |
|             FestivalCheck.shrimp_donut: True_(),
 | |
|             FestivalCheck.smell_of_the_sea: True_(),
 | |
|             FestivalCheck.desert_gumbo: True_(),
 | |
|             FestivalCheck.free_cactis: True_(),
 | |
|             FestivalCheck.monster_hunt: self.monster.can_kill(Monster.serpent),
 | |
|             FestivalCheck.deep_dive: self.region.can_reach(Region.skull_cavern_50),
 | |
|             FestivalCheck.treasure_hunt: self.region.can_reach(Region.skull_cavern_25),
 | |
|             FestivalCheck.touch_calico_statue: self.region.can_reach(Region.skull_cavern_25),
 | |
|             FestivalCheck.real_calico_egg_hunter: self.region.can_reach(Region.skull_cavern_100),
 | |
|             FestivalCheck.willy_challenge: self.fishing.can_catch_fish(content.fishes[Fish.scorpion_carp]),
 | |
|             FestivalCheck.desert_scholar: True_(),
 | |
|             FestivalCheck.squidfest_day_1_copper: self.fishing.can_catch_fish(content.fishes[Fish.squid]),
 | |
|             FestivalCheck.squidfest_day_1_iron: self.fishing.can_catch_fish(content.fishes[Fish.squid]) & self.has(Fishing.bait),
 | |
|             FestivalCheck.squidfest_day_1_gold: self.fishing.can_catch_fish(content.fishes[Fish.squid]) & self.has(Fishing.deluxe_bait),
 | |
|             FestivalCheck.squidfest_day_1_iridium: self.fishing.can_catch_fish(content.fishes[Fish.squid]) &
 | |
|                                                    self.fishing.has_specific_bait(content.fishes[Fish.squid]),
 | |
|             FestivalCheck.squidfest_day_2_copper: self.fishing.can_catch_fish(content.fishes[Fish.squid]),
 | |
|             FestivalCheck.squidfest_day_2_iron: self.fishing.can_catch_fish(content.fishes[Fish.squid]) & self.has(Fishing.bait),
 | |
|             FestivalCheck.squidfest_day_2_gold: self.fishing.can_catch_fish(content.fishes[Fish.squid]) & self.has(Fishing.deluxe_bait),
 | |
|             FestivalCheck.squidfest_day_2_iridium: self.fishing.can_catch_fish(content.fishes[Fish.squid]) &
 | |
|                                                    self.fishing.has_specific_bait(content.fishes[Fish.squid]),
 | |
|         })
 | |
|         for i in range(1, 11):
 | |
|             self.registry.festival_rules[f"{FestivalCheck.trout_derby_reward_pattern}{i}"] = self.fishing.can_catch_fish(content.fishes[Fish.rainbow_trout])
 | |
| 
 | |
|         self.special_order.initialize_rules()
 | |
|         self.special_order.update_rules(self.mod.special_order.get_modded_special_orders_rules())
 | |
| 
 | |
|     def setup_events(self, register_event: Callable[[str, str, StardewRule], None]) -> None:
 | |
|         for logic_event in all_logic_events:
 | |
|             rule = self.registry.item_rules[logic_event.item]
 | |
|             register_event(logic_event.name, logic_event.region, rule)
 | |
|             self.registry.item_rules[logic_event.item] = self.received(logic_event.name)
 | |
| 
 | |
|     def can_smelt(self, item: str) -> StardewRule:
 | |
|         return self.has(Machine.furnace) & self.has(item)
 | |
| 
 | |
|     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_with_n(5, 8),  # 5 Friends
 | |
|             self.relationship.has_hearts_with_n(10, 8),  # 10 friends
 | |
|             self.pet.has_pet_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_win_egg_hunt(self) -> StardewRule:
 | |
|         return True_()
 | |
| 
 | |
|     def can_succeed_luau_soup(self) -> StardewRule:
 | |
|         if self.options.festival_locations != FestivalLocations.option_hard:
 | |
|             return True_()
 | |
|         eligible_fish = (Fish.blobfish, Fish.crimsonfish, Fish.ice_pip, Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish,
 | |
|                          Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, Fish.super_cucumber)
 | |
|         fish_rule = self.has_any(*(f for f in eligible_fish if f in self.content.fishes))  # To filter stingray
 | |
|         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 if kegable in self.content.game_items]
 | |
|         aged_rule = self.has(Machine.cask) & self.logic.or_(*keg_rules)
 | |
|         # 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:
 | |
|             return True_()
 | |
| 
 | |
|         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)
 | |
|         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
 | |
|                        for fruit in
 | |
|                        (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)
 | |
|                        if fruit in self.content.game_items)
 | |
|         fruit_rule = self.has_any(*good_fruits)
 | |
|         good_vegetables = (vegeteable
 | |
|                            for vegeteable in
 | |
|                            (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)
 | |
|                            if vegeteable in self.content.game_items)
 | |
|         vegetable_rule = self.has_any(*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(difficulty=60)
 | |
| 
 | |
|     def has_island_trader(self) -> StardewRule:
 | |
|         if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
 | |
|             return False_()
 | |
|         return self.region.can_reach(Region.island_trader)
 | |
| 
 | |
|     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
 | |
| 
 | |
|         # Master Angler Stardrop
 | |
|         if self.content.features.fishsanity.is_enabled:
 | |
|             number_of_stardrops_to_receive += 1
 | |
|         else:
 | |
|             other_rules.append(self.fishing.can_catch_every_fish())
 | |
| 
 | |
|         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
 | |
| 
 | |
|         # Spouse Stardrop
 | |
|         if self.content.features.friendsanity.is_enabled:
 | |
|             number_of_stardrops_to_receive += 1
 | |
|         else:
 | |
|             other_rules.append(self.relationship.has_hearts_with_any_bachelor(13))
 | |
| 
 | |
|         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) & self.logic.and_(*other_rules)
 | |
| 
 | |
|     def has_all_rarecrows(self) -> StardewRule:
 | |
|         rules = []
 | |
|         for rarecrow_number in range(1, 9):
 | |
|             rules.append(self.received(f"Rarecrow #{rarecrow_number}"))
 | |
|         return self.logic.and_(*rules)
 | |
| 
 | |
|     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.farm) & self.received(obelisk)
 | |
| 
 | |
|     def can_fish_pond(self, fish: str) -> StardewRule:
 | |
|         return self.building.has_building(Building.fish_pond) & self.has(fish)
 |