Stardew Valley 6.x.x: The Content Update (#3478)
Focus of the Update: Compatibility with Stardew Valley 1.6 Released on March 19th 2024 This includes randomization for pretty much all of the new content, including but not limited to - Raccoon Bundles - Booksanity - Skill Masteries - New Recipes, Craftables, Fish, Maps, Farm Type, Festivals and Quests This also includes a significant reorganisation of the code into "Content Packs", to allow for easier modularity of various game mechanics between the settings and the supported mods. This improves maintainability quite a bit. In addition to that, a few **very** requested new features have been introduced, although they weren't the focus of this update - Walnutsanity - Player Buffs - More customizability in settings, such as shorter special orders, ER without farmhouse - New Remixed Bundles
This commit is contained in:
107
worlds/stardew_valley/content/__init__.py
Normal file
107
worlds/stardew_valley/content/__init__.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from . import content_packs
|
||||
from .feature import cropsanity, friendsanity, fishsanity, booksanity
|
||||
from .game_content import ContentPack, StardewContent, StardewFeatures
|
||||
from .unpacking import unpack_content
|
||||
from .. import options
|
||||
|
||||
|
||||
def create_content(player_options: options.StardewValleyOptions) -> StardewContent:
|
||||
active_packs = choose_content_packs(player_options)
|
||||
features = choose_features(player_options)
|
||||
return unpack_content(features, active_packs)
|
||||
|
||||
|
||||
def choose_content_packs(player_options: options.StardewValleyOptions):
|
||||
active_packs = [content_packs.pelican_town, content_packs.the_desert, content_packs.the_farm, content_packs.the_mines]
|
||||
|
||||
if player_options.exclude_ginger_island == options.ExcludeGingerIsland.option_false:
|
||||
active_packs.append(content_packs.ginger_island_content_pack)
|
||||
|
||||
if player_options.special_order_locations & options.SpecialOrderLocations.value_qi:
|
||||
active_packs.append(content_packs.qi_board_content_pack)
|
||||
|
||||
for mod in player_options.mods.value:
|
||||
active_packs.append(content_packs.by_mod[mod])
|
||||
|
||||
return active_packs
|
||||
|
||||
|
||||
def choose_features(player_options: options.StardewValleyOptions) -> StardewFeatures:
|
||||
return StardewFeatures(
|
||||
choose_booksanity(player_options.booksanity),
|
||||
choose_cropsanity(player_options.cropsanity),
|
||||
choose_fishsanity(player_options.fishsanity),
|
||||
choose_friendsanity(player_options.friendsanity, player_options.friendsanity_heart_size)
|
||||
)
|
||||
|
||||
|
||||
booksanity_by_option = {
|
||||
options.Booksanity.option_none: booksanity.BooksanityDisabled(),
|
||||
options.Booksanity.option_power: booksanity.BooksanityPower(),
|
||||
options.Booksanity.option_power_skill: booksanity.BooksanityPowerSkill(),
|
||||
options.Booksanity.option_all: booksanity.BooksanityAll(),
|
||||
}
|
||||
|
||||
|
||||
def choose_booksanity(booksanity_option: options.Booksanity) -> booksanity.BooksanityFeature:
|
||||
booksanity_feature = booksanity_by_option.get(booksanity_option)
|
||||
|
||||
if booksanity_feature is None:
|
||||
raise ValueError(f"No booksanity feature mapped to {str(booksanity_option.value)}")
|
||||
|
||||
return booksanity_feature
|
||||
|
||||
|
||||
cropsanity_by_option = {
|
||||
options.Cropsanity.option_disabled: cropsanity.CropsanityDisabled(),
|
||||
options.Cropsanity.option_enabled: cropsanity.CropsanityEnabled(),
|
||||
}
|
||||
|
||||
|
||||
def choose_cropsanity(cropsanity_option: options.Cropsanity) -> cropsanity.CropsanityFeature:
|
||||
cropsanity_feature = cropsanity_by_option.get(cropsanity_option)
|
||||
|
||||
if cropsanity_feature is None:
|
||||
raise ValueError(f"No cropsanity feature mapped to {str(cropsanity_option.value)}")
|
||||
|
||||
return cropsanity_feature
|
||||
|
||||
|
||||
fishsanity_by_option = {
|
||||
options.Fishsanity.option_none: fishsanity.FishsanityNone(),
|
||||
options.Fishsanity.option_legendaries: fishsanity.FishsanityLegendaries(),
|
||||
options.Fishsanity.option_special: fishsanity.FishsanitySpecial(),
|
||||
options.Fishsanity.option_randomized: fishsanity.FishsanityAll(randomization_ratio=0.4),
|
||||
options.Fishsanity.option_all: fishsanity.FishsanityAll(),
|
||||
options.Fishsanity.option_exclude_legendaries: fishsanity.FishsanityExcludeLegendaries(),
|
||||
options.Fishsanity.option_exclude_hard_fish: fishsanity.FishsanityExcludeHardFish(),
|
||||
options.Fishsanity.option_only_easy_fish: fishsanity.FishsanityOnlyEasyFish(),
|
||||
}
|
||||
|
||||
|
||||
def choose_fishsanity(fishsanity_option: options.Fishsanity) -> fishsanity.FishsanityFeature:
|
||||
fishsanity_feature = fishsanity_by_option.get(fishsanity_option)
|
||||
|
||||
if fishsanity_feature is None:
|
||||
raise ValueError(f"No fishsanity feature mapped to {str(fishsanity_option.value)}")
|
||||
|
||||
return fishsanity_feature
|
||||
|
||||
|
||||
def choose_friendsanity(friendsanity_option: options.Friendsanity, heart_size: options.FriendsanityHeartSize) -> friendsanity.FriendsanityFeature:
|
||||
if friendsanity_option == options.Friendsanity.option_none:
|
||||
return friendsanity.FriendsanityNone()
|
||||
|
||||
if friendsanity_option == options.Friendsanity.option_bachelors:
|
||||
return friendsanity.FriendsanityBachelors(heart_size.value)
|
||||
|
||||
if friendsanity_option == options.Friendsanity.option_starting_npcs:
|
||||
return friendsanity.FriendsanityStartingNpc(heart_size.value)
|
||||
|
||||
if friendsanity_option == options.Friendsanity.option_all:
|
||||
return friendsanity.FriendsanityAll(heart_size.value)
|
||||
|
||||
if friendsanity_option == options.Friendsanity.option_all_with_marriage:
|
||||
return friendsanity.FriendsanityAllWithMarriage(heart_size.value)
|
||||
|
||||
raise ValueError(f"No friendsanity feature mapped to {str(friendsanity_option.value)}")
|
||||
31
worlds/stardew_valley/content/content_packs.py
Normal file
31
worlds/stardew_valley/content/content_packs.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import importlib
|
||||
import pkgutil
|
||||
|
||||
from . import mods
|
||||
from .mod_registry import by_mod
|
||||
from .vanilla.base import base_game
|
||||
from .vanilla.ginger_island import ginger_island_content_pack
|
||||
from .vanilla.pelican_town import pelican_town
|
||||
from .vanilla.qi_board import qi_board_content_pack
|
||||
from .vanilla.the_desert import the_desert
|
||||
from .vanilla.the_farm import the_farm
|
||||
from .vanilla.the_mines import the_mines
|
||||
|
||||
assert base_game
|
||||
assert ginger_island_content_pack
|
||||
assert pelican_town
|
||||
assert qi_board_content_pack
|
||||
assert the_desert
|
||||
assert the_farm
|
||||
assert the_mines
|
||||
|
||||
# Dynamically register everything currently in the mods folder. This would ideally be done through a metaclass, but I have not looked into that yet.
|
||||
mod_modules = pkgutil.iter_modules(mods.__path__)
|
||||
|
||||
loaded_modules = {}
|
||||
for mod_module in mod_modules:
|
||||
module_name = mod_module.name
|
||||
module = importlib.import_module("." + module_name, mods.__name__)
|
||||
loaded_modules[module_name] = module
|
||||
|
||||
assert by_mod
|
||||
4
worlds/stardew_valley/content/feature/__init__.py
Normal file
4
worlds/stardew_valley/content/feature/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from . import booksanity
|
||||
from . import cropsanity
|
||||
from . import fishsanity
|
||||
from . import friendsanity
|
||||
72
worlds/stardew_valley/content/feature/booksanity.py
Normal file
72
worlds/stardew_valley/content/feature/booksanity.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, Optional, Iterable
|
||||
|
||||
from ...data.game_item import GameItem, ItemTag
|
||||
from ...strings.book_names import ordered_lost_books
|
||||
|
||||
item_prefix = "Power: "
|
||||
location_prefix = "Read "
|
||||
|
||||
|
||||
def to_item_name(book: str) -> str:
|
||||
return item_prefix + book
|
||||
|
||||
|
||||
def to_location_name(book: str) -> str:
|
||||
return location_prefix + book
|
||||
|
||||
|
||||
def extract_book_from_location_name(location_name: str) -> Optional[str]:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(location_prefix):]
|
||||
|
||||
|
||||
class BooksanityFeature(ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
to_item_name = staticmethod(to_item_name)
|
||||
progressive_lost_book = "Progressive Lost Book"
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
extract_book_from_location_name = staticmethod(extract_book_from_location_name)
|
||||
|
||||
@abstractmethod
|
||||
def is_included(self, book: GameItem) -> bool:
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def get_randomized_lost_books() -> Iterable[str]:
|
||||
return []
|
||||
|
||||
|
||||
class BooksanityDisabled(BooksanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
def is_included(self, book: GameItem) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class BooksanityPower(BooksanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, book: GameItem) -> bool:
|
||||
return ItemTag.BOOK_POWER in book.tags
|
||||
|
||||
|
||||
class BooksanityPowerSkill(BooksanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, book: GameItem) -> bool:
|
||||
return ItemTag.BOOK_POWER in book.tags or ItemTag.BOOK_SKILL in book.tags
|
||||
|
||||
|
||||
class BooksanityAll(BooksanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, book: GameItem) -> bool:
|
||||
return ItemTag.BOOK_POWER in book.tags or ItemTag.BOOK_SKILL in book.tags
|
||||
|
||||
@staticmethod
|
||||
def get_randomized_lost_books() -> Iterable[str]:
|
||||
return ordered_lost_books
|
||||
42
worlds/stardew_valley/content/feature/cropsanity.py
Normal file
42
worlds/stardew_valley/content/feature/cropsanity.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, Optional
|
||||
|
||||
from ...data.game_item import GameItem, ItemTag
|
||||
|
||||
location_prefix = "Harvest "
|
||||
|
||||
|
||||
def to_location_name(crop: str) -> str:
|
||||
return location_prefix + crop
|
||||
|
||||
|
||||
def extract_crop_from_location_name(location_name: str) -> Optional[str]:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(location_prefix):]
|
||||
|
||||
|
||||
class CropsanityFeature(ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
extract_crop_from_location_name = staticmethod(extract_crop_from_location_name)
|
||||
|
||||
@abstractmethod
|
||||
def is_included(self, crop: GameItem) -> bool:
|
||||
...
|
||||
|
||||
|
||||
class CropsanityDisabled(CropsanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
def is_included(self, crop: GameItem) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class CropsanityEnabled(CropsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, crop: GameItem) -> bool:
|
||||
return ItemTag.CROPSANITY_SEED in crop.tags
|
||||
101
worlds/stardew_valley/content/feature/fishsanity.py
Normal file
101
worlds/stardew_valley/content/feature/fishsanity.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar, Optional
|
||||
|
||||
from ...data.fish_data import FishItem
|
||||
from ...strings.fish_names import Fish
|
||||
|
||||
location_prefix = "Fishsanity: "
|
||||
|
||||
|
||||
def to_location_name(fish: str) -> str:
|
||||
return location_prefix + fish
|
||||
|
||||
|
||||
def extract_fish_from_location_name(location_name: str) -> Optional[str]:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(location_prefix):]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FishsanityFeature(ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
randomization_ratio: float = 1
|
||||
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
extract_fish_from_location_name = staticmethod(extract_fish_from_location_name)
|
||||
|
||||
@property
|
||||
def is_randomized(self) -> bool:
|
||||
return self.randomization_ratio != 1
|
||||
|
||||
@abstractmethod
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
...
|
||||
|
||||
|
||||
class FishsanityNone(FishsanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class FishsanityLegendaries(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return fish.legendary
|
||||
|
||||
|
||||
class FishsanitySpecial(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
included_fishes = {
|
||||
Fish.angler,
|
||||
Fish.crimsonfish,
|
||||
Fish.glacierfish,
|
||||
Fish.legend,
|
||||
Fish.mutant_carp,
|
||||
Fish.blobfish,
|
||||
Fish.lava_eel,
|
||||
Fish.octopus,
|
||||
Fish.scorpion_carp,
|
||||
Fish.ice_pip,
|
||||
Fish.super_cucumber,
|
||||
Fish.dorado
|
||||
}
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return fish.name in self.included_fishes
|
||||
|
||||
|
||||
class FishsanityAll(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class FishsanityExcludeLegendaries(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return not fish.legendary
|
||||
|
||||
|
||||
class FishsanityExcludeHardFish(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return fish.difficulty < 80
|
||||
|
||||
|
||||
class FishsanityOnlyEasyFish(FishsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def is_included(self, fish: FishItem) -> bool:
|
||||
return fish.difficulty < 50
|
||||
139
worlds/stardew_valley/content/feature/friendsanity.py
Normal file
139
worlds/stardew_valley/content/feature/friendsanity.py
Normal file
@@ -0,0 +1,139 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from typing import Optional, Tuple, ClassVar
|
||||
|
||||
from ...data.villagers_data import Villager
|
||||
from ...strings.villager_names import NPC
|
||||
|
||||
suffix = " <3"
|
||||
location_prefix = "Friendsanity: "
|
||||
|
||||
|
||||
def to_item_name(npc_name: str) -> str:
|
||||
return npc_name + suffix
|
||||
|
||||
|
||||
def to_location_name(npc_name: str, heart: int) -> str:
|
||||
return location_prefix + npc_name + " " + str(heart) + suffix
|
||||
|
||||
|
||||
pet_heart_item_name = to_item_name(NPC.pet)
|
||||
|
||||
|
||||
def extract_npc_from_item_name(item_name: str) -> Optional[str]:
|
||||
if not item_name.endswith(suffix):
|
||||
return None
|
||||
|
||||
return item_name[:-len(suffix)]
|
||||
|
||||
|
||||
def extract_npc_from_location_name(location_name: str) -> Tuple[Optional[str], int]:
|
||||
if not location_name.endswith(suffix):
|
||||
return None, 0
|
||||
|
||||
trimmed = location_name[len(location_prefix):-len(suffix)]
|
||||
last_space = trimmed.rindex(" ")
|
||||
return trimmed[:last_space], int(trimmed[last_space + 1:])
|
||||
|
||||
|
||||
@lru_cache(maxsize=32) # Should not go pass 32 values if every friendsanity options are in the multi world
|
||||
def get_heart_steps(max_heart: int, heart_size: int) -> Tuple[int, ...]:
|
||||
return tuple(range(heart_size, max_heart + 1, heart_size)) + ((max_heart,) if max_heart % heart_size else ())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FriendsanityFeature(ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
heart_size: int
|
||||
|
||||
to_item_name = staticmethod(to_item_name)
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
pet_heart_item_name = pet_heart_item_name
|
||||
extract_npc_from_item_name = staticmethod(extract_npc_from_item_name)
|
||||
extract_npc_from_location_name = staticmethod(extract_npc_from_location_name)
|
||||
|
||||
@abstractmethod
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
...
|
||||
|
||||
@property
|
||||
def is_pet_randomized(self):
|
||||
return bool(self.get_pet_randomized_hearts())
|
||||
|
||||
@abstractmethod
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
...
|
||||
|
||||
|
||||
class FriendsanityNone(FriendsanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(1)
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FriendsanityBachelors(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
if not villager.bachelor:
|
||||
return ()
|
||||
|
||||
return get_heart_steps(8, self.heart_size)
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FriendsanityStartingNpc(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
if not villager.available:
|
||||
return ()
|
||||
|
||||
if villager.bachelor:
|
||||
return get_heart_steps(8, self.heart_size)
|
||||
|
||||
return get_heart_steps(10, self.heart_size)
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FriendsanityAll(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
if villager.bachelor:
|
||||
return get_heart_steps(8, self.heart_size)
|
||||
|
||||
return get_heart_steps(10, self.heart_size)
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FriendsanityAllWithMarriage(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
if villager.bachelor:
|
||||
return get_heart_steps(14, self.heart_size)
|
||||
|
||||
return get_heart_steps(10, self.heart_size)
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
117
worlds/stardew_valley/content/game_content.py
Normal file
117
worlds/stardew_valley/content/game_content.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Iterable, Set, Any, Mapping, Type, Tuple, Union
|
||||
|
||||
from .feature import booksanity, cropsanity, fishsanity, friendsanity
|
||||
from ..data.fish_data import FishItem
|
||||
from ..data.game_item import GameItem, ItemSource, ItemTag
|
||||
from ..data.skill import Skill
|
||||
from ..data.villagers_data import Villager
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StardewContent:
|
||||
features: StardewFeatures
|
||||
registered_packs: Set[str] = field(default_factory=set)
|
||||
|
||||
# regions -> To be used with can reach rule
|
||||
|
||||
game_items: Dict[str, GameItem] = field(default_factory=dict)
|
||||
fishes: Dict[str, FishItem] = field(default_factory=dict)
|
||||
villagers: Dict[str, Villager] = field(default_factory=dict)
|
||||
skills: Dict[str, Skill] = field(default_factory=dict)
|
||||
quests: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
def find_sources_of_type(self, types: Union[Type[ItemSource], Tuple[Type[ItemSource]]]) -> Iterable[ItemSource]:
|
||||
for item in self.game_items.values():
|
||||
for source in item.sources:
|
||||
if isinstance(source, types):
|
||||
yield source
|
||||
|
||||
def source_item(self, item_name: str, *sources: ItemSource):
|
||||
item = self.game_items.setdefault(item_name, GameItem(item_name))
|
||||
item.add_sources(sources)
|
||||
|
||||
def tag_item(self, item_name: str, *tags: ItemTag):
|
||||
item = self.game_items.setdefault(item_name, GameItem(item_name))
|
||||
item.add_tags(tags)
|
||||
|
||||
def untag_item(self, item_name: str, tag: ItemTag):
|
||||
self.game_items[item_name].tags.remove(tag)
|
||||
|
||||
def find_tagged_items(self, tag: ItemTag) -> Iterable[GameItem]:
|
||||
# TODO might be worth caching this, but it need to only be cached once the content is finalized...
|
||||
for item in self.game_items.values():
|
||||
if tag in item.tags:
|
||||
yield item
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StardewFeatures:
|
||||
booksanity: booksanity.BooksanityFeature
|
||||
cropsanity: cropsanity.CropsanityFeature
|
||||
fishsanity: fishsanity.FishsanityFeature
|
||||
friendsanity: friendsanity.FriendsanityFeature
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ContentPack:
|
||||
name: str
|
||||
|
||||
dependencies: Iterable[str] = ()
|
||||
""" Hard requirement, generation will fail if it's missing. """
|
||||
weak_dependencies: Iterable[str] = ()
|
||||
""" Not a strict dependency, only used only for ordering the packs to make sure hooks are applied correctly. """
|
||||
|
||||
# items
|
||||
# def item_hook
|
||||
# ...
|
||||
|
||||
harvest_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
|
||||
"""Harvest sources contains both crops and forageables, but also fruits from trees, the cave farm and stuff harvested from tapping like maple syrup."""
|
||||
|
||||
def harvest_source_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
shop_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
|
||||
|
||||
def shop_source_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
fishes: Iterable[FishItem] = ()
|
||||
|
||||
def fish_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
crafting_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
|
||||
|
||||
def crafting_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
artisan_good_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
|
||||
|
||||
def artisan_good_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
villagers: Iterable[Villager] = ()
|
||||
|
||||
def villager_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
skills: Iterable[Skill] = ()
|
||||
|
||||
def skill_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
quests: Iterable[Any] = ()
|
||||
|
||||
def quest_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
def finalize_hook(self, content: StardewContent):
|
||||
"""Last hook called on the pack, once all other content packs have been registered.
|
||||
|
||||
This is the place to do any final adjustments to the content, like adding rules based on tags applied by other packs.
|
||||
"""
|
||||
...
|
||||
7
worlds/stardew_valley/content/mod_registry.py
Normal file
7
worlds/stardew_valley/content/mod_registry.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .game_content import ContentPack
|
||||
|
||||
by_mod = {}
|
||||
|
||||
|
||||
def register_mod_content_pack(content_pack: ContentPack):
|
||||
by_mod[content_pack.name] = content_pack
|
||||
0
worlds/stardew_valley/content/mods/__init__.py
Normal file
0
worlds/stardew_valley/content/mods/__init__.py
Normal file
20
worlds/stardew_valley/content/mods/archeology.py
Normal file
20
worlds/stardew_valley/content/mods/archeology.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data.game_item import ItemTag, Tag
|
||||
from ...data.shop import ShopSource
|
||||
from ...data.skill import Skill
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.book_names import ModBook
|
||||
from ...strings.region_names import LogicRegion
|
||||
from ...strings.skill_names import ModSkill
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.archaeology,
|
||||
shop_sources={
|
||||
ModBook.digging_like_worms: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=500, shop_region=LogicRegion.bookseller_1),),
|
||||
},
|
||||
skills=(Skill(name=ModSkill.archaeology, has_mastery=False),),
|
||||
|
||||
))
|
||||
7
worlds/stardew_valley/content/mods/big_backpack.py
Normal file
7
worlds/stardew_valley/content/mods/big_backpack.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.big_backpack,
|
||||
))
|
||||
13
worlds/stardew_valley/content/mods/boarding_house.py
Normal file
13
worlds/stardew_valley/content/mods/boarding_house.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data import villagers_data
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.boarding_house,
|
||||
villagers=(
|
||||
villagers_data.gregory,
|
||||
villagers_data.sheila,
|
||||
villagers_data.joel,
|
||||
)
|
||||
))
|
||||
28
worlds/stardew_valley/content/mods/deepwoods.py
Normal file
28
worlds/stardew_valley/content/mods/deepwoods.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data.harvest import ForagingSource
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.flower_names import Flower
|
||||
from ...strings.region_names import DeepWoodsRegion
|
||||
from ...strings.season_names import Season
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.deepwoods,
|
||||
harvest_sources={
|
||||
# Deep enough to have seen such a tree at least once
|
||||
Fruit.apple: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.apricot: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.cherry: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.orange: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.peach: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.pomegranate: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Fruit.mango: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
|
||||
Flower.tulip: (ForagingSource(seasons=Season.not_winter, regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Flower.blue_jazz: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Flower.summer_spangle: (ForagingSource(seasons=Season.not_winter, regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Flower.poppy: (ForagingSource(seasons=Season.not_winter, regions=(DeepWoodsRegion.floor_10,)),),
|
||||
Flower.fairy_rose: (ForagingSource(regions=(DeepWoodsRegion.floor_10,)),),
|
||||
}
|
||||
))
|
||||
17
worlds/stardew_valley/content/mods/distant_lands.py
Normal file
17
worlds/stardew_valley/content/mods/distant_lands.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.distant_lands,
|
||||
fishes=(
|
||||
fish_data.void_minnow,
|
||||
fish_data.purple_algae,
|
||||
fish_data.swamp_leech,
|
||||
fish_data.giant_horsehoe_crab,
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.zic,
|
||||
)
|
||||
))
|
||||
14
worlds/stardew_valley/content/mods/jasper.py
Normal file
14
worlds/stardew_valley/content/mods/jasper.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ..override import override
|
||||
from ...data import villagers_data
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.jasper,
|
||||
villagers=(
|
||||
villagers_data.jasper,
|
||||
override(villagers_data.gunther, mod_name=ModNames.jasper),
|
||||
override(villagers_data.marlon, mod_name=ModNames.jasper),
|
||||
)
|
||||
))
|
||||
10
worlds/stardew_valley/content/mods/magic.py
Normal file
10
worlds/stardew_valley/content/mods/magic.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data.skill import Skill
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.skill_names import ModSkill
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.magic,
|
||||
skills=(Skill(name=ModSkill.magic, has_mastery=False),)
|
||||
))
|
||||
88
worlds/stardew_valley/content/mods/npc_mods.py
Normal file
88
worlds/stardew_valley/content/mods/npc_mods.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data import villagers_data
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.alec,
|
||||
villagers=(
|
||||
villagers_data.alec,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.ayeisha,
|
||||
villagers=(
|
||||
villagers_data.ayeisha,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.delores,
|
||||
villagers=(
|
||||
villagers_data.delores,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.eugene,
|
||||
villagers=(
|
||||
villagers_data.eugene,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.juna,
|
||||
villagers=(
|
||||
villagers_data.juna,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.ginger,
|
||||
villagers=(
|
||||
villagers_data.kitty,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.shiko,
|
||||
villagers=(
|
||||
villagers_data.shiko,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.wellwick,
|
||||
villagers=(
|
||||
villagers_data.wellwick,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.yoba,
|
||||
villagers=(
|
||||
villagers_data.yoba,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.riley,
|
||||
villagers=(
|
||||
villagers_data.riley,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.alecto,
|
||||
villagers=(
|
||||
villagers_data.alecto,
|
||||
)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.lacey,
|
||||
villagers=(
|
||||
villagers_data.lacey,
|
||||
)
|
||||
))
|
||||
25
worlds/stardew_valley/content/mods/skill_mods.py
Normal file
25
worlds/stardew_valley/content/mods/skill_mods.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data.skill import Skill
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.skill_names import ModSkill
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.luck_skill,
|
||||
skills=(Skill(name=ModSkill.luck, has_mastery=False),)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.socializing_skill,
|
||||
skills=(Skill(name=ModSkill.socializing, has_mastery=False),)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.cooking_skill,
|
||||
skills=(Skill(name=ModSkill.cooking, has_mastery=False),)
|
||||
))
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.binning_skill,
|
||||
skills=(Skill(name=ModSkill.binning, has_mastery=False),)
|
||||
))
|
||||
@@ -0,0 +1,7 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.skull_cavern_elevator,
|
||||
))
|
||||
126
worlds/stardew_valley/content/mods/sve.py
Normal file
126
worlds/stardew_valley/content/mods/sve.py
Normal file
@@ -0,0 +1,126 @@
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ..override import override
|
||||
from ..vanilla.ginger_island import ginger_island_content_pack as ginger_island_content_pack
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.harvest import ForagingSource
|
||||
from ...data.requirement import YearRequirement
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.fish_names import WaterItem
|
||||
from ...strings.flower_names import Flower
|
||||
from ...strings.forageable_names import Mushroom, Forageable
|
||||
from ...strings.region_names import Region, SVERegion
|
||||
from ...strings.season_names import Season
|
||||
|
||||
|
||||
class SVEContentPack(ContentPack):
|
||||
|
||||
def fish_hook(self, content: StardewContent):
|
||||
if ginger_island_content_pack.name not in content.registered_packs:
|
||||
content.fishes.pop(fish_data.baby_lunaloo.name)
|
||||
content.fishes.pop(fish_data.clownfish.name)
|
||||
content.fishes.pop(fish_data.lunaloo.name)
|
||||
content.fishes.pop(fish_data.seahorse.name)
|
||||
content.fishes.pop(fish_data.shiny_lunaloo.name)
|
||||
content.fishes.pop(fish_data.starfish.name)
|
||||
content.fishes.pop(fish_data.sea_sponge.name)
|
||||
|
||||
# Remove Highlands fishes at it requires 2 Lance hearts for the quest to access it
|
||||
content.fishes.pop(fish_data.daggerfish.name)
|
||||
content.fishes.pop(fish_data.gemfish.name)
|
||||
|
||||
# Remove Fable Reef fishes at it requires 8 Lance hearts for the event to access it
|
||||
content.fishes.pop(fish_data.torpedo_trout.name)
|
||||
|
||||
def villager_hook(self, content: StardewContent):
|
||||
if ginger_island_content_pack.name not in content.registered_packs:
|
||||
# Remove Lance if Ginger Island is not in content since he is first encountered in Volcano Forge
|
||||
content.villagers.pop(villagers_data.lance.name)
|
||||
|
||||
|
||||
register_mod_content_pack(SVEContentPack(
|
||||
ModNames.sve,
|
||||
weak_dependencies=(
|
||||
ginger_island_content_pack.name,
|
||||
ModNames.jasper, # To override Marlon and Gunther
|
||||
),
|
||||
harvest_sources={
|
||||
Mushroom.red: (
|
||||
ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.summer, Season.fall)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), )
|
||||
),
|
||||
Mushroom.purple: (
|
||||
ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), )
|
||||
),
|
||||
Mushroom.morel: (
|
||||
ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), )
|
||||
),
|
||||
Mushroom.chanterelle: (
|
||||
ForagingSource(regions=(SVERegion.forest_west,), seasons=(Season.fall,)), ForagingSource(regions=(SVERegion.sprite_spring_cave,), )
|
||||
),
|
||||
Flower.tulip: (ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.spring,)),),
|
||||
Flower.blue_jazz: (ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.spring,)),),
|
||||
Flower.summer_spangle: (ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.summer,)),),
|
||||
Flower.sunflower: (ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.summer,)),),
|
||||
Flower.fairy_rose: (ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.fall,)),),
|
||||
Fruit.ancient_fruit: (
|
||||
ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.spring, Season.summer, Season.fall), other_requirements=(YearRequirement(3),)),
|
||||
ForagingSource(regions=(SVERegion.sprite_spring_cave,)),
|
||||
),
|
||||
Fruit.sweet_gem_berry: (
|
||||
ForagingSource(regions=(SVERegion.sprite_spring,), seasons=(Season.spring, Season.summer, Season.fall), other_requirements=(YearRequirement(3),)),
|
||||
),
|
||||
|
||||
# Fable Reef
|
||||
WaterItem.coral: (ForagingSource(regions=(SVERegion.fable_reef,)),),
|
||||
Forageable.rainbow_shell: (ForagingSource(regions=(SVERegion.fable_reef,)),),
|
||||
WaterItem.sea_urchin: (ForagingSource(regions=(SVERegion.fable_reef,)),),
|
||||
},
|
||||
fishes=(
|
||||
fish_data.baby_lunaloo, # Removed when no ginger island
|
||||
fish_data.bonefish,
|
||||
fish_data.bull_trout,
|
||||
fish_data.butterfish,
|
||||
fish_data.clownfish, # Removed when no ginger island
|
||||
fish_data.daggerfish,
|
||||
fish_data.frog,
|
||||
fish_data.gemfish,
|
||||
fish_data.goldenfish,
|
||||
fish_data.grass_carp,
|
||||
fish_data.king_salmon,
|
||||
fish_data.kittyfish,
|
||||
fish_data.lunaloo, # Removed when no ginger island
|
||||
fish_data.meteor_carp,
|
||||
fish_data.minnow,
|
||||
fish_data.puppyfish,
|
||||
fish_data.radioactive_bass,
|
||||
fish_data.seahorse, # Removed when no ginger island
|
||||
fish_data.shiny_lunaloo, # Removed when no ginger island
|
||||
fish_data.snatcher_worm,
|
||||
fish_data.starfish, # Removed when no ginger island
|
||||
fish_data.torpedo_trout,
|
||||
fish_data.undeadfish,
|
||||
fish_data.void_eel,
|
||||
fish_data.water_grub,
|
||||
fish_data.sea_sponge, # Removed when no ginger island
|
||||
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.claire,
|
||||
villagers_data.lance, # Removed when no ginger island
|
||||
villagers_data.mommy,
|
||||
villagers_data.sophia,
|
||||
villagers_data.victor,
|
||||
villagers_data.andy,
|
||||
villagers_data.apples,
|
||||
villagers_data.gunther,
|
||||
villagers_data.martin,
|
||||
villagers_data.marlon,
|
||||
villagers_data.morgan,
|
||||
villagers_data.scarlett,
|
||||
villagers_data.susan,
|
||||
villagers_data.morris,
|
||||
# The wizard leaves his tower on sunday, for like 1 hour... Good enough for entrance rando!
|
||||
override(villagers_data.wizard, locations=(Region.wizard_tower, Region.forest), bachelor=True, mod_name=ModNames.sve),
|
||||
)
|
||||
))
|
||||
7
worlds/stardew_valley/content/mods/tractor.py
Normal file
7
worlds/stardew_valley/content/mods/tractor.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from ..game_content import ContentPack
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...mods.mod_data import ModNames
|
||||
|
||||
register_mod_content_pack(ContentPack(
|
||||
ModNames.tractor,
|
||||
))
|
||||
7
worlds/stardew_valley/content/override.py
Normal file
7
worlds/stardew_valley/content/override.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
def override(content: Any, **kwargs) -> Any:
|
||||
attributes = dict(content.__dict__)
|
||||
attributes.update(kwargs)
|
||||
return type(content)(**attributes)
|
||||
97
worlds/stardew_valley/content/unpacking.py
Normal file
97
worlds/stardew_valley/content/unpacking.py
Normal file
@@ -0,0 +1,97 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Mapping, Callable
|
||||
|
||||
from .game_content import StardewContent, ContentPack, StardewFeatures
|
||||
from .vanilla.base import base_game as base_game_content_pack
|
||||
from ..data.game_item import GameItem, ItemSource
|
||||
|
||||
try:
|
||||
from graphlib import TopologicalSorter
|
||||
except ImportError:
|
||||
from graphlib_backport import TopologicalSorter # noqa
|
||||
|
||||
|
||||
def unpack_content(features: StardewFeatures, packs: Iterable[ContentPack]) -> StardewContent:
|
||||
# Base game is always registered first.
|
||||
content = StardewContent(features)
|
||||
packs_to_finalize = [base_game_content_pack]
|
||||
register_pack(content, base_game_content_pack)
|
||||
|
||||
# Content packs are added in order based on their dependencies
|
||||
sorter = TopologicalSorter()
|
||||
packs_by_name = {p.name: p for p in packs}
|
||||
|
||||
# Build the dependency graph
|
||||
for name, pack in packs_by_name.items():
|
||||
sorter.add(name,
|
||||
*pack.dependencies,
|
||||
*(wd for wd in pack.weak_dependencies if wd in packs_by_name))
|
||||
|
||||
# Graph is traversed in BFS
|
||||
sorter.prepare()
|
||||
while sorter.is_active():
|
||||
# Packs get shuffled in TopologicalSorter, most likely due to hash seeding.
|
||||
for pack_name in sorted(sorter.get_ready()):
|
||||
pack = packs_by_name[pack_name]
|
||||
register_pack(content, pack)
|
||||
sorter.done(pack_name)
|
||||
packs_to_finalize.append(pack)
|
||||
|
||||
prune_inaccessible_items(content)
|
||||
|
||||
for pack in packs_to_finalize:
|
||||
pack.finalize_hook(content)
|
||||
|
||||
# Maybe items without source should be removed at some point
|
||||
return content
|
||||
|
||||
|
||||
def register_pack(content: StardewContent, pack: ContentPack):
|
||||
# register regions
|
||||
|
||||
# register entrances
|
||||
|
||||
register_sources_and_call_hook(content, pack.harvest_sources, pack.harvest_source_hook)
|
||||
register_sources_and_call_hook(content, pack.shop_sources, pack.shop_source_hook)
|
||||
register_sources_and_call_hook(content, pack.crafting_sources, pack.crafting_hook)
|
||||
register_sources_and_call_hook(content, pack.artisan_good_sources, pack.artisan_good_hook)
|
||||
|
||||
for fish in pack.fishes:
|
||||
content.fishes[fish.name] = fish
|
||||
pack.fish_hook(content)
|
||||
|
||||
for villager in pack.villagers:
|
||||
content.villagers[villager.name] = villager
|
||||
pack.villager_hook(content)
|
||||
|
||||
for skill in pack.skills:
|
||||
content.skills[skill.name] = skill
|
||||
pack.skill_hook(content)
|
||||
|
||||
# register_quests
|
||||
|
||||
# ...
|
||||
|
||||
content.registered_packs.add(pack.name)
|
||||
|
||||
|
||||
def register_sources_and_call_hook(content: StardewContent,
|
||||
sources_by_item_name: Mapping[str, Iterable[ItemSource]],
|
||||
hook: Callable[[StardewContent], None]):
|
||||
for item_name, sources in sources_by_item_name.items():
|
||||
item = content.game_items.setdefault(item_name, GameItem(item_name))
|
||||
item.add_sources(sources)
|
||||
|
||||
for source in sources:
|
||||
for requirement_name, tags in source.requirement_tags.items():
|
||||
requirement_item = content.game_items.setdefault(requirement_name, GameItem(requirement_name))
|
||||
requirement_item.add_tags(tags)
|
||||
|
||||
hook(content)
|
||||
|
||||
|
||||
def prune_inaccessible_items(content: StardewContent):
|
||||
for item in list(content.game_items.values()):
|
||||
if not item.sources:
|
||||
content.game_items.pop(item.name)
|
||||
0
worlds/stardew_valley/content/vanilla/__init__.py
Normal file
0
worlds/stardew_valley/content/vanilla/__init__.py
Normal file
172
worlds/stardew_valley/content/vanilla/base.py
Normal file
172
worlds/stardew_valley/content/vanilla/base.py
Normal file
@@ -0,0 +1,172 @@
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ...data.artisan import MachineSource
|
||||
from ...data.game_item import ItemTag, CustomRuleSource, GameItem
|
||||
from ...data.harvest import HarvestFruitTreeSource, HarvestCropSource
|
||||
from ...data.skill import Skill
|
||||
from ...strings.artisan_good_names import ArtisanGood
|
||||
from ...strings.craftable_names import WildSeeds
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.flower_names import Flower
|
||||
from ...strings.food_names import Beverage
|
||||
from ...strings.forageable_names import all_edible_mushrooms, Mushroom, Forageable
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.machine_names import Machine
|
||||
from ...strings.monster_names import Monster
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
from ...strings.skill_names import Skill as SkillName
|
||||
|
||||
all_fruits = (
|
||||
Fruit.ancient_fruit, Fruit.apple, Fruit.apricot, Fruit.banana, Forageable.blackberry, Fruit.blueberry, Forageable.cactus_fruit, Fruit.cherry,
|
||||
Forageable.coconut, Fruit.cranberries, Forageable.crystal_fruit, Fruit.grape, Fruit.hot_pepper, Fruit.mango, Fruit.melon, Fruit.orange, Fruit.peach,
|
||||
Fruit.pineapple, Fruit.pomegranate, Fruit.powdermelon, Fruit.qi_fruit, Fruit.rhubarb, Forageable.salmonberry, Forageable.spice_berry, Fruit.starfruit,
|
||||
Fruit.strawberry
|
||||
)
|
||||
|
||||
all_vegetables = (
|
||||
Vegetable.amaranth, Vegetable.artichoke, Vegetable.beet, Vegetable.bok_choy, Vegetable.broccoli, Vegetable.carrot, Vegetable.cauliflower,
|
||||
Vegetable.corn, Vegetable.eggplant, Forageable.fiddlehead_fern, Vegetable.garlic, Vegetable.green_bean, Vegetable.hops, Vegetable.kale,
|
||||
Vegetable.parsnip, Vegetable.potato, Vegetable.pumpkin, Vegetable.radish, Vegetable.red_cabbage, Vegetable.summer_squash, Vegetable.taro_root,
|
||||
Vegetable.tea_leaves, Vegetable.tomato, Vegetable.unmilled_rice, Vegetable.wheat, Vegetable.yam
|
||||
)
|
||||
|
||||
non_juiceable_vegetables = (Vegetable.hops, Vegetable.tea_leaves, Vegetable.wheat, Vegetable.tea_leaves)
|
||||
|
||||
|
||||
# This will hold items, skills and stuff that is available everywhere across the game, but not directly needing pelican town (crops, ore, foraging, etc.)
|
||||
class BaseGameContentPack(ContentPack):
|
||||
|
||||
def harvest_source_hook(self, content: StardewContent):
|
||||
coffee_starter = content.game_items[Seed.coffee_starter]
|
||||
content.game_items[Seed.coffee_starter] = GameItem(Seed.coffee, sources=coffee_starter.sources, tags=coffee_starter.tags)
|
||||
|
||||
content.untag_item(WildSeeds.ancient, ItemTag.CROPSANITY_SEED)
|
||||
|
||||
for fruit in all_fruits:
|
||||
content.tag_item(fruit, ItemTag.FRUIT)
|
||||
|
||||
for vegetable in all_vegetables:
|
||||
content.tag_item(vegetable, ItemTag.VEGETABLE)
|
||||
|
||||
for edible_mushroom in all_edible_mushrooms:
|
||||
if edible_mushroom == Mushroom.magma_cap:
|
||||
continue
|
||||
|
||||
content.tag_item(edible_mushroom, ItemTag.EDIBLE_MUSHROOM)
|
||||
|
||||
def finalize_hook(self, content: StardewContent):
|
||||
# FIXME I hate this design. A listener design pattern would be more appropriate so artisan good are register at the exact moment a FRUIT tag is added.
|
||||
for fruit in tuple(content.find_tagged_items(ItemTag.FRUIT)):
|
||||
wine = ArtisanGood.specific_wine(fruit.name)
|
||||
content.source_item(wine, MachineSource(item=fruit.name, machine=Machine.keg))
|
||||
content.source_item(ArtisanGood.wine, MachineSource(item=fruit.name, machine=Machine.keg))
|
||||
|
||||
if fruit.name == Fruit.grape:
|
||||
content.source_item(ArtisanGood.raisins, MachineSource(item=fruit.name, machine=Machine.dehydrator))
|
||||
else:
|
||||
dried_fruit = ArtisanGood.specific_dried_fruit(fruit.name)
|
||||
content.source_item(dried_fruit, MachineSource(item=fruit.name, machine=Machine.dehydrator))
|
||||
content.source_item(ArtisanGood.dried_fruit, MachineSource(item=fruit.name, machine=Machine.dehydrator))
|
||||
|
||||
jelly = ArtisanGood.specific_jelly(fruit.name)
|
||||
content.source_item(jelly, MachineSource(item=fruit.name, machine=Machine.preserves_jar))
|
||||
content.source_item(ArtisanGood.jelly, MachineSource(item=fruit.name, machine=Machine.preserves_jar))
|
||||
|
||||
for vegetable in tuple(content.find_tagged_items(ItemTag.VEGETABLE)):
|
||||
if vegetable.name not in non_juiceable_vegetables:
|
||||
juice = ArtisanGood.specific_juice(vegetable.name)
|
||||
content.source_item(juice, MachineSource(item=vegetable.name, machine=Machine.keg))
|
||||
content.source_item(ArtisanGood.juice, MachineSource(item=vegetable.name, machine=Machine.keg))
|
||||
|
||||
pickles = ArtisanGood.specific_pickles(vegetable.name)
|
||||
content.source_item(pickles, MachineSource(item=vegetable.name, machine=Machine.preserves_jar))
|
||||
content.source_item(ArtisanGood.pickles, MachineSource(item=vegetable.name, machine=Machine.preserves_jar))
|
||||
|
||||
for mushroom in tuple(content.find_tagged_items(ItemTag.EDIBLE_MUSHROOM)):
|
||||
dried_mushroom = ArtisanGood.specific_dried_mushroom(mushroom.name)
|
||||
content.source_item(dried_mushroom, MachineSource(item=mushroom.name, machine=Machine.dehydrator))
|
||||
content.source_item(ArtisanGood.dried_mushroom, MachineSource(item=mushroom.name, machine=Machine.dehydrator))
|
||||
|
||||
# for fish in tuple(content.find_tagged_items(ItemTag.FISH)):
|
||||
# smoked_fish = ArtisanGood.specific_smoked_fish(fish.name)
|
||||
# content.source_item(smoked_fish, MachineSource(item=fish.name, machine=Machine.fish_smoker))
|
||||
# content.source_item(ArtisanGood.smoked_fish, MachineSource(item=fish.name, machine=Machine.fish_smoker))
|
||||
|
||||
|
||||
base_game = BaseGameContentPack(
|
||||
"Base game (Vanilla)",
|
||||
harvest_sources={
|
||||
# Fruit tree
|
||||
Fruit.apple: (HarvestFruitTreeSource(sapling=Sapling.apple, seasons=(Season.fall,)),),
|
||||
Fruit.apricot: (HarvestFruitTreeSource(sapling=Sapling.apricot, seasons=(Season.spring,)),),
|
||||
Fruit.cherry: (HarvestFruitTreeSource(sapling=Sapling.cherry, seasons=(Season.spring,)),),
|
||||
Fruit.orange: (HarvestFruitTreeSource(sapling=Sapling.orange, seasons=(Season.summer,)),),
|
||||
Fruit.peach: (HarvestFruitTreeSource(sapling=Sapling.peach, seasons=(Season.summer,)),),
|
||||
Fruit.pomegranate: (HarvestFruitTreeSource(sapling=Sapling.pomegranate, seasons=(Season.fall,)),),
|
||||
|
||||
# Crops
|
||||
Vegetable.parsnip: (HarvestCropSource(seed=Seed.parsnip, seasons=(Season.spring,)),),
|
||||
Vegetable.green_bean: (HarvestCropSource(seed=Seed.bean, seasons=(Season.spring,)),),
|
||||
Vegetable.cauliflower: (HarvestCropSource(seed=Seed.cauliflower, seasons=(Season.spring,)),),
|
||||
Vegetable.potato: (HarvestCropSource(seed=Seed.potato, seasons=(Season.spring,)),),
|
||||
Flower.tulip: (HarvestCropSource(seed=Seed.tulip, seasons=(Season.spring,)),),
|
||||
Vegetable.kale: (HarvestCropSource(seed=Seed.kale, seasons=(Season.spring,)),),
|
||||
Flower.blue_jazz: (HarvestCropSource(seed=Seed.jazz, seasons=(Season.spring,)),),
|
||||
Vegetable.garlic: (HarvestCropSource(seed=Seed.garlic, seasons=(Season.spring,)),),
|
||||
Vegetable.unmilled_rice: (HarvestCropSource(seed=Seed.rice, seasons=(Season.spring,)),),
|
||||
|
||||
Fruit.melon: (HarvestCropSource(seed=Seed.melon, seasons=(Season.summer,)),),
|
||||
Vegetable.tomato: (HarvestCropSource(seed=Seed.tomato, seasons=(Season.summer,)),),
|
||||
Fruit.blueberry: (HarvestCropSource(seed=Seed.blueberry, seasons=(Season.summer,)),),
|
||||
Fruit.hot_pepper: (HarvestCropSource(seed=Seed.pepper, seasons=(Season.summer,)),),
|
||||
Vegetable.wheat: (HarvestCropSource(seed=Seed.wheat, seasons=(Season.summer, Season.fall)),),
|
||||
Vegetable.radish: (HarvestCropSource(seed=Seed.radish, seasons=(Season.summer,)),),
|
||||
Flower.poppy: (HarvestCropSource(seed=Seed.poppy, seasons=(Season.summer,)),),
|
||||
Flower.summer_spangle: (HarvestCropSource(seed=Seed.spangle, seasons=(Season.summer,)),),
|
||||
Vegetable.hops: (HarvestCropSource(seed=Seed.hops, seasons=(Season.summer,)),),
|
||||
Vegetable.corn: (HarvestCropSource(seed=Seed.corn, seasons=(Season.summer, Season.fall)),),
|
||||
Flower.sunflower: (HarvestCropSource(seed=Seed.sunflower, seasons=(Season.summer, Season.fall)),),
|
||||
Vegetable.red_cabbage: (HarvestCropSource(seed=Seed.red_cabbage, seasons=(Season.summer,)),),
|
||||
|
||||
Vegetable.eggplant: (HarvestCropSource(seed=Seed.eggplant, seasons=(Season.fall,)),),
|
||||
Vegetable.pumpkin: (HarvestCropSource(seed=Seed.pumpkin, seasons=(Season.fall,)),),
|
||||
Vegetable.bok_choy: (HarvestCropSource(seed=Seed.bok_choy, seasons=(Season.fall,)),),
|
||||
Vegetable.yam: (HarvestCropSource(seed=Seed.yam, seasons=(Season.fall,)),),
|
||||
Fruit.cranberries: (HarvestCropSource(seed=Seed.cranberry, seasons=(Season.fall,)),),
|
||||
Flower.fairy_rose: (HarvestCropSource(seed=Seed.fairy, seasons=(Season.fall,)),),
|
||||
Vegetable.amaranth: (HarvestCropSource(seed=Seed.amaranth, seasons=(Season.fall,)),),
|
||||
Fruit.grape: (HarvestCropSource(seed=Seed.grape, seasons=(Season.fall,)),),
|
||||
Vegetable.artichoke: (HarvestCropSource(seed=Seed.artichoke, seasons=(Season.fall,)),),
|
||||
|
||||
Vegetable.broccoli: (HarvestCropSource(seed=Seed.broccoli, seasons=(Season.fall,)),),
|
||||
Vegetable.carrot: (HarvestCropSource(seed=Seed.carrot, seasons=(Season.spring,)),),
|
||||
Fruit.powdermelon: (HarvestCropSource(seed=Seed.powdermelon, seasons=(Season.summer,)),),
|
||||
Vegetable.summer_squash: (HarvestCropSource(seed=Seed.summer_squash, seasons=(Season.summer,)),),
|
||||
|
||||
Fruit.strawberry: (HarvestCropSource(seed=Seed.strawberry, seasons=(Season.spring,)),),
|
||||
Fruit.sweet_gem_berry: (HarvestCropSource(seed=Seed.rare_seed, seasons=(Season.fall,)),),
|
||||
Fruit.ancient_fruit: (HarvestCropSource(seed=WildSeeds.ancient, seasons=(Season.spring, Season.summer, Season.fall,)),),
|
||||
|
||||
Seed.coffee_starter: (CustomRuleSource(lambda logic: logic.traveling_merchant.has_days(3) & logic.monster.can_kill_many(Monster.dust_sprite)),),
|
||||
Seed.coffee: (HarvestCropSource(seed=Seed.coffee_starter, seasons=(Season.spring, Season.summer,)),),
|
||||
|
||||
Vegetable.tea_leaves: (CustomRuleSource(lambda logic: logic.has(Sapling.tea) & logic.time.has_lived_months(2) & logic.season.has_any_not_winter()),),
|
||||
},
|
||||
artisan_good_sources={
|
||||
Beverage.beer: (MachineSource(item=Vegetable.wheat, machine=Machine.keg),),
|
||||
# Ingredient.vinegar: (MachineSource(item=Ingredient.rice, machine=Machine.keg),),
|
||||
Beverage.coffee: (MachineSource(item=Seed.coffee, machine=Machine.keg),
|
||||
CustomRuleSource(lambda logic: logic.has(Machine.coffee_maker)),
|
||||
CustomRuleSource(lambda logic: logic.has("Hot Java Ring"))),
|
||||
ArtisanGood.green_tea: (MachineSource(item=Vegetable.tea_leaves, machine=Machine.keg),),
|
||||
ArtisanGood.mead: (MachineSource(item=ArtisanGood.honey, machine=Machine.keg),),
|
||||
ArtisanGood.pale_ale: (MachineSource(item=Vegetable.hops, machine=Machine.keg),),
|
||||
},
|
||||
skills=(
|
||||
Skill(SkillName.farming, has_mastery=True),
|
||||
Skill(SkillName.foraging, has_mastery=True),
|
||||
Skill(SkillName.fishing, has_mastery=True),
|
||||
Skill(SkillName.mining, has_mastery=True),
|
||||
Skill(SkillName.combat, has_mastery=True),
|
||||
)
|
||||
)
|
||||
81
worlds/stardew_valley/content/vanilla/ginger_island.py
Normal file
81
worlds/stardew_valley/content/vanilla/ginger_island.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.game_item import ItemTag, Tag
|
||||
from ...data.harvest import ForagingSource, HarvestFruitTreeSource, HarvestCropSource
|
||||
from ...data.shop import ShopSource
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.fish_names import Fish
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.metal_names import Fossil, Mineral
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
|
||||
|
||||
class GingerIslandContentPack(ContentPack):
|
||||
|
||||
def harvest_source_hook(self, content: StardewContent):
|
||||
content.tag_item(Fruit.banana, ItemTag.FRUIT)
|
||||
content.tag_item(Fruit.pineapple, ItemTag.FRUIT)
|
||||
content.tag_item(Fruit.mango, ItemTag.FRUIT)
|
||||
content.tag_item(Vegetable.taro_root, ItemTag.VEGETABLE)
|
||||
content.tag_item(Mushroom.magma_cap, ItemTag.EDIBLE_MUSHROOM)
|
||||
|
||||
|
||||
ginger_island_content_pack = GingerIslandContentPack(
|
||||
"Ginger Island (Vanilla)",
|
||||
weak_dependencies=(
|
||||
pelican_town_content_pack.name,
|
||||
),
|
||||
harvest_sources={
|
||||
# Foraging
|
||||
Forageable.dragon_tooth: (
|
||||
ForagingSource(regions=(Region.volcano_floor_10,)),
|
||||
),
|
||||
Forageable.ginger: (
|
||||
ForagingSource(regions=(Region.island_west,)),
|
||||
),
|
||||
Mushroom.magma_cap: (
|
||||
ForagingSource(regions=(Region.volcano_floor_5,)),
|
||||
),
|
||||
|
||||
# Fruit tree
|
||||
Fruit.banana: (HarvestFruitTreeSource(sapling=Sapling.banana, seasons=(Season.summer,)),),
|
||||
Fruit.mango: (HarvestFruitTreeSource(sapling=Sapling.mango, seasons=(Season.summer,)),),
|
||||
|
||||
# Crop
|
||||
Vegetable.taro_root: (HarvestCropSource(seed=Seed.taro, seasons=(Season.summer,)),),
|
||||
Fruit.pineapple: (HarvestCropSource(seed=Seed.pineapple, seasons=(Season.summer,)),),
|
||||
|
||||
},
|
||||
shop_sources={
|
||||
Seed.taro: (ShopSource(items_price=((2, Fossil.bone_fragment),), shop_region=Region.island_trader),),
|
||||
Seed.pineapple: (ShopSource(items_price=((1, Mushroom.magma_cap),), shop_region=Region.island_trader),),
|
||||
Sapling.banana: (ShopSource(items_price=((5, Forageable.dragon_tooth),), shop_region=Region.island_trader),),
|
||||
Sapling.mango: (ShopSource(items_price=((75, Fish.mussel_node),), shop_region=Region.island_trader),),
|
||||
|
||||
# This one is 10 diamonds, should maybe add time?
|
||||
Book.the_diamond_hunter: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(items_price=((10, Mineral.diamond),), shop_region=Region.volcano_dwarf_shop),
|
||||
),
|
||||
|
||||
},
|
||||
fishes=(
|
||||
# TODO override region so no need to add inaccessible regions in logic
|
||||
fish_data.blue_discus,
|
||||
fish_data.lionfish,
|
||||
fish_data.midnight_carp,
|
||||
fish_data.pufferfish,
|
||||
fish_data.stingray,
|
||||
fish_data.super_cucumber,
|
||||
fish_data.tilapia,
|
||||
fish_data.tuna
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.leo,
|
||||
)
|
||||
)
|
||||
393
worlds/stardew_valley/content/vanilla/pelican_town.py
Normal file
393
worlds/stardew_valley/content/vanilla/pelican_town.py
Normal file
@@ -0,0 +1,393 @@
|
||||
from ..game_content import ContentPack
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.game_item import GenericSource, ItemTag, Tag, CustomRuleSource
|
||||
from ...data.harvest import ForagingSource, SeasonalForagingSource, ArtifactSpotSource
|
||||
from ...data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement
|
||||
from ...data.shop import ShopSource, MysteryBoxSource, ArtifactTroveSource, PrizeMachineSource, FishingTreasureChestSource
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.fish_names import WaterItem
|
||||
from ...strings.food_names import Beverage, Meal
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.generic_names import Generic
|
||||
from ...strings.material_names import Material
|
||||
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
|
||||
|
||||
pelican_town = ContentPack(
|
||||
"Pelican Town (Vanilla)",
|
||||
harvest_sources={
|
||||
# Spring
|
||||
Forageable.daffodil: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.bus_stop, Region.town, Region.railroad)),
|
||||
),
|
||||
Forageable.dandelion: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.bus_stop, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.leek: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.wild_horseradish: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.backwoods, Region.mountain, Region.forest, Region.secret_woods)),
|
||||
),
|
||||
Forageable.salmonberry: (
|
||||
SeasonalForagingSource(season=Season.spring, days=(15, 16, 17, 18),
|
||||
regions=(Region.backwoods, Region.mountain, Region.town, Region.forest, Region.tunnel_entrance, Region.railroad)),
|
||||
),
|
||||
Forageable.spring_onion: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.forest,)),
|
||||
),
|
||||
|
||||
# Summer
|
||||
Fruit.grape: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.spice_berry: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.sweet_pea: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.fiddlehead_fern: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.secret_woods,)),
|
||||
),
|
||||
|
||||
# Fall
|
||||
Forageable.blackberry: (
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.backwoods, Region.town, Region.forest, Region.railroad)),
|
||||
SeasonalForagingSource(season=Season.fall, days=(8, 9, 10, 11),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.tunnel_entrance,
|
||||
Region.railroad)),
|
||||
),
|
||||
Forageable.hazelnut: (
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.wild_plum: (
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
|
||||
# Winter
|
||||
Forageable.crocus: (
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.secret_woods)),
|
||||
),
|
||||
Forageable.crystal_fruit: (
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.holly: (
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.snow_yam: (
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.farm, Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad,
|
||||
Region.secret_woods, Region.beach),
|
||||
other_requirements=(ToolRequirement(Tool.hoe),)),
|
||||
),
|
||||
Forageable.winter_root: (
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.farm, Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad,
|
||||
Region.secret_woods, Region.beach),
|
||||
other_requirements=(ToolRequirement(Tool.hoe),)),
|
||||
),
|
||||
|
||||
# Mushrooms
|
||||
Mushroom.common: (
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.secret_woods,)),
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.backwoods, Region.mountain, Region.forest)),
|
||||
),
|
||||
Mushroom.chanterelle: (
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.secret_woods,)),
|
||||
),
|
||||
Mushroom.morel: (
|
||||
ForagingSource(seasons=(Season.spring, Season.fall), regions=(Region.secret_woods,)),
|
||||
),
|
||||
Mushroom.red: (
|
||||
ForagingSource(seasons=(Season.summer, Season.fall), regions=(Region.secret_woods,)),
|
||||
),
|
||||
|
||||
# Beach
|
||||
WaterItem.coral: (
|
||||
ForagingSource(regions=(Region.tide_pools,)),
|
||||
SeasonalForagingSource(season=Season.summer, days=(12, 13, 14), regions=(Region.beach,)),
|
||||
),
|
||||
WaterItem.nautilus_shell: (
|
||||
ForagingSource(seasons=(Season.winter,), regions=(Region.beach,)),
|
||||
),
|
||||
Forageable.rainbow_shell: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.beach,)),
|
||||
),
|
||||
WaterItem.sea_urchin: (
|
||||
ForagingSource(regions=(Region.tide_pools,)),
|
||||
),
|
||||
|
||||
Seed.mixed: (
|
||||
ForagingSource(seasons=(Season.spring, Season.summer, Season.fall,), regions=(Region.town, Region.farm, Region.forest)),
|
||||
),
|
||||
|
||||
Seed.mixed_flower: (
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.town, Region.farm, Region.forest)),
|
||||
),
|
||||
|
||||
# Books
|
||||
Book.jack_be_nimble_jack_be_thick: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ArtifactSpotSource(amount=22),), # After 22 spots, there are 50.48% chances player received the book.
|
||||
Book.woodys_secret: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
GenericSource(regions=(Region.forest, Region.mountain),
|
||||
other_requirements=(ToolRequirement(Tool.axe, ToolMaterial.iron), SkillRequirement(Skill.foraging, 5))),),
|
||||
},
|
||||
shop_sources={
|
||||
# Saplings
|
||||
Sapling.apple: (ShopSource(money_price=4000, shop_region=Region.pierre_store),),
|
||||
Sapling.apricot: (ShopSource(money_price=2000, shop_region=Region.pierre_store),),
|
||||
Sapling.cherry: (ShopSource(money_price=3400, shop_region=Region.pierre_store),),
|
||||
Sapling.orange: (ShopSource(money_price=4000, shop_region=Region.pierre_store),),
|
||||
Sapling.peach: (ShopSource(money_price=6000, shop_region=Region.pierre_store),),
|
||||
Sapling.pomegranate: (ShopSource(money_price=6000, shop_region=Region.pierre_store),),
|
||||
|
||||
# Crop seeds, assuming they are bought in season, otherwise price is different with missing stock list.
|
||||
Seed.parsnip: (ShopSource(money_price=20, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.bean: (ShopSource(money_price=60, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.cauliflower: (ShopSource(money_price=80, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.potato: (ShopSource(money_price=50, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.tulip: (ShopSource(money_price=20, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.kale: (ShopSource(money_price=70, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.jazz: (ShopSource(money_price=30, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.garlic: (ShopSource(money_price=40, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.rice: (ShopSource(money_price=40, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
|
||||
Seed.melon: (ShopSource(money_price=80, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.tomato: (ShopSource(money_price=50, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.blueberry: (ShopSource(money_price=80, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.pepper: (ShopSource(money_price=40, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.wheat: (ShopSource(money_price=10, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.radish: (ShopSource(money_price=40, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.poppy: (ShopSource(money_price=100, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.spangle: (ShopSource(money_price=50, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.hops: (ShopSource(money_price=60, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.corn: (ShopSource(money_price=150, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.sunflower: (ShopSource(money_price=200, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.red_cabbage: (ShopSource(money_price=100, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
|
||||
Seed.eggplant: (ShopSource(money_price=20, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.pumpkin: (ShopSource(money_price=100, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.bok_choy: (ShopSource(money_price=50, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.yam: (ShopSource(money_price=60, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.cranberry: (ShopSource(money_price=240, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.fairy: (ShopSource(money_price=200, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.amaranth: (ShopSource(money_price=70, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.grape: (ShopSource(money_price=60, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.artichoke: (ShopSource(money_price=30, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
|
||||
Seed.broccoli: (ShopSource(items_price=((5, Material.moss),), shop_region=LogicRegion.raccoon_shop),),
|
||||
Seed.carrot: (ShopSource(items_price=((1, TreeSeed.maple),), shop_region=LogicRegion.raccoon_shop),),
|
||||
Seed.powdermelon: (ShopSource(items_price=((2, TreeSeed.acorn),), shop_region=LogicRegion.raccoon_shop),),
|
||||
Seed.summer_squash: (ShopSource(items_price=((15, Material.sap),), shop_region=LogicRegion.raccoon_shop),),
|
||||
|
||||
Seed.strawberry: (ShopSource(money_price=100, shop_region=LogicRegion.egg_festival, seasons=(Season.spring,)),),
|
||||
Seed.rare_seed: (ShopSource(money_price=1000, shop_region=LogicRegion.traveling_cart, seasons=(Season.spring, Season.summer)),),
|
||||
|
||||
# Saloon
|
||||
Beverage.beer: (ShopSource(money_price=400, shop_region=Region.saloon),),
|
||||
Meal.salad: (ShopSource(money_price=220, shop_region=Region.saloon),),
|
||||
Meal.bread: (ShopSource(money_price=100, shop_region=Region.saloon),),
|
||||
Meal.spaghetti: (ShopSource(money_price=240, shop_region=Region.saloon),),
|
||||
Meal.pizza: (ShopSource(money_price=600, shop_region=Region.saloon),),
|
||||
Beverage.coffee: (ShopSource(money_price=300, shop_region=Region.saloon),),
|
||||
|
||||
# Books
|
||||
Book.animal_catalogue: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=5000, shop_region=Region.ranch),),
|
||||
Book.book_of_mysteries: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
MysteryBoxSource(amount=38),), # After 38 boxes, there are 49.99% chances player received the book.
|
||||
Book.dwarvish_safety_manual: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=4000, shop_region=LogicRegion.mines_dwarf_shop),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.friendship_101: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
PrizeMachineSource(amount=9),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.horse_the_book: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=25000, shop_region=LogicRegion.bookseller_2),),
|
||||
Book.jack_be_nimble_jack_be_thick: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.jewels_of_the_sea: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
FishingTreasureChestSource(amount=21), # After 21 chests, there are 49.44% chances player received the book.
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.mapping_cave_systems: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
GenericSource(regions=Region.adventurer_guild_bedroom),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.monster_compendium: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
CustomRuleSource(create_rule=lambda logic: logic.monster.can_kill_many(Generic.any)),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.ol_slitherlegs: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=25000, shop_region=LogicRegion.bookseller_2),),
|
||||
Book.price_catalogue: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=3000, shop_region=LogicRegion.bookseller_2),),
|
||||
Book.the_alleyway_buffet: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
GenericSource(regions=Region.town,
|
||||
other_requirements=(ToolRequirement(Tool.axe, ToolMaterial.iron), ToolRequirement(Tool.pickaxe, ToolMaterial.iron))),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.the_art_o_crabbing: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
GenericSource(regions=Region.beach,
|
||||
other_requirements=(ToolRequirement(Tool.fishing_rod, ToolMaterial.iridium),
|
||||
SkillRequirement(Skill.fishing, 6),
|
||||
SeasonRequirement(Season.winter))),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.treasure_appraisal_guide: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ArtifactTroveSource(amount=18), # After 18 troves, there is 49,88% chances player received the book.
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
Book.raccoon_journal: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),
|
||||
ShopSource(items_price=((999, Material.fiber),), shop_region=LogicRegion.raccoon_shop),),
|
||||
Book.way_of_the_wind_pt_1: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=15000, shop_region=LogicRegion.bookseller_2),),
|
||||
Book.way_of_the_wind_pt_2: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=35000, shop_region=LogicRegion.bookseller_2, other_requirements=(BookRequirement(Book.way_of_the_wind_pt_1),)),),
|
||||
Book.woodys_secret: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
|
||||
# Experience Books
|
||||
Book.book_of_stars: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.bait_and_bobber: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.combat_quarterly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.mining_monthly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.stardew_valley_almanac: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.woodcutters_weekly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.queen_of_sauce_cookbook: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2),), # Worst book ever
|
||||
},
|
||||
fishes=(
|
||||
fish_data.albacore,
|
||||
fish_data.anchovy,
|
||||
fish_data.bream,
|
||||
fish_data.bullhead,
|
||||
fish_data.carp,
|
||||
fish_data.catfish,
|
||||
fish_data.chub,
|
||||
fish_data.dorado,
|
||||
fish_data.eel,
|
||||
fish_data.flounder,
|
||||
fish_data.goby,
|
||||
fish_data.halibut,
|
||||
fish_data.herring,
|
||||
fish_data.largemouth_bass,
|
||||
fish_data.lingcod,
|
||||
fish_data.midnight_carp, # Ginger island override
|
||||
fish_data.octopus,
|
||||
fish_data.perch,
|
||||
fish_data.pike,
|
||||
fish_data.pufferfish, # Ginger island override
|
||||
fish_data.rainbow_trout,
|
||||
fish_data.red_mullet,
|
||||
fish_data.red_snapper,
|
||||
fish_data.salmon,
|
||||
fish_data.sardine,
|
||||
fish_data.sea_cucumber,
|
||||
fish_data.shad,
|
||||
fish_data.slimejack,
|
||||
fish_data.smallmouth_bass,
|
||||
fish_data.squid,
|
||||
fish_data.sturgeon,
|
||||
fish_data.sunfish,
|
||||
fish_data.super_cucumber, # Ginger island override
|
||||
fish_data.tiger_trout,
|
||||
fish_data.tilapia, # Ginger island override
|
||||
fish_data.tuna, # Ginger island override
|
||||
fish_data.void_salmon,
|
||||
fish_data.walleye,
|
||||
fish_data.woodskip,
|
||||
fish_data.blobfish,
|
||||
fish_data.midnight_squid,
|
||||
fish_data.spook_fish,
|
||||
|
||||
# Legendaries
|
||||
fish_data.angler,
|
||||
fish_data.crimsonfish,
|
||||
fish_data.glacierfish,
|
||||
fish_data.legend,
|
||||
fish_data.mutant_carp,
|
||||
|
||||
# Crab pot
|
||||
fish_data.clam,
|
||||
fish_data.cockle,
|
||||
fish_data.crab,
|
||||
fish_data.crayfish,
|
||||
fish_data.lobster,
|
||||
fish_data.mussel,
|
||||
fish_data.oyster,
|
||||
fish_data.periwinkle,
|
||||
fish_data.shrimp,
|
||||
fish_data.snail,
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.josh,
|
||||
villagers_data.elliott,
|
||||
villagers_data.harvey,
|
||||
villagers_data.sam,
|
||||
villagers_data.sebastian,
|
||||
villagers_data.shane,
|
||||
villagers_data.abigail,
|
||||
villagers_data.emily,
|
||||
villagers_data.haley,
|
||||
villagers_data.leah,
|
||||
villagers_data.maru,
|
||||
villagers_data.penny,
|
||||
villagers_data.caroline,
|
||||
villagers_data.clint,
|
||||
villagers_data.demetrius,
|
||||
villagers_data.evelyn,
|
||||
villagers_data.george,
|
||||
villagers_data.gus,
|
||||
villagers_data.jas,
|
||||
villagers_data.jodi,
|
||||
villagers_data.kent,
|
||||
villagers_data.krobus,
|
||||
villagers_data.lewis,
|
||||
villagers_data.linus,
|
||||
villagers_data.marnie,
|
||||
villagers_data.pam,
|
||||
villagers_data.pierre,
|
||||
villagers_data.robin,
|
||||
villagers_data.vincent,
|
||||
villagers_data.willy,
|
||||
villagers_data.wizard,
|
||||
)
|
||||
)
|
||||
36
worlds/stardew_valley/content/vanilla/qi_board.py
Normal file
36
worlds/stardew_valley/content/vanilla/qi_board.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from .ginger_island import ginger_island_content_pack as ginger_island_content_pack
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ...data import fish_data
|
||||
from ...data.game_item import GenericSource, ItemTag
|
||||
from ...data.harvest import HarvestCropSource
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
|
||||
|
||||
class QiBoardContentPack(ContentPack):
|
||||
def harvest_source_hook(self, content: StardewContent):
|
||||
content.untag_item(Seed.qi_bean, ItemTag.CROPSANITY_SEED)
|
||||
|
||||
|
||||
qi_board_content_pack = QiBoardContentPack(
|
||||
"Qi Board (Vanilla)",
|
||||
dependencies=(
|
||||
pelican_town_content_pack.name,
|
||||
ginger_island_content_pack.name,
|
||||
),
|
||||
harvest_sources={
|
||||
# This one is a bit special, because it's only available during the special order, but it can be found from like, everywhere.
|
||||
Seed.qi_bean: (GenericSource(regions=(Region.qi_walnut_room,)),),
|
||||
Fruit.qi_fruit: (HarvestCropSource(seed=Seed.qi_bean),),
|
||||
},
|
||||
fishes=(
|
||||
fish_data.ms_angler,
|
||||
fish_data.son_of_crimsonfish,
|
||||
fish_data.glacierfish_jr,
|
||||
fish_data.legend_ii,
|
||||
fish_data.radioactive_carp,
|
||||
)
|
||||
)
|
||||
46
worlds/stardew_valley/content/vanilla/the_desert.py
Normal file
46
worlds/stardew_valley/content/vanilla/the_desert.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack
|
||||
from ...data import fish_data, villagers_data
|
||||
from ...data.harvest import ForagingSource, HarvestCropSource
|
||||
from ...data.shop import ShopSource
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
|
||||
the_desert = ContentPack(
|
||||
"The Desert (Vanilla)",
|
||||
dependencies=(
|
||||
pelican_town_content_pack.name,
|
||||
),
|
||||
harvest_sources={
|
||||
Forageable.cactus_fruit: (
|
||||
ForagingSource(regions=(Region.desert,)),
|
||||
HarvestCropSource(seed=Seed.cactus, seasons=())
|
||||
),
|
||||
Forageable.coconut: (
|
||||
ForagingSource(regions=(Region.desert,)),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
ForagingSource(regions=(Region.skull_cavern_25,)),
|
||||
),
|
||||
|
||||
Fruit.rhubarb: (HarvestCropSource(seed=Seed.rhubarb, seasons=(Season.spring,)),),
|
||||
Fruit.starfruit: (HarvestCropSource(seed=Seed.starfruit, seasons=(Season.summer,)),),
|
||||
Vegetable.beet: (HarvestCropSource(seed=Seed.beet, seasons=(Season.fall,)),),
|
||||
},
|
||||
shop_sources={
|
||||
Seed.cactus: (ShopSource(money_price=150, shop_region=Region.oasis),),
|
||||
Seed.rhubarb: (ShopSource(money_price=100, shop_region=Region.oasis, seasons=(Season.spring,)),),
|
||||
Seed.starfruit: (ShopSource(money_price=400, shop_region=Region.oasis, seasons=(Season.summer,)),),
|
||||
Seed.beet: (ShopSource(money_price=20, shop_region=Region.oasis, seasons=(Season.fall,)),),
|
||||
},
|
||||
fishes=(
|
||||
fish_data.sandfish,
|
||||
fish_data.scorpion_carp,
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.sandy,
|
||||
),
|
||||
)
|
||||
43
worlds/stardew_valley/content/vanilla/the_farm.py
Normal file
43
worlds/stardew_valley/content/vanilla/the_farm.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack
|
||||
from ...data.harvest import FruitBatsSource, MushroomCaveSource
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
|
||||
the_farm = ContentPack(
|
||||
"The Farm (Vanilla)",
|
||||
dependencies=(
|
||||
pelican_town_content_pack.name,
|
||||
),
|
||||
harvest_sources={
|
||||
# Fruit cave
|
||||
Forageable.blackberry: (
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.salmonberry: (
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.spice_berry: (
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.wild_plum: (
|
||||
FruitBatsSource(),
|
||||
),
|
||||
|
||||
# Mushrooms
|
||||
Mushroom.common: (
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.chanterelle: (
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.morel: (
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.red: (
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
}
|
||||
)
|
||||
35
worlds/stardew_valley/content/vanilla/the_mines.py
Normal file
35
worlds/stardew_valley/content/vanilla/the_mines.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack
|
||||
from ...data import fish_data, villagers_data
|
||||
from ...data.harvest import ForagingSource
|
||||
from ...data.requirement import ToolRequirement
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.tool_names import Tool
|
||||
|
||||
the_mines = ContentPack(
|
||||
"The Mines (Vanilla)",
|
||||
dependencies=(
|
||||
pelican_town_content_pack.name,
|
||||
),
|
||||
harvest_sources={
|
||||
Forageable.cave_carrot: (
|
||||
ForagingSource(regions=(Region.mines_floor_10,), other_requirements=(ToolRequirement(Tool.hoe),)),
|
||||
),
|
||||
Mushroom.red: (
|
||||
ForagingSource(regions=(Region.mines_floor_95,)),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
ForagingSource(regions=(Region.mines_floor_95,)),
|
||||
)
|
||||
},
|
||||
fishes=(
|
||||
fish_data.ghostfish,
|
||||
fish_data.ice_pip,
|
||||
fish_data.lava_eel,
|
||||
fish_data.stonefish,
|
||||
),
|
||||
villagers=(
|
||||
villagers_data.dwarf,
|
||||
),
|
||||
)
|
||||
Reference in New Issue
Block a user