Stardew Valley: Refactor skill progression to use new feature system (#3662)

* create a first draft of the feature

* use feature in items and locations

* add content to more places

* use feature in logic

* replace option check by feature

* remove unused code

* remove weird white space

* some import nitpicking

* flip negative if
This commit is contained in:
Jouramie
2024-11-30 21:52:07 -05:00
committed by GitHub
parent f735416bda
commit a67688749f
21 changed files with 244 additions and 181 deletions

View File

@@ -16,7 +16,7 @@ from ..data.craftable_data import CraftingRecipe, all_crafting_recipes_by_name
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, SkillProgression
from ..options import Craftsanity, SpecialOrderLocations, ExcludeGingerIsland
from ..stardew_rule import StardewRule, True_, False_
from ..strings.region_names import Region
@@ -101,12 +101,13 @@ SkillLogicMixin, SpecialOrderLogicMixin, CraftingLogicMixin, QuestLogicMixin]]):
craftsanity_prefix = "Craft "
all_recipes_names = []
exclude_island = self.options.exclude_ginger_island == ExcludeGingerIsland.option_true
exclude_masteries = self.options.skill_progression != SkillProgression.option_progressive_with_masteries
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:

View File

@@ -7,7 +7,6 @@ from .has_logic import HasLogicMixin
from .received_logic import ReceivedLogicMixin
from .region_logic import RegionLogicMixin
from .time_logic import TimeLogicMixin
from ..options import Booksanity
from ..stardew_rule import StardewRule, HasProgressionPercent
from ..strings.book_names import Book
from ..strings.craftable_names import Consumable
@@ -39,7 +38,7 @@ class GrindLogic(BaseLogic[Union[GrindLogicMixin, HasLogicMixin, ReceivedLogicMi
opening_rule = self.logic.region.can_reach(Region.blacksmith)
mystery_box_rule = self.logic.has(Consumable.mystery_box)
book_of_mysteries_rule = self.logic.true_ \
if self.options.booksanity == Booksanity.option_none \
if not self.content.features.booksanity.is_enabled \
else self.logic.book.has_book_power(Book.book_of_mysteries)
# Assuming one box per day, but halved because we don't know how many months have passed before Mr. Qi's Plane Ride.
time_rule = self.logic.time.has_lived_months(quantity // 14)

View File

@@ -58,14 +58,19 @@ SkillLogicMixin, CookingLogicMixin]]):
rules = []
weapon_rule = self.logic.mine.get_weapon_rule_for_floor_tier(tier)
rules.append(weapon_rule)
if self.options.tool_progression & ToolProgression.option_progressive:
rules.append(self.logic.tool.has_tool(Tool.pickaxe, ToolMaterial.tiers[tier]))
if self.options.skill_progression >= options.SkillProgression.option_progressive:
skill_tier = min(10, max(0, tier * 2))
rules.append(self.logic.skill.has_level(Skill.combat, skill_tier))
rules.append(self.logic.skill.has_level(Skill.mining, skill_tier))
# No alternative for vanilla because we assume that you will grind the levels in the mines.
if self.content.features.skill_progression.is_progressive:
skill_level = min(10, max(0, tier * 2))
rules.append(self.logic.skill.has_level(Skill.combat, skill_level))
rules.append(self.logic.skill.has_level(Skill.mining, skill_level))
if tier >= 4:
rules.append(self.logic.cooking.can_cook())
return self.logic.and_(*rules)
@cache_self1
@@ -82,10 +87,14 @@ SkillLogicMixin, CookingLogicMixin]]):
rules = []
weapon_rule = self.logic.combat.has_great_weapon
rules.append(weapon_rule)
if self.options.tool_progression & ToolProgression.option_progressive:
rules.append(self.logic.received("Progressive Pickaxe", min(4, max(0, tier + 2))))
if self.options.skill_progression >= options.SkillProgression.option_progressive:
skill_tier = min(10, max(0, tier * 2 + 6))
rules.extend({self.logic.skill.has_level(Skill.combat, skill_tier),
self.logic.skill.has_level(Skill.mining, skill_tier)})
# No alternative for vanilla because we assume that you will grind the levels in the mines.
if self.content.features.skill_progression.is_progressive:
skill_level = min(10, max(0, tier * 2 + 6))
rules.extend((self.logic.skill.has_level(Skill.combat, skill_level),
self.logic.skill.has_level(Skill.mining, skill_level)))
return self.logic.and_(*rules)

View File

@@ -11,7 +11,6 @@ from .region_logic import RegionLogicMixin
from .season_logic import SeasonLogicMixin
from .time_logic import TimeLogicMixin
from .tool_logic import ToolLogicMixin
from .. import options
from ..data.harvest import HarvestCropSource
from ..mods.logic.magic_logic import MagicLogicMixin
from ..mods.logic.mod_skills_levels import get_mod_skill_levels
@@ -77,21 +76,21 @@ CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]):
if level == 0:
return true_
if self.options.skill_progression == options.SkillProgression.option_vanilla:
return self.logic.skill.can_earn_level(skill, level)
if self.content.features.skill_progression.is_progressive:
return self.logic.received(f"{skill} Level", level)
return self.logic.received(f"{skill} Level", level)
return self.logic.skill.can_earn_level(skill, level)
def has_previous_level(self, skill: str, level: int) -> StardewRule:
assert level > 0, f"There is no level before level 0."
if level == 1:
return true_
if self.options.skill_progression == options.SkillProgression.option_vanilla:
months = max(1, level - 1)
return self.logic.time.has_lived_months(months)
if self.content.features.skill_progression.is_progressive:
return self.logic.received(f"{skill} Level", level - 1)
return self.logic.received(f"{skill} Level", level - 1)
months = max(1, level - 1)
return self.logic.time.has_lived_months(months)
@cache_self1
def has_farming_level(self, level: int) -> StardewRule:
@@ -102,7 +101,7 @@ CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]):
if level <= 0:
return True_()
if self.options.skill_progression >= options.SkillProgression.option_progressive:
if self.content.features.skill_progression.is_progressive:
skills_items = vanilla_skill_items
if allow_modded_skills:
skills_items += get_mod_skill_levels(self.options.mods)
@@ -148,7 +147,7 @@ CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]):
@cached_property
def can_get_fishing_xp(self) -> StardewRule:
if self.options.skill_progression >= options.SkillProgression.option_progressive:
if self.content.features.skill_progression.is_progressive:
return self.logic.skill.can_fish() | self.logic.skill.can_crab_pot
return self.logic.skill.can_fish()
@@ -178,7 +177,9 @@ CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]):
@cached_property
def can_crab_pot(self) -> StardewRule:
crab_pot_rule = self.logic.has(Fishing.bait)
if self.options.skill_progression >= options.SkillProgression.option_progressive:
# We can't use the same rule if skills are vanilla, because fishing levels are required to crab pot, which is required to get fishing levels...
if self.content.features.skill_progression.is_progressive:
crab_pot_rule = crab_pot_rule & self.logic.has(Machine.crab_pot)
else:
crab_pot_rule = crab_pot_rule & self.logic.skill.can_get_fishing_xp
@@ -200,14 +201,14 @@ CombatLogicMixin, MagicLogicMixin, HarvestingLogicMixin]]):
return self.logic.skill.can_earn_level(skill, 11) & self.logic.region.can_reach(Region.mastery_cave)
def has_mastery(self, skill: str) -> StardewRule:
if self.options.skill_progression == options.SkillProgression.option_progressive_with_masteries:
if self.content.features.skill_progression.are_masteries_shuffled:
return self.logic.received(f"{skill} Mastery")
return self.logic.skill.can_earn_mastery(skill)
@cached_property
def can_enter_mastery_cave(self) -> StardewRule:
if self.options.skill_progression == options.SkillProgression.option_progressive_with_masteries:
if self.content.features.skill_progression.are_masteries_shuffled:
return self.logic.received(Wallet.mastery_of_the_five_ways)
return self.has_any_skills_maxed(included_modded_skills=False)