Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stardew Valley: Refactor buildings to use content packs #4239

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
929d823
create building data object and rename ItemSource to Source to be mor…
Jouramie Oct 14, 2024
c65917f
remove compound sources, replace by other requirements which already …
Jouramie Oct 14, 2024
1499a42
add coops to content packs
Jouramie Oct 14, 2024
8223ff5
add building progression in game features
Jouramie Oct 14, 2024
c868803
add shippping bin to starting building; remove has_house
Jouramie Oct 14, 2024
a36913f
replace config check with feature
Jouramie Oct 16, 2024
e1a225b
add other buildings in content packs
Jouramie Oct 19, 2024
865f0f8
not passing
Jouramie Oct 24, 2024
75e54dc
tests passes, unbelievable
Jouramie Nov 24, 2024
7f156a7
use newly create methods more
Jouramie Nov 24, 2024
9e7cfd9
use new assets to ease readability
Jouramie Nov 24, 2024
1a0b8a1
self review
Jouramie Nov 24, 2024
f95eb77
fix flake8 maybe
Jouramie Nov 25, 2024
187bdc4
properly split rule for mapping cave systems
Jouramie Nov 25, 2024
e9891ba
fix tractor garage name
Jouramie Dec 1, 2024
4735b53
self review
Jouramie Dec 1, 2024
304a01c
add upgrade_from to farm house buldings
Jouramie Dec 1, 2024
0e71f66
don't override building name variable in logic
Jouramie Dec 1, 2024
a48aebe
remove has_group from buildings
Jouramie Dec 1, 2024
61cfeb2
mark some items easy in grinding logic so blueprints buildings can be…
Jouramie Dec 1, 2024
43bf3c4
move stuff around to maybe avoid future conflicts cuz I have like 10 …
Jouramie Dec 14, 2024
e7a2623
remove price_multiplier, turns out it's unused during generation
Jouramie Dec 14, 2024
16ad797
disable shop source for mapping cave systems
Jouramie Dec 19, 2024
e44178a
bunch of code review changes
Jouramie Dec 19, 2024
746595f
add petbowl and farmhouse to autobuilding
Jouramie Dec 19, 2024
08c8fdf
set min easy items to 300
Jouramie Dec 20, 2024
f38f38f
Merge remote-tracking branch 'archipelago/main' into StardewValley/bu…
Jouramie Jan 23, 2025
11e3455
fix farm type
Jouramie Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions worlds/stardew_valley/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def create_region(name: str, exits: Iterable[str]) -> Region:
self.options)

def add_location(name: str, code: Optional[int], region: str):
region = world_regions[region]
region: Region = world_regions[region]
location = StardewLocation(self.player, name, code, region)
region.locations.append(location)

Expand All @@ -140,7 +140,7 @@ def add_location(name: str, code: Optional[int], region: str):

def create_items(self):
self.precollect_starting_season()
self.precollect_farm_type_items()
self.precollect_building_items()
items_to_exclude = [excluded_items
for excluded_items in self.multiworld.precollected_items[self.player]
if not item_table[excluded_items.name].has_any_group(Group.RESOURCE_PACK,
Expand Down Expand Up @@ -195,9 +195,16 @@ def precollect_starting_season(self):
starting_season = self.create_starting_item(self.random.choice(season_pool))
self.multiworld.push_precollected(starting_season)

def precollect_farm_type_items(self):
if self.options.farm_type == FarmType.option_meadowlands and self.options.building_progression & BuildingProgression.option_progressive:
self.multiworld.push_precollected(self.create_starting_item("Progressive Coop"))
def precollect_building_items(self):
building_progression = self.content.features.building_progression
# Not adding items when building are vanilla because the buildings are already placed in the world.
if not building_progression.is_progressive:
return

for building in building_progression.starting_buildings:
item, quantity = building_progression.to_progressive_item(building)
for _ in range(quantity):
self.multiworld.push_precollected(self.create_starting_item(item))

def setup_player_events(self):
self.setup_action_events()
Expand Down
30 changes: 29 additions & 1 deletion worlds/stardew_valley/content/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from . import content_packs
from .feature import cropsanity, friendsanity, fishsanity, booksanity, skill_progression
from .feature import cropsanity, friendsanity, fishsanity, booksanity, building_progression, skill_progression
from .game_content import ContentPack, StardewContent, StardewFeatures
from .unpacking import unpack_content
from .. import options
from ..strings.building_names import Building


def create_content(player_options: options.StardewValleyOptions) -> StardewContent:
Expand All @@ -29,6 +30,7 @@ def choose_content_packs(player_options: options.StardewValleyOptions):
def choose_features(player_options: options.StardewValleyOptions) -> StardewFeatures:
return StardewFeatures(
choose_booksanity(player_options.booksanity),
choose_building_progression(player_options.building_progression, player_options.farm_type),
choose_cropsanity(player_options.cropsanity),
choose_fishsanity(player_options.fishsanity),
choose_friendsanity(player_options.friendsanity, player_options.friendsanity_heart_size),
Expand Down Expand Up @@ -108,6 +110,32 @@ def choose_friendsanity(friendsanity_option: options.Friendsanity, heart_size: o
raise ValueError(f"No friendsanity feature mapped to {str(friendsanity_option.value)}")


def choose_building_progression(building_option: options.BuildingProgression,
farm_type_option: options.FarmType) -> building_progression.BuildingProgressionFeature:
starting_buildings = {Building.farm_house, Building.pet_bowl, Building.shipping_bin}

if farm_type_option == options.FarmType.option_meadowlands:
starting_buildings.add(Building.coop)

if (building_option == options.BuildingProgression.option_vanilla
or building_option == options.BuildingProgression.option_vanilla_cheap
or building_option == options.BuildingProgression.option_vanilla_very_cheap):
return building_progression.BuildingProgressionVanilla(
starting_buildings=starting_buildings,
)

starting_buildings.remove(Building.shipping_bin)

if (building_option == options.BuildingProgression.option_progressive
or building_option == options.BuildingProgression.option_progressive_cheap
or building_option == options.BuildingProgression.option_progressive_very_cheap):
return building_progression.BuildingProgressionProgressive(
starting_buildings=starting_buildings,
)

raise ValueError(f"No building progression feature mapped to {str(building_option.value)}")


skill_progression_by_option = {
options.SkillProgression.option_vanilla: skill_progression.SkillProgressionVanilla(),
options.SkillProgression.option_progressive: skill_progression.SkillProgressionProgressive(),
Expand Down
1 change: 1 addition & 0 deletions worlds/stardew_valley/content/feature/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from . import booksanity
from . import building_progression
from . import cropsanity
from . import fishsanity
from . import friendsanity
Expand Down
53 changes: 53 additions & 0 deletions worlds/stardew_valley/content/feature/building_progression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from abc import ABC
from dataclasses import dataclass
from typing import ClassVar, Set, Tuple

from ...strings.building_names import Building

progressive_house = "Progressive House"

# This assumes that the farm house is always available, which might not be true forever...
progressive_house_by_upgrade_name = {
Building.farm_house: 0,
Building.kitchen: 1,
Building.kids_room: 2,
Building.cellar: 3
}


def to_progressive_item(building: str) -> Tuple[str, int]:
"""Return the name of the progressive item and its quantity required to unlock the building.
"""
if building in [Building.coop, Building.barn, Building.shed]:
return f"Progressive {building}", 1
elif building.startswith("Big"):
return f"Progressive {building[building.index(' ') + 1:]}", 2
elif building.startswith("Deluxe"):
return f"Progressive {building[building.index(' ') + 1:]}", 3
elif building in progressive_house_by_upgrade_name:
return progressive_house, progressive_house_by_upgrade_name[building]

return building, 1


def to_location_name(building: str) -> str:
return f"{building} Blueprint"


@dataclass(frozen=True)
class BuildingProgressionFeature(ABC):
is_progressive: ClassVar[bool]
starting_buildings: Set[str]

to_progressive_item = staticmethod(to_progressive_item)
progressive_house = progressive_house

to_location_name = staticmethod(to_location_name)


class BuildingProgressionVanilla(BuildingProgressionFeature):
is_progressive = False


class BuildingProgressionProgressive(BuildingProgressionFeature):
is_progressive = True
24 changes: 16 additions & 8 deletions worlds/stardew_valley/content/game_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from dataclasses import dataclass, field
from typing import Dict, Iterable, Set, Any, Mapping, Type, Tuple, Union

from .feature import booksanity, cropsanity, fishsanity, friendsanity, skill_progression
from .feature import booksanity, cropsanity, fishsanity, friendsanity, skill_progression, building_progression
from ..data.building import Building
from ..data.fish_data import FishItem
from ..data.game_item import GameItem, ItemSource, ItemTag
from ..data.game_item import GameItem, Source, ItemTag
from ..data.skill import Skill
from ..data.villagers_data import Villager

Expand All @@ -20,16 +21,17 @@ class StardewContent:
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)
farm_buildings: Dict[str, Building] = 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]:
def find_sources_of_type(self, types: Union[Type[Source], Tuple[Type[Source]]]) -> Iterable[Source]:
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):
def source_item(self, item_name: str, *sources: Source):
item = self.game_items.setdefault(item_name, GameItem(item_name))
item.add_sources(sources)

Expand All @@ -50,6 +52,7 @@ def find_tagged_items(self, tag: ItemTag) -> Iterable[GameItem]:
@dataclass(frozen=True)
class StardewFeatures:
booksanity: booksanity.BooksanityFeature
building_progression: building_progression.BuildingProgressionFeature
cropsanity: cropsanity.CropsanityFeature
fishsanity: fishsanity.FishsanityFeature
friendsanity: friendsanity.FriendsanityFeature
Expand All @@ -69,13 +72,13 @@ class ContentPack:
# def item_hook
# ...

harvest_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
harvest_sources: Mapping[str, Iterable[Source]] = 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)
shop_sources: Mapping[str, Iterable[Source]] = field(default_factory=dict)

def shop_source_hook(self, content: StardewContent):
...
Expand All @@ -85,12 +88,12 @@ def shop_source_hook(self, content: StardewContent):
def fish_hook(self, content: StardewContent):
...

crafting_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
crafting_sources: Mapping[str, Iterable[Source]] = field(default_factory=dict)

def crafting_hook(self, content: StardewContent):
...

artisan_good_sources: Mapping[str, Iterable[ItemSource]] = field(default_factory=dict)
artisan_good_sources: Mapping[str, Iterable[Source]] = field(default_factory=dict)

def artisan_good_hook(self, content: StardewContent):
...
Expand All @@ -100,6 +103,11 @@ def artisan_good_hook(self, content: StardewContent):
def villager_hook(self, content: StardewContent):
...

farm_buildings: Iterable[Building] = ()

def farm_building_hook(self, content: StardewContent):
...

skills: Iterable[Skill] = ()

def skill_hook(self, content: StardewContent):
Expand Down
18 changes: 18 additions & 0 deletions worlds/stardew_valley/content/mods/tractor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
from ..game_content import ContentPack
from ..mod_registry import register_mod_content_pack
from ...data.building import Building
from ...data.shop import ShopSource
from ...mods.mod_data import ModNames
from ...strings.artisan_good_names import ArtisanGood
from ...strings.building_names import ModBuilding
from ...strings.metal_names import MetalBar
from ...strings.region_names import Region

register_mod_content_pack(ContentPack(
ModNames.tractor,
farm_buildings=(
Building(
ModBuilding.tractor_garage,
sources=(
ShopSource(
shop_region=Region.carpenter,
money_price=150_000,
items_price=((20, MetalBar.iron), (5, MetalBar.iridium), (1, ArtisanGood.battery_pack)),
),
),
),
),
))
8 changes: 6 additions & 2 deletions worlds/stardew_valley/content/unpacking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

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
from ..data.game_item import GameItem, Source


def unpack_content(features: StardewFeatures, packs: Iterable[ContentPack]) -> StardewContent:
Expand Down Expand Up @@ -61,6 +61,10 @@ def register_pack(content: StardewContent, pack: ContentPack):
content.villagers[villager.name] = villager
pack.villager_hook(content)

for building in pack.farm_buildings:
content.farm_buildings[building.name] = building
pack.farm_building_hook(content)

for skill in pack.skills:
content.skills[skill.name] = skill
pack.skill_hook(content)
Expand All @@ -73,7 +77,7 @@ def register_pack(content: StardewContent, pack: ContentPack):


def register_sources_and_call_hook(content: StardewContent,
sources_by_item_name: Mapping[str, Iterable[ItemSource]],
sources_by_item_name: Mapping[str, Iterable[Source]],
hook: Callable[[StardewContent], None]):
for item_name, sources in sources_by_item_name.items():
item = content.game_items.setdefault(item_name, GameItem(item_name))
Expand Down
Loading
Loading