Skip to content

Commit

Permalink
Stardew valley: Add Marlon bedroom entrance rule (#3735)
Browse files Browse the repository at this point in the history
* - Created a test for the "Mapping Cave Systems" book

* - Added missing rule to marlon's bedroom

* - Can kill any monster, not just green slime

* - Added a compound source structure, but I ended up deciding to not use it here. Still keeping it as it will probably be useful eventually

* - Use the compound source of the monster compoundium (ironic, I know)

* - Add required elevators

---------

Co-authored-by: NewSoupVi <[email protected]>
  • Loading branch information
agilbert1412 and NewSoupVi authored Sep 17, 2024
1 parent 4e60f3c commit a7c9643
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 7 deletions.
8 changes: 5 additions & 3 deletions worlds/stardew_valley/content/vanilla/pelican_town.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ..game_content import ContentPack
from ...data import villagers_data, fish_data
from ...data.game_item import GenericSource, ItemTag, Tag, CustomRuleSource
from ...data.game_item import GenericSource, ItemTag, Tag, CustomRuleSource, CompoundSource
from ...data.harvest import ForagingSource, SeasonalForagingSource, ArtifactSpotSource
from ...data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement
from ...data.shop import ShopSource, MysteryBoxSource, ArtifactTroveSource, PrizeMachineSource, FishingTreasureChestSource
Expand Down Expand Up @@ -229,8 +229,10 @@
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),),
CompoundSource(sources=(
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)),
Expand Down
5 changes: 5 additions & 0 deletions worlds/stardew_valley/data/game_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class CustomRuleSource(ItemSource):
create_rule: Callable[[Any], StardewRule]


@dataclass(frozen=True, **kw_only)
class CompoundSource(ItemSource):
sources: Tuple[ItemSource, ...] = ()


class Tag(ItemSource):
"""Not a real source, just a way to add tags to an item. Will be removed from the item sources during unpacking."""
tag: Tuple[ItemTag, ...]
Expand Down
12 changes: 10 additions & 2 deletions worlds/stardew_valley/logic/source_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .requirement_logic import RequirementLogicMixin
from .tool_logic import ToolLogicMixin
from ..data.artisan import MachineSource
from ..data.game_item import GenericSource, ItemSource, GameItem, CustomRuleSource
from ..data.game_item import GenericSource, ItemSource, GameItem, CustomRuleSource, CompoundSource
from ..data.harvest import ForagingSource, FruitBatsSource, MushroomCaveSource, SeasonalForagingSource, \
HarvestCropSource, HarvestFruitTreeSource, ArtifactSpotSource
from ..data.shop import ShopSource, MysteryBoxSource, ArtifactTroveSource, PrizeMachineSource, FishingTreasureChestSource
Expand All @@ -25,7 +25,7 @@ def __init__(self, *args, **kwargs):


class SourceLogic(BaseLogic[Union[SourceLogicMixin, HasLogicMixin, ReceivedLogicMixin, HarvestingLogicMixin, MoneyLogicMixin, RegionLogicMixin,
ArtisanLogicMixin, ToolLogicMixin, RequirementLogicMixin, GrindLogicMixin]]):
ArtisanLogicMixin, ToolLogicMixin, RequirementLogicMixin, GrindLogicMixin]]):

def has_access_to_item(self, item: GameItem):
rules = []
Expand All @@ -40,6 +40,10 @@ def has_access_to_any(self, sources: Iterable[ItemSource]):
return self.logic.or_(*(self.logic.source.has_access_to(source) & self.logic.requirement.meet_all_requirements(source.other_requirements)
for source in sources))

def has_access_to_all(self, sources: Iterable[ItemSource]):
return self.logic.and_(*(self.logic.source.has_access_to(source) & self.logic.requirement.meet_all_requirements(source.other_requirements)
for source in sources))

@functools.singledispatchmethod
def has_access_to(self, source: Any):
raise ValueError(f"Sources of type{type(source)} have no rule registered.")
Expand All @@ -52,6 +56,10 @@ def _(self, source: GenericSource):
def _(self, source: CustomRuleSource):
return source.create_rule(self.logic)

@has_access_to.register
def _(self, source: CompoundSource):
return self.logic.source.has_access_to_all(source.sources)

@has_access_to.register
def _(self, source: ForagingSource):
return self.logic.harvesting.can_forage_from(source)
Expand Down
2 changes: 2 additions & 0 deletions worlds/stardew_valley/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, DeepWoodsEntrance, AlecEntrance, \
SVEEntrance, LaceyEntrance, BoardingHouseEntrance, LogicEntrance
from .strings.forageable_names import Forageable
from .strings.generic_names import Generic
from .strings.geode_names import Geode
from .strings.material_names import Material
from .strings.metal_names import MetalBar, Mineral
Expand Down Expand Up @@ -263,6 +264,7 @@ def set_entrance_rules(logic: StardewLogic, multiworld, player, world_options: S
set_entrance_rule(multiworld, player, LogicEntrance.buy_experience_books, logic.time.has_lived_months(2))
set_entrance_rule(multiworld, player, LogicEntrance.buy_year1_books, logic.time.has_year_two)
set_entrance_rule(multiworld, player, LogicEntrance.buy_year3_books, logic.time.has_year_three)
set_entrance_rule(multiworld, player, Entrance.adventurer_guild_to_bedroom, logic.monster.can_kill_max(Generic.any))


def set_dangerous_mine_rules(logic, multiworld, player, world_options: StardewValleyOptions):
Expand Down
4 changes: 2 additions & 2 deletions worlds/stardew_valley/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@ def run_default_tests(self) -> bool:
return False
return super().run_default_tests

def collect_lots_of_money(self):
def collect_lots_of_money(self, percent: float = 0.25):
self.multiworld.state.collect(self.world.create_item("Shipping Bin"), prevent_sweep=False)
real_total_prog_items = self.multiworld.worlds[self.player].total_progression_items
required_prog_items = int(round(real_total_prog_items * 0.25))
required_prog_items = int(round(real_total_prog_items * percent))
for i in range(required_prog_items):
self.multiworld.state.collect(self.world.create_item("Stardrop"), prevent_sweep=False)
self.multiworld.worlds[self.player].total_progression_items = real_total_prog_items
Expand Down
26 changes: 26 additions & 0 deletions worlds/stardew_valley/test/rules/TestBooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from ... import options
from ...test import SVTestBase


class TestBooksLogic(SVTestBase):
options = {
options.Booksanity.internal_name: options.Booksanity.option_all,
}

def test_need_weapon_for_mapping_cave_systems(self):
self.collect_lots_of_money(0.5)

location = self.multiworld.get_location("Read Mapping Cave Systems", self.player)

self.assert_reach_location_false(location, self.multiworld.state)

self.collect("Progressive Mine Elevator")
self.collect("Progressive Mine Elevator")
self.collect("Progressive Mine Elevator")
self.collect("Progressive Mine Elevator")
self.assert_reach_location_false(location, self.multiworld.state)

self.collect("Progressive Weapon")
self.assert_reach_location_true(location, self.multiworld.state)


0 comments on commit a7c9643

Please sign in to comment.