Stardew Valley: Add void mayo requirement for Goblin Problem quest (#4933)

This adds the requirement of a void mayo for the Goblin Problem quest. There are also some small adjustments to related rules
- Fishing a void mayo is only considered an option during the Goblin Problem quest, as the odds of finding one after the quest drops drastically.
- Entrance to the witch hut now requires the goblin problem quest, not just a void mayo.
- Fishing rules are all moved to `fishing_logic.py`.
- `can_fish_at` no longer check that you have any of the fishing regions and the region you actually want to fish in.
- created `can_fish_anywhere` and `can_crab_pot_anywhere` to better illustrate when any fish satisfies the rule.
This commit is contained in:
Jérémie Bolduc
2025-05-04 10:28:38 -04:00
committed by GitHub
parent 68e37b8f9a
commit b2d2c8e596
9 changed files with 86 additions and 78 deletions

View File

@@ -154,7 +154,7 @@ class FestivalLogic(BaseLogic):
# Salads at the bar are good enough
cooking_rule = self.logic.money.can_spend_at(Region.saloon, 220)
fish_rule = self.logic.skill.can_fish(difficulty=50)
fish_rule = self.logic.fishing.can_fish_anywhere(50)
# Hazelnut always available since the grange display is in fall
forage_rule = self.logic.region.can_reach_any((Region.forest, Region.backwoods))
@@ -179,7 +179,7 @@ class FestivalLogic(BaseLogic):
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.logic.skill.can_fish(difficulty=60)
return self.logic.fishing.can_fish(60)
def has_all_rarecrows(self) -> StardewRule:
rules = []

View File

@@ -1,3 +1,5 @@
from functools import cached_property
from Utils import cache_self1
from .base_logic import BaseLogicMixin, BaseLogic
from ..data import fish_data
@@ -12,6 +14,8 @@ from ..strings.quality_names import FishQuality
from ..strings.region_names import Region
from ..strings.skill_names import Skill
fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west)
class FishingLogicMixin(BaseLogicMixin):
def __init__(self, *args, **kwargs):
@@ -20,17 +24,35 @@ class FishingLogicMixin(BaseLogicMixin):
class FishingLogic(BaseLogic):
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))
@cache_self1
def can_fish_anywhere(self, difficulty: int = 0) -> StardewRule:
return self.logic.fishing.can_fish(difficulty) & self.logic.region.can_reach_any(fishing_regions)
def can_fish_in_freshwater(self) -> StardewRule:
return self.logic.fishing.can_fish() & self.logic.region.can_reach_any((Region.forest, Region.town, Region.mountain))
@cached_property
def has_max_fishing(self) -> StardewRule:
return self.logic.tool.has_fishing_rod(4) & self.logic.skill.has_level(Skill.fishing, 10)
@cached_property
def can_fish_chests(self) -> StardewRule:
return self.logic.tool.has_fishing_rod(4) & self.logic.skill.has_level(Skill.fishing, 6)
@cache_self1
def can_fish_at(self, region: str) -> StardewRule:
return self.logic.skill.can_fish() & self.logic.region.can_reach(region)
return self.logic.fishing.can_fish() & self.logic.region.can_reach(region)
@cache_self1
def can_fish(self, difficulty: int = 0) -> StardewRule:
skill_required = min(10, max(0, int((difficulty / 10) - 1)))
if difficulty <= 40:
skill_required = 0
skill_rule = self.logic.skill.has_level(Skill.fishing, skill_required)
# Training rod only works with fish < 50. Fiberglass does not help you to catch higher difficulty fish, so it's skipped in logic.
number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4)
return self.logic.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule
@cache_self1
def can_catch_fish(self, fish: FishItem) -> StardewRule:
@@ -39,14 +61,17 @@ class FishingLogic(BaseLogic):
quest_rule = self.logic.fishing.can_start_extended_family_quest()
region_rule = self.logic.region.can_reach_any(fish.locations)
season_rule = self.logic.season.has_any(fish.seasons)
if fish.difficulty == -1:
difficulty_rule = self.logic.skill.can_crab_pot
difficulty_rule = self.logic.fishing.can_crab_pot
else:
difficulty_rule = self.logic.skill.can_fish(difficulty=(120 if fish.legendary else fish.difficulty))
difficulty_rule = self.logic.fishing.can_fish(120 if fish.legendary else fish.difficulty)
if fish.name == SVEFish.kittyfish:
item_rule = self.logic.received(SVEQuestItem.kittyfish_spell)
else:
item_rule = True_()
return quest_rule & region_rule & season_rule & difficulty_rule & item_rule
def can_catch_fish_for_fishsanity(self, fish: FishItem) -> StardewRule:
@@ -78,7 +103,7 @@ class FishingLogic(BaseLogic):
return self.logic.tool.has_fishing_rod(4) & self.logic.has(tackle)
def can_catch_every_fish(self) -> StardewRule:
rules = [self.has_max_fishing()]
rules = [self.has_max_fishing]
rules.extend(
self.logic.fishing.can_catch_fish(fish)
@@ -89,3 +114,23 @@ class FishingLogic(BaseLogic):
def has_specific_bait(self, fish: FishItem) -> StardewRule:
return self.can_catch_fish(fish) & self.logic.has(Machine.bait_maker)
@cached_property
def can_crab_pot_anywhere(self) -> StardewRule:
return self.logic.fishing.can_fish() & self.logic.region.can_reach_any(fishing_regions)
@cache_self1
def can_crab_pot_at(self, region: str) -> StardewRule:
return self.logic.fishing.can_crab_pot & self.logic.region.can_reach(region)
@cached_property
def can_crab_pot(self) -> StardewRule:
crab_pot_rule = self.logic.has(Fishing.bait)
# 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
return crab_pot_rule

View File

@@ -60,7 +60,7 @@ class GoalLogic(BaseLogic):
if not self.content.features.fishsanity.is_enabled:
return self.logic.fishing.can_catch_every_fish()
rules = [self.logic.fishing.has_max_fishing()]
rules = [self.logic.fishing.has_max_fishing]
rules.extend(
self.logic.fishing.can_catch_fish_for_fishsanity(fish)

View File

@@ -130,9 +130,9 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
# @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(),
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),
@@ -164,7 +164,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
AnimalProduct.large_milk: self.animal.has_happy_animal(Animal.cow),
AnimalProduct.milk: self.animal.has_animal(Animal.cow),
AnimalProduct.rabbit_foot: self.animal.has_happy_animal(Animal.rabbit),
AnimalProduct.roe: self.skill.can_fish() & self.building.has_building(Building.fish_pond),
AnimalProduct.roe: self.fishing.can_fish_anywhere() & 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(),
@@ -198,7 +198,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
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)),
ArtisanGood.void_mayonnaise: 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),
@@ -217,15 +217,15 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
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.crab: self.fishing.can_crab_pot_at(Region.beach),
Fish.crayfish: self.fishing.can_crab_pot_at(Region.town),
Fish.lobster: self.fishing.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),
Fish.periwinkle: self.fishing.can_crab_pot_at(Region.town),
Fish.shrimp: self.fishing.can_crab_pot_at(Region.beach),
Fish.snail: self.fishing.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), #
@@ -235,7 +235,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
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_spine: self.fishing.can_fish_at(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),
@@ -296,12 +296,12 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
RetainingSoil.quality: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150),
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.broken_cd: self.fishing.can_crab_pot_anywhere,
Trash.broken_glasses: self.fishing.can_crab_pot_anywhere,
Trash.driftwood: self.fishing.can_crab_pot_anywhere,
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,
Trash.soggy_newspaper: self.fishing.can_crab_pot_anywhere,
Trash.trash: self.fishing.can_crab_pot_anywhere,
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(),
@@ -314,8 +314,8 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
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),
WaterItem.seaweed: self.fishing.can_fish_at(Region.tide_pools),
WaterItem.white_algae: self.fishing.can_fish_at(Region.mines_floor_20),
WildSeeds.grass_starter: self.money.can_spend_at(Region.pierre_store, 100),
})
# @formatter:on

View File

@@ -39,7 +39,7 @@ class QuestLogic(BaseLogic):
Quest.raising_animals: self.logic.quest.can_complete_quest(Quest.getting_started) & self.logic.building.has_building(Building.coop),
Quest.feeding_animals: self.logic.quest.can_complete_quest(Quest.getting_started) & self.logic.building.has_building(Building.silo),
Quest.advancement: self.logic.quest.can_complete_quest(Quest.getting_started) & self.logic.has(Craftable.scarecrow),
Quest.archaeology: self.logic.tool.has_tool(Tool.hoe) | self.logic.mine.can_mine_in_the_mines_floor_1_40() | self.logic.skill.can_fish(),
Quest.archaeology: self.logic.tool.has_tool(Tool.hoe) | self.logic.mine.can_mine_in_the_mines_floor_1_40() | self.logic.fishing.can_fish_chests,
Quest.rat_problem: self.logic.region.can_reach_all((Region.town, Region.community_center)),
Quest.meet_the_wizard: self.logic.quest.can_complete_quest(Quest.rat_problem),
Quest.forging_ahead: self.logic.has(Ore.copper) & self.logic.has(Machine.furnace),
@@ -86,7 +86,9 @@ class QuestLogic(BaseLogic):
Quest.catch_a_lingcod: self.logic.season.has(Season.winter) & self.logic.has(Fish.lingcod) & self.logic.relationship.can_meet(NPC.willy),
Quest.dark_talisman: self.logic.region.can_reach(Region.railroad) & self.logic.wallet.has_rusty_key() & self.logic.relationship.can_meet(
NPC.krobus),
Quest.goblin_problem: self.logic.region.can_reach(Region.witch_swamp),
Quest.goblin_problem: self.logic.region.can_reach(Region.witch_swamp)
# Void mayo can be fished at 5% chance in the witch swamp while the quest is active. It drops a lot after the quest.
& (self.logic.has(ArtisanGood.void_mayonnaise) | self.logic.fishing.can_fish()),
Quest.magic_ink: self.logic.relationship.can_meet(NPC.wizard),
Quest.the_pirates_wife: self.logic.relationship.can_meet(NPC.kent) & self.logic.relationship.can_meet(NPC.gus) &
self.logic.relationship.can_meet(NPC.sandy) & self.logic.relationship.can_meet(NPC.george) &

View File

@@ -1,13 +1,10 @@
from functools import cached_property
from typing import Union, Tuple
from Utils import cache_self1
from .base_logic import BaseLogicMixin, BaseLogic
from ..data.harvest import HarvestCropSource
from ..mods.logic.mod_skills_levels import get_mod_skill_levels
from ..stardew_rule import StardewRule, true_, True_, False_
from ..strings.craftable_names import Fishing
from ..strings.machine_names import Machine
from ..strings.performance_names import Performance
from ..strings.quality_names import ForageQuality
from ..strings.region_names import Region
@@ -15,7 +12,6 @@ from ..strings.skill_names import Skill, all_mod_skills, all_vanilla_skills
from ..strings.tool_names import ToolMaterial, Tool
from ..strings.wallet_item_names import Wallet
fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west)
vanilla_skill_items = ("Farming Level", "Mining Level", "Foraging Level", "Fishing Level", "Combat Level")
@@ -138,44 +134,9 @@ class SkillLogic(BaseLogic):
@cached_property
def can_get_fishing_xp(self) -> StardewRule:
if self.content.features.skill_progression.is_progressive:
return self.logic.skill.can_fish() | self.logic.skill.can_crab_pot
return self.logic.fishing.can_fish_anywhere() | self.logic.fishing.can_crab_pot
return self.logic.skill.can_fish()
# Should be cached
def can_fish(self, regions: Union[str, Tuple[str, ...]] = None, difficulty: int = 0) -> StardewRule:
if isinstance(regions, str):
regions = regions,
if regions is None or len(regions) == 0:
regions = fishing_regions
skill_required = min(10, max(0, int((difficulty / 10) - 1)))
if difficulty <= 40:
skill_required = 0
skill_rule = self.logic.skill.has_level(Skill.fishing, skill_required)
region_rule = self.logic.region.can_reach_any(regions)
# Training rod only works with fish < 50. Fiberglass does not help you to catch higher difficulty fish, so it's skipped in logic.
number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4)
return self.logic.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule & region_rule
@cache_self1
def can_crab_pot_at(self, region: str) -> StardewRule:
return self.logic.skill.can_crab_pot & self.logic.region.can_reach(region)
@cached_property
def can_crab_pot(self) -> StardewRule:
crab_pot_rule = self.logic.has(Fishing.bait)
# 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
water_region_rules = self.logic.region.can_reach_any(fishing_regions)
return crab_pot_rule & water_region_rules
return self.logic.fishing.can_fish_anywhere()
def can_forage_quality(self, quality: str) -> StardewRule:
if quality == ForageQuality.basic:

View File

@@ -42,7 +42,7 @@ class SpecialOrderLogic(BaseLogic):
SpecialOrder.fragments_of_the_past: self.logic.monster.can_kill(Monster.skeleton),
SpecialOrder.gus_famous_omelet: self.logic.has(AnimalProduct.any_egg),
SpecialOrder.crop_order: self.logic.ability.can_farm_perfectly() & self.logic.shipping.can_use_shipping_bin,
SpecialOrder.community_cleanup: self.logic.skill.can_crab_pot,
SpecialOrder.community_cleanup: self.logic.fishing.can_crab_pot_anywhere,
SpecialOrder.the_strong_stuff: self.logic.has(ArtisanGood.specific_juice(Vegetable.potato)),
SpecialOrder.pierres_prime_produce: self.logic.ability.can_farm_perfectly(),
SpecialOrder.robins_project: self.logic.relationship.can_meet(NPC.robin) & self.logic.ability.can_chop_perfectly() &

View File

@@ -44,9 +44,9 @@ class ModSkillLogic(BaseLogic):
def can_earn_luck_skill_level(self, level: int) -> StardewRule:
if level >= 6:
return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.magma)
return self.logic.fishing.can_fish_chests | self.logic.action.can_open_geode(Geode.magma)
if level >= 3:
return self.logic.fishing.can_fish_chests() | self.logic.action.can_open_geode(Geode.geode)
return self.logic.fishing.can_fish_chests | self.logic.action.can_open_geode(Geode.geode)
return True_() # You can literally wake up and or get them by opening starting chests.
def can_earn_magic_skill_level(self, level: int) -> StardewRule:

View File

@@ -214,7 +214,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S
set_entrance_rule(multiworld, player, Entrance.mountain_to_railroad, logic.received("Railroad Boulder Removed"))
set_entrance_rule(multiworld, player, Entrance.enter_witch_warp_cave, logic.quest.has_dark_talisman() | (logic.mod.magic.can_blink()))
set_entrance_rule(multiworld, player, Entrance.enter_witch_hut, (logic.has(ArtisanGood.void_mayonnaise) | logic.mod.magic.can_blink()))
set_entrance_rule(multiworld, player, Entrance.enter_witch_hut, (logic.quest.can_complete_quest(Quest.goblin_problem) | logic.mod.magic.can_blink()))
set_entrance_rule(multiworld, player, Entrance.enter_mutant_bug_lair,
(logic.wallet.has_rusty_key() & logic.region.can_reach(Region.railroad) & logic.relationship.can_meet(
NPC.krobus)) | logic.mod.magic.can_blink())
@@ -923,9 +923,9 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i
set_rule(multiworld.get_location("Analyze: Fireball", player),
logic.has("Fire Quartz"))
set_rule(multiworld.get_location("Analyze: Frostbolt", player),
logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85))
logic.region.can_reach(Region.mines_floor_60) & logic.fishing.can_fish(85))
set_rule(multiworld.get_location("Analyze All Elemental School Locations", player),
logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.skill.can_fish(difficulty=85))
logic.has("Fire Quartz") & logic.region.can_reach(Region.mines_floor_60) & logic.fishing.can_fish(85))
# set_rule(multiworld.get_location("Analyze: Lantern", player),)
set_rule(multiworld.get_location("Analyze: Tendrils", player),
logic.region.can_reach(Region.farm))
@@ -948,7 +948,7 @@ def set_magic_spell_rules(logic: StardewLogic, multiworld: MultiWorld, player: i
& (logic.tool.has_tool("Axe", "Basic") | logic.tool.has_tool("Pickaxe", "Basic")) &
logic.has("Coffee") & logic.has("Life Elixir")
& logic.ability.can_mine_perfectly() & logic.has("Earth Crystal") &
logic.has("Fire Quartz") & logic.skill.can_fish(difficulty=85) &
logic.has("Fire Quartz") & logic.fishing.can_fish(85) &
logic.region.can_reach(Region.witch_hut) &
logic.region.can_reach(Region.mines_floor_100) &
logic.region.can_reach(Region.farm) & logic.time.has_lived_months(12)))