Stardew Valley: Added rules requiring museum access to make donations (#2107)

This commit is contained in:
agilbert1412 2023-08-16 10:18:50 -04:00 committed by GitHub
parent 6c7a7d2be5
commit 7ce9f20bc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 30 deletions

View File

@ -43,8 +43,8 @@ class MuseumItem(GameItem):
unlikely = ()
all_artifact_items: List[MuseumItem] = []
all_mineral_items: List[MuseumItem] = []
all_museum_artifacts: List[MuseumItem] = []
all_museum_minerals: List[MuseumItem] = []
all_museum_items: List[MuseumItem] = []
@ -56,7 +56,7 @@ def create_artifact(name: str,
geodes: Union[str, Tuple[str, ...]] = (),
monsters: Union[str, Tuple[str, ...]] = ()) -> MuseumItem:
artifact_item = MuseumItem.of(name, item_id, difficulty, locations, geodes, monsters)
all_artifact_items.append(artifact_item)
all_museum_artifacts.append(artifact_item)
all_museum_items.append(artifact_item)
return artifact_item
@ -79,7 +79,7 @@ def create_mineral(name: str,
difficulty += 31.0 / 2750.0 * 100
mineral_item = MuseumItem.of(name, item_id, difficulty, locations, geodes, monsters)
all_mineral_items.append(mineral_item)
all_museum_minerals.append(mineral_item)
all_museum_items.append(mineral_item)
return mineral_item

View File

@ -9,7 +9,7 @@ from .data import all_fish, FishItem, all_purchasable_seeds, SeedItem, all_crops
from .data.bundle_data import BundleItem
from .data.crops_data import crops_by_name
from .data.fish_data import island_fish
from .data.museum_data import all_museum_items, MuseumItem, all_artifact_items, dwarf_scrolls
from .data.museum_data import all_museum_items, MuseumItem, all_museum_artifacts, dwarf_scrolls, all_museum_minerals
from .data.recipe_data import all_cooking_recipes, CookingRecipe, RecipeSource, FriendshipSource, QueenOfSauceSource, \
StarterSource, ShopSource, SkillSource
from .data.villagers_data import all_villagers_by_name, Villager
@ -475,8 +475,8 @@ class StardewLogic:
FestivalCheck.mermaid_pearl: self.has_season(Season.winter) & self.can_reach_region(Region.beach),
FestivalCheck.cone_hat: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(2500),
FestivalCheck.iridium_fireplace: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(15000),
FestivalCheck.rarecrow_7: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_artifacts(20),
FestivalCheck.rarecrow_8: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_find_museum_items(40),
FestivalCheck.rarecrow_7: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_donate_museum_artifacts(20),
FestivalCheck.rarecrow_8: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(5000) & self.can_donate_museum_items(40),
FestivalCheck.lupini_red_eagle: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200),
FestivalCheck.lupini_portrait_mermaid: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200),
FestivalCheck.lupini_solar_kingdom: self.has_season(Season.winter) & self.can_reach_region(Region.beach) & self.can_spend_money(1200),
@ -1213,7 +1213,7 @@ class StardewLogic:
self.can_have_earned_total_money(1000000), # 1 000 000g second point
self.has_total_skill_level(30), # Total Skills: 30
self.has_total_skill_level(50), # Total Skills: 50
# Completing the museum not expected
self.can_complete_museum(), # Completing the museum for a point
# Catching every fish not expected
# Shipping every item not expected
self.can_get_married() & self.has_house(2),
@ -1224,7 +1224,7 @@ class StardewLogic:
self.can_complete_community_center(), # CC Ceremony first point
self.can_complete_community_center(), # CC Ceremony second point
self.received(Wallet.skull_key), # Skull Key obtained
self.has_rusty_key(), # Rusty key not expected
self.has_rusty_key(), # Rusty key obtained
]
return Count(12, rules_worth_a_point)
@ -1266,9 +1266,21 @@ class StardewLogic:
def can_speak_dwarf(self) -> StardewRule:
if self.options[options.Museumsanity] == options.Museumsanity.option_none:
return self.has([item.name for item in dwarf_scrolls])
return And([self.can_donate_museum_item(item) for item in dwarf_scrolls])
return self.received("Dwarvish Translation Guide")
def can_donate_museum_item(self, item: MuseumItem) -> StardewRule:
return self.can_reach_region(Region.museum) & self.can_find_museum_item(item)
def can_donate_museum_items(self, number: int) -> StardewRule:
return self.can_reach_region(Region.museum) & self.can_find_museum_items(number)
def can_donate_museum_artifacts(self, number: int) -> StardewRule:
return self.can_reach_region(Region.museum) & self.can_find_museum_artifacts(number)
def can_donate_museum_minerals(self, number: int) -> StardewRule:
return self.can_reach_region(Region.museum) & self.can_find_museum_minerals(number)
def can_find_museum_item(self, item: MuseumItem) -> StardewRule:
region_rule = self.can_reach_all_regions_except_one(item.locations)
geodes_rule = And([self.can_open_geode(geode) for geode in item.geodes])
@ -1281,9 +1293,15 @@ class StardewLogic:
def can_find_museum_artifacts(self, number: int) -> StardewRule:
rules = []
for donation in all_museum_items:
if donation in all_artifact_items:
rules.append(self.can_find_museum_item(donation))
for artifact in all_museum_artifacts:
rules.append(self.can_find_museum_item(artifact))
return Count(number, rules)
def can_find_museum_minerals(self, number: int) -> StardewRule:
rules = []
for mineral in all_museum_minerals:
rules.append(self.can_find_museum_item(mineral))
return Count(number, rules)
@ -1295,7 +1313,7 @@ class StardewLogic:
return Count(number, rules)
def can_complete_museum(self) -> StardewRule:
rules = [self.can_mine_perfectly()]
rules = [self.can_reach_region(Region.museum), self.can_mine_perfectly()]
if self.options[options.Museumsanity] != options.Museumsanity.option_none:
rules.append(self.received("Traveling Merchant Metal Detector", 4))

View File

@ -5,15 +5,14 @@ from BaseClasses import MultiWorld
from worlds.generic import Rules as MultiWorldRules
from . import options, locations
from .bundles import Bundle
from .data.crops_data import crops_by_name
from .strings.entrance_names import dig_to_mines_floor, dig_to_skull_floor, Entrance, move_to_woods_depth, \
DeepWoodsEntrance, AlecEntrance, MagicEntrance
from .data.museum_data import all_museum_items, all_mineral_items, all_artifact_items, \
from .data.museum_data import all_museum_items, all_museum_minerals, all_museum_artifacts, \
dwarf_scrolls, skeleton_front, \
skeleton_middle, skeleton_back, all_museum_items_by_name
skeleton_middle, skeleton_back, all_museum_items_by_name, Artifact
from .strings.region_names import Region
from .mods.mod_data import ModNames
from .mods.logic import magic, skills, deepwoods
from .mods.logic import magic, deepwoods
from .locations import LocationTags
from .logic import StardewLogic, And, tool_upgrade_prices
from .options import StardewOptions
@ -23,7 +22,6 @@ from .strings.calendar_names import Weekday
from .strings.craftable_names import Craftable
from .strings.material_names import Material
from .strings.metal_names import MetalBar
from .strings.spells import MagicSpell
from .strings.skill_names import ModSkill, Skill
from .strings.tool_names import Tool, ToolMaterial
from .strings.villager_names import NPC, ModNPC
@ -432,7 +430,7 @@ def set_museum_individual_donations_rules(all_location_names, logic: StardewLogi
if museum_location.name in all_location_names:
donation_name = museum_location.name[len(museum_prefix):]
required_detectors = counter * 5 // number_donations
rule = logic.has(donation_name) & logic.received("Traveling Merchant Metal Detector", required_detectors)
rule = logic.can_donate_museum_item(all_museum_items_by_name[donation_name]) & logic.received("Traveling Merchant Metal Detector", required_detectors)
MultiWorldRules.set_rule(multi_world.get_location(museum_location.name, player),
rule.simplify())
counter += 1
@ -447,31 +445,31 @@ def set_museum_milestone_rule(logic: StardewLogic, multi_world: MultiWorld, muse
metal_detector = "Traveling Merchant Metal Detector"
rule = None
if milestone_name.endswith(donations_suffix):
rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items)
rule = get_museum_item_count_rule(logic, donations_suffix, milestone_name, all_museum_items, logic.can_donate_museum_items)
elif milestone_name.endswith(minerals_suffix):
rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_mineral_items)
rule = get_museum_item_count_rule(logic, minerals_suffix, milestone_name, all_museum_minerals, logic.can_donate_museum_minerals)
elif milestone_name.endswith(artifacts_suffix):
rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_artifact_items)
rule = get_museum_item_count_rule(logic, artifacts_suffix, milestone_name, all_museum_artifacts, logic.can_donate_museum_artifacts)
elif milestone_name == "Dwarf Scrolls":
rule = logic.has([item.name for item in dwarf_scrolls]) & logic.received(metal_detector, 4)
rule = And([logic.can_donate_museum_item(item) for item in dwarf_scrolls]) & logic.received(metal_detector, 4)
elif milestone_name == "Skeleton Front":
rule = logic.has([item.name for item in skeleton_front]) & logic.received(metal_detector, 4)
rule = And([logic.can_donate_museum_item(item) for item in skeleton_front]) & logic.received(metal_detector, 4)
elif milestone_name == "Skeleton Middle":
rule = logic.has([item.name for item in skeleton_middle]) & logic.received(metal_detector, 4)
rule = And([logic.can_donate_museum_item(item) for item in skeleton_middle]) & logic.received(metal_detector, 4)
elif milestone_name == "Skeleton Back":
rule = logic.has([item.name for item in skeleton_back]) & logic.received(metal_detector, 4)
rule = And([logic.can_donate_museum_item(item) for item in skeleton_back]) & logic.received(metal_detector, 4)
elif milestone_name == "Ancient Seed":
rule = logic.has("Ancient Seed") & logic.received(metal_detector, 4)
rule = logic.can_donate_museum_item(Artifact.ancient_seed) & logic.received(metal_detector, 4)
if rule is None:
return
MultiWorldRules.set_rule(multi_world.get_location(museum_milestone.name, player), rule.simplify())
def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, accepted_items):
def get_museum_item_count_rule(logic: StardewLogic, suffix, milestone_name, accepted_items, donation_func):
metal_detector = "Traveling Merchant Metal Detector"
num = int(milestone_name[:milestone_name.index(suffix)])
required_detectors = (num - 1) * 5 // len(accepted_items)
rule = logic.has([item.name for item in accepted_items], num) & logic.received(metal_detector, required_detectors)
rule = donation_func(num) & logic.received(metal_detector, required_detectors)
return rule

View File

@ -2,10 +2,12 @@ from collections import Counter
from . import SVTestBase
from .. import options
from ..locations import locations_by_tag, LocationTags, location_table
from ..strings.animal_names import Animal
from ..strings.animal_product_names import AnimalProduct
from ..strings.artisan_good_names import ArtisanGood
from ..strings.crop_names import Vegetable
from ..strings.entrance_names import Entrance
from ..strings.food_names import Meal
from ..strings.ingredient_names import Ingredient
from ..strings.machine_names import Machine
@ -369,3 +371,76 @@ class TestRecipeLogic(SVTestBase):
# self.assertTrue(logic.has(Machine.cheese_press)(self.multiworld.state))
# self.assertTrue(logic.has(ArtisanGood.cheese)(self.multiworld.state))
# self.assertTrue(logic.has(Meal.pizza)(self.multiworld.state))
class TestDonationLogicAll(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_all
}
def test_cannot_make_any_donation_without_museum_access(self):
guild_item = "Adventurer's Guild"
swap_museum_and_guild(self.multiworld, self.player)
collect_all_except(self.multiworld, guild_item)
for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]:
self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item(guild_item), event=True)
for donation in locations_by_tag[LocationTags.MUSEUM_DONATIONS]:
self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
class TestDonationLogicRandomized(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_randomized
}
def test_cannot_make_any_donation_without_museum_access(self):
guild_item = "Adventurer's Guild"
swap_museum_and_guild(self.multiworld, self.player)
collect_all_except(self.multiworld, guild_item)
donation_locations = [location for location in self.multiworld.get_locations() if not location.event and LocationTags.MUSEUM_DONATIONS in location_table[location.name].tags]
for donation in donation_locations:
self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item(guild_item), event=True)
for donation in donation_locations:
self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
class TestDonationLogicMilestones(SVTestBase):
options = {
options.Museumsanity.internal_name: options.Museumsanity.option_milestones
}
def test_cannot_make_any_donation_without_museum_access(self):
guild_item = "Adventurer's Guild"
swap_museum_and_guild(self.multiworld, self.player)
collect_all_except(self.multiworld, guild_item)
for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]:
self.assertFalse(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
self.multiworld.state.collect(self.world.create_item(guild_item), event=True)
for donation in locations_by_tag[LocationTags.MUSEUM_MILESTONES]:
self.assertTrue(self.world.logic.can_reach_location(donation.name)(self.multiworld.state))
def swap_museum_and_guild(multiworld, player):
museum_region = multiworld.get_region(Region.museum, player)
guild_region = multiworld.get_region(Region.adventurer_guild, player)
museum_entrance = multiworld.get_entrance(Entrance.town_to_museum, player)
guild_entrance = multiworld.get_entrance(Entrance.mountain_to_adventurer_guild, player)
museum_entrance.connect(guild_region)
guild_entrance.connect(museum_region)
def collect_all_except(multiworld, item_to_not_collect: str):
for item in multiworld.get_items():
if item.name != item_to_not_collect:
multiworld.state.collect(item)