mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
Stardew Valley: Move all the goal logic into its own file (#4383)
This commit is contained in:
@@ -214,67 +214,67 @@ class StardewValleyWorld(World):
|
||||
def setup_victory(self):
|
||||
if self.options.goal == Goal.option_community_center:
|
||||
self.create_event_location(location_table[GoalName.community_center],
|
||||
self.logic.bundle.can_complete_community_center,
|
||||
self.logic.goal.can_complete_community_center(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_grandpa_evaluation:
|
||||
self.create_event_location(location_table[GoalName.grandpa_evaluation],
|
||||
self.logic.can_finish_grandpa_evaluation(),
|
||||
self.logic.goal.can_finish_grandpa_evaluation(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_bottom_of_the_mines:
|
||||
self.create_event_location(location_table[GoalName.bottom_of_the_mines],
|
||||
True_(),
|
||||
self.logic.goal.can_complete_bottom_of_the_mines(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_cryptic_note:
|
||||
self.create_event_location(location_table[GoalName.cryptic_note],
|
||||
self.logic.quest.can_complete_quest("Cryptic Note"),
|
||||
self.logic.goal.can_complete_cryptic_note(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_master_angler:
|
||||
self.create_event_location(location_table[GoalName.master_angler],
|
||||
self.logic.fishing.can_catch_every_fish_for_fishsanity(),
|
||||
self.logic.goal.can_complete_master_angler(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_complete_collection:
|
||||
self.create_event_location(location_table[GoalName.complete_museum],
|
||||
self.logic.museum.can_complete_museum(),
|
||||
self.logic.goal.can_complete_complete_collection(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_full_house:
|
||||
self.create_event_location(location_table[GoalName.full_house],
|
||||
(self.logic.relationship.has_children(2) & self.logic.relationship.can_reproduce()),
|
||||
self.logic.goal.can_complete_full_house(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_greatest_walnut_hunter:
|
||||
self.create_event_location(location_table[GoalName.greatest_walnut_hunter],
|
||||
self.logic.walnut.has_walnut(130),
|
||||
self.logic.goal.can_complete_greatest_walnut_hunter(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_protector_of_the_valley:
|
||||
self.create_event_location(location_table[GoalName.protector_of_the_valley],
|
||||
self.logic.monster.can_complete_all_monster_slaying_goals(),
|
||||
self.logic.goal.can_complete_protector_of_the_valley(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_full_shipment:
|
||||
self.create_event_location(location_table[GoalName.full_shipment],
|
||||
self.logic.shipping.can_ship_everything_in_slot(self.get_all_location_names()),
|
||||
self.logic.goal.can_complete_full_shipment(self.get_all_location_names()),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_gourmet_chef:
|
||||
self.create_event_location(location_table[GoalName.gourmet_chef],
|
||||
self.logic.cooking.can_cook_everything,
|
||||
self.logic.goal.can_complete_gourmet_chef(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_craft_master:
|
||||
self.create_event_location(location_table[GoalName.craft_master],
|
||||
self.logic.crafting.can_craft_everything,
|
||||
self.logic.goal.can_complete_craft_master(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_legend:
|
||||
self.create_event_location(location_table[GoalName.legend],
|
||||
self.logic.money.can_have_earned_total(10_000_000),
|
||||
self.logic.goal.can_complete_legend(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_mystery_of_the_stardrops:
|
||||
self.create_event_location(location_table[GoalName.mystery_of_the_stardrops],
|
||||
self.logic.has_all_stardrops(),
|
||||
self.logic.goal.can_complete_mystery_of_the_stardrop(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_allsanity:
|
||||
self.create_event_location(location_table[GoalName.allsanity],
|
||||
HasProgressionPercent(self.player, 100),
|
||||
self.logic.goal.can_complete_allsanity(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_perfection:
|
||||
self.create_event_location(location_table[GoalName.perfection],
|
||||
HasProgressionPercent(self.player, 100),
|
||||
self.logic.goal.can_complete_perfection(),
|
||||
Event.victory)
|
||||
|
||||
self.multiworld.completion_condition[self.player] = lambda state: state.has(Event.victory, self.player)
|
||||
|
@@ -13,12 +13,9 @@ from .relationship_logic import RelationshipLogicMixin
|
||||
from .season_logic import SeasonLogicMixin
|
||||
from .skill_logic import SkillLogicMixin
|
||||
from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \
|
||||
QueenOfSauceSource, CookingRecipe, ShopFriendshipSource, \
|
||||
all_cooking_recipes_by_name
|
||||
QueenOfSauceSource, CookingRecipe, ShopFriendshipSource
|
||||
from ..data.recipe_source import CutsceneSource, ShopTradeSource
|
||||
from ..locations import locations_by_tag, LocationTags
|
||||
from ..options import Chefsanity
|
||||
from ..options import ExcludeGingerIsland
|
||||
from ..stardew_rule import StardewRule, True_, False_
|
||||
from ..strings.region_names import LogicRegion
|
||||
from ..strings.skill_names import Skill
|
||||
@@ -92,17 +89,3 @@ BuildingLogicMixin, RelationshipLogicMixin, SkillLogicMixin, CookingLogicMixin]]
|
||||
@cache_self1
|
||||
def received_recipe(self, meal_name: str):
|
||||
return self.logic.received(f"{meal_name} Recipe")
|
||||
|
||||
@cached_property
|
||||
def can_cook_everything(self) -> StardewRule:
|
||||
cooksanity_prefix = "Cook "
|
||||
all_recipes_names = []
|
||||
exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true
|
||||
for location in locations_by_tag[LocationTags.COOKSANITY]:
|
||||
if exclude_island and LocationTags.GINGER_ISLAND in location.tags:
|
||||
continue
|
||||
if location.mod_name and location.mod_name not in self.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))
|
||||
|
@@ -1,4 +1,3 @@
|
||||
from functools import cached_property
|
||||
from typing import Union
|
||||
|
||||
from Utils import cache_self1
|
||||
@@ -12,11 +11,10 @@ from .relationship_logic import RelationshipLogicMixin
|
||||
from .skill_logic import SkillLogicMixin
|
||||
from .special_order_logic import SpecialOrderLogicMixin
|
||||
from .. import options
|
||||
from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name
|
||||
from ..data.craftable_data import CraftingRecipe
|
||||
from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \
|
||||
FestivalShopSource, QuestSource, StarterSource, ShopSource, SkillSource, MasterySource, FriendshipSource, SkillCraftsanitySource
|
||||
from ..locations import locations_by_tag, LocationTags
|
||||
from ..options import Craftsanity, SpecialOrderLocations, ExcludeGingerIsland
|
||||
from ..options import Craftsanity, SpecialOrderLocations
|
||||
from ..stardew_rule import StardewRule, True_, False_
|
||||
from ..strings.region_names import Region
|
||||
|
||||
@@ -71,7 +69,8 @@ SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin, QuestLogicMixin]]):
|
||||
if isinstance(recipe.source, ShopSource):
|
||||
return self.logic.money.can_spend_at(recipe.source.region, recipe.source.price)
|
||||
if isinstance(recipe.source, SkillCraftsanitySource):
|
||||
return self.logic.skill.has_level(recipe.source.skill, recipe.source.level) & self.logic.skill.can_earn_level(recipe.source.skill, recipe.source.level)
|
||||
return self.logic.skill.has_level(recipe.source.skill, recipe.source.level) & self.logic.skill.can_earn_level(recipe.source.skill,
|
||||
recipe.source.level)
|
||||
if isinstance(recipe.source, SkillSource):
|
||||
return self.logic.skill.has_level(recipe.source.skill, recipe.source.level)
|
||||
if isinstance(recipe.source, MasterySource):
|
||||
@@ -95,23 +94,3 @@ SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin, QuestLogicMixin]]):
|
||||
@cache_self1
|
||||
def received_recipe(self, item_name: str):
|
||||
return self.logic.received(f"{item_name} Recipe")
|
||||
|
||||
@cached_property
|
||||
def can_craft_everything(self) -> StardewRule:
|
||||
craftsanity_prefix = "Craft "
|
||||
all_recipes_names = []
|
||||
exclude_island = self.options.exclude_ginger_island == 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))
|
||||
|
@@ -29,7 +29,7 @@ class FishingLogicMixin(BaseLogicMixin):
|
||||
|
||||
|
||||
class FishingLogic(BaseLogic[Union[HasLogicMixin, FishingLogicMixin, ReceivedLogicMixin, RegionLogicMixin, SeasonLogicMixin, ToolLogicMixin,
|
||||
SkillLogicMixin]]):
|
||||
SkillLogicMixin]]):
|
||||
def can_fish_in_freshwater(self) -> StardewRule:
|
||||
return self.logic.skill.can_fish() & self.logic.region.can_reach_any((Region.forest, Region.town, Region.mountain))
|
||||
|
||||
@@ -97,19 +97,5 @@ class FishingLogic(BaseLogic[Union[HasLogicMixin, FishingLogicMixin, ReceivedLog
|
||||
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
def can_catch_every_fish_for_fishsanity(self) -> StardewRule:
|
||||
if not self.content.features.fishsanity.is_enabled:
|
||||
return self.can_catch_every_fish()
|
||||
|
||||
rules = [self.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 has_specific_bait(self, fish: FishItem) -> StardewRule:
|
||||
return self.can_catch_fish(fish) & self.logic.has(Machine.bait_maker)
|
||||
|
173
worlds/stardew_valley/logic/goal_logic.py
Normal file
173
worlds/stardew_valley/logic/goal_logic.py
Normal file
@@ -0,0 +1,173 @@
|
||||
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
|
||||
self.logic.relationship.can_get_married() & self.logic.building.has_house(2),
|
||||
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)
|
@@ -1,5 +1,5 @@
|
||||
from .base_logic import BaseLogic
|
||||
from ..stardew_rule import StardewRule, And, Or, Has, Count, true_, false_
|
||||
from ..stardew_rule import StardewRule, And, Or, Has, Count, true_, false_, HasProgressionPercent
|
||||
|
||||
|
||||
class HasLogicMixin(BaseLogic[None]):
|
||||
@@ -23,6 +23,12 @@ class HasLogicMixin(BaseLogic[None]):
|
||||
def has_n(self, *items: str, count: int):
|
||||
return self.count(count, *(self.has(item) for item in items))
|
||||
|
||||
def has_progress_percent(self, percent: int):
|
||||
assert percent >= 0, "Can't have a negative progress percent"
|
||||
assert percent <= 100, "Can't have a progress percent over 100"
|
||||
|
||||
return HasProgressionPercent(self.player, percent)
|
||||
|
||||
@staticmethod
|
||||
def count(count: int, *rules: StardewRule) -> StardewRule:
|
||||
assert rules, "Can't create a Count conditions without rules"
|
||||
@@ -47,8 +53,14 @@ class HasLogicMixin(BaseLogic[None]):
|
||||
return Count(rules, count)
|
||||
|
||||
@staticmethod
|
||||
def and_(*rules: StardewRule) -> StardewRule:
|
||||
assert rules, "Can't create a And conditions without rules"
|
||||
def and_(*rules: StardewRule, allow_empty: bool = False) -> StardewRule:
|
||||
"""
|
||||
:param rules: The rules to combine
|
||||
:param allow_empty: If True, return true_ when no rules are given. Otherwise, raise an error.
|
||||
"""
|
||||
if not rules:
|
||||
assert allow_empty, "Can't create a And conditions without rules"
|
||||
return true_
|
||||
|
||||
if len(rules) == 1:
|
||||
return rules[0]
|
||||
@@ -56,8 +68,14 @@ class HasLogicMixin(BaseLogic[None]):
|
||||
return And(*rules)
|
||||
|
||||
@staticmethod
|
||||
def or_(*rules: StardewRule) -> StardewRule:
|
||||
assert rules, "Can't create a Or conditions without rules"
|
||||
def or_(*rules: StardewRule, allow_empty: bool = False) -> StardewRule:
|
||||
"""
|
||||
:param rules: The rules to combine
|
||||
:param allow_empty: If True, return false_ when no rules are given. Otherwise, raise an error.
|
||||
"""
|
||||
if not rules:
|
||||
assert allow_empty, "Can't create a Or conditions without rules"
|
||||
return false_
|
||||
|
||||
if len(rules) == 1:
|
||||
return rules[0]
|
||||
|
@@ -19,6 +19,7 @@ from .farming_logic import FarmingLogicMixin
|
||||
from .festival_logic import FestivalLogicMixin
|
||||
from .fishing_logic import FishingLogicMixin
|
||||
from .gift_logic import GiftLogicMixin
|
||||
from .goal_logic import GoalLogicMixin
|
||||
from .grind_logic import GrindLogicMixin
|
||||
from .harvesting_logic import HarvestingLogicMixin
|
||||
from .has_logic import HasLogicMixin
|
||||
@@ -50,8 +51,7 @@ from ..data.museum_data import all_museum_items
|
||||
from ..data.recipe_data import all_cooking_recipes
|
||||
from ..mods.logic.magic_logic import MagicLogicMixin
|
||||
from ..mods.logic.mod_logic import ModLogicMixin
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..options import ExcludeGingerIsland, FestivalLocations, StardewValleyOptions
|
||||
from ..options import ExcludeGingerIsland, StardewValleyOptions
|
||||
from ..stardew_rule import False_, True_, StardewRule
|
||||
from ..strings.animal_names import Animal
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
@@ -93,7 +93,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin,
|
||||
SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin,
|
||||
SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin,
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, FestivalLogicMixin, WalnutLogicMixin):
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, FestivalLogicMixin, WalnutLogicMixin, GoalLogicMixin):
|
||||
player: int
|
||||
options: StardewValleyOptions
|
||||
content: StardewContent
|
||||
@@ -375,71 +375,11 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
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 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_abandoned_jojamart(self) -> StardewRule:
|
||||
return self.received(CommunityUpgrade.movie_theater, 1)
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
from functools import cached_property
|
||||
from typing import Union, List
|
||||
from typing import Union
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
@@ -8,7 +8,7 @@ from .has_logic import HasLogicMixin
|
||||
from .received_logic import ReceivedLogicMixin
|
||||
from .region_logic import RegionLogicMixin
|
||||
from ..locations import LocationTags, locations_by_tag
|
||||
from ..options import ExcludeGingerIsland, Shipsanity
|
||||
from ..options import ExcludeGingerIsland
|
||||
from ..options import SpecialOrderLocations
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.building_names import Building
|
||||
@@ -45,15 +45,3 @@ class ShippingLogic(BaseLogic[Union[ReceivedLogicMixin, ShippingLogicMixin, Buil
|
||||
continue
|
||||
all_items_to_ship.append(location.name[len(shipsanity_prefix):])
|
||||
return self.logic.building.has_building(Building.shipping_bin) & self.logic.has_all(*all_items_to_ship)
|
||||
|
||||
def can_ship_everything_in_slot(self, all_location_names_in_slot: List[str]) -> StardewRule:
|
||||
if self.options.shipsanity == Shipsanity.option_none:
|
||||
return self.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)
|
||||
|
Reference in New Issue
Block a user