| 
									
										
										
										
											2025-03-22 15:29:16 -04:00
										 |  |  | import typing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from .base_logic import BaseLogic, BaseLogicMixin | 
					
						
							|  |  |  | from ..data.craftable_data import all_crafting_recipes_by_name | 
					
						
							|  |  |  | from ..data.recipe_data import all_cooking_recipes_by_name | 
					
						
							|  |  |  | from ..locations import LocationTags, locations_by_tag | 
					
						
							|  |  |  | from ..mods.mod_data import ModNames | 
					
						
							|  |  |  | from ..options import options | 
					
						
							|  |  |  | from ..stardew_rule import StardewRule | 
					
						
							|  |  |  | from ..strings.building_names import Building | 
					
						
							|  |  |  | from ..strings.quest_names import Quest | 
					
						
							|  |  |  | from ..strings.season_names import Season | 
					
						
							|  |  |  | from ..strings.wallet_item_names import Wallet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if typing.TYPE_CHECKING: | 
					
						
							|  |  |  |     from .logic import StardewLogic | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     StardewLogic = object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GoalLogicMixin(BaseLogicMixin): | 
					
						
							|  |  |  |     def __init__(self, *args, **kwargs): | 
					
						
							|  |  |  |         super().__init__(*args, **kwargs) | 
					
						
							|  |  |  |         self.goal = GoalLogic(*args, **kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GoalLogic(BaseLogic[StardewLogic]): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_community_center(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.bundle.can_complete_community_center | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_finish_grandpa_evaluation(self) -> StardewRule: | 
					
						
							|  |  |  |         # https://stardewvalleywiki.com/Grandpa | 
					
						
							|  |  |  |         rules_worth_a_point = [ | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(50_000), | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(100_000), | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(200_000), | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(300_000), | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(500_000), | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(1_000_000),  # first point | 
					
						
							|  |  |  |             self.logic.money.can_have_earned_total(1_000_000),  # second point | 
					
						
							|  |  |  |             self.logic.skill.has_total_level(30), | 
					
						
							|  |  |  |             self.logic.skill.has_total_level(50), | 
					
						
							|  |  |  |             self.logic.museum.can_complete_museum(), | 
					
						
							|  |  |  |             # Catching every fish not expected | 
					
						
							|  |  |  |             # Shipping every item not expected | 
					
						
							| 
									
										
										
										
											2025-04-08 12:37:45 -04:00
										 |  |  |             self.logic.relationship.can_get_married() & self.logic.building.has_building(Building.kids_room), | 
					
						
							| 
									
										
										
										
											2025-03-22 15:29:16 -04:00
										 |  |  |             self.logic.relationship.has_hearts_with_n(5, 8),  # 5 Friends | 
					
						
							|  |  |  |             self.logic.relationship.has_hearts_with_n(10, 8),  # 10 friends | 
					
						
							|  |  |  |             self.logic.pet.has_pet_hearts(5),  # Max Pet | 
					
						
							|  |  |  |             self.logic.bundle.can_complete_community_center,  # 1 point for Community Center Completion | 
					
						
							|  |  |  |             self.logic.bundle.can_complete_community_center,  # Ceremony first point | 
					
						
							|  |  |  |             self.logic.bundle.can_complete_community_center,  # Ceremony second point | 
					
						
							|  |  |  |             self.logic.received(Wallet.skull_key), | 
					
						
							|  |  |  |             self.logic.wallet.has_rusty_key(), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         return self.logic.count(12, *rules_worth_a_point) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_bottom_of_the_mines(self) -> StardewRule: | 
					
						
							|  |  |  |         # The location is in the bottom of the mines region, so no actual rule is required | 
					
						
							|  |  |  |         return self.logic.true_ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_cryptic_note(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.quest.can_complete_quest(Quest.cryptic_note) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_master_angler(self) -> StardewRule: | 
					
						
							|  |  |  |         if not self.content.features.fishsanity.is_enabled: | 
					
						
							|  |  |  |             return self.logic.fishing.can_catch_every_fish() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rules = [self.logic.fishing.has_max_fishing()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rules.extend( | 
					
						
							|  |  |  |             self.logic.fishing.can_catch_fish_for_fishsanity(fish) | 
					
						
							|  |  |  |             for fish in self.content.fishes.values() | 
					
						
							|  |  |  |             if self.content.features.fishsanity.is_included(fish) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self.logic.and_(*rules) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_complete_collection(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.museum.can_complete_museum() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_full_house(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_greatest_walnut_hunter(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.walnut.has_walnut(130) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_protector_of_the_valley(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.monster.can_complete_all_monster_slaying_goals() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_full_shipment(self, all_location_names_in_slot: list[str]) -> StardewRule: | 
					
						
							|  |  |  |         if self.options.shipsanity == options.Shipsanity.option_none: | 
					
						
							|  |  |  |             return self.logic.shipping.can_ship_everything() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         rules = [self.logic.building.has_building(Building.shipping_bin)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for shipsanity_location in locations_by_tag[LocationTags.SHIPSANITY]: | 
					
						
							|  |  |  |             if shipsanity_location.name not in all_location_names_in_slot: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             rules.append(self.logic.region.can_reach_location(shipsanity_location.name)) | 
					
						
							|  |  |  |         return self.logic.and_(*rules) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_gourmet_chef(self) -> StardewRule: | 
					
						
							|  |  |  |         cooksanity_prefix = "Cook " | 
					
						
							|  |  |  |         all_recipes_names = [] | 
					
						
							|  |  |  |         exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true | 
					
						
							|  |  |  |         for location in locations_by_tag[LocationTags.COOKSANITY]: | 
					
						
							|  |  |  |             if exclude_island and LocationTags.GINGER_ISLAND in location.tags: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if location.mod_name and location.mod_name not in self.options.mods: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             all_recipes_names.append(location.name[len(cooksanity_prefix):]) | 
					
						
							|  |  |  |         all_recipes = [all_cooking_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] | 
					
						
							|  |  |  |         return self.logic.and_(*(self.logic.cooking.can_cook(recipe) for recipe in all_recipes)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_craft_master(self) -> StardewRule: | 
					
						
							|  |  |  |         craftsanity_prefix = "Craft " | 
					
						
							|  |  |  |         all_recipes_names = [] | 
					
						
							|  |  |  |         exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true | 
					
						
							|  |  |  |         exclude_masteries = not self.content.features.skill_progression.are_masteries_shuffled | 
					
						
							|  |  |  |         for location in locations_by_tag[LocationTags.CRAFTSANITY]: | 
					
						
							|  |  |  |             if not location.name.startswith(craftsanity_prefix): | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if exclude_island and LocationTags.GINGER_ISLAND in location.tags: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             # FIXME Remove when recipes are in content packs | 
					
						
							|  |  |  |             if exclude_masteries and LocationTags.REQUIRES_MASTERIES in location.tags: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             if location.mod_name and location.mod_name not in self.options.mods: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             all_recipes_names.append(location.name[len(craftsanity_prefix):]) | 
					
						
							|  |  |  |         all_recipes = [all_crafting_recipes_by_name[recipe_name] for recipe_name in all_recipes_names] | 
					
						
							|  |  |  |         return self.logic.and_(*(self.logic.crafting.can_craft(recipe) for recipe in all_recipes)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_legend(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.money.can_have_earned_total(10_000_000) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_mystery_of_the_stardrop(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.logic.fishing.can_catch_every_fish()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.options.festival_locations == options.FestivalLocations.option_disabled:  # Fair Stardrop | 
					
						
							|  |  |  |             other_rules.append(self.logic.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.logic.relationship.has_hearts_with_any_bachelor(13)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ModNames.deepwoods in self.options.mods:  # Petting the Unicorn | 
					
						
							|  |  |  |             number_of_stardrops_to_receive += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self.logic.received("Stardrop", number_of_stardrops_to_receive) & self.logic.and_(*other_rules, allow_empty=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_allsanity(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.has_progress_percent(100) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def can_complete_perfection(self) -> StardewRule: | 
					
						
							|  |  |  |         return self.logic.has_progress_percent(100) |