mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-07 15:13:52 -08:00
Stardew Valley: 7.x.x - The Jojapocalypse Update (#5432)
Major Content update for Stardew Valley ### Features - New BundleRandomization Value: Meme Bundles - Over 100 custom bundles, designed to be jokes, references, trolls, etc - New Setting: Bundles Per Room modifier - New Setting: Backpack Size - New Setting: Secretsanity - Checks for triggering easter eggs and secrets - New Setting: Moviesanity - Checks for watching movies and sharing snacks with Villagers - New Setting: Eatsanity - Checks for eating items - New Setting: Hatsanity - Checks for wearing Hats - New Setting: Start Without - Allows you to select any combination of various "starting" items, that you will actually not start with. Notably, tools, backpack slots, Day5 unlocks, etc. - New Setting: Allowed Filler Items - Allows you to customize the filler items you'll get - New Setting: Endgame Locations - Checks for various expensive endgame tasks and purchases - New Shipsanity value: Crops and Fish - New Settings: Jojapocalypse and settings to customize it - Bundle Plando: Replaced with BundleWhitelist and BundleBlacklist, for more customization freedom - Added a couple of Host.yaml settings to help hosts allow or ban specific difficult settings that could cause problems if the people don't know what they are signing up for. Plus a truckload of improvements on the mod side, not seen in this PR. ### Removed features - Integration for Stardew Valley Expanded. It is simply disabled, the code is all still there, but I'm extremely tired of providing tech support for it, plus Stardew Valley 1.7 was announced and that will break it again, so I'm done. When a maintainer steps up, it can be re-enabled.
This commit is contained in:
@@ -1,30 +1,41 @@
|
||||
import logging
|
||||
import math
|
||||
import typing
|
||||
from collections import Counter
|
||||
from functools import wraps
|
||||
from random import Random
|
||||
from typing import Dict, Any, Optional, List, TextIO
|
||||
from typing import Dict, List, Any, ClassVar, TextIO, Optional
|
||||
|
||||
import entrance_rando
|
||||
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState
|
||||
from Options import PerGameCommonOptions
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from worlds.LauncherComponents import components, Component, icon_paths, Type
|
||||
from .bundles.bundle_room import BundleRoom
|
||||
from .bundles.bundles import get_all_bundles
|
||||
from .bundles.bundles import get_all_bundles, get_trash_bear_requests
|
||||
from .content import StardewContent, create_content
|
||||
from .early_items import setup_early_items
|
||||
from .items import item_table, ItemData, Group, items_by_group
|
||||
from .items.item_creation import create_items, get_all_filler_items, remove_limited_amount_packs, \
|
||||
generate_filler_choice_pool
|
||||
from .content.feature.special_order_locations import get_qi_gem_amount
|
||||
from .content.feature.walnutsanity import get_walnut_amount
|
||||
from .items import item_table, ItemData, Group, items_by_group, create_items, generate_filler_choice_pool, \
|
||||
setup_early_items
|
||||
from .items.item_data import FILLER_GROUPS
|
||||
from .locations import location_table, create_locations, LocationData, locations_by_tag
|
||||
from .logic.combat_logic import valid_weapons
|
||||
from .logic.logic import StardewLogic
|
||||
from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, EnabledFillerBuffs, \
|
||||
NumberOfMovementBuffs, BuildingProgression, EntranceRandomization, FarmType
|
||||
from .options.forced_options import force_change_options_if_incompatible
|
||||
NumberOfMovementBuffs, BuildingProgression, EntranceRandomization, ToolProgression, BackpackProgression, TrapDistribution, BundlePrice, \
|
||||
BundleWhitelist, BundleBlacklist, BundlePerRoom, FarmType
|
||||
from .options.forced_options import force_change_options_if_incompatible, force_change_options_if_banned
|
||||
from .options.jojapocalypse_options import JojaAreYouSure
|
||||
from .options.option_groups import sv_option_groups
|
||||
from .options.presets import sv_options_presets
|
||||
from .options.settings import StardewSettings
|
||||
from .options.worlds_group import apply_most_restrictive_options
|
||||
from .regions import create_regions, prepare_mod_data
|
||||
from .rules import set_rules
|
||||
from .stardew_rule import True_, StardewRule, HasProgressionPercent
|
||||
from .strings.ap_names.ap_option_names import StartWithoutOptionName
|
||||
from .strings.ap_names.ap_weapon_names import APWeapon
|
||||
from .strings.ap_names.event_names import Event
|
||||
from .strings.goal_names import Goal as GoalName
|
||||
|
||||
@@ -34,6 +45,7 @@ STARDEW_VALLEY = "Stardew Valley"
|
||||
UNIVERSAL_TRACKER_SEED_PROPERTY = "ut_seed"
|
||||
|
||||
client_version = 0
|
||||
TRACKER_ENABLED = True
|
||||
|
||||
|
||||
class StardewLocation(Location):
|
||||
@@ -42,6 +54,12 @@ class StardewLocation(Location):
|
||||
|
||||
class StardewItem(Item):
|
||||
game: str = STARDEW_VALLEY
|
||||
events_to_collect: Counter[str]
|
||||
|
||||
@wraps(Item.__init__)
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.events_to_collect = Counter()
|
||||
|
||||
|
||||
class StardewWebWorld(WebWorld):
|
||||
@@ -71,13 +89,35 @@ class StardewWebWorld(WebWorld):
|
||||
tutorials = [setup_en, setup_fr]
|
||||
|
||||
|
||||
if TRACKER_ENABLED:
|
||||
from .. import user_folder
|
||||
import os
|
||||
|
||||
# Best effort to detect if universal tracker is installed
|
||||
if any("tracker.apworld" in f.name for f in os.scandir(user_folder)):
|
||||
def launch_client(*args):
|
||||
from worlds.LauncherComponents import launch
|
||||
from .client import launch as client_main
|
||||
launch(client_main, name="Stardew Valley Tracker", args=args)
|
||||
|
||||
|
||||
components.append(Component(
|
||||
"Stardew Valley Tracker",
|
||||
func=launch_client,
|
||||
component_type=Type.CLIENT,
|
||||
icon='stardew'
|
||||
))
|
||||
|
||||
icon_paths['stardew'] = f"ap:{__name__}/stardew.png"
|
||||
|
||||
|
||||
class StardewValleyWorld(World):
|
||||
"""
|
||||
Stardew Valley is an open-ended country-life RPG. You can farm, fish, mine, fight, complete quests,
|
||||
befriend villagers, and uncover dark secrets.
|
||||
"""
|
||||
game = STARDEW_VALLEY
|
||||
topology_present = False
|
||||
topology_present = True
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = {name: data.code for name, data in location_table.items()}
|
||||
@@ -95,14 +135,17 @@ class StardewValleyWorld(World):
|
||||
|
||||
options_dataclass = StardewValleyOptions
|
||||
options: StardewValleyOptions
|
||||
settings: ClassVar[StardewSettings]
|
||||
content: StardewContent
|
||||
logic: StardewLogic
|
||||
|
||||
web = StardewWebWorld()
|
||||
modified_bundles: List[BundleRoom]
|
||||
randomized_entrances: Dict[str, str]
|
||||
trash_bear_requests: Dict[str, List[str]]
|
||||
|
||||
total_progression_items: int
|
||||
classifications_to_override_post_fill: list[tuple[StardewItem, ItemClassification]]
|
||||
|
||||
@classmethod
|
||||
def create_group(cls, multiworld: MultiWorld, new_player_id: int, players: set[int]) -> World:
|
||||
@@ -111,13 +154,15 @@ class StardewValleyWorld(World):
|
||||
group_options = typing.cast(StardewValleyOptions, world_group.options)
|
||||
worlds_options = [typing.cast(StardewValleyOptions, multiworld.worlds[player].options) for player in players]
|
||||
apply_most_restrictive_options(group_options, worlds_options)
|
||||
world_group.content = create_content(group_options)
|
||||
|
||||
return world_group
|
||||
|
||||
def __init__(self, multiworld: MultiWorld, player: int):
|
||||
super().__init__(multiworld, player)
|
||||
self.filler_item_pool_names = []
|
||||
self.filler_item_pool_names = None
|
||||
self.total_progression_items = 0
|
||||
self.classifications_to_override_post_fill = []
|
||||
|
||||
# Taking the seed specified in slot data for UT, otherwise just generating the seed.
|
||||
self.seed = getattr(multiworld, "re_gen_passthrough", {}).get(STARDEW_VALLEY, self.random.getrandbits(64))
|
||||
@@ -128,9 +173,25 @@ class StardewValleyWorld(World):
|
||||
seed = slot_data.get(UNIVERSAL_TRACKER_SEED_PROPERTY)
|
||||
if seed is None:
|
||||
logger.warning(f"World was generated before Universal Tracker support. Tracker might not be accurate.")
|
||||
for option_name in slot_data:
|
||||
if option_name in self.options_dataclass.type_hints:
|
||||
option_value = slot_data[option_name]
|
||||
option_type = self.options_dataclass.type_hints[option_name]
|
||||
if isinstance(option_value, option_type):
|
||||
self.options.__setattr__(option_name, option_value)
|
||||
continue
|
||||
parsed_option_value = option_type.from_any(option_value)
|
||||
if isinstance(parsed_option_value, option_type):
|
||||
self.options.__setattr__(option_name, parsed_option_value)
|
||||
continue
|
||||
logger.warning(f"Option {option_name} was found in slot data, but could not be automatically parsed to be used in generation.\n"
|
||||
f"Slot Data Value: {option_value}"
|
||||
f"Parsed Value: {parsed_option_value}"
|
||||
f"Yaml Value: {self.options.__getattribute__(option_name)}")
|
||||
return seed
|
||||
|
||||
def generate_early(self):
|
||||
force_change_options_if_banned(self.options, self.settings, self.player, self.player_name)
|
||||
force_change_options_if_incompatible(self.options, self.player, self.player_name)
|
||||
self.content = create_content(self.options)
|
||||
|
||||
@@ -141,23 +202,31 @@ class StardewValleyWorld(World):
|
||||
world_regions = create_regions(create_region, self.options, self.content)
|
||||
|
||||
self.logic = StardewLogic(self.player, self.options, self.content, world_regions.keys())
|
||||
self.modified_bundles = get_all_bundles(self.random, self.logic, self.content, self.options)
|
||||
self.modified_bundles = get_all_bundles(self.random, self.logic, self.content, self.options, self.player_name)
|
||||
self.trash_bear_requests = get_trash_bear_requests(self.random, self.content, self.options)
|
||||
|
||||
for bundle_room in self.modified_bundles:
|
||||
bundle_room.special_behavior(self)
|
||||
|
||||
def add_location(name: str, code: Optional[int], region: str):
|
||||
assert region in world_regions, f"Location {name} cannot be created in region {region}, because the region does not exist in this slot"
|
||||
region: Region = world_regions[region]
|
||||
location = StardewLocation(self.player, name, code, region)
|
||||
region.locations.append(location)
|
||||
|
||||
create_locations(add_location, self.modified_bundles, self.options, self.content, self.random)
|
||||
create_locations(add_location, self.modified_bundles, self.trash_bear_requests, self.options, self.content, self.random)
|
||||
self.multiworld.regions.extend(world_regions.values())
|
||||
|
||||
def create_items(self):
|
||||
self.precollect_start_inventory_items_if_needed()
|
||||
self.precollect_start_without_items()
|
||||
self.precollect_starting_season()
|
||||
self.precollect_building_items()
|
||||
self.precollect_starting_backpacks()
|
||||
items_to_exclude = [excluded_items
|
||||
for excluded_items in self.multiworld.precollected_items[self.player]
|
||||
if item_table[excluded_items.name].has_any_group(Group.MAXIMUM_ONE)
|
||||
or not item_table[excluded_items.name].has_any_group(Group.RESOURCE_PACK, Group.FRIENDSHIP_PACK)]
|
||||
or not item_table[excluded_items.name].has_any_group(*FILLER_GROUPS, Group.FRIENDSHIP_PACK)]
|
||||
|
||||
if self.options.season_randomization == SeasonRandomization.option_disabled:
|
||||
items_to_exclude = [item for item in items_to_exclude
|
||||
@@ -172,6 +241,7 @@ class StardewValleyWorld(World):
|
||||
self.multiworld.itempool += created_items
|
||||
|
||||
setup_early_items(self.multiworld, self.options, self.content, self.player, self.random)
|
||||
|
||||
self.setup_logic_events()
|
||||
self.setup_victory()
|
||||
|
||||
@@ -187,6 +257,31 @@ class StardewValleyWorld(World):
|
||||
self.total_progression_items += sum(1 for i in created_items if i.advancement)
|
||||
self.total_progression_items -= 1 # -1 for the victory event
|
||||
|
||||
player_state = self.multiworld.state.prog_items[self.player]
|
||||
self.update_received_progression_percent(player_state)
|
||||
|
||||
def precollect_start_inventory_items_if_needed(self):
|
||||
# The only reason this is necessary, is because in an UT context, precollected items was not filled up, and this messes with the seeded random later
|
||||
for item_name in self.options.start_inventory:
|
||||
item_count = self.options.start_inventory[item_name]
|
||||
precollected_count = len([precollected_item for precollected_item in self.multiworld.precollected_items[self.player]
|
||||
if precollected_item.name == item_name])
|
||||
while precollected_count < item_count:
|
||||
self.multiworld.push_precollected(self.create_item(item_name))
|
||||
precollected_count += 1
|
||||
|
||||
|
||||
def precollect_start_without_items(self):
|
||||
if StartWithoutOptionName.landslide not in self.options.start_without:
|
||||
self.multiworld.push_precollected(self.create_item("Landslide Removed"))
|
||||
if StartWithoutOptionName.community_center not in self.options.start_without:
|
||||
self.multiworld.push_precollected(self.create_item("Community Center Key"))
|
||||
self.multiworld.push_precollected(self.create_item("Forest Magic"))
|
||||
self.multiworld.push_precollected(self.create_item("Wizard Invitation"))
|
||||
if StartWithoutOptionName.buildings not in self.options.start_without:
|
||||
self.multiworld.push_precollected(self.create_item("Shipping Bin"))
|
||||
self.multiworld.push_precollected(self.create_item("Pet Bowl"))
|
||||
|
||||
def precollect_starting_season(self):
|
||||
if self.options.season_randomization == SeasonRandomization.option_progressive:
|
||||
return
|
||||
@@ -220,9 +315,23 @@ class StardewValleyWorld(World):
|
||||
for _ in range(quantity):
|
||||
self.multiworld.push_precollected(self.create_item(item))
|
||||
|
||||
def precollect_starting_backpacks(self):
|
||||
if self.options.backpack_progression != BackpackProgression.option_vanilla and StartWithoutOptionName.backpack in self.options.start_without:
|
||||
minimum_start_slots = 4 if StartWithoutOptionName.tools in self.options.start_without else 6
|
||||
num_starting_slots = max(minimum_start_slots, self.options.backpack_size.value)
|
||||
num_starting_backpacks = math.ceil(num_starting_slots / self.options.backpack_size.value)
|
||||
num_already_starting_backpacks = 0
|
||||
for precollected_item in self.multiworld.precollected_items[self.player]:
|
||||
if precollected_item.name == "Progressive Backpack":
|
||||
num_already_starting_backpacks += 1
|
||||
for i in range(num_starting_backpacks - num_already_starting_backpacks):
|
||||
self.multiworld.push_precollected(self.create_item("Progressive Backpack"))
|
||||
|
||||
def setup_logic_events(self):
|
||||
def register_event(name: str, region: str, rule: StardewRule):
|
||||
event_location = LocationData(None, region, name)
|
||||
def register_event(name: str, region: str, rule: StardewRule, location_name: str | None = None) -> None:
|
||||
if location_name is None:
|
||||
location_name = name
|
||||
event_location = LocationData(None, region, location_name)
|
||||
self.create_event_location(event_location, rule, name)
|
||||
|
||||
self.logic.setup_events(register_event)
|
||||
@@ -284,6 +393,14 @@ class StardewValleyWorld(World):
|
||||
self.create_event_location(location_table[GoalName.mystery_of_the_stardrops],
|
||||
self.logic.goal.can_complete_mystery_of_the_stardrop(),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_mad_hatter:
|
||||
self.create_event_location(location_table[GoalName.mad_hatter],
|
||||
self.logic.goal.can_complete_mad_hatter(self.get_all_location_names()),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_ultimate_foodie:
|
||||
self.create_event_location(location_table[GoalName.ultimate_foodie],
|
||||
self.logic.goal.can_complete_ultimate_foodie(self.get_all_location_names()),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_allsanity:
|
||||
self.create_event_location(location_table[GoalName.allsanity],
|
||||
self.logic.goal.can_complete_allsanity(),
|
||||
@@ -298,18 +415,36 @@ class StardewValleyWorld(World):
|
||||
def get_all_location_names(self) -> List[str]:
|
||||
return list(location.name for location in self.multiworld.get_locations(self.player))
|
||||
|
||||
def create_item(self, item: str | ItemData, override_classification: ItemClassification = None) -> StardewItem:
|
||||
def create_item(self, item: str | ItemData,
|
||||
classification_pre_fill: ItemClassification = None,
|
||||
classification_post_fill: ItemClassification = None) -> StardewItem:
|
||||
if isinstance(item, str):
|
||||
item = item_table[item]
|
||||
|
||||
if override_classification is None:
|
||||
override_classification = item.classification
|
||||
if classification_pre_fill is None:
|
||||
classification_pre_fill = item.classification
|
||||
|
||||
return StardewItem(item.name, override_classification, item.code, self.player)
|
||||
stardew_item = StardewItem(item.name, classification_pre_fill, item.code, self.player)
|
||||
|
||||
if stardew_item.advancement:
|
||||
# Progress is only counted for pre-fill progression items, so we don't count filler items later converted to progression post-fill.
|
||||
stardew_item.events_to_collect[Event.received_progression_item] = 1
|
||||
|
||||
if (walnut_amount := get_walnut_amount(stardew_item.name)) > 0:
|
||||
stardew_item.events_to_collect[Event.received_walnuts] = walnut_amount
|
||||
|
||||
if (qi_gem_amount := get_qi_gem_amount(stardew_item.name)) > 0:
|
||||
stardew_item.events_to_collect[Event.received_qi_gems] = qi_gem_amount
|
||||
|
||||
if classification_post_fill is not None:
|
||||
self.classifications_to_override_post_fill.append((stardew_item, classification_post_fill))
|
||||
|
||||
return stardew_item
|
||||
|
||||
def create_event_location(self, location_data: LocationData, rule: StardewRule, item: str):
|
||||
region = self.multiworld.get_region(location_data.region, self.player)
|
||||
region.add_event(location_data.name, item, rule, StardewLocation, StardewItem)
|
||||
item = typing.cast(StardewItem, region.add_event(location_data.name, item, rule, StardewLocation, StardewItem))
|
||||
item.events_to_collect[Event.received_progression_item] = 1
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self)
|
||||
@@ -322,9 +457,14 @@ class StardewValleyWorld(World):
|
||||
def generate_basic(self):
|
||||
pass
|
||||
|
||||
def post_fill(self) -> None:
|
||||
# Not updating the prog item count, as any change could make some locations inaccessible, which is pretty much illegal in post fill.
|
||||
for item, classification in self.classifications_to_override_post_fill:
|
||||
item.classification = classification
|
||||
|
||||
def get_filler_item_name(self) -> str:
|
||||
if not self.filler_item_pool_names:
|
||||
self.filler_item_pool_names = generate_filler_choice_pool(self.options)
|
||||
self.filler_item_pool_names = generate_filler_choice_pool(self.options, self.content)
|
||||
return self.random.choice(self.filler_item_pool_names)
|
||||
|
||||
def write_spoiler_header(self, spoiler_handle: TextIO) -> None:
|
||||
@@ -365,9 +505,10 @@ class StardewValleyWorld(World):
|
||||
for bundle in room.bundles:
|
||||
bundles[room.name][bundle.name] = {"number_required": bundle.number_required}
|
||||
for i, item in enumerate(bundle.items):
|
||||
bundles[room.name][bundle.name][i] = f"{item.get_item()}|{item.amount}|{item.quality}"
|
||||
bundles[room.name][bundle.name][str(i)] = f"{item.get_item()}|{item.amount}|{item.quality}"
|
||||
|
||||
excluded_options = [BundleRandomization, NumberOfMovementBuffs, EnabledFillerBuffs]
|
||||
excluded_options = [BundleRandomization, BundlePerRoom, NumberOfMovementBuffs,
|
||||
EnabledFillerBuffs, TrapDistribution, BundleWhitelist, BundleBlacklist, JojaAreYouSure]
|
||||
excluded_option_names = [option.internal_name for option in excluded_options]
|
||||
generic_option_names = [option_name for option_name in PerGameCommonOptions.type_hints]
|
||||
excluded_option_names.extend(generic_option_names)
|
||||
@@ -377,8 +518,9 @@ class StardewValleyWorld(World):
|
||||
UNIVERSAL_TRACKER_SEED_PROPERTY: self.seed,
|
||||
"seed": self.random.randrange(1000000000), # Seed should be max 9 digits
|
||||
"randomized_entrances": self.randomized_entrances,
|
||||
"trash_bear_requests": self.trash_bear_requests,
|
||||
"modified_bundles": bundles,
|
||||
"client_version": "6.0.0",
|
||||
"client_version": self.world_version.as_simple_string(),
|
||||
})
|
||||
|
||||
return slot_data
|
||||
@@ -389,18 +531,12 @@ class StardewValleyWorld(World):
|
||||
return False
|
||||
|
||||
player_state = state.prog_items[self.player]
|
||||
player_state.update(item.events_to_collect)
|
||||
|
||||
received_progression_count = player_state[Event.received_progression_item]
|
||||
received_progression_count += 1
|
||||
if self.total_progression_items:
|
||||
# Total progression items is not set until all items are created, but collect will be called during the item creation when an item is precollected.
|
||||
# We can't update the percentage if we don't know the total progression items, can't divide by 0.
|
||||
player_state[Event.received_progression_percent] = received_progression_count * 100 // self.total_progression_items
|
||||
player_state[Event.received_progression_item] = received_progression_count
|
||||
self.update_received_progression_percent(player_state)
|
||||
|
||||
walnut_amount = self.get_walnut_amount(item.name)
|
||||
if walnut_amount:
|
||||
player_state[Event.received_walnuts] += walnut_amount
|
||||
if item.name in APWeapon.all_weapons:
|
||||
player_state[Event.received_progressive_weapon] = max(player_state[Event.received_progressive_weapon], player_state[item.name])
|
||||
|
||||
return True
|
||||
|
||||
@@ -410,26 +546,18 @@ class StardewValleyWorld(World):
|
||||
return False
|
||||
|
||||
player_state = state.prog_items[self.player]
|
||||
player_state.subtract(item.events_to_collect)
|
||||
|
||||
received_progression_count = player_state[Event.received_progression_item]
|
||||
received_progression_count -= 1
|
||||
if self.total_progression_items:
|
||||
# We can't update the percentage if we don't know the total progression items, can't divide by 0.
|
||||
player_state[Event.received_progression_percent] = received_progression_count * 100 // self.total_progression_items
|
||||
player_state[Event.received_progression_item] = received_progression_count
|
||||
self.update_received_progression_percent(player_state)
|
||||
|
||||
walnut_amount = self.get_walnut_amount(item.name)
|
||||
if walnut_amount:
|
||||
player_state[Event.received_walnuts] -= walnut_amount
|
||||
if item.name in APWeapon.all_weapons:
|
||||
player_state[Event.received_progressive_weapon] = max(player_state[weapon] for weapon in APWeapon.all_weapons)
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_walnut_amount(item_name: str) -> int:
|
||||
if item_name == "Golden Walnut":
|
||||
return 1
|
||||
if item_name == "3 Golden Walnuts":
|
||||
return 3
|
||||
if item_name == "5 Golden Walnuts":
|
||||
return 5
|
||||
return 0
|
||||
def update_received_progression_percent(self, player_state: Counter[str]) -> None:
|
||||
if self.total_progression_items:
|
||||
received_progression_count = player_state[Event.received_progression_item]
|
||||
# Total progression items is not set until all items are created, but collect will be called during the item creation when an item is precollected.
|
||||
# We can't update the percentage if we don't know the total progression items, can't divide by 0.
|
||||
player_state[Event.received_progression_percent] = received_progression_count * 100 // self.total_progression_items
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"game": "Stardew Valley",
|
||||
"authors": ["Kaito Kid", "Jouramie", "Witchybun (Mod Support)", "Exempt-Medic (Proofreading)"],
|
||||
"minimum_ap_version": "0.6.4",
|
||||
"world_version": "6.0.0"
|
||||
"world_version": "7.4.0"
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ from dataclasses import dataclass
|
||||
from random import Random
|
||||
from typing import List, Tuple
|
||||
|
||||
from Options import DeathLink
|
||||
from .bundle_item import BundleItem
|
||||
from ..content import StardewContent
|
||||
from ..options import BundlePrice, StardewValleyOptions, ExcludeGingerIsland, FestivalLocations
|
||||
from ..strings.currency_names import Currency
|
||||
from ..options import BundlePrice, StardewValleyOptions, ExcludeGingerIsland, FestivalLocations, TrapDifficulty, \
|
||||
MultipleDaySleepEnabled, Gifting, EntranceRandomization
|
||||
from ..strings.bundle_names import MemeBundleName
|
||||
from ..strings.currency_names import Currency, MemeCurrency
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -19,6 +22,10 @@ class Bundle:
|
||||
def __repr__(self):
|
||||
return f"{self.name} -> {self.number_required} from {repr(self.items)}"
|
||||
|
||||
def special_behavior(self, world):
|
||||
if self.name == MemeBundleName.clickbait:
|
||||
world.options.exclude_locations.value.add(MemeBundleName.clickbait)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BundleTemplate:
|
||||
@@ -42,6 +49,7 @@ class BundleTemplate:
|
||||
template.number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
try:
|
||||
number_required, price_multiplier = get_bundle_final_prices(options.bundle_price, self.number_required_items, False)
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
@@ -53,13 +61,89 @@ class BundleTemplate:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(max(1, math.floor(item.amount * price_multiplier))) for item in chosen_items]
|
||||
chosen_items = [item.as_amount(min(999, max(1, math.floor(item.amount * price_multiplier)))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed at creating bundle '{self.name}'. Error: {e}")
|
||||
|
||||
|
||||
def can_appear(self, options: StardewValleyOptions) -> bool:
|
||||
if self.name == MemeBundleName.trap and options.trap_items.value == TrapDifficulty.option_no_traps:
|
||||
return False
|
||||
if self.name == MemeBundleName.hibernation and options.multiple_day_sleep_enabled == MultipleDaySleepEnabled.option_false:
|
||||
return False
|
||||
if self.name == MemeBundleName.cooperation and options.gifting == Gifting.option_false:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class FixedMultiplierBundleTemplate(BundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int,
|
||||
number_required_items: int):
|
||||
super().__init__(room, name, items, number_possible_items, number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
number_required = get_number_required_items(options.bundle_price, self.number_required_items)
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
number_chosen_items = self.number_possible_items
|
||||
if number_chosen_items < number_required:
|
||||
number_chosen_items = number_required
|
||||
|
||||
if number_chosen_items > number_items:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(min(999, max(1, item.amount))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
|
||||
|
||||
class FixedPriceBundleTemplate(BundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int,
|
||||
number_required_items: int):
|
||||
super().__init__(room, name, items, number_possible_items, number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
number_chosen_items = self.number_possible_items
|
||||
if number_chosen_items < self.number_required_items:
|
||||
number_chosen_items = self.number_required_items
|
||||
|
||||
if number_chosen_items > number_items:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(max(1, math.floor(item.amount))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, self.number_required_items)
|
||||
|
||||
|
||||
# This type of bundle will always match the number of slots and the number of items
|
||||
class FixedSlotsBundleTemplate(BundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int,
|
||||
number_required_items: int):
|
||||
super().__init__(room, name, items, number_possible_items, number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
try:
|
||||
number_required, price_multiplier = get_bundle_final_prices(options.bundle_price, self.number_required_items, False)
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
number_chosen_items = number_required
|
||||
if number_chosen_items > number_items:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(min(999, max(1, math.floor(item.amount * price_multiplier)))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed at creating bundle '{self.name}'. Error: {e}")
|
||||
|
||||
|
||||
|
||||
class CurrencyBundleTemplate(BundleTemplate):
|
||||
item: BundleItem
|
||||
|
||||
@@ -77,15 +161,33 @@ class CurrencyBundleTemplate(BundleTemplate):
|
||||
return currency_amount
|
||||
|
||||
def can_appear(self, options: StardewValleyOptions) -> bool:
|
||||
if not super().can_appear(options):
|
||||
return False
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
if self.item.item_name == Currency.qi_gem or self.item.item_name == Currency.golden_walnut or self.item.item_name == Currency.cinder_shard:
|
||||
return False
|
||||
if options.festival_locations == FestivalLocations.option_disabled:
|
||||
if self.item.item_name == Currency.star_token:
|
||||
return False
|
||||
if options.entrance_randomization != EntranceRandomization.option_disabled:
|
||||
if self.item.item_name == MemeCurrency.time_elapsed:
|
||||
return False
|
||||
if options.death_link != DeathLink.option_true:
|
||||
if self.item.item_name == MemeCurrency.deathlinks:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class FixedPriceCurrencyBundleTemplate(CurrencyBundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, item: BundleItem):
|
||||
super().__init__(room, name, item)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
currency_amount = self.item.amount
|
||||
return Bundle(self.room, self.name, [BundleItem(self.item.item_name, currency_amount)], 1)
|
||||
|
||||
|
||||
class MoneyBundleTemplate(CurrencyBundleTemplate):
|
||||
|
||||
def __init__(self, room: str, default_name: str, item: BundleItem):
|
||||
@@ -111,11 +213,15 @@ class MoneyBundleTemplate(CurrencyBundleTemplate):
|
||||
|
||||
class IslandBundleTemplate(BundleTemplate):
|
||||
def can_appear(self, options: StardewValleyOptions) -> bool:
|
||||
if not super().can_appear(options):
|
||||
return False
|
||||
return options.exclude_ginger_island == ExcludeGingerIsland.option_false
|
||||
|
||||
|
||||
class FestivalBundleTemplate(BundleTemplate):
|
||||
def can_appear(self, options: StardewValleyOptions) -> bool:
|
||||
if not super().can_appear(options):
|
||||
return False
|
||||
return options.festival_locations != FestivalLocations.option_disabled
|
||||
|
||||
|
||||
@@ -149,6 +255,96 @@ class DeepBundleTemplate(BundleTemplate):
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
|
||||
|
||||
class FixedPriceDeepBundleTemplate(DeepBundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, categories: List[List[BundleItem]], number_possible_items: int,
|
||||
number_required_items: int):
|
||||
super().__init__(room, name, categories, number_possible_items, number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
number_required = self.number_required_items
|
||||
number_categories = len(self.categories)
|
||||
number_chosen_categories = self.number_possible_items
|
||||
if number_chosen_categories < number_required:
|
||||
number_chosen_categories = number_required
|
||||
|
||||
if number_chosen_categories > number_categories:
|
||||
chosen_categories = self.categories + random.choices(self.categories,
|
||||
k=number_chosen_categories - number_categories)
|
||||
else:
|
||||
chosen_categories = random.sample(self.categories, number_chosen_categories)
|
||||
|
||||
chosen_items = []
|
||||
for category in chosen_categories:
|
||||
filtered_items = [item for item in category if item.can_appear(content, options)]
|
||||
chosen_items.append(random.choice(filtered_items))
|
||||
|
||||
chosen_items = [item.as_amount(max(1, math.floor(item.amount))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BureaucracyBundleTemplate(BundleTemplate):
|
||||
|
||||
def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int,
|
||||
number_required_items: int):
|
||||
super(BureaucracyBundleTemplate, self).__init__(room, name, items, number_possible_items, number_required_items)
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
number_required = self.number_required_items + options.bundle_price.value
|
||||
number_required = min(12, max(4, number_required))
|
||||
if options.bundle_price == BundlePrice.option_minimum:
|
||||
number_required = 4
|
||||
if options.bundle_price == BundlePrice.option_maximum:
|
||||
number_required = 12
|
||||
price_multiplier = 1
|
||||
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
number_chosen_items = self.number_possible_items
|
||||
if number_chosen_items < number_required:
|
||||
number_chosen_items = number_required
|
||||
|
||||
if number_chosen_items > number_items:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(max(1, math.floor(item.amount * price_multiplier))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
|
||||
|
||||
@dataclass
|
||||
class RecursiveBundleTemplate(BundleTemplate):
|
||||
number_sub_bundles: int
|
||||
|
||||
def __init__(self, room: str, name: str, items: List[BundleItem], number_possible_items: int,
|
||||
number_required_items: int, number_sub_bundles: int):
|
||||
super(RecursiveBundleTemplate, self).__init__(room, name, items, number_possible_items, number_required_items)
|
||||
self.number_sub_bundles = number_sub_bundles
|
||||
|
||||
def create_bundle(self, random: Random, content: StardewContent, options: StardewValleyOptions) -> Bundle:
|
||||
number_required = self.number_required_items + (options.bundle_price.value * self.number_sub_bundles)
|
||||
if options.bundle_price == BundlePrice.option_minimum:
|
||||
number_required = self.number_sub_bundles
|
||||
if options.bundle_price == BundlePrice.option_maximum:
|
||||
number_required = self.number_sub_bundles * 8
|
||||
number_required = min(self.number_sub_bundles * 8, max(self.number_sub_bundles, number_required))
|
||||
price_multiplier = get_price_multiplier(options.bundle_price, False)
|
||||
|
||||
filtered_items = [item for item in self.items if item.can_appear(content, options)]
|
||||
number_items = len(filtered_items)
|
||||
number_chosen_items = self.number_possible_items
|
||||
if number_chosen_items < number_required:
|
||||
number_chosen_items = number_required
|
||||
|
||||
if number_chosen_items > number_items:
|
||||
chosen_items = filtered_items + random.choices(filtered_items, k=number_chosen_items - number_items)
|
||||
else:
|
||||
chosen_items = random.sample(filtered_items, number_chosen_items)
|
||||
chosen_items = [item.as_amount(max(1, math.floor(item.amount * price_multiplier))) for item in chosen_items]
|
||||
return Bundle(self.room, self.name, chosen_items, number_required)
|
||||
|
||||
|
||||
def get_bundle_final_prices(bundle_price_option: BundlePrice, default_required_items: int, is_currency: bool) -> Tuple[int, float]:
|
||||
number_required_items = get_number_required_items(bundle_price_option, default_required_items)
|
||||
price_multiplier = get_price_multiplier(bundle_price_option, is_currency)
|
||||
|
||||
@@ -37,6 +37,11 @@ class MasteryItemSource(BundleItemSource):
|
||||
return content.features.skill_progression.are_masteries_shuffled
|
||||
|
||||
|
||||
class QiBoardItemSource(BundleItemSource):
|
||||
def can_appear(self, content: StardewContent, options: StardewValleyOptions) -> bool:
|
||||
return content_packs.qi_board_content_pack.name in content.registered_packs
|
||||
|
||||
|
||||
class ContentItemSource(BundleItemSource):
|
||||
"""This is meant to be used for items that are managed by the content packs."""
|
||||
|
||||
@@ -51,6 +56,7 @@ class BundleItem:
|
||||
island = IslandItemSource()
|
||||
festival = FestivalItemSource()
|
||||
masteries = MasteryItemSource()
|
||||
qi_board = QiBoardItemSource()
|
||||
content = ContentItemSource()
|
||||
|
||||
item_name: str
|
||||
|
||||
@@ -5,6 +5,7 @@ from typing import List
|
||||
from .bundle import Bundle, BundleTemplate
|
||||
from ..content import StardewContent
|
||||
from ..options import StardewValleyOptions
|
||||
from ..strings.bundle_names import CCRoom
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -12,6 +13,24 @@ class BundleRoom:
|
||||
name: str
|
||||
bundles: List[Bundle]
|
||||
|
||||
def special_behavior(self, world):
|
||||
for bundle in self.bundles:
|
||||
bundle.special_behavior(world)
|
||||
|
||||
|
||||
def simplify_name(name: str) -> str:
|
||||
return name.lower().replace(" ", "").replace("-", "").replace("_", "").replace(".", "")
|
||||
|
||||
|
||||
# In the context of meme bundles, some of the bundles are directly references to specific people, mostly content creators.
|
||||
# This ensures that they roll their own bundle as part of their community center.
|
||||
def is_bundle_related_to_player(bundle: BundleTemplate, player_name: str) -> bool:
|
||||
if player_name == "":
|
||||
return False
|
||||
simple_bundle = simplify_name(bundle.name)
|
||||
simple_player = simplify_name(player_name)
|
||||
return simple_player in simple_bundle or simple_bundle in simple_player
|
||||
|
||||
|
||||
@dataclass
|
||||
class BundleRoomTemplate:
|
||||
@@ -19,25 +38,40 @@ class BundleRoomTemplate:
|
||||
bundles: List[BundleTemplate]
|
||||
number_bundles: int
|
||||
|
||||
def create_bundle_room(self, random: Random, content: StardewContent, options: StardewValleyOptions):
|
||||
def create_bundle_room(self, random: Random, content: StardewContent, options: StardewValleyOptions, player_name: str = "", is_entire_cc: bool = False):
|
||||
filtered_bundles = [bundle for bundle in self.bundles if bundle.can_appear(options)]
|
||||
|
||||
priority_bundles = []
|
||||
whitelist_bundles = []
|
||||
unpriority_bundles = []
|
||||
blacklist_bundles = []
|
||||
for bundle in filtered_bundles:
|
||||
if bundle.name in options.bundle_plando:
|
||||
priority_bundles.append(bundle)
|
||||
else:
|
||||
if options.bundle_whitelist.prioritizes(bundle.name) or is_bundle_related_to_player(bundle, player_name):
|
||||
whitelist_bundles.append(bundle)
|
||||
elif options.bundle_blacklist.allows(bundle.name):
|
||||
unpriority_bundles.append(bundle)
|
||||
|
||||
if self.number_bundles <= len(priority_bundles):
|
||||
chosen_bundles = random.sample(priority_bundles, self.number_bundles)
|
||||
else:
|
||||
chosen_bundles = priority_bundles
|
||||
num_remaining_bundles = self.number_bundles - len(priority_bundles)
|
||||
if num_remaining_bundles > len(unpriority_bundles):
|
||||
blacklist_bundles.append(bundle)
|
||||
|
||||
modifier = options.bundle_per_room.value
|
||||
if is_entire_cc:
|
||||
modifier *= 6
|
||||
number_bundles = self.number_bundles + modifier
|
||||
bundles_cap = max(len(filtered_bundles), self.number_bundles)
|
||||
number_bundles = max(1, min(bundles_cap, number_bundles))
|
||||
if number_bundles < len(whitelist_bundles):
|
||||
chosen_bundles = random.sample(whitelist_bundles, number_bundles)
|
||||
else:
|
||||
chosen_bundles = whitelist_bundles
|
||||
num_remaining_bundles = number_bundles - len(whitelist_bundles)
|
||||
if num_remaining_bundles < len(unpriority_bundles):
|
||||
chosen_bundles.extend(random.sample(unpriority_bundles, num_remaining_bundles))
|
||||
else:
|
||||
chosen_bundles.extend(unpriority_bundles)
|
||||
num_remaining_bundles = num_remaining_bundles - len(unpriority_bundles)
|
||||
if num_remaining_bundles > 0:
|
||||
if self.name == CCRoom.raccoon_requests:
|
||||
chosen_bundles.extend(random.choices(unpriority_bundles, k=num_remaining_bundles))
|
||||
else:
|
||||
chosen_bundles.extend(random.sample(unpriority_bundles, num_remaining_bundles))
|
||||
chosen_bundles.extend(random.sample(blacklist_bundles, num_remaining_bundles))
|
||||
|
||||
return BundleRoom(self.name, [bundle.create_bundle(random, content, options) for bundle in chosen_bundles])
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
from random import Random
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, Dict
|
||||
|
||||
from .bundle import Bundle
|
||||
from .bundle_room import BundleRoom, BundleRoomTemplate
|
||||
from ..content import StardewContent
|
||||
from ..data.bundle_data import pantry_vanilla, crafts_room_vanilla, fish_tank_vanilla, boiler_room_vanilla, bulletin_board_vanilla, vault_vanilla, \
|
||||
pantry_thematic, crafts_room_thematic, fish_tank_thematic, boiler_room_thematic, bulletin_board_thematic, vault_thematic, pantry_remixed, \
|
||||
crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, all_bundle_items_except_money, \
|
||||
abandoned_joja_mart_thematic, abandoned_joja_mart_vanilla, abandoned_joja_mart_remixed, raccoon_vanilla, raccoon_thematic, raccoon_remixed, \
|
||||
community_center_remixed_anywhere
|
||||
from ..data.bundles_data.bundle_data import pantry_remixed, \
|
||||
crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, \
|
||||
all_bundle_items_except_money, \
|
||||
abandoned_joja_mart_remixed, giant_stump_remixed
|
||||
from ..data.bundles_data.bundle_set import vanilla_bundles, remixed_bundles, thematic_bundles
|
||||
from ..data.bundles_data.meme_bundles import community_center_meme_bundles, pantry_meme, crafts_room_meme, \
|
||||
fish_tank_meme, bulletin_board_meme, \
|
||||
boiler_room_meme, vault_meme
|
||||
from ..data.bundles_data.remixed_anywhere_bundles import community_center_remixed_anywhere
|
||||
from ..data.game_item import ItemTag
|
||||
from ..data.recipe_data import all_cooking_recipes
|
||||
from ..logic.logic import StardewLogic
|
||||
from ..options import BundleRandomization, StardewValleyOptions
|
||||
from ..strings.bundle_names import CCRoom
|
||||
|
||||
|
||||
def get_all_bundles(random: Random, logic: StardewLogic, content: StardewContent, options: StardewValleyOptions) -> List[BundleRoom]:
|
||||
def get_all_bundles(random: Random, logic: StardewLogic, content: StardewContent, options: StardewValleyOptions, player_name: str) -> List[BundleRoom]:
|
||||
if options.bundle_randomization == BundleRandomization.option_vanilla:
|
||||
return get_vanilla_bundles(random, content, options)
|
||||
elif options.bundle_randomization == BundleRandomization.option_thematic:
|
||||
@@ -24,72 +31,76 @@ def get_all_bundles(random: Random, logic: StardewLogic, content: StardewContent
|
||||
return get_remixed_bundles_anywhere(random, content, options)
|
||||
elif options.bundle_randomization == BundleRandomization.option_shuffled:
|
||||
return get_shuffled_bundles(random, logic, content, options)
|
||||
elif options.bundle_randomization == BundleRandomization.option_meme:
|
||||
return get_meme_bundles(random, content, options, player_name)
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def get_vanilla_bundles(random: Random, content: StardewContent, options: StardewValleyOptions) -> List[BundleRoom]:
|
||||
pantry = pantry_vanilla.create_bundle_room(random, content, options)
|
||||
crafts_room = crafts_room_vanilla.create_bundle_room(random, content, options)
|
||||
fish_tank = fish_tank_vanilla.create_bundle_room(random, content, options)
|
||||
boiler_room = boiler_room_vanilla.create_bundle_room(random, content, options)
|
||||
bulletin_board = bulletin_board_vanilla.create_bundle_room(random, content, options)
|
||||
vault = vault_vanilla.create_bundle_room(random, content, options)
|
||||
abandoned_joja_mart = abandoned_joja_mart_vanilla.create_bundle_room(random, content, options)
|
||||
raccoon = raccoon_vanilla.create_bundle_room(random, content, options)
|
||||
fix_raccoon_bundle_names(raccoon)
|
||||
return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart, raccoon]
|
||||
generated_bundle_rooms = {room_name: vanilla_bundles.bundles_by_room[room_name].create_bundle_room(random, content, options) for room_name in
|
||||
vanilla_bundles.bundles_by_room}
|
||||
fix_raccoon_bundle_names(generated_bundle_rooms[CCRoom.raccoon_requests])
|
||||
return list(generated_bundle_rooms.values())
|
||||
|
||||
|
||||
def get_thematic_bundles(random: Random, content: StardewContent, options: StardewValleyOptions) -> List[BundleRoom]:
|
||||
pantry = pantry_thematic.create_bundle_room(random, content, options)
|
||||
crafts_room = crafts_room_thematic.create_bundle_room(random, content, options)
|
||||
fish_tank = fish_tank_thematic.create_bundle_room(random, content, options)
|
||||
boiler_room = boiler_room_thematic.create_bundle_room(random, content, options)
|
||||
bulletin_board = bulletin_board_thematic.create_bundle_room(random, content, options)
|
||||
vault = vault_thematic.create_bundle_room(random, content, options)
|
||||
abandoned_joja_mart = abandoned_joja_mart_thematic.create_bundle_room(random, content, options)
|
||||
raccoon = raccoon_thematic.create_bundle_room(random, content, options)
|
||||
fix_raccoon_bundle_names(raccoon)
|
||||
return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart, raccoon]
|
||||
generated_bundle_rooms = {room_name: thematic_bundles.bundles_by_room[room_name].create_bundle_room(random, content, options) for room_name in
|
||||
thematic_bundles.bundles_by_room}
|
||||
fix_raccoon_bundle_names(generated_bundle_rooms[CCRoom.raccoon_requests])
|
||||
return list(generated_bundle_rooms.values())
|
||||
|
||||
|
||||
def get_remixed_bundles(random: Random, content: StardewContent, options: StardewValleyOptions) -> List[BundleRoom]:
|
||||
pantry = pantry_remixed.create_bundle_room(random, content, options)
|
||||
crafts_room = crafts_room_remixed.create_bundle_room(random, content, options)
|
||||
fish_tank = fish_tank_remixed.create_bundle_room(random, content, options)
|
||||
boiler_room = boiler_room_remixed.create_bundle_room(random, content, options)
|
||||
bulletin_board = bulletin_board_remixed.create_bundle_room(random, content, options)
|
||||
vault = vault_remixed.create_bundle_room(random, content, options)
|
||||
abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(random, content, options)
|
||||
raccoon = raccoon_remixed.create_bundle_room(random, content, options)
|
||||
fix_raccoon_bundle_names(raccoon)
|
||||
return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart, raccoon]
|
||||
generated_bundle_rooms = {room_name: remixed_bundles.bundles_by_room[room_name].create_bundle_room(random, content, options) for room_name in
|
||||
remixed_bundles.bundles_by_room}
|
||||
fix_raccoon_bundle_names(generated_bundle_rooms[CCRoom.raccoon_requests])
|
||||
return list(generated_bundle_rooms.values())
|
||||
|
||||
|
||||
def get_remixed_bundles_anywhere(random: Random, content: StardewContent, options: StardewValleyOptions) -> List[BundleRoom]:
|
||||
big_room = community_center_remixed_anywhere.create_bundle_room(random, content, options)
|
||||
big_room = community_center_remixed_anywhere.create_bundle_room(random, content, options, is_entire_cc=True)
|
||||
all_chosen_bundles = big_room.bundles
|
||||
random.shuffle(all_chosen_bundles)
|
||||
|
||||
end_index = 0
|
||||
|
||||
pantry, end_index = create_room_from_bundles(pantry_remixed, all_chosen_bundles, end_index)
|
||||
crafts_room, end_index = create_room_from_bundles(crafts_room_remixed, all_chosen_bundles, end_index)
|
||||
fish_tank, end_index = create_room_from_bundles(fish_tank_remixed, all_chosen_bundles, end_index)
|
||||
boiler_room, end_index = create_room_from_bundles(boiler_room_remixed, all_chosen_bundles, end_index)
|
||||
bulletin_board, end_index = create_room_from_bundles(bulletin_board_remixed, all_chosen_bundles, end_index)
|
||||
pantry, end_index = create_room_from_bundles(pantry_remixed, all_chosen_bundles, options, end_index)
|
||||
crafts_room, end_index = create_room_from_bundles(crafts_room_remixed, all_chosen_bundles, options, end_index)
|
||||
fish_tank, end_index = create_room_from_bundles(fish_tank_remixed, all_chosen_bundles, options, end_index)
|
||||
boiler_room, end_index = create_room_from_bundles(boiler_room_remixed, all_chosen_bundles, options, end_index)
|
||||
bulletin_board, end_index = create_room_from_bundles(bulletin_board_remixed, all_chosen_bundles, options, end_index)
|
||||
vault, end_index = create_room_from_bundles(vault_remixed, all_chosen_bundles, options, end_index)
|
||||
|
||||
vault = vault_remixed.create_bundle_room(random, content, options)
|
||||
abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(random, content, options)
|
||||
raccoon = raccoon_remixed.create_bundle_room(random, content, options)
|
||||
raccoon = giant_stump_remixed.create_bundle_room(random, content, options)
|
||||
fix_raccoon_bundle_names(raccoon)
|
||||
return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart, raccoon]
|
||||
|
||||
|
||||
def create_room_from_bundles(template: BundleRoomTemplate, all_bundles: List[Bundle], end_index: int) -> Tuple[BundleRoom, int]:
|
||||
def get_meme_bundles(random: Random, content: StardewContent, options: StardewValleyOptions, player_name: str) -> List[BundleRoom]:
|
||||
big_room = community_center_meme_bundles.create_bundle_room(random, content, options, player_name, is_entire_cc=True)
|
||||
all_chosen_bundles = big_room.bundles
|
||||
random.shuffle(all_chosen_bundles)
|
||||
|
||||
end_index = 0
|
||||
|
||||
pantry, end_index = create_room_from_bundles(pantry_meme, all_chosen_bundles, options, end_index)
|
||||
crafts_room, end_index = create_room_from_bundles(crafts_room_meme, all_chosen_bundles, options, end_index)
|
||||
fish_tank, end_index = create_room_from_bundles(fish_tank_meme, all_chosen_bundles, options, end_index)
|
||||
boiler_room, end_index = create_room_from_bundles(boiler_room_meme, all_chosen_bundles, options, end_index)
|
||||
bulletin_board, end_index = create_room_from_bundles(bulletin_board_meme, all_chosen_bundles, options, end_index)
|
||||
vault, end_index = create_room_from_bundles(vault_meme, all_chosen_bundles, options, end_index)
|
||||
|
||||
abandoned_joja_mart = abandoned_joja_mart_remixed.create_bundle_room(random, content, options)
|
||||
raccoon = giant_stump_remixed.create_bundle_room(random, content, options)
|
||||
fix_raccoon_bundle_names(raccoon)
|
||||
return [pantry, crafts_room, fish_tank, boiler_room, bulletin_board, vault, abandoned_joja_mart, raccoon]
|
||||
|
||||
|
||||
def create_room_from_bundles(template: BundleRoomTemplate, all_bundles: List[Bundle], options: StardewValleyOptions, end_index: int) -> Tuple[BundleRoom, int]:
|
||||
start_index = end_index
|
||||
end_index += template.number_bundles
|
||||
end_index += template.number_bundles + options.bundle_per_room.value
|
||||
return BundleRoom(template.name, all_bundles[start_index:end_index]), end_index
|
||||
|
||||
|
||||
@@ -122,3 +133,31 @@ def fix_raccoon_bundle_names(raccoon):
|
||||
for i in range(len(raccoon.bundles)):
|
||||
raccoon_bundle = raccoon.bundles[i]
|
||||
raccoon_bundle.name = f"Raccoon Request {i + 1}"
|
||||
|
||||
|
||||
def get_trash_bear_requests(random: Random, content: StardewContent, options: StardewValleyOptions) -> Dict[str, List[str]]:
|
||||
trash_bear_requests = dict()
|
||||
num_per_type = 2
|
||||
if options.bundle_price < 0:
|
||||
num_per_type = 1
|
||||
elif options.bundle_price > 0:
|
||||
num_per_type = min(4, num_per_type + options.bundle_price)
|
||||
|
||||
trash_bear_requests["Foraging"] = pick_trash_bear_items(ItemTag.FORAGE, content, num_per_type, random)
|
||||
if options.bundle_per_room >= 0:
|
||||
# Cooking items are not in content packs yet. This can be simplified once they are
|
||||
# trash_bear_requests["Cooking"] = pick_trash_bear_items(ItemTag.COOKING, content, num_per_type, random)
|
||||
trash_bear_requests["Cooking"] = random.sample(
|
||||
[recipe.meal for recipe in all_cooking_recipes if not recipe.content_pack or content.is_enabled(recipe.content_pack)], num_per_type)
|
||||
if options.bundle_per_room >= 1:
|
||||
trash_bear_requests["Farming"] = pick_trash_bear_items(ItemTag.CROPSANITY, content, num_per_type, random)
|
||||
if options.bundle_per_room >= 2:
|
||||
# Fish items are not tagged properly in content packs yet. This can be simplified once they are
|
||||
# trash_bear_requests["Fishing"] = pick_trash_bear_items(ItemTag.FISH, content, num_per_type, random)
|
||||
trash_bear_requests["Fishing"] = random.sample([fish for fish in content.fishes], num_per_type)
|
||||
return trash_bear_requests
|
||||
|
||||
|
||||
def pick_trash_bear_items(item_tag: ItemTag, content: StardewContent, number_items: int, random: Random):
|
||||
forage_items = [item.name for item in content.find_tagged_items(item_tag)]
|
||||
return random.sample(forage_items, number_items)
|
||||
|
||||
284
worlds/stardew_valley/client.py
Normal file
284
worlds/stardew_valley/client.py
Normal file
@@ -0,0 +1,284 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import re
|
||||
# webserver imports
|
||||
import urllib.parse
|
||||
from collections.abc import Iterable
|
||||
|
||||
import Utils
|
||||
from BaseClasses import CollectionState, Location
|
||||
from CommonClient import logger, get_base_parser, gui_enabled, server_loop
|
||||
from MultiServer import mark_raw
|
||||
from NetUtils import JSONMessagePart
|
||||
from kvui import CommandPromptTextInput
|
||||
from . import StardewValleyWorld
|
||||
from .logic.logic import StardewLogic
|
||||
from .stardew_rule.rule_explain import explain, ExplainMode, RuleExplanation
|
||||
|
||||
try:
|
||||
from worlds.tracker.TrackerClient import TrackerGameContext, TrackerCommandProcessor as ClientCommandProcessor, UT_VERSION # noqa
|
||||
from worlds.tracker.TrackerCore import TrackerCore
|
||||
|
||||
tracker_loaded = True
|
||||
except ImportError as e:
|
||||
logger.error(e)
|
||||
from CommonClient import CommonContext, ClientCommandProcessor
|
||||
|
||||
TrackerCore = object
|
||||
|
||||
|
||||
class TrackerGameContextMixin:
|
||||
"""Expecting the TrackerGameContext to have these methods."""
|
||||
tracker_core: TrackerCore
|
||||
|
||||
def make_gui(self, manager):
|
||||
...
|
||||
|
||||
def run_generator(self):
|
||||
...
|
||||
|
||||
|
||||
class TrackerGameContext(CommonContext, TrackerGameContextMixin):
|
||||
pass
|
||||
|
||||
|
||||
tracker_loaded = False
|
||||
UT_VERSION = "Not found"
|
||||
|
||||
|
||||
class StardewCommandProcessor(ClientCommandProcessor):
|
||||
ctx: StardewClientContext
|
||||
|
||||
@mark_raw
|
||||
def _cmd_explain(self, location: str = ""):
|
||||
"""Explain the logic behind a location."""
|
||||
logic = self.ctx.logic
|
||||
if logic is None:
|
||||
return
|
||||
|
||||
try:
|
||||
rule = logic.region.can_reach_location(location)
|
||||
expl = explain(rule, self.ctx.current_state, expected=None, mode=ExplainMode.CLIENT)
|
||||
except KeyError:
|
||||
|
||||
result, usable, response = Utils.get_intended_text(location, [loc.name for loc in self.ctx.all_locations])
|
||||
if usable:
|
||||
rule = logic.region.can_reach_location(result)
|
||||
expl = explain(rule, self.ctx.current_state, expected=None, mode=ExplainMode.CLIENT)
|
||||
else:
|
||||
self.ctx.ui.last_autofillable_command = "/explain"
|
||||
self.output(response)
|
||||
return
|
||||
|
||||
self.ctx.previous_explanation = expl
|
||||
self.ctx.ui.print_json(parse_explanation(expl))
|
||||
|
||||
@mark_raw
|
||||
def _cmd_explain_item(self, item: str = ""):
|
||||
"""Explain the logic behind a game item."""
|
||||
logic = self.ctx.logic
|
||||
if logic is None:
|
||||
return
|
||||
|
||||
result, usable, response = Utils.get_intended_text(item, logic.registry.item_rules.keys())
|
||||
if usable:
|
||||
rule = logic.has(result)
|
||||
expl = explain(rule, self.ctx.current_state, expected=None, mode=ExplainMode.CLIENT)
|
||||
else:
|
||||
self.ctx.ui.last_autofillable_command = "/explain_item"
|
||||
self.output(response)
|
||||
return
|
||||
|
||||
self.ctx.previous_explanation = expl
|
||||
self.ctx.ui.print_json(parse_explanation(expl))
|
||||
|
||||
@mark_raw
|
||||
def _cmd_explain_missing(self, location: str = ""):
|
||||
"""Explain what is missing for a location to be in logic. It explains the logic behind a location, while skipping the rules that are already satisfied."""
|
||||
self.__explain("/explain_missing", location, expected=True)
|
||||
|
||||
@mark_raw
|
||||
def _cmd_explain_how(self, location: str = ""):
|
||||
"""Explain how a location is in logic. It explains the logic behind the location, while skipping the rules that are not satisfied."""
|
||||
self.__explain("/explain_how", location, expected=False)
|
||||
|
||||
def __explain(self, command: str, location: str, expected: bool | None = None):
|
||||
logic = self.ctx.logic
|
||||
if logic is None:
|
||||
return
|
||||
|
||||
try:
|
||||
rule = logic.region.can_reach_location(location)
|
||||
expl = explain(rule, self.ctx.current_state, expected=expected, mode=ExplainMode.CLIENT)
|
||||
except KeyError:
|
||||
|
||||
result, usable, response = Utils.get_intended_text(location, [loc.name for loc in self.ctx.all_locations])
|
||||
if usable:
|
||||
rule = logic.region.can_reach_location(result)
|
||||
expl = explain(rule, self.ctx.current_state, expected=expected, mode=ExplainMode.CLIENT)
|
||||
else:
|
||||
self.ctx.ui.last_autofillable_command = command
|
||||
self.output(response)
|
||||
return
|
||||
|
||||
self.ctx.previous_explanation = expl
|
||||
self.ctx.ui.print_json(parse_explanation(expl))
|
||||
|
||||
@mark_raw
|
||||
def _cmd_more(self, index: str = ""):
|
||||
"""Will tell you what's missing to consider a location in logic."""
|
||||
if self.ctx.previous_explanation is None:
|
||||
self.output("No previous explanation found.")
|
||||
return
|
||||
|
||||
try:
|
||||
expl = self.ctx.previous_explanation.more(int(index))
|
||||
except (ValueError, IndexError):
|
||||
self.output("Which previous rule do you want to explained?")
|
||||
self.ctx.ui.last_autofillable_command = "/more"
|
||||
for i, rule in enumerate(self.ctx.previous_explanation.more_explanations):
|
||||
# TODO handle autofillable commands
|
||||
self.output(f"/more {i} -> {str(rule)})")
|
||||
return
|
||||
|
||||
self.ctx.previous_explanation = expl
|
||||
self.ctx.ui.print_json(parse_explanation(expl))
|
||||
|
||||
if not tracker_loaded:
|
||||
del _cmd_explain
|
||||
del _cmd_explain_missing
|
||||
|
||||
|
||||
class StardewClientContext(TrackerGameContext):
|
||||
game = "Stardew Valley"
|
||||
command_processor = StardewCommandProcessor
|
||||
previous_explanation: RuleExplanation | None = None
|
||||
|
||||
def make_gui(self):
|
||||
ui = super().make_gui() # before the kivy imports so kvui gets loaded first
|
||||
|
||||
class StardewManager(ui):
|
||||
base_title = f"Stardew Valley Tracker with UT {UT_VERSION} for AP version" # core appends ap version so this works
|
||||
ctx: StardewClientContext
|
||||
|
||||
def build(self):
|
||||
container = super().build()
|
||||
if not tracker_loaded:
|
||||
logger.info("To enable the tracker page, install Universal Tracker.")
|
||||
|
||||
# Until self.ctx.ui.last_autofillable_command allows for / commands, this is needed to remove the "!" before the /commands when using intended text autofill.
|
||||
def on_text_remove_hardcoded_exclamation_mark_garbage(textinput: CommandPromptTextInput, text: str) -> None:
|
||||
if text.startswith("!/"):
|
||||
textinput.text = text[1:]
|
||||
|
||||
self.textinput.bind(text=on_text_remove_hardcoded_exclamation_mark_garbage)
|
||||
|
||||
return container
|
||||
|
||||
return StardewManager
|
||||
|
||||
@property
|
||||
def logic(self) -> StardewLogic | None:
|
||||
if self.tracker_core.get_current_world() is None:
|
||||
logger.warning("Internal logic was not able to load, check your yamls and relaunch.")
|
||||
return None
|
||||
|
||||
if self.game != "Stardew Valley":
|
||||
logger.warning(f"Please connect to a slot with explainable logic (not {self.game}).")
|
||||
return None
|
||||
|
||||
return self.tracker_core.get_current_world().logic
|
||||
|
||||
@property
|
||||
def current_state(self) -> CollectionState:
|
||||
return self.tracker_core.updateTracker().state
|
||||
|
||||
@property
|
||||
def world(self) -> StardewValleyWorld:
|
||||
return self.tracker_core.get_current_world()
|
||||
|
||||
@property
|
||||
def all_locations(self) -> Iterable[Location]:
|
||||
return self.tracker_core.multiworld.get_locations(self.tracker_core.player_id)
|
||||
|
||||
|
||||
def parse_explanation(explanation: RuleExplanation) -> list[JSONMessagePart]:
|
||||
# Split the explanation in parts, by isolating all the delimiters, being \(, \), & , -> , | , \d+x , \[ , \] , \(\w+\), \n\s*
|
||||
result_regex = r"(\(|\)| & | -> | \| |\d+x | \[|\](?: ->)?\s*| \(\w+\)|\n\s*)"
|
||||
splits = re.split(result_regex, str(explanation).strip())
|
||||
|
||||
messages = []
|
||||
for s in splits:
|
||||
if len(s) == 0:
|
||||
continue
|
||||
|
||||
if s == "True":
|
||||
messages.append({"type": "color", "color": "green", "text": s})
|
||||
elif s == "False":
|
||||
messages.append({"type": "color", "color": "salmon", "text": s})
|
||||
elif s.startswith("Reach Location "):
|
||||
messages.append({"type": "text", "text": "Reach Location "})
|
||||
messages.append({"type": "location_name", "text": s[15:]})
|
||||
elif s.startswith("Reach Entrance "):
|
||||
messages.append({"type": "text", "text": "Reach Entrance "})
|
||||
messages.append({"type": "entrance_name", "text": s[15:]})
|
||||
elif s.startswith("Reach Region "):
|
||||
messages.append({"type": "text", "text": "Reach Region "})
|
||||
messages.append({"type": "color", "color": "yellow", "text": s[13:]})
|
||||
elif s.startswith("Received event "):
|
||||
messages.append({"type": "text", "text": "Received event "})
|
||||
messages.append({"type": "item_name", "text": s[15:]})
|
||||
elif s.startswith("Received "):
|
||||
messages.append({"type": "text", "text": "Received "})
|
||||
messages.append({"type": "item_name", "flags": 0b001, "text": s[9:]})
|
||||
elif s.startswith("Has "):
|
||||
if s[4].isdigit():
|
||||
messages.append({"type": "text", "text": "Has "})
|
||||
digit_end = re.search(r"\D", s[4:])
|
||||
digit = s[4:4 + digit_end.start()]
|
||||
messages.append({"type": "color", "color": "cyan", "text": digit})
|
||||
messages.append({"type": "text", "text": s[4 + digit_end.start():]})
|
||||
|
||||
else:
|
||||
messages.append({"text": s, "type": "text"})
|
||||
else:
|
||||
messages.append({"text": s, "type": "text"})
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
async def main(args):
|
||||
ctx = StardewClientContext(args.connect, args.password)
|
||||
|
||||
ctx.auth = args.name
|
||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="server loop")
|
||||
|
||||
if tracker_loaded:
|
||||
ctx.run_generator()
|
||||
else:
|
||||
logger.warning("Could not find Universal Tracker.")
|
||||
|
||||
if gui_enabled:
|
||||
ctx.run_gui()
|
||||
ctx.run_cli()
|
||||
|
||||
await ctx.exit_event.wait()
|
||||
await ctx.shutdown()
|
||||
|
||||
|
||||
def launch(*args):
|
||||
parser = get_base_parser(description="Gameless Archipelago Client, for text interfacing.")
|
||||
parser.add_argument('--name', default=None, help="Slot Name to connect as.")
|
||||
parser.add_argument("url", nargs="?", help="Archipelago connection url")
|
||||
args = parser.parse_args(args)
|
||||
|
||||
if args.url:
|
||||
url = urllib.parse.urlparse(args.url)
|
||||
args.connect = url.netloc
|
||||
if url.username:
|
||||
args.name = urllib.parse.unquote(url.username)
|
||||
if url.password:
|
||||
args.password = urllib.parse.unquote(url.password)
|
||||
|
||||
asyncio.run(main(args))
|
||||
@@ -1,8 +1,9 @@
|
||||
from . import content_packs
|
||||
from .feature import cropsanity, friendsanity, fishsanity, booksanity, building_progression, skill_progression, tool_progression
|
||||
from .feature import cropsanity, friendsanity, fishsanity, booksanity, building_progression, skill_progression, tool_progression, hatsanity, museumsanity
|
||||
from .game_content import ContentPack, StardewContent, StardewFeatures
|
||||
from .unpacking import unpack_content
|
||||
from .. import options
|
||||
from ..strings.ap_names.ap_option_names import StartWithoutOptionName
|
||||
from ..strings.building_names import Building
|
||||
|
||||
|
||||
@@ -34,8 +35,10 @@ def choose_features(player_options: options.StardewValleyOptions) -> StardewFeat
|
||||
choose_cropsanity(player_options.cropsanity),
|
||||
choose_fishsanity(player_options.fishsanity),
|
||||
choose_friendsanity(player_options.friendsanity, player_options.friendsanity_heart_size),
|
||||
choose_hatsanity(player_options.hatsanity),
|
||||
choose_museumsanity(player_options.museumsanity),
|
||||
choose_skill_progression(player_options.skill_progression),
|
||||
choose_tool_progression(player_options.tool_progression, player_options.skill_progression),
|
||||
choose_tool_progression(player_options.tool_progression, player_options.skill_progression, player_options.start_without),
|
||||
)
|
||||
|
||||
|
||||
@@ -56,6 +59,33 @@ def choose_booksanity(booksanity_option: options.Booksanity) -> booksanity.Books
|
||||
return booksanity_feature
|
||||
|
||||
|
||||
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)
|
||||
starting_buildings.remove(Building.pet_bowl)
|
||||
|
||||
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)}")
|
||||
|
||||
|
||||
cropsanity_by_option = {
|
||||
options.Cropsanity.option_disabled: cropsanity.CropsanityDisabled(),
|
||||
options.Cropsanity.option_enabled: cropsanity.CropsanityEnabled(),
|
||||
@@ -111,30 +141,27 @@ 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}
|
||||
def choose_hatsanity(hat_option: options.Hatsanity) -> hatsanity.HatsanityFeature:
|
||||
if hat_option == options.Hatsanity.preset_none:
|
||||
return hatsanity.HatsanityNone()
|
||||
|
||||
if farm_type_option == options.FarmType.option_meadowlands:
|
||||
starting_buildings.add(Building.coop)
|
||||
return hatsanity.HatsanityHats(enabled_hats=frozenset(hat_option.value))
|
||||
|
||||
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)
|
||||
def choose_museumsanity(museumsanity_option: options.Museumsanity) -> museumsanity.MuseumsanityFeature:
|
||||
if museumsanity_option == options.Museumsanity.option_none:
|
||||
return museumsanity.MuseumsanityNone()
|
||||
|
||||
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,
|
||||
)
|
||||
if museumsanity_option == options.Museumsanity.option_milestones:
|
||||
return museumsanity.MuseumsanityMilestones()
|
||||
|
||||
raise ValueError(f"No building progression feature mapped to {str(building_option.value)}")
|
||||
if museumsanity_option == options.Museumsanity.option_randomized:
|
||||
return museumsanity.MuseumsanityRandomized()
|
||||
|
||||
if museumsanity_option == options.Museumsanity.option_all:
|
||||
return museumsanity.MuseumsanityAll()
|
||||
|
||||
raise ValueError(f"No museumsanity feature mapped to {str(museumsanity_option.value)}")
|
||||
|
||||
|
||||
skill_progression_by_option = {
|
||||
@@ -153,16 +180,17 @@ def choose_skill_progression(skill_progression_option: options.SkillProgression)
|
||||
return skill_progression_feature
|
||||
|
||||
|
||||
def choose_tool_progression(tool_option: options.ToolProgression, skill_option: options.SkillProgression) -> tool_progression.ToolProgressionFeature:
|
||||
def choose_tool_progression(tool_option: options.ToolProgression, skill_option: options.SkillProgression, start_without_option: options.StartWithout) -> tool_progression.ToolProgressionFeature:
|
||||
if tool_option.is_vanilla:
|
||||
return tool_progression.ToolProgressionVanilla()
|
||||
|
||||
tools_distribution = tool_progression.get_tools_distribution(
|
||||
if tool_option.is_progressive:
|
||||
starting_tools, tools_distribution = tool_progression.get_tools_distribution(
|
||||
progressive_tools_enabled=True,
|
||||
skill_masteries_enabled=skill_option == options.SkillProgression.option_progressive_with_masteries,
|
||||
no_starting_tools_enabled=bool(StartWithoutOptionName.tools in start_without_option),
|
||||
)
|
||||
|
||||
if tool_option.is_progressive:
|
||||
return tool_progression.ToolProgressionProgressive(tools_distribution)
|
||||
return tool_progression.ToolProgressionProgressive(starting_tools, tools_distribution)
|
||||
|
||||
raise ValueError(f"No tool progression feature mapped to {str(tool_option.value)}")
|
||||
|
||||
@@ -11,14 +11,6 @@ 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__)
|
||||
|
||||
@@ -28,4 +20,13 @@ for mod_module in mod_modules:
|
||||
module = importlib.import_module("." + module_name, mods.__name__)
|
||||
loaded_modules[module_name] = module
|
||||
|
||||
assert by_mod
|
||||
vanilla_content_pack_names = frozenset({
|
||||
base_game.name,
|
||||
ginger_island_content_pack.name,
|
||||
pelican_town.name,
|
||||
qi_board_content_pack.name,
|
||||
the_desert.name,
|
||||
the_farm.name,
|
||||
the_mines.name
|
||||
})
|
||||
all_content_pack_names = vanilla_content_pack_names | frozenset(by_mod.keys())
|
||||
|
||||
@@ -1,7 +1,31 @@
|
||||
from . import booksanity
|
||||
from . import building_progression
|
||||
from . import cropsanity
|
||||
from . import fishsanity
|
||||
from . import friendsanity
|
||||
from . import skill_progression
|
||||
from . import tool_progression
|
||||
from . import booksanity, building_progression, cropsanity, fishsanity, friendsanity, hatsanity, museumsanity, skill_progression, tool_progression
|
||||
from .booksanity import BooksanityFeature
|
||||
from .building_progression import BuildingProgressionFeature
|
||||
from .cropsanity import CropsanityFeature
|
||||
from .fishsanity import FishsanityFeature
|
||||
from .friendsanity import FriendsanityFeature
|
||||
from .hatsanity import HatsanityFeature
|
||||
from .museumsanity import MuseumsanityFeature
|
||||
from .skill_progression import SkillProgressionFeature
|
||||
from .tool_progression import ToolProgressionFeature
|
||||
|
||||
__exports__ = [
|
||||
"booksanity",
|
||||
"BooksanityFeature",
|
||||
"building_progression",
|
||||
"BuildingProgressionFeature",
|
||||
"cropsanity",
|
||||
"CropsanityFeature",
|
||||
"fishsanity",
|
||||
"FishsanityFeature",
|
||||
"friendsanity",
|
||||
"FriendsanityFeature",
|
||||
"hatsanity",
|
||||
"HatsanityFeature",
|
||||
"museumsanity",
|
||||
"MuseumsanityFeature",
|
||||
"skill_progression",
|
||||
"SkillProgressionFeature",
|
||||
"tool_progression"
|
||||
"ToolProgressionFeature",
|
||||
]
|
||||
|
||||
71
worlds/stardew_valley/content/feature/base.py
Normal file
71
worlds/stardew_valley/content/feature/base.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import inspect
|
||||
from abc import ABC
|
||||
from collections.abc import Mapping
|
||||
from typing import TYPE_CHECKING, Protocol
|
||||
|
||||
from ...data.game_item import Source, Requirement
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ... import StardewContent
|
||||
|
||||
|
||||
class DisableSourceHook(Protocol):
|
||||
def __call__(self, source: Source, /, *, content: "StardewContent") -> bool:
|
||||
"""Return True if the source should be disabled by this feature."""
|
||||
...
|
||||
|
||||
|
||||
class DisableRequirementHook(Protocol):
|
||||
def __call__(self, requirement: Requirement, /, *, content: "StardewContent") -> bool:
|
||||
"""Return True if the requirement should be disabled by this feature."""
|
||||
...
|
||||
|
||||
|
||||
def wrap_optional_content_arg(hook):
|
||||
"""Wraps a hook to ensure it has the correct signature."""
|
||||
if "content" in hook.__annotations__:
|
||||
return hook
|
||||
|
||||
def wrapper(*args, content: "StardewContent", **kwargs):
|
||||
return hook(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class FeatureBase(ABC):
|
||||
|
||||
@property
|
||||
def disable_source_hooks(self) -> Mapping[type[Source], DisableSourceHook]:
|
||||
"""All hooks to call when a source is created to check if it has to be disabled by this feature."""
|
||||
disable_source_hooks = {}
|
||||
for attribute_name in dir(self):
|
||||
if not attribute_name.startswith("_disable_") or not callable((attribute := getattr(self, attribute_name))):
|
||||
continue
|
||||
|
||||
sig = inspect.signature(attribute)
|
||||
|
||||
source_param = sig.parameters.get("source")
|
||||
if source_param is not None:
|
||||
source_type = source_param.annotation
|
||||
disable_source_hooks[source_type] = wrap_optional_content_arg(attribute)
|
||||
continue
|
||||
|
||||
return disable_source_hooks
|
||||
|
||||
@property
|
||||
def disable_requirement_hooks(self) -> Mapping[type[Requirement], DisableRequirementHook]:
|
||||
"""All hooks to call when a requirement is created to check if it has to be disabled by this feature."""
|
||||
disable_requirement_hooks = {}
|
||||
for attribute_name in dir(self):
|
||||
if not attribute_name.startswith("_disable_") or not callable((attribute := getattr(self, attribute_name))):
|
||||
continue
|
||||
|
||||
sig = inspect.signature(attribute)
|
||||
|
||||
requirement_param = sig.parameters.get("requirement")
|
||||
if requirement_param is not None:
|
||||
requirement_type = requirement_param.annotation
|
||||
disable_requirement_hooks[requirement_type] = wrap_optional_content_arg(attribute)
|
||||
continue
|
||||
|
||||
return disable_requirement_hooks
|
||||
@@ -1,6 +1,8 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, Optional, Iterable
|
||||
from collections.abc import Iterable
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.game_item import GameItem, ItemTag
|
||||
from ...strings.book_names import ordered_lost_books
|
||||
|
||||
@@ -16,14 +18,14 @@ def to_location_name(book: str) -> str:
|
||||
return location_prefix + book
|
||||
|
||||
|
||||
def extract_book_from_location_name(location_name: str) -> Optional[str]:
|
||||
def extract_book_from_location_name(location_name: str) -> str | None:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(location_prefix):]
|
||||
|
||||
|
||||
class BooksanityFeature(ABC):
|
||||
class BooksanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
to_item_name = staticmethod(to_item_name)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from abc import ABC
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar, Set, Tuple
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...strings.building_names import Building
|
||||
|
||||
progressive_house = "Progressive House"
|
||||
@@ -15,7 +16,7 @@ progressive_house_by_upgrade_name = {
|
||||
}
|
||||
|
||||
|
||||
def to_progressive_item(building: str) -> Tuple[str, int]:
|
||||
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]:
|
||||
@@ -35,9 +36,9 @@ def to_location_name(building: str) -> str:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BuildingProgressionFeature(ABC):
|
||||
class BuildingProgressionFeature(FeatureBase, ABC):
|
||||
is_progressive: ClassVar[bool]
|
||||
starting_buildings: Set[str]
|
||||
starting_buildings: set[str]
|
||||
|
||||
to_progressive_item = staticmethod(to_progressive_item)
|
||||
progressive_house = progressive_house
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, Optional
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.game_item import GameItem, ItemTag
|
||||
|
||||
location_prefix = "Harvest "
|
||||
@@ -10,14 +11,14 @@ def to_location_name(crop: str) -> str:
|
||||
return location_prefix + crop
|
||||
|
||||
|
||||
def extract_crop_from_location_name(location_name: str) -> Optional[str]:
|
||||
def extract_crop_from_location_name(location_name: str) -> str | None:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(location_prefix):]
|
||||
|
||||
|
||||
class CropsanityFeature(ABC):
|
||||
class CropsanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar, Optional
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.fish_data import FishItem
|
||||
from ...strings.fish_names import Fish
|
||||
|
||||
@@ -12,7 +13,7 @@ def to_location_name(fish: str) -> str:
|
||||
return location_prefix + fish
|
||||
|
||||
|
||||
def extract_fish_from_location_name(location_name: str) -> Optional[str]:
|
||||
def extract_fish_from_location_name(location_name: str) -> str | None:
|
||||
if not location_name.startswith(location_prefix):
|
||||
return None
|
||||
|
||||
@@ -20,7 +21,7 @@ def extract_fish_from_location_name(location_name: str) -> Optional[str]:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FishsanityFeature(ABC):
|
||||
class FishsanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
randomization_ratio: float = 1
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from typing import Optional, Tuple, ClassVar
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.villagers_data import Villager
|
||||
from ...strings.villager_names import NPC
|
||||
|
||||
@@ -21,14 +22,14 @@ def to_location_name(npc_name: str, heart: int) -> str:
|
||||
pet_heart_item_name = to_item_name(NPC.pet)
|
||||
|
||||
|
||||
def extract_npc_from_item_name(item_name: str) -> Optional[str]:
|
||||
def extract_npc_from_item_name(item_name: str) -> str | None:
|
||||
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]:
|
||||
def extract_npc_from_location_name(location_name: str) -> tuple[str | None, int]:
|
||||
if not location_name.endswith(suffix):
|
||||
return None, 0
|
||||
|
||||
@@ -38,12 +39,12 @@ def extract_npc_from_location_name(location_name: str) -> Tuple[Optional[str], i
|
||||
|
||||
|
||||
@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, ...]:
|
||||
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):
|
||||
class FriendsanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
heart_size: int
|
||||
@@ -55,7 +56,7 @@ class FriendsanityFeature(ABC):
|
||||
extract_npc_from_location_name = staticmethod(extract_npc_from_location_name)
|
||||
|
||||
@abstractmethod
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
def get_randomized_hearts(self, villager: Villager) -> tuple[int, ...]:
|
||||
...
|
||||
|
||||
@property
|
||||
@@ -63,7 +64,7 @@ class FriendsanityFeature(ABC):
|
||||
return bool(self.get_pet_randomized_hearts())
|
||||
|
||||
@abstractmethod
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
...
|
||||
|
||||
|
||||
@@ -73,10 +74,10 @@ class FriendsanityNone(FriendsanityFeature):
|
||||
def __init__(self):
|
||||
super().__init__(1)
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
def get_randomized_hearts(self, villager: Villager) -> tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
|
||||
@@ -84,13 +85,13 @@ class FriendsanityNone(FriendsanityFeature):
|
||||
class FriendsanityBachelors(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
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, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
return ()
|
||||
|
||||
|
||||
@@ -98,7 +99,7 @@ class FriendsanityBachelors(FriendsanityFeature):
|
||||
class FriendsanityStartingNpc(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
def get_randomized_hearts(self, villager: Villager) -> tuple[int, ...]:
|
||||
if not villager.available:
|
||||
return ()
|
||||
|
||||
@@ -107,7 +108,7 @@ class FriendsanityStartingNpc(FriendsanityFeature):
|
||||
|
||||
return get_heart_steps(10, self.heart_size)
|
||||
|
||||
def get_pet_randomized_hearts(self) -> Tuple[int, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
|
||||
|
||||
@@ -115,13 +116,13 @@ class FriendsanityStartingNpc(FriendsanityFeature):
|
||||
class FriendsanityAll(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
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, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
|
||||
|
||||
@@ -129,11 +130,11 @@ class FriendsanityAll(FriendsanityFeature):
|
||||
class FriendsanityAllWithMarriage(FriendsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
def get_randomized_hearts(self, villager: Villager) -> Tuple[int, ...]:
|
||||
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, ...]:
|
||||
def get_pet_randomized_hearts(self) -> tuple[int, ...]:
|
||||
return get_heart_steps(5, self.heart_size)
|
||||
|
||||
52
worlds/stardew_valley/content/feature/hatsanity.py
Normal file
52
worlds/stardew_valley/content/feature/hatsanity.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.hats_data import HatItem
|
||||
|
||||
wear_prefix = "Wear "
|
||||
|
||||
|
||||
def to_location_name(hat: str | HatItem) -> str:
|
||||
if isinstance(hat, HatItem):
|
||||
hat = hat.name
|
||||
return f"{wear_prefix}{hat}"
|
||||
|
||||
|
||||
def extract_hat_from_location_name(location_name: str) -> str | None:
|
||||
if not location_name.startswith(wear_prefix):
|
||||
return None
|
||||
|
||||
return location_name[len(wear_prefix):]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HatsanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
to_location_name = staticmethod(to_location_name)
|
||||
extract_hat_from_location_name = staticmethod(extract_hat_from_location_name)
|
||||
|
||||
@abstractmethod
|
||||
def is_included(self, hat: HatItem) -> bool:
|
||||
...
|
||||
|
||||
|
||||
class HatsanityNone(HatsanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
def is_included(self, hat: HatItem) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HatsanityHats(HatsanityFeature):
|
||||
is_enabled = True
|
||||
enabled_hats: frozenset[str]
|
||||
|
||||
def is_included(self, hat: HatItem) -> bool:
|
||||
for difficulty in hat.difficulty:
|
||||
if difficulty not in self.enabled_hats:
|
||||
return False
|
||||
return True
|
||||
38
worlds/stardew_valley/content/feature/museumsanity.py
Normal file
38
worlds/stardew_valley/content/feature/museumsanity.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from abc import ABC
|
||||
from dataclasses import dataclass
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.requirement import MuseumCompletionRequirement
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MuseumsanityFeature(FeatureBase, ABC):
|
||||
is_enabled: ClassVar[bool]
|
||||
|
||||
|
||||
class MuseumsanityNone(MuseumsanityFeature):
|
||||
is_enabled = False
|
||||
|
||||
@staticmethod
|
||||
def _disable_museum_completion_requirement(requirement: MuseumCompletionRequirement) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MuseumsanityMilestones(MuseumsanityFeature):
|
||||
is_enabled = True
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MuseumsanityRandomized(MuseumsanityFeature):
|
||||
is_enabled = True
|
||||
amount_of_randomized_donations: int = 40
|
||||
|
||||
def _disable_museum_completion_requirement(self, requirement: MuseumCompletionRequirement) -> bool:
|
||||
return requirement.number_donated > self.amount_of_randomized_donations
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MuseumsanityAll(MuseumsanityFeature):
|
||||
is_enabled = True
|
||||
@@ -1,15 +1,17 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import ClassVar, Iterable, Tuple
|
||||
from collections.abc import Iterable
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...data.skill import Skill
|
||||
|
||||
|
||||
class SkillProgressionFeature(ABC):
|
||||
class SkillProgressionFeature(FeatureBase, ABC):
|
||||
is_progressive: ClassVar[bool]
|
||||
are_masteries_shuffled: ClassVar[bool]
|
||||
|
||||
@abstractmethod
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[Tuple[int, str]]:
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[tuple[int, str]]:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
@@ -21,7 +23,7 @@ class SkillProgressionVanilla(SkillProgressionFeature):
|
||||
is_progressive = False
|
||||
are_masteries_shuffled = False
|
||||
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[Tuple[int, str]]:
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[tuple[int, str]]:
|
||||
return ()
|
||||
|
||||
def is_mastery_randomized(self, skill: Skill) -> bool:
|
||||
@@ -32,7 +34,7 @@ class SkillProgressionProgressive(SkillProgressionFeature):
|
||||
is_progressive = True
|
||||
are_masteries_shuffled = False
|
||||
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[Tuple[int, str]]:
|
||||
def get_randomized_level_names_by_level(self, skill: Skill) -> Iterable[tuple[int, str]]:
|
||||
return skill.level_names_by_level
|
||||
|
||||
def is_mastery_randomized(self, skill: Skill) -> bool:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
def get_qi_gem_amount(item_name: str) -> int:
|
||||
amount = item_name.replace(" Qi Gems", "")
|
||||
if amount.isdigit():
|
||||
return int(amount)
|
||||
return 0
|
||||
@@ -6,14 +6,19 @@ from functools import cache
|
||||
from types import MappingProxyType
|
||||
from typing import ClassVar
|
||||
|
||||
from .base import FeatureBase
|
||||
from ...strings.tool_names import Tool
|
||||
|
||||
|
||||
def to_progressive_item(tool: str) -> str:
|
||||
def to_progressive_item_name(tool: str) -> str:
|
||||
"""Return the name of the progressive item."""
|
||||
return f"Progressive {tool}"
|
||||
|
||||
|
||||
def to_upgrade_location_name(tool: str, material: str) -> str:
|
||||
return f"{material} {tool} Upgrade"
|
||||
|
||||
|
||||
# The golden scythe is always randomized
|
||||
VANILLA_TOOL_DISTRIBUTION = MappingProxyType({
|
||||
Tool.scythe: 1,
|
||||
@@ -29,6 +34,17 @@ PROGRESSIVE_TOOL_DISTRIBUTION = MappingProxyType({
|
||||
Tool.fishing_rod: 4,
|
||||
})
|
||||
|
||||
VANILLA_STARTING_TOOLS_DISTRIBUTION = MappingProxyType({
|
||||
Tool.scythe: 1,
|
||||
Tool.axe: 1,
|
||||
Tool.hoe: 1,
|
||||
Tool.pickaxe: 1,
|
||||
Tool.pan: 0,
|
||||
Tool.trash_can: 1,
|
||||
Tool.watering_can: 1,
|
||||
Tool.fishing_rod: 0,
|
||||
})
|
||||
|
||||
# Masteries add another tier to the scythe and the fishing rod
|
||||
SKILL_MASTERIES_TOOL_DISTRIBUTION = MappingProxyType({
|
||||
Tool.scythe: 1,
|
||||
@@ -37,8 +53,10 @@ SKILL_MASTERIES_TOOL_DISTRIBUTION = MappingProxyType({
|
||||
|
||||
|
||||
@cache
|
||||
def get_tools_distribution(progressive_tools_enabled: bool, skill_masteries_enabled: bool) -> Mapping[str, int]:
|
||||
def get_tools_distribution(progressive_tools_enabled: bool, skill_masteries_enabled: bool, no_starting_tools_enabled: bool) \
|
||||
-> tuple[Mapping[str, int], Mapping[str, int]]:
|
||||
distribution = Counter(VANILLA_TOOL_DISTRIBUTION)
|
||||
starting = Counter(VANILLA_STARTING_TOOLS_DISTRIBUTION)
|
||||
|
||||
if progressive_tools_enabled:
|
||||
distribution += PROGRESSIVE_TOOL_DISTRIBUTION
|
||||
@@ -46,21 +64,31 @@ def get_tools_distribution(progressive_tools_enabled: bool, skill_masteries_enab
|
||||
if skill_masteries_enabled:
|
||||
distribution += SKILL_MASTERIES_TOOL_DISTRIBUTION
|
||||
|
||||
return MappingProxyType(distribution)
|
||||
if no_starting_tools_enabled:
|
||||
distribution += VANILLA_STARTING_TOOLS_DISTRIBUTION
|
||||
starting.clear()
|
||||
|
||||
return MappingProxyType(starting), MappingProxyType(distribution)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ToolProgressionFeature(ABC):
|
||||
class ToolProgressionFeature(FeatureBase, ABC):
|
||||
is_progressive: ClassVar[bool]
|
||||
starting_tools: Mapping[str, int]
|
||||
tool_distribution: Mapping[str, int]
|
||||
|
||||
to_progressive_item = staticmethod(to_progressive_item)
|
||||
to_progressive_item_name = staticmethod(to_progressive_item_name)
|
||||
to_upgrade_location_name = staticmethod(to_upgrade_location_name)
|
||||
|
||||
def get_tools_distribution(self) -> tuple[Mapping[str, int], Mapping[str, int]]:
|
||||
return self.starting_tools, self.tool_distribution
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ToolProgressionVanilla(ToolProgressionFeature):
|
||||
is_progressive = False
|
||||
# FIXME change the default_factory to a simple default when python 3.11 is no longer supported
|
||||
starting_tools: Mapping[str, int] = field(default_factory=lambda: VANILLA_STARTING_TOOLS_DISTRIBUTION)
|
||||
tool_distribution: Mapping[str, int] = field(default_factory=lambda: VANILLA_TOOL_DISTRIBUTION)
|
||||
|
||||
|
||||
|
||||
8
worlds/stardew_valley/content/feature/walnutsanity.py
Normal file
8
worlds/stardew_valley/content/feature/walnutsanity.py
Normal file
@@ -0,0 +1,8 @@
|
||||
def get_walnut_amount(item_name: str) -> int:
|
||||
if item_name == "Golden Walnut":
|
||||
return 1
|
||||
if item_name == "3 Golden Walnuts":
|
||||
return 3
|
||||
if item_name == "5 Golden Walnuts":
|
||||
return 5
|
||||
return 0
|
||||
@@ -1,13 +1,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Iterable, Set, Any, Mapping, Type, Tuple, Union
|
||||
from functools import cached_property
|
||||
from types import MappingProxyType
|
||||
from typing import Iterable, Set, Any, Mapping, Generator
|
||||
|
||||
from .feature import booksanity, cropsanity, fishsanity, friendsanity, skill_progression, building_progression, tool_progression
|
||||
from .feature import BooksanityFeature, BuildingProgressionFeature, CropsanityFeature, FishsanityFeature, FriendsanityFeature, HatsanityFeature, \
|
||||
MuseumsanityFeature, SkillProgressionFeature, ToolProgressionFeature
|
||||
from .feature.base import DisableSourceHook, DisableRequirementHook, FeatureBase
|
||||
from ..data.animal import Animal
|
||||
from ..data.building import Building
|
||||
from ..data.fish_data import FishItem
|
||||
from ..data.game_item import GameItem, Source, ItemTag
|
||||
from ..data.game_item import GameItem, Source, ItemTag, Requirement
|
||||
from ..data.hats_data import HatItem
|
||||
from ..data.skill import Skill
|
||||
from ..data.villagers_data import Villager
|
||||
|
||||
@@ -26,16 +31,25 @@ class StardewContent:
|
||||
animals: dict[str, Animal] = field(default_factory=dict)
|
||||
skills: dict[str, Skill] = field(default_factory=dict)
|
||||
quests: dict[str, Any] = field(default_factory=dict)
|
||||
hats: dict[str, HatItem] = field(default_factory=dict)
|
||||
|
||||
def find_sources_of_type(self, types: Union[Type[Source], Tuple[Type[Source]]]) -> Iterable[Source]:
|
||||
def find_sources_of_type(self, *types: 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: Source):
|
||||
def source_item(self, item_name: str, *sources: Source) -> GameItem:
|
||||
filtered_sources = list(self._filter_sources(sources))
|
||||
|
||||
item = self.game_items.setdefault(item_name, GameItem(item_name))
|
||||
item.add_sources(sources)
|
||||
item.add_sources(filtered_sources)
|
||||
|
||||
for source in filtered_sources:
|
||||
for requirement_name, tags in source.requirement_tags.items():
|
||||
self.tag_item(requirement_name, *tags)
|
||||
|
||||
return item
|
||||
|
||||
def tag_item(self, item_name: str, *tags: ItemTag):
|
||||
item = self.game_items.setdefault(item_name, GameItem(item_name))
|
||||
@@ -44,22 +58,79 @@ class StardewContent:
|
||||
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]:
|
||||
def find_tagged_items(self, tag: ItemTag) -> Generator[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
|
||||
|
||||
def are_all_enabled(self, content_packs: frozenset[str]) -> bool:
|
||||
return content_packs.issubset(self.registered_packs)
|
||||
|
||||
def is_enabled(self, content_pack: str | ContentPack) -> bool:
|
||||
if isinstance(content_pack, ContentPack):
|
||||
content_pack = content_pack.name
|
||||
|
||||
return content_pack in self.registered_packs
|
||||
|
||||
def _filter_sources(self, sources: Iterable[Source]) -> Generator[Source]:
|
||||
"""Filters out sources that are disabled by features."""
|
||||
for source in sources:
|
||||
if not self._is_disabled(source):
|
||||
yield source
|
||||
|
||||
def _is_disabled(self, source: Source) -> bool:
|
||||
"""Checks if a source is disabled by any feature."""
|
||||
try:
|
||||
hook = self.features.disable_source_hooks[type(source)]
|
||||
if hook(source, content=self):
|
||||
return True
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for requirement in source.all_requirements:
|
||||
try:
|
||||
hook = self.features.disable_requirement_hooks[type(requirement)]
|
||||
if hook(requirement, content=self):
|
||||
return True
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class StardewFeatures:
|
||||
booksanity: booksanity.BooksanityFeature
|
||||
building_progression: building_progression.BuildingProgressionFeature
|
||||
cropsanity: cropsanity.CropsanityFeature
|
||||
fishsanity: fishsanity.FishsanityFeature
|
||||
friendsanity: friendsanity.FriendsanityFeature
|
||||
skill_progression: skill_progression.SkillProgressionFeature
|
||||
tool_progression: tool_progression.ToolProgressionFeature
|
||||
booksanity: BooksanityFeature
|
||||
building_progression: BuildingProgressionFeature
|
||||
cropsanity: CropsanityFeature
|
||||
fishsanity: FishsanityFeature
|
||||
friendsanity: FriendsanityFeature
|
||||
hatsanity: HatsanityFeature
|
||||
museumsanity: MuseumsanityFeature
|
||||
skill_progression: SkillProgressionFeature
|
||||
tool_progression: ToolProgressionFeature
|
||||
|
||||
@cached_property
|
||||
def all_features(self) -> Iterable[FeatureBase]:
|
||||
return (self.booksanity, self.building_progression, self.cropsanity, self.fishsanity, self.friendsanity, self.hatsanity, self.museumsanity,
|
||||
self.skill_progression, self.tool_progression)
|
||||
|
||||
@cached_property
|
||||
def disable_source_hooks(self) -> Mapping[type[Source], DisableSourceHook]:
|
||||
"""Returns a set of source types that are disabled by features. Need to be exact types, subclasses are not considered."""
|
||||
hooks = {}
|
||||
for feature in self.all_features:
|
||||
hooks.update(feature.disable_source_hooks)
|
||||
return MappingProxyType(hooks)
|
||||
|
||||
@cached_property
|
||||
def disable_requirement_hooks(self) -> Mapping[type[Requirement], DisableRequirementHook]:
|
||||
"""Returns a set of requirement types that are disabled by features. Need to be exact types, subclasses are not considered."""
|
||||
hooks = {}
|
||||
for feature in self.all_features:
|
||||
hooks.update(feature.disable_requirement_hooks)
|
||||
return MappingProxyType(hooks)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -125,6 +196,12 @@ class ContentPack:
|
||||
|
||||
def quest_hook(self, content: StardewContent):
|
||||
...
|
||||
...
|
||||
|
||||
hat_sources: Mapping[HatItem, Iterable[Source]] = field(default_factory=dict)
|
||||
|
||||
def hat_source_hook(self, content: StardewContent):
|
||||
...
|
||||
|
||||
def finalize_hook(self, content: StardewContent):
|
||||
"""Last hook called on the pack, once all other content packs have been registered.
|
||||
|
||||
@@ -1,34 +1,46 @@
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ..mod_registry import register_mod_content_pack
|
||||
from ...data.artisan import MachineSource
|
||||
from ...data.game_item import ItemTag, Tag
|
||||
from ...data.harvest import ArtifactSpotSource
|
||||
from ...data.requirement import SkillRequirement
|
||||
from ...data.skill import Skill
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.ap_names.mods.mod_items import ModBooks
|
||||
from ...strings.craftable_names import ModMachine
|
||||
from ...strings.fish_names import ModTrash
|
||||
from ...strings.metal_names import all_artifacts, all_fossils
|
||||
from ...strings.metal_names import all_artifacts, all_fossils, Fossil
|
||||
from ...strings.skill_names import ModSkill
|
||||
|
||||
|
||||
def source_display_items(item: str, content: StardewContent):
|
||||
wood_display = f"Wooden Display: {item}"
|
||||
hardwood_display = f"Hardwood Display: {item}"
|
||||
if item == Fossil.trilobite:
|
||||
wood_display = f"Wooden Display: Trilobite Fossil"
|
||||
hardwood_display = f"Hardwood Display: Trilobite Fossil"
|
||||
content.source_item(wood_display, MachineSource(item=str(item), machine=ModMachine.preservation_chamber))
|
||||
content.source_item(hardwood_display, MachineSource(item=str(item), machine=ModMachine.hardwood_preservation_chamber))
|
||||
|
||||
|
||||
class ArchaeologyContentPack(ContentPack):
|
||||
def artisan_good_hook(self, content: StardewContent):
|
||||
# Done as honestly there are too many display items to put into the initial registration traditionally.
|
||||
display_items = all_artifacts + all_fossils
|
||||
for item in display_items:
|
||||
self.source_display_items(item, content)
|
||||
source_display_items(item, content)
|
||||
content.source_item(ModTrash.rusty_scrap, *(MachineSource(item=artifact, machine=ModMachine.grinder) for artifact in all_artifacts))
|
||||
|
||||
def source_display_items(self, item: str, content: StardewContent):
|
||||
wood_display = f"Wooden Display: {item}"
|
||||
hardwood_display = f"Hardwood Display: {item}"
|
||||
if item == "Trilobite":
|
||||
wood_display = f"Wooden Display: Trilobite Fossil"
|
||||
hardwood_display = f"Hardwood Display: Trilobite Fossil"
|
||||
content.source_item(wood_display, MachineSource(item=str(item), machine=ModMachine.preservation_chamber))
|
||||
content.source_item(hardwood_display, MachineSource(item=str(item), machine=ModMachine.hardwood_preservation_chamber))
|
||||
|
||||
|
||||
register_mod_content_pack(ArchaeologyContentPack(
|
||||
ModNames.archaeology,
|
||||
skills=(Skill(name=ModSkill.archaeology, has_mastery=False),),
|
||||
harvest_sources={
|
||||
ModBooks.digging_like_worms: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ArtifactSpotSource(amount=22, # I'm just copying Jack Be Nimble's chances for now -reptar
|
||||
other_requirements=(SkillRequirement(ModSkill.archaeology, 2),)),
|
||||
)
|
||||
}
|
||||
|
||||
))
|
||||
|
||||
@@ -5,7 +5,7 @@ from ..vanilla.ginger_island import ginger_island_content_pack as ginger_island_
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.game_item import ItemTag, Tag
|
||||
from ...data.harvest import ForagingSource, HarvestCropSource
|
||||
from ...data.requirement import YearRequirement, CombatRequirement, RelationshipRequirement, ToolRequirement, SkillRequirement, FishingRequirement
|
||||
from ...data.requirement import YearRequirement, CombatRequirement, SpecificFriendRequirement, ToolRequirement, SkillRequirement, FishingRequirement
|
||||
from ...data.shop import ShopSource
|
||||
from ...mods.mod_data import ModNames
|
||||
from ...strings.craftable_names import ModEdible
|
||||
@@ -82,18 +82,18 @@ register_mod_content_pack(SVEContentPack(
|
||||
ModNames.jasper, # To override Marlon and Gunther
|
||||
),
|
||||
shop_sources={
|
||||
SVEGift.aged_blue_moon_wine: (ShopSource(money_price=28000, shop_region=SVERegion.blue_moon_vineyard),),
|
||||
SVEGift.blue_moon_wine: (ShopSource(money_price=3000, shop_region=SVERegion.blue_moon_vineyard),),
|
||||
ModEdible.lightning_elixir: (ShopSource(money_price=12000, shop_region=SVERegion.galmoran_outpost),),
|
||||
ModEdible.barbarian_elixir: (ShopSource(money_price=22000, shop_region=SVERegion.galmoran_outpost),),
|
||||
ModEdible.gravity_elixir: (ShopSource(money_price=4000, shop_region=SVERegion.galmoran_outpost),),
|
||||
SVEMeal.grampleton_orange_chicken: (ShopSource(money_price=650,
|
||||
SVEGift.aged_blue_moon_wine: (ShopSource(price=28000, shop_region=SVERegion.blue_moon_vineyard),),
|
||||
SVEGift.blue_moon_wine: (ShopSource(price=3000, shop_region=SVERegion.blue_moon_vineyard),),
|
||||
ModEdible.lightning_elixir: (ShopSource(price=12000, shop_region=SVERegion.galmoran_outpost),),
|
||||
ModEdible.barbarian_elixir: (ShopSource(price=22000, shop_region=SVERegion.galmoran_outpost),),
|
||||
ModEdible.gravity_elixir: (ShopSource(price=4000, shop_region=SVERegion.galmoran_outpost),),
|
||||
SVEMeal.grampleton_orange_chicken: (ShopSource(price=650,
|
||||
shop_region=Region.saloon,
|
||||
other_requirements=(RelationshipRequirement(ModNPC.sophia, 6),)),),
|
||||
ModEdible.hero_elixir: (ShopSource(money_price=8000, shop_region=SVERegion.isaac_shop),),
|
||||
ModEdible.aegis_elixir: (ShopSource(money_price=28000, shop_region=SVERegion.galmoran_outpost),),
|
||||
SVEBeverage.sports_drink: (ShopSource(money_price=750, shop_region=Region.hospital),),
|
||||
SVEMeal.stamina_capsule: (ShopSource(money_price=4000, shop_region=Region.hospital),),
|
||||
other_requirements=(SpecificFriendRequirement(ModNPC.sophia, 6),)),),
|
||||
ModEdible.hero_elixir: (ShopSource(price=8000, shop_region=SVERegion.isaac_shop),),
|
||||
ModEdible.aegis_elixir: (ShopSource(price=28000, shop_region=SVERegion.galmoran_outpost),),
|
||||
SVEBeverage.sports_drink: (ShopSource(price=750, shop_region=Region.hospital),),
|
||||
SVEMeal.stamina_capsule: (ShopSource(price=4000, shop_region=Region.hospital),),
|
||||
},
|
||||
harvest_sources={
|
||||
Mushroom.red: (
|
||||
|
||||
@@ -16,7 +16,7 @@ register_mod_content_pack(ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=150_000,
|
||||
price=150_000,
|
||||
items_price=((20, MetalBar.iron), (5, MetalBar.iridium), (1, ArtisanGood.battery_pack)),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,7 +5,7 @@ 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, Source
|
||||
from ..data.game_item import Source
|
||||
|
||||
|
||||
def unpack_content(features: StardewFeatures, packs: Iterable[ContentPack]) -> StardewContent:
|
||||
@@ -73,6 +73,13 @@ def register_pack(content: StardewContent, pack: ContentPack):
|
||||
content.skills[skill.name] = skill
|
||||
pack.skill_hook(content)
|
||||
|
||||
for hat, sources in pack.hat_sources.items():
|
||||
item = content.source_item(hat.clarified_name, *sources)
|
||||
# Some sources may be filtered out. We don't want to register a hat without source.
|
||||
if item.sources:
|
||||
content.hats[hat.name] = hat
|
||||
pack.hat_source_hook(content)
|
||||
|
||||
# register_quests
|
||||
|
||||
# ...
|
||||
@@ -84,14 +91,7 @@ def register_sources_and_call_hook(content: StardewContent,
|
||||
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))
|
||||
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)
|
||||
|
||||
content.source_item(item_name, *sources)
|
||||
hook(content)
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
from ..game_content import ContentPack, StardewContent
|
||||
from ...data.artisan import MachineSource
|
||||
from ...data.game_item import ItemTag, CustomRuleSource, GameItem
|
||||
from ...data.game_item import ItemTag, CustomRuleSource, GameItem, Tag
|
||||
from ...data.harvest import HarvestFruitTreeSource, HarvestCropSource
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.requirement import ToolRequirement, TotalEarningsRequirement, ShipOneCropRequirement, CraftedItemsRequirement, CookedRecipesRequirement, \
|
||||
CaughtFishRequirement
|
||||
from ...data.shop import HatMouseSource
|
||||
from ...data.skill import Skill
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...strings.animal_product_names import AnimalProduct
|
||||
from ...strings.artisan_good_names import ArtisanGood
|
||||
from ...strings.craftable_names import WildSeeds
|
||||
from ...strings.craftable_names import WildSeeds, Edible, Consumable, Lighting
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.fish_names import Fish, WaterChest
|
||||
from ...strings.flower_names import Flower
|
||||
from ...strings.food_names import Beverage
|
||||
from ...strings.food_names import Beverage, Meal
|
||||
from ...strings.forageable_names import all_edible_mushrooms, Mushroom, Forageable
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.gift_names import Gift
|
||||
from ...strings.machine_names import Machine
|
||||
from ...strings.metal_names import Fossil, Artifact
|
||||
from ...strings.monster_names import Monster
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
from ...strings.seed_names import Seed, TreeSeed
|
||||
from ...strings.skill_names import Skill as SkillName
|
||||
from ...strings.tool_names import Tool, ToolMaterial
|
||||
|
||||
all_fruits = (
|
||||
Fruit.ancient_fruit, Fruit.apple, Fruit.apricot, Fruit.banana, Forageable.blackberry, Fruit.blueberry, Forageable.cactus_fruit, Fruit.cherry,
|
||||
@@ -110,16 +120,19 @@ base_game = BaseGameContentPack(
|
||||
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,)),),
|
||||
Vegetable.kale: (HarvestCropSource(seed=Seed.kale, seasons=(Season.spring,),
|
||||
other_requirements=(ToolRequirement(Tool.scythe),)),),
|
||||
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,)),),
|
||||
Vegetable.unmilled_rice: (HarvestCropSource(seed=Seed.rice, seasons=(Season.spring,),
|
||||
other_requirements=(ToolRequirement(Tool.scythe),)),),
|
||||
|
||||
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.wheat: (HarvestCropSource(seed=Seed.wheat, seasons=(Season.summer, Season.fall),
|
||||
other_requirements=(ToolRequirement(Tool.scythe),)),),
|
||||
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,)),),
|
||||
@@ -134,7 +147,8 @@ base_game = BaseGameContentPack(
|
||||
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,)),),
|
||||
Vegetable.amaranth: (HarvestCropSource(seed=Seed.amaranth, seasons=(Season.fall,),
|
||||
other_requirements=(ToolRequirement(Tool.scythe),)),),
|
||||
Fruit.grape: (HarvestCropSource(seed=Seed.grape, seasons=(Season.fall,)),),
|
||||
Vegetable.artichoke: (HarvestCropSource(seed=Seed.artichoke, seasons=(Season.fall,)),),
|
||||
|
||||
@@ -147,18 +161,18 @@ base_game = BaseGameContentPack(
|
||||
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_starter: (CustomRuleSource(create_rule=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(WildSeeds.tea_sapling) & logic.time.has_lived_months(2) & logic.season.has_any_not_winter()),),
|
||||
CustomRuleSource(create_rule=lambda logic: logic.has(WildSeeds.tea_sapling) & 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"))),
|
||||
CustomRuleSource(create_rule=lambda logic: logic.has(Machine.coffee_maker)),
|
||||
CustomRuleSource(create_rule=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),),
|
||||
@@ -169,5 +183,48 @@ base_game = BaseGameContentPack(
|
||||
Skill(SkillName.fishing, has_mastery=True),
|
||||
Skill(SkillName.mining, has_mastery=True),
|
||||
Skill(SkillName.combat, has_mastery=True),
|
||||
)
|
||||
),
|
||||
hat_sources={
|
||||
Hats.good_ol_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(TotalEarningsRequirement(15000),)),),
|
||||
Hats.lucky_bow: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(TotalEarningsRequirement(50000),)),),
|
||||
Hats.cool_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(TotalEarningsRequirement(250000),)),),
|
||||
Hats.bowler: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(TotalEarningsRequirement(1000000),)),),
|
||||
Hats.sombrero: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(TotalEarningsRequirement(10000000),)),),
|
||||
Hats.delicate_bow: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CookedRecipesRequirement(10),)),),
|
||||
Hats.plum_chapeau: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CookedRecipesRequirement(25),)),),
|
||||
Hats.daisy: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CraftedItemsRequirement(15),)),),
|
||||
Hats.trucker_hat: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CraftedItemsRequirement(30),)),),
|
||||
Hats.souwester: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CaughtFishRequirement(10, unique=True),)),),
|
||||
Hats.official_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CaughtFishRequirement(24, unique=True),)),),
|
||||
Hats.watermelon_band: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CaughtFishRequirement(100, unique=False),)),),
|
||||
Hats.cowgal_hat: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(ShipOneCropRequirement(300),)),),
|
||||
Hats.living_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.grind.can_grind_weeds(100000)),),
|
||||
Hats.spotted_headscarf: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Mushroom.red,)),),
|
||||
Hats.beanie: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(TreeSeed.acorn, TreeSeed.mahogany, TreeSeed.maple, TreeSeed.pine,)),),
|
||||
Hats.blobfish_mask: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fish.blobfish,)),),
|
||||
Hats.bridal_veil: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Gift.pearl,)),),
|
||||
Hats.dinosaur_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(AnimalProduct.dinosaur_egg,)),),
|
||||
Hats.fashion_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(ArtisanGood.caviar,)),),
|
||||
Hats.flat_topped_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Meal.cranberry_sauce, Meal.stuffing,)),),
|
||||
Hats.floppy_beanie: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(ArtisanGood.maple_syrup, ArtisanGood.oak_resin, ArtisanGood.pine_tar,)),),
|
||||
Hats.goggles: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Edible.bug_steak,)),),
|
||||
Hats.hair_bone: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fossil.prehistoric_tibia,)),),
|
||||
Hats.party_hat_blue: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Meal.chocolate_cake, Consumable.fireworks_purple,)),),
|
||||
Hats.party_hat_green: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Consumable.fireworks_green, Meal.fish_taco,)),),
|
||||
Hats.party_hat_red: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Consumable.fireworks_red, Meal.pizza,)),),
|
||||
Hats.pirate_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(WaterChest.treasure,)),),
|
||||
Hats.propeller_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Meal.miners_treat,)),),
|
||||
Hats.pumpkin_mask: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Lighting.jack_o_lantern,)),),
|
||||
Hats.wearable_dwarf_helm: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Artifact.dwarf_gadget, Artifact.dwarvish_helm,)),),
|
||||
Hats.white_turban: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fruit.sweet_gem_berry,)),),
|
||||
Hats.witch_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Gift.golden_pumpkin,)),),
|
||||
Hats.totem_mask: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Consumable.rain_totem, Consumable.warp_totem_farm,
|
||||
Consumable.warp_totem_mountains, Consumable.warp_totem_beach,
|
||||
Consumable.warp_totem_desert, Consumable.treasure_totem)),),
|
||||
|
||||
Hats.copper_pan_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.tool.has_pan(ToolMaterial.copper)),),
|
||||
Hats.steel_pan_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.tool.has_pan(ToolMaterial.iron)),),
|
||||
Hats.gold_pan_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.tool.has_pan(ToolMaterial.gold)),),
|
||||
Hats.iridium_pan_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.tool.has_pan(ToolMaterial.iridium)),),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2,22 +2,34 @@ 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.animal import Animal, AnimalName, OstrichIncubatorSource
|
||||
from ...data.fish_data import FishingSource
|
||||
from ...data.game_item import ItemTag, Tag, CustomRuleSource
|
||||
from ...data.harvest import ForagingSource, HarvestFruitTreeSource, HarvestCropSource
|
||||
from ...data.requirement import WalnutRequirement
|
||||
from ...data.shop import ShopSource
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.monster_data import MonsterSource
|
||||
from ...data.requirement import WalnutRequirement, ForgeInfinityWeaponRequirement, CookedRecipesRequirement, \
|
||||
CaughtFishRequirement, FullShipmentRequirement, RegionRequirement, \
|
||||
AllAchievementsRequirement, PerfectionPercentRequirement, ReadAllBooksRequirement, HasItemRequirement, ToolRequirement
|
||||
from ...data.shop import ShopSource, HatMouseSource
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...logic.time_logic import MAX_MONTHS
|
||||
from ...strings.animal_product_names import AnimalProduct
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.building_names import Building
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.currency_names import Currency
|
||||
from ...strings.fish_names import Fish
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.generic_names import Generic
|
||||
from ...strings.geode_names import Geode
|
||||
from ...strings.material_names import Material
|
||||
from ...strings.metal_names import Fossil, Mineral
|
||||
from ...strings.monster_names import Monster
|
||||
from ...strings.region_names import Region, LogicRegion
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
from ...strings.seed_names import Seed, TreeSeed
|
||||
from ...strings.tool_names import Tool
|
||||
|
||||
|
||||
class GingerIslandContentPack(ContentPack):
|
||||
@@ -38,12 +50,16 @@ ginger_island_content_pack = GingerIslandContentPack(
|
||||
harvest_sources={
|
||||
# Foraging
|
||||
Forageable.dragon_tooth: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.volcano_floor_10,)),
|
||||
),
|
||||
Forageable.ginger: (
|
||||
ForagingSource(regions=(Region.island_west,)),
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.island_west,),
|
||||
other_requirements=(ToolRequirement(Tool.hoe),)),
|
||||
),
|
||||
Mushroom.magma_cap: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.volcano_floor_5,)),
|
||||
),
|
||||
|
||||
@@ -76,8 +92,7 @@ ginger_island_content_pack = GingerIslandContentPack(
|
||||
),
|
||||
Book.queen_of_sauce_cookbook: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2, other_requirements=(WalnutRequirement(100),)),), # Worst book ever
|
||||
|
||||
ShopSource(price=50000, shop_region=LogicRegion.bookseller_permanent, other_requirements=(WalnutRequirement(100),)),), # Worst book ever
|
||||
},
|
||||
fishes=(
|
||||
# TODO override region so no need to add inaccessible regions in logic
|
||||
@@ -99,5 +114,40 @@ ginger_island_content_pack = GingerIslandContentPack(
|
||||
sources=(
|
||||
OstrichIncubatorSource(AnimalProduct.ostrich_egg_starter),
|
||||
)),
|
||||
)
|
||||
),
|
||||
hat_sources={
|
||||
Hats.infinity_crown: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(ForgeInfinityWeaponRequirement(),)),),
|
||||
Hats.archers_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CookedRecipesRequirement(9999),)),),
|
||||
Hats.chef_hat: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CookedRecipesRequirement(9999),)),),
|
||||
Hats.eye_patch: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CaughtFishRequirement(9999, unique=True),)),),
|
||||
Hats.cowpoke_hat: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(FullShipmentRequirement(),)),),
|
||||
Hats.goblin_mask: (Tag(ItemTag.HAT), HatMouseSource(price=10000, unlock_requirements=(FullShipmentRequirement(),)),),
|
||||
Hats.elegant_turban: (Tag(ItemTag.HAT), HatMouseSource(price=50000, unlock_requirements=(AllAchievementsRequirement(),)),),
|
||||
Hats.junimo_hat: (Tag(ItemTag.HAT), HatMouseSource(price=25000, unlock_requirements=(PerfectionPercentRequirement(100),)),),
|
||||
Hats.paper_hat: (Tag(ItemTag.HAT), HatMouseSource(price=10000, unlock_requirements=(RegionRequirement(Region.island_south),)),),
|
||||
Hats.pageboy_cap: (Tag(ItemTag.HAT), HatMouseSource(price=5000, unlock_requirements=(ReadAllBooksRequirement(),)),),
|
||||
|
||||
Hats.concerned_ape_mask: (Tag(ItemTag.HAT), ShopSource(price=10000, shop_region=LogicRegion.lost_items_shop,
|
||||
other_requirements=(PerfectionPercentRequirement(100), RegionRequirement(Region.volcano_floor_10))),),
|
||||
Hats.golden_helmet: (Tag(ItemTag.HAT), ShopSource(price=10000, shop_region=LogicRegion.lost_items_shop,
|
||||
other_requirements=(RegionRequirement(Region.blacksmith), HasItemRequirement(Geode.golden_coconut),)),),
|
||||
Hats.bluebird_mask: (Tag(ItemTag.HAT), ShopSource(price=30, currency=Vegetable.taro_root, shop_region=Region.island_trader),),
|
||||
Hats.deluxe_cowboy_hat: (Tag(ItemTag.HAT), ShopSource(price=30, currency=Vegetable.taro_root, shop_region=Region.island_trader),),
|
||||
Hats.small_cap: (Tag(ItemTag.HAT), ShopSource(price=30, currency=Vegetable.taro_root, shop_region=Region.island_trader),),
|
||||
Hats.mr_qis_hat: (Tag(ItemTag.HAT), ShopSource(price=5, currency=Currency.qi_gem, shop_region=Region.qi_walnut_room),),
|
||||
Hats.pink_bow: (Tag(ItemTag.HAT), ShopSource(price=10000, shop_region=Region.volcano_dwarf_shop),),
|
||||
|
||||
Hats.tiger_hat: (Tag(ItemTag.HAT), MonsterSource(monsters=(Monster.tiger_slime,), amount_tier=MAX_MONTHS,
|
||||
other_requirements=(RegionRequirement(region=Region.adventurer_guild),)),),
|
||||
Hats.deluxe_pirate_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.volcano, Region.volcano_floor_5, Region.volcano_floor_10,),
|
||||
require_all_regions=True),),
|
||||
|
||||
Hats.foragers_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Forageable.ginger,)),),
|
||||
Hats.sunglasses: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Material.cinder_shard,)),),
|
||||
Hats.swashbuckler_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Forageable.dragon_tooth,)),),
|
||||
Hats.warrior_helmet: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(AnimalProduct.ostrich_egg,)),),
|
||||
Hats.star_helmet: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(TreeSeed.mushroom,)),),
|
||||
|
||||
Hats.frog_hat: (Tag(ItemTag.HAT), FishingSource(region=Region.gourmand_frog_cave,),),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,99 +1,131 @@
|
||||
from ..game_content import ContentPack
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.building import Building
|
||||
from ...data.game_item import GenericSource, ItemTag, Tag, CustomRuleSource
|
||||
from ...data.game_item import GenericSource, ItemTag, Tag, CustomRuleSource, AllRegionsSource
|
||||
from ...data.harvest import ForagingSource, SeasonalForagingSource, ArtifactSpotSource
|
||||
from ...data.requirement import ToolRequirement, BookRequirement, SkillRequirement, YearRequirement
|
||||
from ...data.shop import ShopSource, MysteryBoxSource, ArtifactTroveSource, PrizeMachineSource, FishingTreasureChestSource
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.monster_data import MonsterSource
|
||||
from ...data.requirement import ToolRequirement, BookRequirement, SkillRequirement, YearRequirement, \
|
||||
GrangeDisplayRequirement, EggHuntRequirement, MuseumCompletionRequirement, BuildingRequirement, \
|
||||
NumberOfFriendsRequirement, HelpWantedRequirement, FishingCompetitionRequirement, MovieRequirement, LuauDelightRequirementRequirement, \
|
||||
ReceivedRaccoonsRequirement, \
|
||||
PrizeMachineRequirement, SpecificFriendRequirement, RegionRequirement, CatalogueRequirement
|
||||
from ...data.shop import ShopSource, MysteryBoxSource, ArtifactTroveSource, PrizeMachineSource, \
|
||||
FishingTreasureChestSource, HatMouseSource
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...logic.time_logic import MAX_MONTHS
|
||||
from ...strings.artisan_good_names import ArtisanGood
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.building_names import Building as BuildingNames
|
||||
from ...strings.catalogue_names import Catalogue
|
||||
from ...strings.craftable_names import Furniture
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.fish_names import WaterItem
|
||||
from ...strings.currency_names import Currency
|
||||
from ...strings.fish_names import WaterItem, Fish
|
||||
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.metal_names import MetalBar
|
||||
from ...strings.monster_names import Monster
|
||||
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
|
||||
from ...strings.villager_names import NPC
|
||||
|
||||
pelican_town = ContentPack(
|
||||
"Pelican Town (Vanilla)",
|
||||
harvest_sources={
|
||||
# Spring
|
||||
Forageable.daffodil: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.bus_stop, Region.town, Region.railroad)),
|
||||
),
|
||||
Forageable.dandelion: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.bus_stop, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.leek: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.wild_horseradish: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.backwoods, Region.mountain, Region.forest, Region.secret_woods)),
|
||||
),
|
||||
Forageable.salmonberry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
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: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.forest,)),
|
||||
),
|
||||
|
||||
# Summer
|
||||
Fruit.grape: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.spice_berry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.sweet_pea: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.fiddlehead_fern: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.secret_woods,)),
|
||||
),
|
||||
|
||||
# Fall
|
||||
Forageable.blackberry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
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: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
Forageable.wild_plum: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.mountain, Region.bus_stop, Region.railroad)),
|
||||
),
|
||||
|
||||
# Winter
|
||||
Forageable.crocus: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.secret_woods)),
|
||||
),
|
||||
Forageable.crystal_fruit: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.holly: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.winter,),
|
||||
regions=(Region.backwoods, Region.mountain, Region.bus_stop, Region.town, Region.forest, Region.railroad)),
|
||||
),
|
||||
Forageable.snow_yam: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
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: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
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),
|
||||
@@ -102,31 +134,39 @@ pelican_town = ContentPack(
|
||||
|
||||
# Mushrooms
|
||||
Mushroom.common: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring,), regions=(Region.secret_woods,)),
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.backwoods, Region.mountain, Region.forest)),
|
||||
),
|
||||
Mushroom.chanterelle: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.fall,), regions=(Region.secret_woods,)),
|
||||
),
|
||||
Mushroom.morel: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.spring, Season.fall), regions=(Region.secret_woods,)),
|
||||
),
|
||||
Mushroom.red: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer, Season.fall), regions=(Region.secret_woods,)),
|
||||
),
|
||||
|
||||
# Beach
|
||||
WaterItem.coral: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.tide_pools,)),
|
||||
SeasonalForagingSource(season=Season.summer, days=(12, 13, 14), regions=(Region.beach,)),
|
||||
),
|
||||
WaterItem.nautilus_shell: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.winter,), regions=(Region.beach,)),
|
||||
),
|
||||
Forageable.rainbow_shell: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(seasons=(Season.summer,), regions=(Region.beach,)),
|
||||
),
|
||||
WaterItem.sea_urchin: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.tide_pools,)),
|
||||
),
|
||||
|
||||
@@ -149,150 +189,159 @@ pelican_town = ContentPack(
|
||||
},
|
||||
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),),
|
||||
Sapling.apple: (ShopSource(price=4000, shop_region=Region.pierre_store),),
|
||||
Sapling.apricot: (ShopSource(price=2000, shop_region=Region.pierre_store),),
|
||||
Sapling.cherry: (ShopSource(price=3400, shop_region=Region.pierre_store),),
|
||||
Sapling.orange: (ShopSource(price=4000, shop_region=Region.pierre_store),),
|
||||
Sapling.peach: (ShopSource(price=6000, shop_region=Region.pierre_store),),
|
||||
Sapling.pomegranate: (ShopSource(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.parsnip: (ShopSource(price=20, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.bean: (ShopSource(price=60, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.cauliflower: (ShopSource(price=80, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.potato: (ShopSource(price=50, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.tulip: (ShopSource(price=20, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.kale: (ShopSource(price=70, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.jazz: (ShopSource(price=30, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.garlic: (ShopSource(price=40, shop_region=Region.pierre_store, seasons=(Season.spring,)),),
|
||||
Seed.rice: (ShopSource(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.melon: (ShopSource(price=80, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.tomato: (ShopSource(price=50, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.blueberry: (ShopSource(price=80, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.pepper: (ShopSource(price=40, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.wheat: (ShopSource(price=10, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.radish: (ShopSource(price=40, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.poppy: (ShopSource(price=100, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.spangle: (ShopSource(price=50, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.hops: (ShopSource(price=60, shop_region=Region.pierre_store, seasons=(Season.summer,)),),
|
||||
Seed.corn: (ShopSource(price=150, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.sunflower: (ShopSource(price=200, shop_region=Region.pierre_store, seasons=(Season.summer, Season.fall)),),
|
||||
Seed.red_cabbage: (ShopSource(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.eggplant: (ShopSource(price=20, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.pumpkin: (ShopSource(price=100, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.bok_choy: (ShopSource(price=50, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.yam: (ShopSource(price=60, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.cranberry: (ShopSource(price=240, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.fairy: (ShopSource(price=200, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.amaranth: (ShopSource(price=70, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.grape: (ShopSource(price=60, shop_region=Region.pierre_store, seasons=(Season.fall,)),),
|
||||
Seed.artichoke: (ShopSource(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.broccoli: (ShopSource(items_price=((5, Material.moss),), shop_region=LogicRegion.raccoon_shop_1),),
|
||||
Seed.carrot: (ShopSource(items_price=((1, TreeSeed.maple),), shop_region=LogicRegion.raccoon_shop_1),),
|
||||
Seed.powdermelon: (ShopSource(items_price=((2, TreeSeed.acorn),), shop_region=LogicRegion.raccoon_shop_1),),
|
||||
Seed.summer_squash: (ShopSource(items_price=((15, Material.sap),), shop_region=LogicRegion.raccoon_shop_1),),
|
||||
|
||||
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)),),
|
||||
Seed.strawberry: (ShopSource(price=100, shop_region=LogicRegion.egg_festival, seasons=(Season.spring,)),),
|
||||
Seed.rare_seed: (ShopSource(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),),
|
||||
Beverage.beer: (ShopSource(price=400, shop_region=Region.saloon),),
|
||||
Meal.salad: (ShopSource(price=220, shop_region=Region.saloon),),
|
||||
Meal.bread: (ShopSource(price=100, shop_region=Region.saloon),),
|
||||
Meal.spaghetti: (ShopSource(price=240, shop_region=Region.saloon),),
|
||||
Meal.pizza: (ShopSource(price=600, shop_region=Region.saloon),),
|
||||
Beverage.coffee: (ShopSource(price=300, shop_region=Region.saloon),),
|
||||
|
||||
# Books
|
||||
Book.animal_catalogue: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=5000, shop_region=Region.ranch, other_requirements=(YearRequirement(2),)),),
|
||||
ShopSource(price=5000, shop_region=Region.ranch, other_requirements=(YearRequirement(2),)),),
|
||||
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.
|
||||
MysteryBoxSource(amount=50),), # 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),),
|
||||
ShopSource(price=4000, shop_region=LogicRegion.mines_dwarf_shop),),
|
||||
# ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),), # Repeatable, so no need for bookseller
|
||||
Book.friendship_101: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
PrizeMachineSource(amount=9),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
Book.horse_the_book: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=25000, shop_region=LogicRegion.bookseller_2),),
|
||||
ShopSource(price=25000, shop_region=LogicRegion.bookseller_permanent),),
|
||||
Book.jack_be_nimble_jack_be_thick: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
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),),
|
||||
FishingTreasureChestSource(amount=25), # After 21 chests, there are 49.44% chances player received the book.
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
Book.mapping_cave_systems: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
GenericSource(regions=(Region.adventurer_guild_bedroom,)),
|
||||
AllRegionsSource(regions=(Region.adventurer_guild_bedroom, LogicRegion.bookseller_rare,)),
|
||||
# Disabling the shop source for better game design.
|
||||
# ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),
|
||||
# ShopSource(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),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
Book.ol_slitherlegs: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=25000, shop_region=LogicRegion.bookseller_2),),
|
||||
ShopSource(price=25000, shop_region=LogicRegion.bookseller_permanent),),
|
||||
Book.price_catalogue: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=3000, shop_region=LogicRegion.bookseller_2),),
|
||||
ShopSource(price=3000, shop_region=LogicRegion.bookseller_permanent),),
|
||||
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),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
Book.the_art_o_crabbing: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
CustomRuleSource(create_rule=lambda logic: logic.festival.has_squidfest_day_1_iridium_reward()),
|
||||
ShopSource(money_price=20000, shop_region=LogicRegion.bookseller_3),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
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),),
|
||||
ArtifactTroveSource(amount=20), # After 18 troves, there is 49,88% chances player received the book.
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
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),),
|
||||
# ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare), # Repeatable, so no need for bookseller
|
||||
ShopSource(items_price=((999, Material.fiber),), shop_region=LogicRegion.raccoon_shop_2),),
|
||||
Book.way_of_the_wind_pt_1: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(money_price=15000, shop_region=LogicRegion.bookseller_2),),
|
||||
ShopSource(price=15000, shop_region=LogicRegion.bookseller_permanent),),
|
||||
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),)),),
|
||||
ShopSource(price=35000, shop_region=LogicRegion.bookseller_permanent, 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),),
|
||||
ShopSource(price=20000, shop_region=LogicRegion.bookseller_rare),),
|
||||
|
||||
# Experience Books
|
||||
Book.book_of_stars: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_permanent),),
|
||||
Book.bait_and_bobber: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_experience),),
|
||||
Book.combat_quarterly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_experience),),
|
||||
Book.mining_monthly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_experience),),
|
||||
Book.stardew_valley_almanac: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_experience),),
|
||||
Book.woodcutters_weekly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
ShopSource(price=5000, shop_region=LogicRegion.bookseller_experience),),
|
||||
|
||||
# Catalogues
|
||||
Catalogue.wizard: (ShopSource(price=150000, shop_region=Region.sewer, other_requirements=(CatalogueRequirement(Catalogue.wizard),)),),
|
||||
Catalogue.furniture: (ShopSource(price=200000, shop_region=Region.carpenter, other_requirements=(CatalogueRequirement(Catalogue.furniture),BuildingRequirement(BuildingNames.kitchen),)),),
|
||||
|
||||
# Furniture
|
||||
Furniture.single_bed: (ShopSource(price=500, shop_region=Region.carpenter),),
|
||||
Furniture.crane_game_house_plant: (ShopSource(price=500, shop_region=Region.movie_theater),),
|
||||
Furniture.cursed_mannequin: (MonsterSource(monsters=(Monster.haunted_skull,), amount_tier=MAX_MONTHS),),
|
||||
},
|
||||
fishes=(
|
||||
fish_data.albacore,
|
||||
@@ -396,7 +445,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=6000,
|
||||
price=6000,
|
||||
items_price=((350, Material.wood), (150, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -406,7 +455,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=12_000,
|
||||
price=12_000,
|
||||
items_price=((450, Material.wood), (200, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -417,7 +466,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=25_000,
|
||||
price=25_000,
|
||||
items_price=((550, Material.wood), (300, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -428,7 +477,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=4000,
|
||||
price=4000,
|
||||
items_price=((300, Material.wood), (100, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -438,7 +487,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=10_000,
|
||||
price=10_000,
|
||||
items_price=((400, Material.wood), (150, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -449,7 +498,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=20_000,
|
||||
price=20_000,
|
||||
items_price=((500, Material.wood), (200, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -460,7 +509,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=5000,
|
||||
price=5000,
|
||||
items_price=((200, Material.stone), (5, WaterItem.seaweed), (5, WaterItem.green_algae))
|
||||
),
|
||||
),
|
||||
@@ -470,7 +519,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=2500,
|
||||
price=2500,
|
||||
items_price=((50, Material.stone), (150, Material.wood), (4, ArtisanGood.cloth))
|
||||
),
|
||||
),
|
||||
@@ -480,7 +529,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=15_000,
|
||||
price=15_000,
|
||||
items_price=((300, Material.wood),)
|
||||
),
|
||||
),
|
||||
@@ -490,7 +539,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=20_000,
|
||||
price=20_000,
|
||||
items_price=((550, Material.wood), (300, Material.stone))
|
||||
),
|
||||
),
|
||||
@@ -501,7 +550,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=100,
|
||||
price=100,
|
||||
items_price=((100, Material.stone), (10, Material.clay), (5, MetalBar.copper))
|
||||
),
|
||||
),
|
||||
@@ -511,7 +560,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=10_000,
|
||||
price=10_000,
|
||||
items_price=((500, Material.stone), (10, MetalBar.quartz), (1, MetalBar.iridium))
|
||||
),
|
||||
),
|
||||
@@ -521,7 +570,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=10_000,
|
||||
price=10_000,
|
||||
items_price=((100, Material.hardwood), (5, MetalBar.iron))
|
||||
),
|
||||
),
|
||||
@@ -531,7 +580,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=1000,
|
||||
price=1000,
|
||||
items_price=((75, Material.stone),)
|
||||
),
|
||||
),
|
||||
@@ -541,7 +590,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=250,
|
||||
price=250,
|
||||
items_price=((150, Material.wood),)
|
||||
),
|
||||
),
|
||||
@@ -551,7 +600,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=5000,
|
||||
price=5000,
|
||||
items_price=((25, Material.hardwood),)
|
||||
),
|
||||
),
|
||||
@@ -561,7 +610,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=10_000,
|
||||
price=10_000,
|
||||
items_price=((450, Material.wood),)
|
||||
),
|
||||
),
|
||||
@@ -572,7 +621,7 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=65_000,
|
||||
price=65_000,
|
||||
items_price=((100, Material.hardwood),)
|
||||
),
|
||||
),
|
||||
@@ -583,10 +632,115 @@ pelican_town = ContentPack(
|
||||
sources=(
|
||||
ShopSource(
|
||||
shop_region=Region.carpenter,
|
||||
money_price=100_000,
|
||||
price=100_000,
|
||||
),
|
||||
),
|
||||
upgrade_from=BuildingNames.kids_room,
|
||||
),
|
||||
)
|
||||
# Building(
|
||||
# WizardBuilding.earth_obelisk,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=500_000,
|
||||
# items_price=((10, MetalBar.iridium), (10, Mineral.earth_crystal),)
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
# Building(
|
||||
# WizardBuilding.water_obelisk,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=500_000,
|
||||
# items_price=((5, MetalBar.iridium), (10, Fish.clam), (10, WaterItem.coral),)
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
# Building(
|
||||
# WizardBuilding.desert_obelisk,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=1_000_000,
|
||||
# items_price=((20, MetalBar.iridium), (10, Forageable.coconut), (10, Forageable.cactus_fruit),)
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
# Building(
|
||||
# WizardBuilding.island_obelisk,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=1_000_000,
|
||||
# items_price=((10, MetalBar.iridium), (10, Forageable.dragon_tooth), (10, Fruit.banana),)
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
# Building(
|
||||
# WizardBuilding.junimo_hut,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=20_000,
|
||||
# items_price=((200, Material.stone), (9, Fruit.starfruit), (100, Material.fiber),)
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
# Building(
|
||||
# WizardBuilding.gold_clock,
|
||||
# sources=(
|
||||
# ShopSource(
|
||||
# shop_region=Region.wizard_tower,
|
||||
# price=10_000_000,
|
||||
# ),
|
||||
# ),
|
||||
# ),
|
||||
),
|
||||
hat_sources={
|
||||
# Hats from the Hat Mouse
|
||||
Hats.blue_ribbon: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(GrangeDisplayRequirement(),)),),
|
||||
Hats.blue_bonnet: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(MuseumCompletionRequirement(40),)),),
|
||||
Hats.cowboy: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(MuseumCompletionRequirement(),)),),
|
||||
Hats.butterfly_bow: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(1, 5),)),),
|
||||
Hats.mouse_ears: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(1, 10),)),),
|
||||
Hats.cat_ears: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(8, 10),)),),
|
||||
Hats.tiara: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(4, 5),)),),
|
||||
Hats.santa_hat: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(10, 5),)),),
|
||||
Hats.earmuffs: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(NumberOfFriendsRequirement(20, 5),)),),
|
||||
Hats.tropiclip: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(BuildingRequirement(BuildingNames.kitchen),)),),
|
||||
Hats.hunters_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(BuildingRequirement(BuildingNames.cellar),)),),
|
||||
Hats.polka_bow: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(HelpWantedRequirement(10),)),),
|
||||
Hats.chicken_mask: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(HelpWantedRequirement(40),)),),
|
||||
Hats.straw: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(EggHuntRequirement(),)),),
|
||||
Hats.sailors_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(FishingCompetitionRequirement(),)),),
|
||||
Hats.jester_hat: (Tag(ItemTag.HAT), HatMouseSource(price=25000, unlock_requirements=(MovieRequirement(),)),),
|
||||
Hats.governors_hat: (Tag(ItemTag.HAT), HatMouseSource(price=5000, unlock_requirements=(LuauDelightRequirementRequirement(),)),),
|
||||
Hats.white_bow: (Tag(ItemTag.HAT), HatMouseSource(price=5000, unlock_requirements=(ReceivedRaccoonsRequirement(8),)),),
|
||||
Hats.sports_cap: (Tag(ItemTag.HAT), HatMouseSource(price=5000, unlock_requirements=(PrizeMachineRequirement(11),)),),
|
||||
|
||||
Hats.emilys_magic_hat: (Tag(ItemTag.HAT), ShopSource(price=10000, shop_region=LogicRegion.lost_items_shop,
|
||||
other_requirements=(
|
||||
SpecificFriendRequirement(NPC.emily, 14), RegionRequirement(Region.farm))),),
|
||||
Hats.fedora: (Tag(ItemTag.HAT), ShopSource(price=500, currency=Currency.star_token, shop_region=LogicRegion.fair),),
|
||||
Hats.cone_hat: (Tag(ItemTag.HAT), ShopSource(price=5000, shop_region=LogicRegion.night_market),),
|
||||
Hats.red_fez: (Tag(ItemTag.HAT), ShopSource(price=8000, shop_region=LogicRegion.traveling_cart),),
|
||||
|
||||
Hats.garbage_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.town,), grind_months=12),),
|
||||
Hats.mystery_hat: (Tag(ItemTag.HAT), MysteryBoxSource(amount=100),),
|
||||
|
||||
Hats.fishing_hat: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fish.stonefish, Fish.ice_pip, Fish.scorpion_carp, Fish.spook_fish,
|
||||
Fish.midnight_squid, Fish.void_salmon, Fish.slimejack,)),),
|
||||
Hats.bucket_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.hat.has_bucket_hat),),
|
||||
|
||||
Hats.leprechaun_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.forest,), seasons=(Season.spring,), ),),
|
||||
Hats.mushroom_cap: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.farm,), seasons=(Season.fall,),
|
||||
other_requirements=(ToolRequirement(Tool.axe),),),),
|
||||
|
||||
Hats.raccoon_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.quest.has_raccoon_shop(3) &
|
||||
logic.region.can_reach(LogicRegion.raccoon_shop_3)),),
|
||||
|
||||
Hats.squid_hat: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.festival.can_squidfest_iridium_reward()),),
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
@@ -2,9 +2,14 @@ from .ginger_island import ginger_island_content_pack as ginger_island_content_p
|
||||
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.game_item import GenericSource, ItemTag, Tag
|
||||
from ...data.harvest import HarvestCropSource
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.requirement import DangerousMinesRequirement, CraftedItemsRequirement
|
||||
from ...data.shop import HatMouseSource
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...strings.crop_names import Fruit
|
||||
from ...strings.metal_names import MetalBar
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.seed_names import Seed
|
||||
|
||||
@@ -31,5 +36,11 @@ qi_board_content_pack = QiBoardContentPack(
|
||||
fish_data.glacierfish_jr,
|
||||
fish_data.legend_ii,
|
||||
fish_data.radioactive_carp,
|
||||
)
|
||||
),
|
||||
hat_sources={
|
||||
Hats.space_helmet: (HatMouseSource(price=20000, unlock_requirements=(DangerousMinesRequirement(120),)),),
|
||||
Hats.qi_mask: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fruit.qi_fruit,)),),
|
||||
Hats.radioactive_goggles: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(MetalBar.radioactive,)),),
|
||||
Hats.gnomes_cap: (Tag(ItemTag.HAT), HatMouseSource(price=1000, unlock_requirements=(CraftedItemsRequirement(9999),)),),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
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.game_item import CustomRuleSource, ItemTag, Tag
|
||||
from ...data.harvest import ForagingSource, HarvestCropSource
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.monster_data import MonsterSource
|
||||
from ...data.requirement import RegionRequirement, MeetRequirement, MonsterKillRequirement
|
||||
from ...data.shop import ShopSource
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...logic.time_logic import MAX_MONTHS
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
from ...strings.currency_names import Currency
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.geode_names import Geode
|
||||
from ...strings.metal_names import Artifact
|
||||
from ...strings.monster_names import Monster
|
||||
from ...strings.region_names import Region, LogicRegion
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
from ...strings.villager_names import NPC
|
||||
|
||||
the_desert = ContentPack(
|
||||
"The Desert (Vanilla)",
|
||||
@@ -16,13 +27,16 @@ the_desert = ContentPack(
|
||||
),
|
||||
harvest_sources={
|
||||
Forageable.cactus_fruit: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.desert,)),
|
||||
HarvestCropSource(seed=Seed.cactus, seasons=())
|
||||
),
|
||||
Forageable.coconut: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.desert,)),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.skull_cavern_25,)),
|
||||
),
|
||||
|
||||
@@ -31,10 +45,10 @@ the_desert = ContentPack(
|
||||
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,)),),
|
||||
Seed.cactus: (ShopSource(price=150, shop_region=Region.oasis),),
|
||||
Seed.rhubarb: (ShopSource(price=100, shop_region=Region.oasis, seasons=(Season.spring,)),),
|
||||
Seed.starfruit: (ShopSource(price=400, shop_region=Region.oasis, seasons=(Season.summer,)),),
|
||||
Seed.beet: (ShopSource(price=20, shop_region=Region.oasis, seasons=(Season.fall,)),),
|
||||
},
|
||||
fishes=(
|
||||
fish_data.sandfish,
|
||||
@@ -43,4 +57,33 @@ the_desert = ContentPack(
|
||||
villagers=(
|
||||
villagers_data.sandy,
|
||||
),
|
||||
hat_sources={
|
||||
Hats.top_hat: (Tag(ItemTag.HAT), ShopSource(price=8000, shop_region=Region.casino, currency=Currency.qi_coin),),
|
||||
Hats.gils_hat: (Tag(ItemTag.HAT), ShopSource(price=10000, shop_region=LogicRegion.lost_items_shop,
|
||||
other_requirements=(
|
||||
RegionRequirement(Region.skull_cavern_100), RegionRequirement(LogicRegion.desert_festival),)),),
|
||||
Hats.abigails_bow: (Tag(ItemTag.HAT), ShopSource(price=60, currency=Currency.calico_egg, shop_region=LogicRegion.desert_festival,
|
||||
other_requirements=(MeetRequirement(NPC.abigail),)),),
|
||||
Hats.tricorn: (Tag(ItemTag.HAT), ShopSource(price=100, currency=Currency.calico_egg, shop_region=LogicRegion.desert_festival,
|
||||
other_requirements=(MeetRequirement(NPC.elliott),)),),
|
||||
Hats.blue_bow: (Tag(ItemTag.HAT), ShopSource(price=60, currency=Currency.calico_egg, shop_region=LogicRegion.desert_festival),),
|
||||
Hats.dark_velvet_bow: (Tag(ItemTag.HAT), ShopSource(price=75, currency=Currency.calico_egg, shop_region=LogicRegion.desert_festival),),
|
||||
Hats.mummy_mask: (Tag(ItemTag.HAT), ShopSource(price=120, currency=Currency.calico_egg, shop_region=LogicRegion.desert_festival),),
|
||||
Hats.arcane_hat: (Tag(ItemTag.HAT), ShopSource(price=20000, shop_region=Region.adventurer_guild,
|
||||
other_requirements=(MonsterKillRequirement((Monster.mummy,), 100),)),),
|
||||
Hats.green_turban: (Tag(ItemTag.HAT), ShopSource(price=50, currency=Geode.omni, shop_region=Region.desert,),),
|
||||
Hats.magic_cowboy_hat: (Tag(ItemTag.HAT), ShopSource(price=333, currency=Geode.omni, shop_region=Region.desert,),),
|
||||
Hats.magic_turban: (Tag(ItemTag.HAT), ShopSource(price=333, currency=Geode.omni, shop_region=Region.desert,),),
|
||||
|
||||
Hats.laurel_wreath_crown: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.hat.can_get_unlikely_hat_at_outfit_services),),
|
||||
Hats.joja_cap: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.hat.can_get_unlikely_hat_at_outfit_services),),
|
||||
Hats.dark_ballcap: (Tag(ItemTag.HAT), CustomRuleSource(create_rule=lambda logic: logic.hat.can_get_unlikely_hat_at_outfit_services),),
|
||||
Hats.dark_cowboy_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.skull_cavern_100,)),),
|
||||
Hats.blue_cowboy_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.skull_cavern_100,))),
|
||||
Hats.red_cowboy_hat: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.skull_cavern_100,))),
|
||||
Hats.golden_mask: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Artifact.golden_mask,)),),
|
||||
Hats.white_turban: (Tag(ItemTag.HAT), ForagingSource(regions=(Region.skull_cavern_100,))),
|
||||
Hats.knights_helmet: (Tag(ItemTag.HAT), MonsterSource(monsters=(Monster.pepper_rex,), amount_tier=MAX_MONTHS,
|
||||
other_requirements=(RegionRequirement(region=Region.adventurer_guild),)),),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from .pelican_town import pelican_town as pelican_town_content_pack
|
||||
from ..game_content import ContentPack
|
||||
from ...data.animal import IncubatorSource, Animal, AnimalName
|
||||
from ...data.game_item import Tag, ItemTag
|
||||
from ...data.harvest import FruitBatsSource, MushroomCaveSource
|
||||
from ...data.shop import ShopSource
|
||||
from ...strings.animal_product_names import AnimalProduct
|
||||
@@ -16,32 +17,41 @@ the_farm = ContentPack(
|
||||
harvest_sources={
|
||||
# Fruit cave
|
||||
Forageable.blackberry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.salmonberry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.spice_berry: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
FruitBatsSource(),
|
||||
),
|
||||
Forageable.wild_plum: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
FruitBatsSource(),
|
||||
),
|
||||
|
||||
# Mushrooms
|
||||
Mushroom.common: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.chanterelle: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.morel: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
Mushroom.red: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
MushroomCaveSource(),
|
||||
),
|
||||
},
|
||||
@@ -49,41 +59,41 @@ the_farm = ContentPack(
|
||||
Animal(AnimalName.chicken,
|
||||
required_building=Building.coop,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=800),
|
||||
ShopSource(shop_region=Region.ranch, price=800),
|
||||
# For now there is no way to obtain the starter item, so this adds additional rules in the system for nothing.
|
||||
# IncubatorSource(AnimalProduct.egg_starter)
|
||||
)),
|
||||
Animal(AnimalName.cow,
|
||||
required_building=Building.barn,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=1500),
|
||||
ShopSource(shop_region=Region.ranch, price=1500),
|
||||
)),
|
||||
Animal(AnimalName.goat,
|
||||
required_building=Building.big_barn,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=4000),
|
||||
ShopSource(shop_region=Region.ranch, price=4000),
|
||||
)),
|
||||
Animal(AnimalName.duck,
|
||||
required_building=Building.big_coop,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=1200),
|
||||
ShopSource(shop_region=Region.ranch, price=1200),
|
||||
# For now there is no way to obtain the starter item, so this adds additional rules in the system for nothing.
|
||||
# IncubatorSource(AnimalProduct.duck_egg_starter)
|
||||
)),
|
||||
Animal(AnimalName.sheep,
|
||||
required_building=Building.deluxe_barn,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=8000),
|
||||
ShopSource(shop_region=Region.ranch, price=8000),
|
||||
)),
|
||||
Animal(AnimalName.rabbit,
|
||||
required_building=Building.deluxe_coop,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=8000),
|
||||
ShopSource(shop_region=Region.ranch, price=8000),
|
||||
)),
|
||||
Animal(AnimalName.pig,
|
||||
required_building=Building.deluxe_barn,
|
||||
sources=(
|
||||
ShopSource(shop_region=Region.ranch, money_price=16000),
|
||||
ShopSource(shop_region=Region.ranch, price=16000),
|
||||
)),
|
||||
Animal(AnimalName.void_chicken,
|
||||
required_building=Building.big_coop,
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
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.game_item import Tag, ItemTag
|
||||
from ...data.harvest import ForagingSource
|
||||
from ...data.requirement import ToolRequirement
|
||||
from ...data.hats_data import Hats
|
||||
from ...data.monster_data import MonsterSource
|
||||
from ...data.requirement import ToolRequirement, RegionRequirement
|
||||
from ...logic.tailoring_logic import TailoringSource
|
||||
from ...logic.time_logic import MAX_MONTHS
|
||||
from ...strings.fish_names import Fish
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.monster_names import Monster
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.tool_names import Tool
|
||||
|
||||
@@ -14,12 +21,15 @@ the_mines = ContentPack(
|
||||
),
|
||||
harvest_sources={
|
||||
Forageable.cave_carrot: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.mines_floor_10,), other_requirements=(ToolRequirement(Tool.hoe),)),
|
||||
),
|
||||
Mushroom.red: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.mines_floor_95,)),
|
||||
),
|
||||
Mushroom.purple: (
|
||||
Tag(ItemTag.FORAGE),
|
||||
ForagingSource(regions=(Region.mines_floor_95,)),
|
||||
)
|
||||
},
|
||||
@@ -32,4 +42,15 @@ the_mines = ContentPack(
|
||||
villagers=(
|
||||
villagers_data.dwarf,
|
||||
),
|
||||
hat_sources={
|
||||
Hats.logo_cap: (Tag(ItemTag.HAT), TailoringSource(tailoring_items=(Fish.lava_eel,)),),
|
||||
Hats.hard_hat: (Tag(ItemTag.HAT), MonsterSource(monsters=(Monster.duggy, Monster.duggy_dangerous, Monster.magma_duggy,),
|
||||
amount_tier=3,
|
||||
other_requirements=(RegionRequirement(region=Region.adventurer_guild),)),),
|
||||
Hats.skeleton_mask: (Tag(ItemTag.HAT), MonsterSource(monsters=(Monster.skeleton, Monster.skeleton_mage, Monster.skeleton_dangerous,),
|
||||
amount_tier=MAX_MONTHS,
|
||||
other_requirements=(RegionRequirement(region=Region.adventurer_guild),)),),
|
||||
Hats.squires_helmet: (Tag(ItemTag.HAT), MonsterSource(monsters=(Monster.metal_head,),
|
||||
amount_tier=MAX_MONTHS),),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,906 +0,0 @@
|
||||
from ..bundles.bundle import BundleTemplate, IslandBundleTemplate, DeepBundleTemplate, CurrencyBundleTemplate, MoneyBundleTemplate, FestivalBundleTemplate
|
||||
from ..bundles.bundle_item import BundleItem
|
||||
from ..bundles.bundle_room import BundleRoomTemplate
|
||||
from ..content import content_packs
|
||||
from ..content.vanilla.base import all_fruits, all_vegetables, all_edible_mushrooms
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.bundle_names import CCRoom, BundleName
|
||||
from ..strings.craftable_names import Fishing, Craftable, Bomb, Consumable, Lighting
|
||||
from ..strings.crop_names import Fruit, Vegetable
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.fertilizer_names import Fertilizer, RetainingSoil, SpeedGro
|
||||
from ..strings.fish_names import Fish, WaterItem, Trash
|
||||
from ..strings.flower_names import Flower
|
||||
from ..strings.food_names import Beverage, Meal
|
||||
from ..strings.forageable_names import Forageable, Mushroom
|
||||
from ..strings.geode_names import Geode
|
||||
from ..strings.gift_names import Gift
|
||||
from ..strings.ingredient_names import Ingredient
|
||||
from ..strings.material_names import Material
|
||||
from ..strings.metal_names import MetalBar, Artifact, Fossil, Ore, Mineral
|
||||
from ..strings.monster_drop_names import Loot
|
||||
from ..strings.quality_names import ForageQuality, ArtisanQuality, FishQuality
|
||||
from ..strings.seed_names import Seed, TreeSeed
|
||||
|
||||
wild_horseradish = BundleItem(Forageable.wild_horseradish)
|
||||
daffodil = BundleItem(Forageable.daffodil)
|
||||
leek = BundleItem(Forageable.leek)
|
||||
dandelion = BundleItem(Forageable.dandelion)
|
||||
morel = BundleItem(Mushroom.morel)
|
||||
common_mushroom = BundleItem(Mushroom.common)
|
||||
salmonberry = BundleItem(Forageable.salmonberry)
|
||||
spring_onion = BundleItem(Forageable.spring_onion)
|
||||
|
||||
grape = BundleItem(Fruit.grape)
|
||||
spice_berry = BundleItem(Forageable.spice_berry)
|
||||
sweet_pea = BundleItem(Forageable.sweet_pea)
|
||||
red_mushroom = BundleItem(Mushroom.red)
|
||||
fiddlehead_fern = BundleItem(Forageable.fiddlehead_fern)
|
||||
|
||||
wild_plum = BundleItem(Forageable.wild_plum)
|
||||
hazelnut = BundleItem(Forageable.hazelnut)
|
||||
blackberry = BundleItem(Forageable.blackberry)
|
||||
chanterelle = BundleItem(Mushroom.chanterelle)
|
||||
|
||||
winter_root = BundleItem(Forageable.winter_root)
|
||||
crystal_fruit = BundleItem(Forageable.crystal_fruit)
|
||||
snow_yam = BundleItem(Forageable.snow_yam)
|
||||
crocus = BundleItem(Forageable.crocus)
|
||||
holly = BundleItem(Forageable.holly)
|
||||
|
||||
coconut = BundleItem(Forageable.coconut)
|
||||
cactus_fruit = BundleItem(Forageable.cactus_fruit)
|
||||
cave_carrot = BundleItem(Forageable.cave_carrot)
|
||||
purple_mushroom = BundleItem(Mushroom.purple)
|
||||
maple_syrup = BundleItem(ArtisanGood.maple_syrup)
|
||||
oak_resin = BundleItem(ArtisanGood.oak_resin)
|
||||
pine_tar = BundleItem(ArtisanGood.pine_tar)
|
||||
nautilus_shell = BundleItem(WaterItem.nautilus_shell)
|
||||
coral = BundleItem(WaterItem.coral)
|
||||
sea_urchin = BundleItem(WaterItem.sea_urchin)
|
||||
rainbow_shell = BundleItem(Forageable.rainbow_shell)
|
||||
clam = BundleItem(Fish.clam)
|
||||
cockle = BundleItem(Fish.cockle)
|
||||
mussel = BundleItem(Fish.mussel)
|
||||
oyster = BundleItem(Fish.oyster)
|
||||
seaweed = BundleItem(WaterItem.seaweed, can_have_quality=False)
|
||||
|
||||
wood = BundleItem(Material.wood, 99)
|
||||
stone = BundleItem(Material.stone, 99)
|
||||
hardwood = BundleItem(Material.hardwood, 10)
|
||||
clay = BundleItem(Material.clay, 10)
|
||||
fiber = BundleItem(Material.fiber, 99)
|
||||
moss = BundleItem(Material.moss, 10)
|
||||
|
||||
mixed_seeds = BundleItem(Seed.mixed)
|
||||
acorn = BundleItem(TreeSeed.acorn)
|
||||
maple_seed = BundleItem(TreeSeed.maple)
|
||||
pine_cone = BundleItem(TreeSeed.pine)
|
||||
mahogany_seed = BundleItem(TreeSeed.mahogany)
|
||||
mushroom_tree_seed = BundleItem(TreeSeed.mushroom, source=BundleItem.Sources.island)
|
||||
mystic_tree_seed = BundleItem(TreeSeed.mystic, source=BundleItem.Sources.masteries)
|
||||
mossy_seed = BundleItem(TreeSeed.mossy)
|
||||
|
||||
strawberry_seeds = BundleItem(Seed.strawberry)
|
||||
|
||||
blue_jazz = BundleItem(Flower.blue_jazz)
|
||||
cauliflower = BundleItem(Vegetable.cauliflower)
|
||||
green_bean = BundleItem(Vegetable.green_bean)
|
||||
kale = BundleItem(Vegetable.kale)
|
||||
parsnip = BundleItem(Vegetable.parsnip)
|
||||
potato = BundleItem(Vegetable.potato)
|
||||
strawberry = BundleItem(Fruit.strawberry, source=BundleItem.Sources.festival)
|
||||
tulip = BundleItem(Flower.tulip)
|
||||
unmilled_rice = BundleItem(Vegetable.unmilled_rice)
|
||||
coffee_bean = BundleItem(Seed.coffee)
|
||||
garlic = BundleItem(Vegetable.garlic)
|
||||
blueberry = BundleItem(Fruit.blueberry)
|
||||
corn = BundleItem(Vegetable.corn)
|
||||
hops = BundleItem(Vegetable.hops)
|
||||
hot_pepper = BundleItem(Fruit.hot_pepper)
|
||||
melon = BundleItem(Fruit.melon)
|
||||
poppy = BundleItem(Flower.poppy)
|
||||
radish = BundleItem(Vegetable.radish)
|
||||
summer_spangle = BundleItem(Flower.summer_spangle)
|
||||
sunflower = BundleItem(Flower.sunflower)
|
||||
tomato = BundleItem(Vegetable.tomato)
|
||||
wheat = BundleItem(Vegetable.wheat)
|
||||
hay = BundleItem(Forageable.hay)
|
||||
amaranth = BundleItem(Vegetable.amaranth)
|
||||
bok_choy = BundleItem(Vegetable.bok_choy)
|
||||
cranberries = BundleItem(Fruit.cranberries)
|
||||
eggplant = BundleItem(Vegetable.eggplant)
|
||||
fairy_rose = BundleItem(Flower.fairy_rose)
|
||||
pumpkin = BundleItem(Vegetable.pumpkin)
|
||||
yam = BundleItem(Vegetable.yam)
|
||||
sweet_gem_berry = BundleItem(Fruit.sweet_gem_berry)
|
||||
rhubarb = BundleItem(Fruit.rhubarb)
|
||||
beet = BundleItem(Vegetable.beet)
|
||||
red_cabbage = BundleItem(Vegetable.red_cabbage)
|
||||
starfruit = BundleItem(Fruit.starfruit)
|
||||
artichoke = BundleItem(Vegetable.artichoke)
|
||||
pineapple = BundleItem(Fruit.pineapple, source=BundleItem.Sources.content)
|
||||
taro_root = BundleItem(Vegetable.taro_root, source=BundleItem.Sources.content)
|
||||
|
||||
carrot = BundleItem(Vegetable.carrot)
|
||||
summer_squash = BundleItem(Vegetable.summer_squash)
|
||||
broccoli = BundleItem(Vegetable.broccoli)
|
||||
powdermelon = BundleItem(Fruit.powdermelon)
|
||||
|
||||
egg = BundleItem(AnimalProduct.egg)
|
||||
large_egg = BundleItem(AnimalProduct.large_egg)
|
||||
brown_egg = BundleItem(AnimalProduct.brown_egg)
|
||||
large_brown_egg = BundleItem(AnimalProduct.large_brown_egg)
|
||||
wool = BundleItem(AnimalProduct.wool)
|
||||
milk = BundleItem(AnimalProduct.milk)
|
||||
large_milk = BundleItem(AnimalProduct.large_milk)
|
||||
goat_milk = BundleItem(AnimalProduct.goat_milk)
|
||||
large_goat_milk = BundleItem(AnimalProduct.large_goat_milk)
|
||||
truffle = BundleItem(AnimalProduct.truffle)
|
||||
duck_feather = BundleItem(AnimalProduct.duck_feather)
|
||||
duck_egg = BundleItem(AnimalProduct.duck_egg)
|
||||
rabbit_foot = BundleItem(AnimalProduct.rabbit_foot)
|
||||
dinosaur_egg = BundleItem(AnimalProduct.dinosaur_egg)
|
||||
void_egg = BundleItem(AnimalProduct.void_egg)
|
||||
ostrich_egg = BundleItem(AnimalProduct.ostrich_egg, source=BundleItem.Sources.content)
|
||||
golden_egg = BundleItem(AnimalProduct.golden_egg)
|
||||
|
||||
truffle_oil = BundleItem(ArtisanGood.truffle_oil)
|
||||
cloth = BundleItem(ArtisanGood.cloth)
|
||||
goat_cheese = BundleItem(ArtisanGood.goat_cheese)
|
||||
cheese = BundleItem(ArtisanGood.cheese)
|
||||
honey = BundleItem(ArtisanGood.honey)
|
||||
beer = BundleItem(Beverage.beer)
|
||||
juice = BundleItem(ArtisanGood.juice)
|
||||
mead = BundleItem(ArtisanGood.mead)
|
||||
pale_ale = BundleItem(ArtisanGood.pale_ale)
|
||||
wine = BundleItem(ArtisanGood.wine)
|
||||
jelly = BundleItem(ArtisanGood.jelly)
|
||||
pickles = BundleItem(ArtisanGood.pickles)
|
||||
caviar = BundleItem(ArtisanGood.caviar)
|
||||
aged_roe = BundleItem(ArtisanGood.aged_roe)
|
||||
roe = BundleItem(AnimalProduct.roe)
|
||||
squid_ink = BundleItem(AnimalProduct.squid_ink)
|
||||
coffee = BundleItem(Beverage.coffee)
|
||||
green_tea = BundleItem(ArtisanGood.green_tea)
|
||||
apple = BundleItem(Fruit.apple)
|
||||
apricot = BundleItem(Fruit.apricot)
|
||||
orange = BundleItem(Fruit.orange)
|
||||
peach = BundleItem(Fruit.peach)
|
||||
pomegranate = BundleItem(Fruit.pomegranate)
|
||||
cherry = BundleItem(Fruit.cherry)
|
||||
banana = BundleItem(Fruit.banana, source=BundleItem.Sources.content)
|
||||
mango = BundleItem(Fruit.mango, source=BundleItem.Sources.content)
|
||||
|
||||
basic_fertilizer = BundleItem(Fertilizer.basic, 100)
|
||||
quality_fertilizer = BundleItem(Fertilizer.quality, 20)
|
||||
deluxe_fertilizer = BundleItem(Fertilizer.deluxe, 5, source=BundleItem.Sources.island)
|
||||
basic_retaining_soil = BundleItem(RetainingSoil.basic, 80)
|
||||
quality_retaining_soil = BundleItem(RetainingSoil.quality, 50)
|
||||
deluxe_retaining_soil = BundleItem(RetainingSoil.deluxe, 20, source=BundleItem.Sources.island)
|
||||
speed_gro = BundleItem(SpeedGro.basic, 40)
|
||||
deluxe_speed_gro = BundleItem(SpeedGro.deluxe, 20)
|
||||
hyper_speed_gro = BundleItem(SpeedGro.hyper, 5, source=BundleItem.Sources.island)
|
||||
tree_fertilizer = BundleItem(Fertilizer.tree, 20)
|
||||
|
||||
lobster = BundleItem(Fish.lobster)
|
||||
crab = BundleItem(Fish.crab)
|
||||
shrimp = BundleItem(Fish.shrimp)
|
||||
crayfish = BundleItem(Fish.crayfish)
|
||||
snail = BundleItem(Fish.snail)
|
||||
periwinkle = BundleItem(Fish.periwinkle)
|
||||
trash = BundleItem(Trash.trash)
|
||||
driftwood = BundleItem(Trash.driftwood)
|
||||
soggy_newspaper = BundleItem(Trash.soggy_newspaper)
|
||||
broken_cd = BundleItem(Trash.broken_cd)
|
||||
broken_glasses = BundleItem(Trash.broken_glasses)
|
||||
|
||||
chub = BundleItem(Fish.chub)
|
||||
catfish = BundleItem(Fish.catfish)
|
||||
rainbow_trout = BundleItem(Fish.rainbow_trout)
|
||||
lingcod = BundleItem(Fish.lingcod)
|
||||
walleye = BundleItem(Fish.walleye)
|
||||
perch = BundleItem(Fish.perch)
|
||||
pike = BundleItem(Fish.pike)
|
||||
bream = BundleItem(Fish.bream)
|
||||
salmon = BundleItem(Fish.salmon)
|
||||
sunfish = BundleItem(Fish.sunfish)
|
||||
tiger_trout = BundleItem(Fish.tiger_trout)
|
||||
shad = BundleItem(Fish.shad)
|
||||
smallmouth_bass = BundleItem(Fish.smallmouth_bass)
|
||||
dorado = BundleItem(Fish.dorado)
|
||||
carp = BundleItem(Fish.carp)
|
||||
midnight_carp = BundleItem(Fish.midnight_carp)
|
||||
largemouth_bass = BundleItem(Fish.largemouth_bass)
|
||||
sturgeon = BundleItem(Fish.sturgeon)
|
||||
bullhead = BundleItem(Fish.bullhead)
|
||||
tilapia = BundleItem(Fish.tilapia)
|
||||
pufferfish = BundleItem(Fish.pufferfish)
|
||||
tuna = BundleItem(Fish.tuna)
|
||||
super_cucumber = BundleItem(Fish.super_cucumber)
|
||||
flounder = BundleItem(Fish.flounder)
|
||||
anchovy = BundleItem(Fish.anchovy)
|
||||
sardine = BundleItem(Fish.sardine)
|
||||
red_mullet = BundleItem(Fish.red_mullet)
|
||||
herring = BundleItem(Fish.herring)
|
||||
eel = BundleItem(Fish.eel)
|
||||
octopus = BundleItem(Fish.octopus)
|
||||
red_snapper = BundleItem(Fish.red_snapper)
|
||||
squid = BundleItem(Fish.squid)
|
||||
sea_cucumber = BundleItem(Fish.sea_cucumber)
|
||||
albacore = BundleItem(Fish.albacore)
|
||||
halibut = BundleItem(Fish.halibut)
|
||||
scorpion_carp = BundleItem(Fish.scorpion_carp)
|
||||
sandfish = BundleItem(Fish.sandfish)
|
||||
woodskip = BundleItem(Fish.woodskip)
|
||||
lava_eel = BundleItem(Fish.lava_eel)
|
||||
ice_pip = BundleItem(Fish.ice_pip)
|
||||
stonefish = BundleItem(Fish.stonefish)
|
||||
ghostfish = BundleItem(Fish.ghostfish)
|
||||
|
||||
bouquet = BundleItem(Gift.bouquet)
|
||||
wilted_bouquet = BundleItem(Gift.wilted_bouquet)
|
||||
copper_bar = BundleItem(MetalBar.copper)
|
||||
iron_Bar = BundleItem(MetalBar.iron)
|
||||
gold_bar = BundleItem(MetalBar.gold)
|
||||
iridium_bar = BundleItem(MetalBar.iridium)
|
||||
refined_quartz = BundleItem(MetalBar.quartz)
|
||||
coal = BundleItem(Material.coal, 5)
|
||||
iridium_ore = BundleItem(Ore.iridium)
|
||||
gold_ore = BundleItem(Ore.gold)
|
||||
iron_ore = BundleItem(Ore.iron)
|
||||
copper_ore = BundleItem(Ore.copper)
|
||||
battery_pack = BundleItem(ArtisanGood.battery_pack)
|
||||
|
||||
quartz = BundleItem(Mineral.quartz)
|
||||
fire_quartz = BundleItem(Mineral.fire_quartz)
|
||||
frozen_tear = BundleItem(Mineral.frozen_tear)
|
||||
earth_crystal = BundleItem(Mineral.earth_crystal)
|
||||
emerald = BundleItem(Mineral.emerald)
|
||||
aquamarine = BundleItem(Mineral.aquamarine)
|
||||
ruby = BundleItem(Mineral.ruby)
|
||||
amethyst = BundleItem(Mineral.amethyst)
|
||||
topaz = BundleItem(Mineral.topaz)
|
||||
jade = BundleItem(Mineral.jade)
|
||||
|
||||
slime = BundleItem(Loot.slime, 99)
|
||||
bug_meat = BundleItem(Loot.bug_meat, 10)
|
||||
bat_wing = BundleItem(Loot.bat_wing, 10)
|
||||
solar_essence = BundleItem(Loot.solar_essence)
|
||||
void_essence = BundleItem(Loot.void_essence)
|
||||
|
||||
petrified_slime = BundleItem(Mineral.petrified_slime)
|
||||
blue_slime_egg = BundleItem(AnimalProduct.slime_egg_blue)
|
||||
red_slime_egg = BundleItem(AnimalProduct.slime_egg_red)
|
||||
purple_slime_egg = BundleItem(AnimalProduct.slime_egg_purple)
|
||||
green_slime_egg = BundleItem(AnimalProduct.slime_egg_green)
|
||||
tiger_slime_egg = BundleItem(AnimalProduct.slime_egg_tiger, source=BundleItem.Sources.island)
|
||||
|
||||
cherry_bomb = BundleItem(Bomb.cherry_bomb, 5)
|
||||
bomb = BundleItem(Bomb.bomb, 2)
|
||||
mega_bomb = BundleItem(Bomb.mega_bomb)
|
||||
explosive_ammo = BundleItem(Craftable.explosive_ammo, 5)
|
||||
|
||||
maki_roll = BundleItem(Meal.maki_roll)
|
||||
fried_egg = BundleItem(Meal.fried_egg)
|
||||
omelet = BundleItem(Meal.omelet)
|
||||
pizza = BundleItem(Meal.pizza)
|
||||
hashbrowns = BundleItem(Meal.hashbrowns)
|
||||
pancakes = BundleItem(Meal.pancakes)
|
||||
bread = BundleItem(Meal.bread)
|
||||
tortilla = BundleItem(Meal.tortilla)
|
||||
triple_shot_espresso = BundleItem(Beverage.triple_shot_espresso)
|
||||
farmer_s_lunch = BundleItem(Meal.farmer_lunch)
|
||||
survival_burger = BundleItem(Meal.survival_burger)
|
||||
dish_o_the_sea = BundleItem(Meal.dish_o_the_sea)
|
||||
miner_s_treat = BundleItem(Meal.miners_treat)
|
||||
roots_platter = BundleItem(Meal.roots_platter)
|
||||
salad = BundleItem(Meal.salad)
|
||||
cheese_cauliflower = BundleItem(Meal.cheese_cauliflower)
|
||||
parsnip_soup = BundleItem(Meal.parsnip_soup)
|
||||
fried_mushroom = BundleItem(Meal.fried_mushroom)
|
||||
salmon_dinner = BundleItem(Meal.salmon_dinner)
|
||||
pepper_poppers = BundleItem(Meal.pepper_poppers)
|
||||
spaghetti = BundleItem(Meal.spaghetti)
|
||||
sashimi = BundleItem(Meal.sashimi)
|
||||
blueberry_tart = BundleItem(Meal.blueberry_tart)
|
||||
algae_soup = BundleItem(Meal.algae_soup)
|
||||
pale_broth = BundleItem(Meal.pale_broth)
|
||||
chowder = BundleItem(Meal.chowder)
|
||||
cookie = BundleItem(Meal.cookie)
|
||||
ancient_doll = BundleItem(Artifact.ancient_doll)
|
||||
ice_cream = BundleItem(Meal.ice_cream)
|
||||
cranberry_candy = BundleItem(Meal.cranberry_candy)
|
||||
ginger_ale = BundleItem(Beverage.ginger_ale, source=BundleItem.Sources.island)
|
||||
pink_cake = BundleItem(Meal.pink_cake)
|
||||
plum_pudding = BundleItem(Meal.plum_pudding)
|
||||
chocolate_cake = BundleItem(Meal.chocolate_cake)
|
||||
rhubarb_pie = BundleItem(Meal.rhubarb_pie)
|
||||
shrimp_cocktail = BundleItem(Meal.shrimp_cocktail)
|
||||
pina_colada = BundleItem(Beverage.pina_colada, source=BundleItem.Sources.island)
|
||||
stuffing = BundleItem(Meal.stuffing)
|
||||
magic_rock_candy = BundleItem(Meal.magic_rock_candy)
|
||||
spicy_eel = BundleItem(Meal.spicy_eel)
|
||||
crab_cakes = BundleItem(Meal.crab_cakes)
|
||||
eggplant_parmesan = BundleItem(Meal.eggplant_parmesan)
|
||||
pumpkin_soup = BundleItem(Meal.pumpkin_soup)
|
||||
lucky_lunch = BundleItem(Meal.lucky_lunch)
|
||||
|
||||
green_algae = BundleItem(WaterItem.green_algae)
|
||||
white_algae = BundleItem(WaterItem.white_algae)
|
||||
geode = BundleItem(Geode.geode)
|
||||
frozen_geode = BundleItem(Geode.frozen)
|
||||
magma_geode = BundleItem(Geode.magma)
|
||||
omni_geode = BundleItem(Geode.omni)
|
||||
sap = BundleItem(Material.sap)
|
||||
|
||||
dwarf_scroll_1 = BundleItem(Artifact.dwarf_scroll_i)
|
||||
dwarf_scroll_2 = BundleItem(Artifact.dwarf_scroll_ii)
|
||||
dwarf_scroll_3 = BundleItem(Artifact.dwarf_scroll_iii)
|
||||
dwarf_scroll_4 = BundleItem(Artifact.dwarf_scroll_iv)
|
||||
elvish_jewelry = BundleItem(Artifact.elvish_jewelry)
|
||||
ancient_drum = BundleItem(Artifact.ancient_drum)
|
||||
dried_starfish = BundleItem(Fossil.dried_starfish)
|
||||
bone_fragment = BundleItem(Fossil.bone_fragment)
|
||||
|
||||
golden_mask = BundleItem(Artifact.golden_mask)
|
||||
golden_relic = BundleItem(Artifact.golden_relic)
|
||||
dwarf_gadget = BundleItem(Artifact.dwarf_gadget)
|
||||
dwarvish_helm = BundleItem(Artifact.dwarvish_helm)
|
||||
prehistoric_handaxe = BundleItem(Artifact.prehistoric_handaxe)
|
||||
bone_flute = BundleItem(Artifact.bone_flute)
|
||||
anchor = BundleItem(Artifact.anchor)
|
||||
prehistoric_tool = BundleItem(Artifact.prehistoric_tool)
|
||||
chicken_statue = BundleItem(Artifact.chicken_statue)
|
||||
rusty_cog = BundleItem(Artifact.rusty_cog)
|
||||
rusty_spur = BundleItem(Artifact.rusty_spur)
|
||||
rusty_spoon = BundleItem(Artifact.rusty_spoon)
|
||||
ancient_sword = BundleItem(Artifact.ancient_sword)
|
||||
ornamental_fan = BundleItem(Artifact.ornamental_fan)
|
||||
chipped_amphora = BundleItem(Artifact.chipped_amphora)
|
||||
|
||||
prehistoric_scapula = BundleItem(Fossil.prehistoric_scapula)
|
||||
prehistoric_tibia = BundleItem(Fossil.prehistoric_tibia)
|
||||
prehistoric_skull = BundleItem(Fossil.prehistoric_skull)
|
||||
skeletal_hand = BundleItem(Fossil.skeletal_hand)
|
||||
prehistoric_rib = BundleItem(Fossil.prehistoric_rib)
|
||||
prehistoric_vertebra = BundleItem(Fossil.prehistoric_vertebra)
|
||||
skeletal_tail = BundleItem(Fossil.skeletal_tail)
|
||||
nautilus_fossil = BundleItem(Fossil.nautilus_fossil)
|
||||
amphibian_fossil = BundleItem(Fossil.amphibian_fossil)
|
||||
palm_fossil = BundleItem(Fossil.palm_fossil)
|
||||
trilobite = BundleItem(Fossil.trilobite)
|
||||
|
||||
dinosaur_mayo = BundleItem(ArtisanGood.dinosaur_mayonnaise)
|
||||
void_mayo = BundleItem(ArtisanGood.void_mayonnaise)
|
||||
prismatic_shard = BundleItem(Mineral.prismatic_shard)
|
||||
diamond = BundleItem(Mineral.diamond)
|
||||
ancient_fruit = BundleItem(Fruit.ancient_fruit)
|
||||
void_salmon = BundleItem(Fish.void_salmon)
|
||||
tea_leaves = BundleItem(Vegetable.tea_leaves)
|
||||
blobfish = BundleItem(Fish.blobfish)
|
||||
spook_fish = BundleItem(Fish.spook_fish)
|
||||
lionfish = BundleItem(Fish.lionfish, source=BundleItem.Sources.island)
|
||||
blue_discus = BundleItem(Fish.blue_discus, source=BundleItem.Sources.island)
|
||||
stingray = BundleItem(Fish.stingray, source=BundleItem.Sources.island)
|
||||
spookfish = BundleItem(Fish.spookfish)
|
||||
midnight_squid = BundleItem(Fish.midnight_squid)
|
||||
|
||||
angler = BundleItem(Fish.angler)
|
||||
crimsonfish = BundleItem(Fish.crimsonfish)
|
||||
mutant_carp = BundleItem(Fish.mutant_carp)
|
||||
glacierfish = BundleItem(Fish.glacierfish)
|
||||
legend = BundleItem(Fish.legend)
|
||||
|
||||
spinner = BundleItem(Fishing.spinner)
|
||||
dressed_spinner = BundleItem(Fishing.dressed_spinner)
|
||||
trap_bobber = BundleItem(Fishing.trap_bobber)
|
||||
sonar_bobber = BundleItem(Fishing.sonar_bobber)
|
||||
cork_bobber = BundleItem(Fishing.cork_bobber)
|
||||
lead_bobber = BundleItem(Fishing.lead_bobber)
|
||||
treasure_hunter = BundleItem(Fishing.treasure_hunter)
|
||||
barbed_hook = BundleItem(Fishing.barbed_hook)
|
||||
curiosity_lure = BundleItem(Fishing.curiosity_lure)
|
||||
quality_bobber = BundleItem(Fishing.quality_bobber)
|
||||
bait = BundleItem(Fishing.bait, 100)
|
||||
deluxe_bait = BundleItem(Fishing.deluxe_bait, 50)
|
||||
magnet = BundleItem(Fishing.magnet)
|
||||
wild_bait = BundleItem(Fishing.wild_bait, 20)
|
||||
magic_bait = BundleItem(Fishing.magic_bait, 10, source=BundleItem.Sources.island)
|
||||
pearl = BundleItem(Gift.pearl)
|
||||
challenge_bait = BundleItem(Fishing.challenge_bait, 25, source=BundleItem.Sources.masteries)
|
||||
targeted_bait = BundleItem(ArtisanGood.targeted_bait, 25, source=BundleItem.Sources.content)
|
||||
|
||||
ginger = BundleItem(Forageable.ginger, source=BundleItem.Sources.content)
|
||||
magma_cap = BundleItem(Mushroom.magma_cap, source=BundleItem.Sources.content)
|
||||
|
||||
wheat_flour = BundleItem(Ingredient.wheat_flour)
|
||||
sugar = BundleItem(Ingredient.sugar)
|
||||
vinegar = BundleItem(Ingredient.vinegar)
|
||||
|
||||
jack_o_lantern = BundleItem(Lighting.jack_o_lantern)
|
||||
prize_ticket = BundleItem(Currency.prize_ticket)
|
||||
mystery_box = BundleItem(Consumable.mystery_box)
|
||||
gold_mystery_box = BundleItem(Consumable.gold_mystery_box, source=BundleItem.Sources.masteries)
|
||||
calico_egg = BundleItem(Currency.calico_egg)
|
||||
|
||||
raccoon_crab_pot_fish_items = [periwinkle.as_amount(5), snail.as_amount(5), crayfish.as_amount(5), mussel.as_amount(5),
|
||||
oyster.as_amount(5), cockle.as_amount(5), clam.as_amount(5)]
|
||||
raccoon_smoked_fish_items = [BundleItem(ArtisanGood.smoked_fish, flavor=fish) for fish in
|
||||
[Fish.largemouth_bass, Fish.bream, Fish.bullhead, Fish.chub, Fish.ghostfish, Fish.flounder, Fish.shad,
|
||||
Fish.rainbow_trout, Fish.tilapia, Fish.red_mullet, Fish.tuna, Fish.midnight_carp, Fish.salmon, Fish.perch]]
|
||||
raccoon_fish_items_flat = [*raccoon_crab_pot_fish_items, *raccoon_smoked_fish_items]
|
||||
raccoon_fish_items_deep = [raccoon_crab_pot_fish_items, raccoon_smoked_fish_items]
|
||||
raccoon_fish_bundle_vanilla = DeepBundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_fish, raccoon_fish_items_deep, 2, 2)
|
||||
raccoon_fish_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_fish, raccoon_fish_items_flat, 3, 2)
|
||||
|
||||
all_specific_jellies = [BundleItem(ArtisanGood.jelly, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits]
|
||||
all_specific_pickles = [BundleItem(ArtisanGood.pickles, flavor=vegetable, source=BundleItem.Sources.content) for vegetable in all_vegetables]
|
||||
all_specific_dried_fruits = [*[BundleItem(ArtisanGood.dried_fruit, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits],
|
||||
BundleItem(ArtisanGood.raisins, source=BundleItem.Sources.content)]
|
||||
all_specific_juices = [BundleItem(ArtisanGood.juice, flavor=vegetable, source=BundleItem.Sources.content) for vegetable in all_vegetables]
|
||||
raccoon_artisan_items = [*all_specific_jellies, *all_specific_pickles, *all_specific_dried_fruits, *all_specific_juices]
|
||||
raccoon_artisan_bundle_vanilla = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_artisan, raccoon_artisan_items, 2, 2)
|
||||
raccoon_artisan_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_artisan, raccoon_artisan_items, 3, 2)
|
||||
|
||||
all_specific_dried_mushrooms = [BundleItem(ArtisanGood.dried_mushroom, flavor=mushroom, source=BundleItem.Sources.content) for mushroom in all_edible_mushrooms]
|
||||
raccoon_food_items = [egg.as_amount(5), cave_carrot.as_amount(5), white_algae.as_amount(5)]
|
||||
raccoon_food_items_vanilla = [all_specific_dried_mushrooms, raccoon_food_items]
|
||||
raccoon_food_items_thematic = [*all_specific_dried_mushrooms, *raccoon_food_items, brown_egg.as_amount(5), large_egg.as_amount(2), large_brown_egg.as_amount(2),
|
||||
green_algae.as_amount(10)]
|
||||
raccoon_food_bundle_vanilla = DeepBundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_food, raccoon_food_items_vanilla, 2, 2)
|
||||
raccoon_food_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_food, raccoon_food_items_thematic, 3, 2)
|
||||
|
||||
raccoon_foraging_items = [moss, rusty_spoon, trash.as_amount(5), slime.as_amount(99), bat_wing.as_amount(10), geode.as_amount(8),
|
||||
frozen_geode.as_amount(5), magma_geode.as_amount(3), coral.as_amount(4), sea_urchin.as_amount(2), bug_meat.as_amount(10),
|
||||
diamond, topaz.as_amount(3), ghostfish.as_amount(3)]
|
||||
raccoon_foraging_bundle_vanilla = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_foraging, raccoon_foraging_items, 2, 2)
|
||||
raccoon_foraging_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_foraging, raccoon_foraging_items, 3, 2)
|
||||
|
||||
raccoon_bundles_vanilla = [raccoon_fish_bundle_vanilla, raccoon_artisan_bundle_vanilla, raccoon_food_bundle_vanilla, raccoon_foraging_bundle_vanilla]
|
||||
raccoon_bundles_thematic = [raccoon_fish_bundle_thematic, raccoon_artisan_bundle_thematic, raccoon_food_bundle_thematic, raccoon_foraging_bundle_thematic]
|
||||
raccoon_bundles_remixed = raccoon_bundles_thematic
|
||||
raccoon_vanilla = BundleRoomTemplate(CCRoom.raccoon_requests, raccoon_bundles_vanilla, 8)
|
||||
raccoon_thematic = BundleRoomTemplate(CCRoom.raccoon_requests, raccoon_bundles_thematic, 8)
|
||||
raccoon_remixed = BundleRoomTemplate(CCRoom.raccoon_requests, raccoon_bundles_remixed, 8)
|
||||
|
||||
# Crafts Room
|
||||
spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion]
|
||||
spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel]
|
||||
spring_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.spring_foraging, spring_foraging_items_vanilla, 4, 4)
|
||||
spring_foraging_bundle_thematic = BundleTemplate.extend_from(spring_foraging_bundle_vanilla, spring_foraging_items_thematic)
|
||||
|
||||
summer_foraging_items_vanilla = [grape, spice_berry, sweet_pea]
|
||||
summer_foraging_items_thematic = [*summer_foraging_items_vanilla, fiddlehead_fern, red_mushroom, rainbow_shell]
|
||||
summer_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.summer_foraging, summer_foraging_items_vanilla, 3, 3)
|
||||
summer_foraging_bundle_thematic = BundleTemplate.extend_from(summer_foraging_bundle_vanilla, summer_foraging_items_thematic)
|
||||
|
||||
fall_foraging_items_vanilla = [common_mushroom, wild_plum, hazelnut, blackberry]
|
||||
fall_foraging_items_thematic = [*fall_foraging_items_vanilla, chanterelle]
|
||||
fall_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.fall_foraging, fall_foraging_items_vanilla, 4, 4)
|
||||
fall_foraging_bundle_thematic = BundleTemplate.extend_from(fall_foraging_bundle_vanilla, fall_foraging_items_thematic)
|
||||
|
||||
winter_foraging_items_vanilla = [winter_root, crystal_fruit, snow_yam, crocus]
|
||||
winter_foraging_items_thematic = [*winter_foraging_items_vanilla, holly, nautilus_shell]
|
||||
winter_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.winter_foraging, winter_foraging_items_vanilla, 4, 4)
|
||||
winter_foraging_bundle_thematic = BundleTemplate.extend_from(winter_foraging_bundle_vanilla, winter_foraging_items_thematic)
|
||||
|
||||
construction_items_vanilla = [wood, stone, hardwood]
|
||||
construction_items_thematic = [*construction_items_vanilla, clay, fiber, sap.as_amount(50)]
|
||||
construction_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.construction, construction_items_vanilla, 4, 4)
|
||||
construction_bundle_thematic = BundleTemplate.extend_from(construction_bundle_vanilla, construction_items_thematic)
|
||||
|
||||
exotic_foraging_items_vanilla = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, maple_syrup, oak_resin, pine_tar, morel]
|
||||
exotic_foraging_items_thematic = [*exotic_foraging_items_vanilla, coral, sea_urchin, clam, cockle, mussel, oyster, seaweed]
|
||||
exotic_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.exotic_foraging, exotic_foraging_items_vanilla, 9, 5)
|
||||
exotic_foraging_bundle_thematic = BundleTemplate.extend_from(exotic_foraging_bundle_vanilla, exotic_foraging_items_thematic)
|
||||
|
||||
beach_foraging_items = [nautilus_shell, coral, sea_urchin, rainbow_shell, clam, cockle, mussel, oyster, seaweed]
|
||||
beach_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.beach_foraging, beach_foraging_items, 4, 4)
|
||||
|
||||
mines_foraging_items = [quartz, earth_crystal, frozen_tear, fire_quartz, red_mushroom, purple_mushroom, cave_carrot]
|
||||
mines_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.mines_foraging, mines_foraging_items, 4, 4)
|
||||
|
||||
desert_foraging_items = [cactus_fruit.as_quality(ForageQuality.gold), cactus_fruit.as_amount(5), coconut.as_quality(ForageQuality.gold), coconut.as_amount(5)]
|
||||
desert_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.desert_foraging, desert_foraging_items, 2, 2)
|
||||
|
||||
island_foraging_items = [ginger.as_amount(5), magma_cap.as_quality(ForageQuality.gold), magma_cap.as_amount(5),
|
||||
fiddlehead_fern.as_quality(ForageQuality.gold), fiddlehead_fern.as_amount(5)]
|
||||
island_foraging_bundle = IslandBundleTemplate(CCRoom.crafts_room, BundleName.island_foraging, island_foraging_items, 2, 2)
|
||||
|
||||
sticky_items = [sap.as_amount(500), sap.as_amount(500)]
|
||||
sticky_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.sticky, sticky_items, 1, 1)
|
||||
|
||||
forest_items = [moss, fiber.as_amount(200), acorn.as_amount(10), maple_seed.as_amount(10), pine_cone.as_amount(10), mahogany_seed,
|
||||
mushroom_tree_seed, mossy_seed.as_amount(5), mystic_tree_seed]
|
||||
forest_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.forest, forest_items, 4, 2)
|
||||
|
||||
wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]]
|
||||
wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3)
|
||||
|
||||
quality_foraging_items = sorted({item.as_quality(ForageQuality.gold).as_amount(3)
|
||||
for item in
|
||||
[*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic,
|
||||
*winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap] if item.can_have_quality})
|
||||
quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3)
|
||||
|
||||
green_rain_items = [moss.as_amount(200), fiber.as_amount(200), mossy_seed.as_amount(20), fiddlehead_fern.as_amount(10)]
|
||||
green_rain_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.green_rain, green_rain_items, 4, 3)
|
||||
|
||||
crafts_room_bundles_vanilla = [spring_foraging_bundle_vanilla, summer_foraging_bundle_vanilla, fall_foraging_bundle_vanilla,
|
||||
winter_foraging_bundle_vanilla, construction_bundle_vanilla, exotic_foraging_bundle_vanilla]
|
||||
crafts_room_bundles_thematic = [spring_foraging_bundle_thematic, summer_foraging_bundle_thematic, fall_foraging_bundle_thematic,
|
||||
winter_foraging_bundle_thematic, construction_bundle_thematic, exotic_foraging_bundle_thematic]
|
||||
crafts_room_bundles_remixed = [*crafts_room_bundles_thematic, beach_foraging_bundle, mines_foraging_bundle, desert_foraging_bundle,
|
||||
island_foraging_bundle, sticky_bundle, forest_bundle, wild_medicine_bundle, quality_foraging_bundle, green_rain_bundle]
|
||||
crafts_room_vanilla = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_vanilla, 6)
|
||||
crafts_room_thematic = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_thematic, 6)
|
||||
crafts_room_remixed = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_remixed, 6)
|
||||
|
||||
# Pantry
|
||||
spring_crops_items_vanilla = [parsnip, green_bean, cauliflower, potato]
|
||||
spring_crops_items_thematic = [*spring_crops_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice, carrot]
|
||||
spring_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.spring_crops, spring_crops_items_vanilla, 4, 4)
|
||||
spring_crops_bundle_thematic = BundleTemplate.extend_from(spring_crops_bundle_vanilla, spring_crops_items_thematic)
|
||||
|
||||
summer_crops_items_vanilla = [tomato, hot_pepper, blueberry, melon]
|
||||
summer_crops_items_thematic = [*summer_crops_items_vanilla, corn, hops, poppy, radish, red_cabbage, starfruit, summer_spangle, sunflower, wheat, summer_squash]
|
||||
summer_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.summer_crops, summer_crops_items_vanilla, 4, 4)
|
||||
summer_crops_bundle_thematic = BundleTemplate.extend_from(summer_crops_bundle_vanilla, summer_crops_items_thematic)
|
||||
|
||||
fall_crops_items_vanilla = [corn, eggplant, pumpkin, yam]
|
||||
fall_crops_items_thematic = [*fall_crops_items_vanilla, amaranth, artichoke, beet, bok_choy, cranberries, fairy_rose, grape,
|
||||
sunflower, wheat, sweet_gem_berry, broccoli]
|
||||
fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4)
|
||||
fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic)
|
||||
|
||||
all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic, powdermelon})
|
||||
|
||||
quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]]
|
||||
quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items]
|
||||
quality_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.quality_crops, quality_crops_items_vanilla, 4, 3)
|
||||
quality_crops_bundle_thematic = BundleTemplate.extend_from(quality_crops_bundle_vanilla, quality_crops_items_thematic)
|
||||
|
||||
animal_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg]
|
||||
animal_items_thematic = [*animal_items_vanilla, egg, brown_egg, milk, goat_milk, truffle,
|
||||
duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg, ostrich_egg]
|
||||
animal_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.animal, animal_items_vanilla, 6, 5)
|
||||
animal_bundle_thematic = BundleTemplate.extend_from(animal_bundle_vanilla, animal_items_thematic)
|
||||
|
||||
artisan_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry]
|
||||
artisan_items_thematic = [*artisan_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango]
|
||||
artisan_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.artisan, artisan_items_vanilla, 12, 6)
|
||||
artisan_bundle_thematic = BundleTemplate.extend_from(artisan_bundle_vanilla, artisan_items_thematic)
|
||||
|
||||
rare_crops_items = [ancient_fruit, sweet_gem_berry]
|
||||
rare_crops_bundle = BundleTemplate(CCRoom.pantry, BundleName.rare_crops, rare_crops_items, 2, 2)
|
||||
|
||||
# all_specific_roes = [BundleItem(AnimalProduct.roe, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fish]
|
||||
fish_farmer_items = [roe.as_amount(15), aged_roe.as_amount(5), squid_ink, caviar.as_amount(5)]
|
||||
fish_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.fish_farmer, fish_farmer_items, 3, 2)
|
||||
|
||||
garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose, poppy, bouquet]
|
||||
garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4)
|
||||
|
||||
brewer_items = [mead, pale_ale, wine, juice, green_tea, beer]
|
||||
brewer_bundle = BundleTemplate(CCRoom.pantry, BundleName.brewer, brewer_items, 5, 4)
|
||||
|
||||
orchard_items = [apple, apricot, orange, peach, pomegranate, cherry, banana, mango]
|
||||
orchard_bundle = BundleTemplate(CCRoom.pantry, BundleName.orchard, orchard_items, 6, 4)
|
||||
|
||||
island_crops_items = [pineapple, taro_root, banana, mango]
|
||||
island_crops_bundle = IslandBundleTemplate(CCRoom.pantry, BundleName.island_crops, island_crops_items, 3, 3)
|
||||
|
||||
agronomist_items = [basic_fertilizer, quality_fertilizer, deluxe_fertilizer,
|
||||
basic_retaining_soil, quality_retaining_soil, deluxe_retaining_soil,
|
||||
speed_gro, deluxe_speed_gro, hyper_speed_gro, tree_fertilizer]
|
||||
agronomist_bundle = BundleTemplate(CCRoom.pantry, BundleName.agronomist, agronomist_items, 4, 3)
|
||||
|
||||
slime_farmer_items = [slime.as_amount(99), petrified_slime.as_amount(10), blue_slime_egg, red_slime_egg,
|
||||
purple_slime_egg, green_slime_egg, tiger_slime_egg]
|
||||
slime_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.slime_farmer, slime_farmer_items, 4, 3)
|
||||
|
||||
sommelier_items = [BundleItem(ArtisanGood.wine, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits]
|
||||
sommelier_bundle = BundleTemplate(CCRoom.pantry, BundleName.sommelier, sommelier_items, 6, 3)
|
||||
|
||||
dry_items = [*[BundleItem(ArtisanGood.dried_fruit, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits],
|
||||
*[BundleItem(ArtisanGood.dried_mushroom, flavor=mushroom, source=BundleItem.Sources.content) for mushroom in all_edible_mushrooms],
|
||||
BundleItem(ArtisanGood.raisins, source=BundleItem.Sources.content)]
|
||||
dry_bundle = BundleTemplate(CCRoom.pantry, BundleName.dry, dry_items, 6, 3)
|
||||
|
||||
pantry_bundles_vanilla = [spring_crops_bundle_vanilla, summer_crops_bundle_vanilla, fall_crops_bundle_vanilla,
|
||||
quality_crops_bundle_vanilla, animal_bundle_vanilla, artisan_bundle_vanilla]
|
||||
pantry_bundles_thematic = [spring_crops_bundle_thematic, summer_crops_bundle_thematic, fall_crops_bundle_thematic,
|
||||
quality_crops_bundle_thematic, animal_bundle_thematic, artisan_bundle_thematic]
|
||||
pantry_bundles_remixed = [*pantry_bundles_thematic, rare_crops_bundle, fish_farmer_bundle, garden_bundle,
|
||||
brewer_bundle, orchard_bundle, island_crops_bundle, agronomist_bundle, slime_farmer_bundle, sommelier_bundle, dry_bundle]
|
||||
pantry_vanilla = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_vanilla, 6)
|
||||
pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6)
|
||||
pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6)
|
||||
|
||||
# Fish Tank
|
||||
river_fish_items_vanilla = [sunfish, catfish, shad, tiger_trout]
|
||||
river_fish_items_thematic = [*river_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, smallmouth_bass, dorado]
|
||||
river_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.river_fish, river_fish_items_vanilla, 4, 4)
|
||||
river_fish_bundle_thematic = BundleTemplate.extend_from(river_fish_bundle_vanilla, river_fish_items_thematic)
|
||||
|
||||
lake_fish_items_vanilla = [largemouth_bass, carp, bullhead, sturgeon]
|
||||
lake_fish_items_thematic = [*lake_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, midnight_carp]
|
||||
lake_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.lake_fish, lake_fish_items_vanilla, 4, 4)
|
||||
lake_fish_bundle_thematic = BundleTemplate.extend_from(lake_fish_bundle_vanilla, lake_fish_items_thematic)
|
||||
|
||||
ocean_fish_items_vanilla = [sardine, tuna, red_snapper, tilapia]
|
||||
ocean_fish_items_thematic = [*ocean_fish_items_vanilla, pufferfish, super_cucumber, flounder, anchovy, red_mullet,
|
||||
herring, eel, octopus, squid, sea_cucumber, albacore, halibut]
|
||||
ocean_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.ocean_fish, ocean_fish_items_vanilla, 4, 4)
|
||||
ocean_fish_bundle_thematic = BundleTemplate.extend_from(ocean_fish_bundle_vanilla, ocean_fish_items_thematic)
|
||||
|
||||
night_fish_items_vanilla = [walleye, bream, eel]
|
||||
night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp, midnight_squid]
|
||||
night_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.night_fish, night_fish_items_vanilla, 3, 3)
|
||||
night_fish_bundle_thematic = BundleTemplate.extend_from(night_fish_bundle_vanilla, night_fish_items_thematic)
|
||||
|
||||
crab_pot_items_vanilla = [lobster, crayfish, crab, cockle, mussel, shrimp, snail, periwinkle, oyster, clam]
|
||||
crab_pot_trash_items = [trash, driftwood, soggy_newspaper, broken_cd, broken_glasses]
|
||||
crab_pot_items_thematic = [*crab_pot_items_vanilla, *crab_pot_trash_items]
|
||||
crab_pot_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.crab_pot, crab_pot_items_vanilla, 10, 5)
|
||||
crab_pot_bundle_thematic = BundleTemplate.extend_from(crab_pot_bundle_vanilla, crab_pot_items_thematic)
|
||||
trash_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.trash, crab_pot_trash_items, 4, 4)
|
||||
|
||||
specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip]
|
||||
specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip,
|
||||
stonefish, void_salmon, stingray, spookfish, midnight_squid]
|
||||
specialty_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.specialty_fish, specialty_fish_items_vanilla, 4, 4)
|
||||
specialty_fish_bundle_thematic = BundleTemplate.extend_from(specialty_fish_bundle_vanilla, specialty_fish_items_thematic)
|
||||
|
||||
spring_fish_items = [herring, halibut, shad, flounder, sunfish, sardine, catfish, anchovy, smallmouth_bass, eel, legend]
|
||||
spring_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.spring_fish, spring_fish_items, 4, 4)
|
||||
|
||||
summer_fish_items = [tuna, pike, red_mullet, sturgeon, red_snapper, super_cucumber, tilapia, pufferfish, rainbow_trout,
|
||||
octopus, dorado, halibut, shad, flounder, sunfish, crimsonfish]
|
||||
summer_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.summer_fish, summer_fish_items, 4, 4)
|
||||
|
||||
fall_fish_items = [red_snapper, super_cucumber, tilapia, shad, sardine, catfish, anchovy, smallmouth_bass, eel, midnight_carp,
|
||||
walleye, sea_cucumber, tiger_trout, albacore, salmon, angler]
|
||||
fall_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.fall_fish, fall_fish_items, 4, 4)
|
||||
|
||||
winter_fish_items = [perch, squid, lingcod, tuna, pike, red_mullet, sturgeon, red_snapper, herring, halibut, sardine,
|
||||
midnight_carp, sea_cucumber, tiger_trout, albacore, glacierfish]
|
||||
winter_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.winter_fish, winter_fish_items, 4, 4)
|
||||
|
||||
rain_fish_items = [red_snapper, shad, catfish, eel, walleye]
|
||||
rain_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.rain_fish, rain_fish_items, 3, 3)
|
||||
|
||||
quality_fish_items = sorted({
|
||||
item.as_quality(FishQuality.gold).as_amount(2)
|
||||
for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]
|
||||
})
|
||||
quality_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.quality_fish, quality_fish_items, 4, 3)
|
||||
|
||||
master_fisher_items = [lava_eel, scorpion_carp, octopus, blobfish, lingcod, ice_pip, super_cucumber, stingray, void_salmon, pufferfish]
|
||||
master_fisher_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.master_fisher, master_fisher_items, 4, 2)
|
||||
|
||||
legendary_fish_items = [angler, legend, mutant_carp, crimsonfish, glacierfish]
|
||||
legendary_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.legendary_fish, legendary_fish_items, 4, 2)
|
||||
|
||||
island_fish_items = [lionfish, blue_discus, stingray]
|
||||
island_fish_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.island_fish, island_fish_items, 3, 3)
|
||||
|
||||
tackle_items = [spinner, dressed_spinner, trap_bobber, sonar_bobber, cork_bobber, lead_bobber, treasure_hunter, barbed_hook, curiosity_lure, quality_bobber]
|
||||
tackle_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.tackle, tackle_items, 3, 2)
|
||||
|
||||
bait_items = [bait, magnet, wild_bait, magic_bait, challenge_bait, deluxe_bait, targeted_bait]
|
||||
bait_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.bait, bait_items, 3, 2)
|
||||
|
||||
# This bundle could change based on content packs, once the fish are properly in it. Until then, I'm not sure how, so pelican town only
|
||||
specific_bait_items = [BundleItem(ArtisanGood.targeted_bait, flavor=fish.name).as_amount(10) for fish in content_packs.pelican_town.fishes]
|
||||
specific_bait_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.specific_bait, specific_bait_items, 6, 3)
|
||||
|
||||
deep_fishing_items = [blobfish, spook_fish, midnight_squid, sea_cucumber, super_cucumber, octopus, pearl, seaweed]
|
||||
deep_fishing_bundle = FestivalBundleTemplate(CCRoom.fish_tank, BundleName.deep_fishing, deep_fishing_items, 4, 3)
|
||||
|
||||
smokeable_fish = [Fish.largemouth_bass, Fish.bream, Fish.bullhead, Fish.chub, Fish.ghostfish, Fish.flounder, Fish.shad, Fish.rainbow_trout, Fish.tilapia,
|
||||
Fish.red_mullet, Fish.tuna, Fish.midnight_carp, Fish.salmon, Fish.perch]
|
||||
fish_smoker_items = [BundleItem(ArtisanGood.smoked_fish, flavor=fish) for fish in smokeable_fish]
|
||||
fish_smoker_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.fish_smoker, fish_smoker_items, 6, 3)
|
||||
|
||||
fish_tank_bundles_vanilla = [river_fish_bundle_vanilla, lake_fish_bundle_vanilla, ocean_fish_bundle_vanilla,
|
||||
night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla]
|
||||
fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic,
|
||||
night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic]
|
||||
fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle, fall_fish_bundle, winter_fish_bundle, trash_bundle,
|
||||
rain_fish_bundle, quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle, tackle_bundle, bait_bundle,
|
||||
specific_bait_bundle, deep_fishing_bundle, fish_smoker_bundle]
|
||||
|
||||
# In Remixed, the trash items are in the recycling bundle, so we don't use the thematic version of the crab pot bundle that added trash items to it
|
||||
fish_tank_bundles_remixed.remove(crab_pot_bundle_thematic)
|
||||
fish_tank_bundles_remixed.append(crab_pot_bundle_vanilla)
|
||||
fish_tank_vanilla = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_vanilla, 6)
|
||||
fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6)
|
||||
fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6)
|
||||
|
||||
# Boiler Room
|
||||
blacksmith_items_vanilla = [copper_bar, iron_Bar, gold_bar]
|
||||
blacksmith_items_thematic = [*blacksmith_items_vanilla, iridium_bar, refined_quartz.as_amount(3), wilted_bouquet]
|
||||
blacksmith_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.blacksmith, blacksmith_items_vanilla, 3, 3)
|
||||
blacksmith_bundle_thematic = BundleTemplate.extend_from(blacksmith_bundle_vanilla, blacksmith_items_thematic)
|
||||
|
||||
geologist_items_vanilla = [quartz, earth_crystal, frozen_tear, fire_quartz]
|
||||
geologist_items_thematic = [*geologist_items_vanilla, emerald, aquamarine, ruby, amethyst, topaz, jade, diamond]
|
||||
geologist_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.geologist, geologist_items_vanilla, 4, 4)
|
||||
geologist_bundle_thematic = BundleTemplate.extend_from(geologist_bundle_vanilla, geologist_items_thematic)
|
||||
|
||||
adventurer_items_vanilla = [slime, bat_wing, solar_essence, void_essence]
|
||||
adventurer_items_thematic = [*adventurer_items_vanilla, bug_meat, coal, bone_fragment.as_amount(10)]
|
||||
adventurer_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.adventurer, adventurer_items_vanilla, 4, 2)
|
||||
adventurer_bundle_thematic = BundleTemplate.extend_from(adventurer_bundle_vanilla, adventurer_items_thematic)
|
||||
|
||||
# Where to put radioactive bar?
|
||||
treasure_hunter_items = [emerald, aquamarine, ruby, amethyst, topaz, jade, diamond]
|
||||
treasure_hunter_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.treasure_hunter, treasure_hunter_items, 6, 5)
|
||||
|
||||
engineer_items = [iridium_ore.as_amount(5), battery_pack, refined_quartz.as_amount(5), diamond]
|
||||
engineer_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.engineer, engineer_items, 3, 3)
|
||||
|
||||
demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo]
|
||||
demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3)
|
||||
|
||||
recycling_items = [stone, coal, iron_ore, wood, cloth, refined_quartz]
|
||||
recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4)
|
||||
|
||||
archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool,
|
||||
chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora]
|
||||
archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 6, 3)
|
||||
|
||||
paleontologist_items = [prehistoric_scapula, prehistoric_tibia, prehistoric_skull, skeletal_hand, prehistoric_rib, prehistoric_vertebra, skeletal_tail,
|
||||
nautilus_fossil, amphibian_fossil, palm_fossil, trilobite]
|
||||
paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 6, 3)
|
||||
|
||||
boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla]
|
||||
boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic]
|
||||
boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle,
|
||||
demolition_bundle, recycling_bundle, archaeologist_bundle, paleontologist_bundle]
|
||||
boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3)
|
||||
boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3)
|
||||
boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3)
|
||||
|
||||
# Bulletin Board
|
||||
chef_items_vanilla = [maple_syrup, fiddlehead_fern, truffle, poppy, maki_roll, fried_egg]
|
||||
# More recipes?
|
||||
chef_items_thematic = [maki_roll, fried_egg, omelet, pizza, hashbrowns, pancakes, bread, tortilla,
|
||||
farmer_s_lunch, survival_burger, dish_o_the_sea, miner_s_treat, roots_platter, salad,
|
||||
cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti,
|
||||
sashimi, blueberry_tart, algae_soup, pale_broth, chowder]
|
||||
chef_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.chef, chef_items_vanilla, 6, 6)
|
||||
chef_bundle_thematic = BundleTemplate.extend_from(chef_bundle_vanilla, chef_items_thematic)
|
||||
|
||||
dye_items_vanilla = [red_mushroom, sea_urchin, sunflower, duck_feather, aquamarine, red_cabbage]
|
||||
dye_red_items = [cranberries, hot_pepper, radish, rhubarb, spaghetti, strawberry, tomato, tulip, red_mushroom]
|
||||
dye_orange_items = [poppy, pumpkin, apricot, orange, spice_berry, winter_root]
|
||||
dye_yellow_items = [corn, parsnip, summer_spangle, sunflower, starfruit]
|
||||
dye_green_items = [fiddlehead_fern, kale, artichoke, bok_choy, green_bean, cactus_fruit, duck_feather, dinosaur_egg]
|
||||
dye_blue_items = [blueberry, blue_jazz, blackberry, crystal_fruit, aquamarine]
|
||||
dye_purple_items = [beet, crocus, eggplant, red_cabbage, sweet_pea, iridium_bar, sea_urchin, amaranth]
|
||||
dye_items_thematic = [dye_red_items, dye_orange_items, dye_yellow_items, dye_green_items, dye_blue_items, dye_purple_items]
|
||||
dye_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_vanilla, 6, 6)
|
||||
dye_bundle_thematic = DeepBundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_thematic, 6, 6)
|
||||
|
||||
field_research_items_vanilla = [purple_mushroom, nautilus_shell, chub, frozen_geode]
|
||||
field_research_items_thematic = [*field_research_items_vanilla, geode, magma_geode, omni_geode,
|
||||
rainbow_shell, amethyst, bream, carp]
|
||||
field_research_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.field_research, field_research_items_vanilla, 4, 4)
|
||||
field_research_bundle_thematic = BundleTemplate.extend_from(field_research_bundle_vanilla, field_research_items_thematic)
|
||||
|
||||
fodder_items_vanilla = [wheat.as_amount(10), hay.as_amount(10), apple.as_amount(3)]
|
||||
fodder_items_thematic = [*fodder_items_vanilla, kale.as_amount(3), corn.as_amount(3), green_bean.as_amount(3),
|
||||
potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)]
|
||||
fodder_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.fodder, fodder_items_vanilla, 3, 3)
|
||||
fodder_bundle_thematic = BundleTemplate.extend_from(fodder_bundle_vanilla, fodder_items_thematic)
|
||||
|
||||
enchanter_items_vanilla = [oak_resin, wine, rabbit_foot, pomegranate]
|
||||
enchanter_items_thematic = [*enchanter_items_vanilla, purple_mushroom, solar_essence,
|
||||
super_cucumber, void_essence, fire_quartz, frozen_tear, jade]
|
||||
enchanter_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.enchanter, enchanter_items_vanilla, 4, 4)
|
||||
enchanter_bundle_thematic = BundleTemplate.extend_from(enchanter_bundle_vanilla, enchanter_items_thematic)
|
||||
|
||||
children_items = [salmonberry.as_amount(10), cookie, ancient_doll, ice_cream, cranberry_candy, ginger_ale,
|
||||
grape.as_amount(10), pink_cake, snail, fairy_rose, plum_pudding]
|
||||
children_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.children, children_items, 4, 3)
|
||||
|
||||
forager_items = [salmonberry.as_amount(50), blackberry.as_amount(50), wild_plum.as_amount(20), snow_yam.as_amount(20),
|
||||
common_mushroom.as_amount(20), grape.as_amount(20), spring_onion.as_amount(20)]
|
||||
forager_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.forager, forager_items, 3, 2)
|
||||
|
||||
home_cook_items = [egg.as_amount(10), milk.as_amount(10), wheat_flour.as_amount(100), sugar.as_amount(100), vinegar.as_amount(100),
|
||||
chocolate_cake, pancakes, rhubarb_pie]
|
||||
home_cook_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.home_cook, home_cook_items, 3, 3)
|
||||
|
||||
helper_items = [prize_ticket, mystery_box.as_amount(5), gold_mystery_box]
|
||||
helper_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.helper, helper_items, 2, 2)
|
||||
|
||||
spirit_eve_items = [jack_o_lantern, corn.as_amount(10), bat_wing.as_amount(10)]
|
||||
spirit_eve_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.spirit_eve, spirit_eve_items, 3, 3)
|
||||
|
||||
winter_star_items = [holly.as_amount(5), plum_pudding, stuffing, powdermelon.as_amount(5)]
|
||||
winter_star_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.winter_star, winter_star_items, 2, 2)
|
||||
|
||||
bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, cranberry_candy, beer, pale_ale, pina_colada]
|
||||
bartender_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.bartender, bartender_items, 3, 3)
|
||||
|
||||
calico_items = [calico_egg.as_amount(200), calico_egg.as_amount(200), calico_egg.as_amount(200), calico_egg.as_amount(200),
|
||||
magic_rock_candy, mega_bomb.as_amount(10), mystery_box.as_amount(10), mixed_seeds.as_amount(50),
|
||||
strawberry_seeds.as_amount(20),
|
||||
spicy_eel.as_amount(5), crab_cakes.as_amount(5), eggplant_parmesan.as_amount(5),
|
||||
pumpkin_soup.as_amount(5), lucky_lunch.as_amount(5) ]
|
||||
calico_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.calico, calico_items, 2, 2)
|
||||
|
||||
raccoon_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.raccoon, raccoon_foraging_items, 4, 4)
|
||||
|
||||
bulletin_board_bundles_vanilla = [chef_bundle_vanilla, dye_bundle_vanilla, field_research_bundle_vanilla, fodder_bundle_vanilla, enchanter_bundle_vanilla]
|
||||
bulletin_board_bundles_thematic = [chef_bundle_thematic, dye_bundle_thematic, field_research_bundle_thematic, fodder_bundle_thematic, enchanter_bundle_thematic]
|
||||
bulletin_board_bundles_remixed = [*bulletin_board_bundles_thematic, children_bundle, forager_bundle, home_cook_bundle,
|
||||
helper_bundle, spirit_eve_bundle, winter_star_bundle, bartender_bundle, calico_bundle, raccoon_bundle]
|
||||
bulletin_board_vanilla = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_vanilla, 5)
|
||||
bulletin_board_thematic = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_thematic, 5)
|
||||
bulletin_board_remixed = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_remixed, 5)
|
||||
|
||||
missing_bundle_items_vanilla = [wine.as_quality(ArtisanQuality.silver), dinosaur_mayo, prismatic_shard, caviar,
|
||||
ancient_fruit.as_quality_crop(), void_salmon.as_quality(FishQuality.gold)]
|
||||
missing_bundle_items_thematic = [*missing_bundle_items_vanilla, pale_ale.as_quality(ArtisanQuality.silver), beer.as_quality(ArtisanQuality.silver),
|
||||
mead.as_quality(ArtisanQuality.silver),
|
||||
cheese.as_quality(ArtisanQuality.silver), goat_cheese.as_quality(ArtisanQuality.silver), void_mayo, cloth, green_tea,
|
||||
truffle_oil, diamond,
|
||||
sweet_gem_berry.as_quality_crop(), starfruit.as_quality_crop(),
|
||||
tea_leaves.as_amount(5), lava_eel.as_quality(FishQuality.gold), scorpion_carp.as_quality(FishQuality.gold),
|
||||
blobfish.as_quality(FishQuality.gold)]
|
||||
missing_bundle_vanilla = BundleTemplate(CCRoom.abandoned_joja_mart, BundleName.missing_bundle, missing_bundle_items_vanilla, 6, 5)
|
||||
missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic)
|
||||
|
||||
abandoned_joja_mart_bundles_vanilla = [missing_bundle_vanilla]
|
||||
abandoned_joja_mart_bundles_thematic = [missing_bundle_thematic]
|
||||
abandoned_joja_mart_vanilla = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_vanilla, 1)
|
||||
abandoned_joja_mart_thematic = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_thematic, 1)
|
||||
abandoned_joja_mart_remixed = abandoned_joja_mart_thematic
|
||||
|
||||
vault_2500_gold = BundleItem.money_bundle(2500)
|
||||
vault_5000_gold = BundleItem.money_bundle(5000)
|
||||
vault_10000_gold = BundleItem.money_bundle(10000)
|
||||
vault_25000_gold = BundleItem.money_bundle(25000)
|
||||
|
||||
vault_2500_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_2500, vault_2500_gold)
|
||||
vault_5000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_5000, vault_5000_gold)
|
||||
vault_10000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_10000, vault_10000_gold)
|
||||
vault_25000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_25000, vault_25000_gold)
|
||||
|
||||
vault_gambler_items = BundleItem(Currency.qi_coin, 10000)
|
||||
vault_gambler_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.gambler, vault_gambler_items)
|
||||
|
||||
vault_carnival_items = BundleItem(Currency.star_token, 2500, source=BundleItem.Sources.festival)
|
||||
vault_carnival_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.carnival, vault_carnival_items)
|
||||
|
||||
vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25)
|
||||
vault_walnut_hunter_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.walnut_hunter, vault_walnut_hunter_items)
|
||||
|
||||
vault_qi_helper_items = BundleItem(Currency.qi_gem, 25, source=BundleItem.Sources.island)
|
||||
vault_qi_helper_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.qi_helper, vault_qi_helper_items)
|
||||
|
||||
vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle]
|
||||
vault_bundles_thematic = vault_bundles_vanilla
|
||||
vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle, vault_carnival_bundle] # , vault_walnut_hunter_bundle
|
||||
vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles_vanilla, 4)
|
||||
vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4)
|
||||
vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4)
|
||||
|
||||
all_cc_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed,
|
||||
*boiler_room_bundles_remixed, *bulletin_board_bundles_remixed]
|
||||
community_center_remixed_anywhere = BundleRoomTemplate("Community Center", all_cc_remixed_bundles, 26)
|
||||
|
||||
all_bundle_items_except_money = []
|
||||
all_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed,
|
||||
*boiler_room_bundles_remixed, *bulletin_board_bundles_remixed, missing_bundle_thematic,
|
||||
*raccoon_bundles_remixed]
|
||||
for bundle in all_remixed_bundles:
|
||||
all_bundle_items_except_money.extend(bundle.items)
|
||||
|
||||
all_bundle_items_by_name = {item.item_name: item for item in all_bundle_items_except_money}
|
||||
0
worlds/stardew_valley/data/bundles_data/__init__.py
Normal file
0
worlds/stardew_valley/data/bundles_data/__init__.py
Normal file
10
worlds/stardew_valley/data/bundles_data/bundle_data.py
Normal file
10
worlds/stardew_valley/data/bundles_data/bundle_data.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from .remixed_bundles import *
|
||||
|
||||
all_bundle_items_except_money = []
|
||||
all_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed,
|
||||
*boiler_room_bundles_remixed, *bulletin_board_bundles_remixed, missing_bundle_thematic,
|
||||
*giant_stump_bundles_remixed]
|
||||
for bundle in all_remixed_bundles:
|
||||
all_bundle_items_except_money.extend(bundle.items)
|
||||
|
||||
all_bundle_items_by_name = {item.item_name: item for item in all_bundle_items_except_money}
|
||||
599
worlds/stardew_valley/data/bundles_data/bundle_items_data.py
Normal file
599
worlds/stardew_valley/data/bundles_data/bundle_items_data.py
Normal file
@@ -0,0 +1,599 @@
|
||||
from ..hats_data import Hats
|
||||
from ..shirt_data import Shirts
|
||||
from ...bundles.bundle_item import BundleItem
|
||||
from ...strings.animal_product_names import AnimalProduct
|
||||
from ...strings.artisan_good_names import ArtisanGood
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.boot_names import Boots
|
||||
from ...strings.catalogue_names import CatalogueItem
|
||||
from ...strings.craftable_names import Consumable, Lighting, Fishing, Craftable, Bomb, Furniture, Floor, Edible, Statue
|
||||
from ...strings.crop_names import Vegetable, Fruit
|
||||
from ...strings.currency_names import Currency
|
||||
from ...strings.decoration_names import Decoration
|
||||
from ...strings.fertilizer_names import Fertilizer, SpeedGro, RetainingSoil
|
||||
from ...strings.fish_names import Fish, WaterItem, Trash
|
||||
from ...strings.flower_names import Flower
|
||||
from ...strings.food_names import Meal, Beverage
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.geode_names import Geode
|
||||
from ...strings.gift_names import Gift
|
||||
from ...strings.ingredient_names import Ingredient
|
||||
from ...strings.machine_names import Machine
|
||||
from ...strings.material_names import Material
|
||||
from ...strings.meme_item_names import MemeItem
|
||||
from ...strings.metal_names import Fossil, Ore, MetalBar, Mineral, Artifact
|
||||
from ...strings.monster_drop_names import Loot
|
||||
from ...strings.seed_names import TreeSeed, Seed
|
||||
from ...strings.special_item_names import SpecialItem, NotReallyAnItem
|
||||
|
||||
wild_horseradish = BundleItem(Forageable.wild_horseradish)
|
||||
daffodil = BundleItem(Forageable.daffodil)
|
||||
leek = BundleItem(Forageable.leek)
|
||||
dandelion = BundleItem(Forageable.dandelion)
|
||||
morel = BundleItem(Mushroom.morel)
|
||||
common_mushroom = BundleItem(Mushroom.common)
|
||||
salmonberry = BundleItem(Forageable.salmonberry, can_have_quality=False)
|
||||
spring_onion = BundleItem(Forageable.spring_onion)
|
||||
|
||||
grape = BundleItem(Fruit.grape)
|
||||
spice_berry = BundleItem(Forageable.spice_berry)
|
||||
sweet_pea = BundleItem(Forageable.sweet_pea)
|
||||
red_mushroom = BundleItem(Mushroom.red)
|
||||
fiddlehead_fern = BundleItem(Forageable.fiddlehead_fern)
|
||||
|
||||
wild_plum = BundleItem(Forageable.wild_plum)
|
||||
hazelnut = BundleItem(Forageable.hazelnut)
|
||||
blackberry = BundleItem(Forageable.blackberry)
|
||||
chanterelle = BundleItem(Mushroom.chanterelle)
|
||||
|
||||
winter_root = BundleItem(Forageable.winter_root)
|
||||
crystal_fruit = BundleItem(Forageable.crystal_fruit)
|
||||
snow_yam = BundleItem(Forageable.snow_yam)
|
||||
crocus = BundleItem(Forageable.crocus)
|
||||
holly = BundleItem(Forageable.holly)
|
||||
|
||||
coconut = BundleItem(Forageable.coconut)
|
||||
golden_coconut = BundleItem(Geode.golden_coconut, source=BundleItem.Sources.island)
|
||||
cactus_fruit = BundleItem(Forageable.cactus_fruit)
|
||||
cave_carrot = BundleItem(Forageable.cave_carrot)
|
||||
purple_mushroom = BundleItem(Mushroom.purple)
|
||||
maple_syrup = BundleItem(ArtisanGood.maple_syrup)
|
||||
oak_resin = BundleItem(ArtisanGood.oak_resin)
|
||||
pine_tar = BundleItem(ArtisanGood.pine_tar)
|
||||
nautilus_shell = BundleItem(WaterItem.nautilus_shell)
|
||||
coral = BundleItem(WaterItem.coral)
|
||||
sea_urchin = BundleItem(WaterItem.sea_urchin)
|
||||
rainbow_shell = BundleItem(Forageable.rainbow_shell)
|
||||
clam = BundleItem(Fish.clam)
|
||||
cockle = BundleItem(Fish.cockle)
|
||||
mussel = BundleItem(Fish.mussel)
|
||||
oyster = BundleItem(Fish.oyster)
|
||||
seaweed = BundleItem(WaterItem.seaweed, can_have_quality=False)
|
||||
|
||||
wood = BundleItem(Material.wood, 99)
|
||||
stone = BundleItem(Material.stone, 99)
|
||||
hardwood = BundleItem(Material.hardwood, 10)
|
||||
clay = BundleItem(Material.clay)
|
||||
fiber = BundleItem(Material.fiber)
|
||||
moss = BundleItem(Material.moss)
|
||||
|
||||
mixed_seeds = BundleItem(Seed.mixed)
|
||||
acorn = BundleItem(TreeSeed.acorn)
|
||||
maple_seed = BundleItem(TreeSeed.maple)
|
||||
pine_cone = BundleItem(TreeSeed.pine)
|
||||
mahogany_seed = BundleItem(TreeSeed.mahogany)
|
||||
mushroom_tree_seed = BundleItem(TreeSeed.mushroom, source=BundleItem.Sources.island)
|
||||
mystic_tree_seed = BundleItem(TreeSeed.mystic, source=BundleItem.Sources.masteries)
|
||||
mossy_seed = BundleItem(TreeSeed.mossy)
|
||||
|
||||
strawberry_seeds = BundleItem(Seed.strawberry)
|
||||
sunflower_seeds = BundleItem(Seed.sunflower)
|
||||
|
||||
blue_jazz = BundleItem(Flower.blue_jazz)
|
||||
cauliflower = BundleItem(Vegetable.cauliflower)
|
||||
green_bean = BundleItem(Vegetable.green_bean)
|
||||
kale = BundleItem(Vegetable.kale)
|
||||
parsnip = BundleItem(Vegetable.parsnip)
|
||||
potato = BundleItem(Vegetable.potato)
|
||||
strawberry = BundleItem(Fruit.strawberry, source=BundleItem.Sources.festival)
|
||||
tulip = BundleItem(Flower.tulip)
|
||||
unmilled_rice = BundleItem(Vegetable.unmilled_rice)
|
||||
coffee_bean = BundleItem(Seed.coffee)
|
||||
garlic = BundleItem(Vegetable.garlic)
|
||||
blueberry = BundleItem(Fruit.blueberry)
|
||||
corn = BundleItem(Vegetable.corn)
|
||||
hops = BundleItem(Vegetable.hops)
|
||||
hot_pepper = BundleItem(Fruit.hot_pepper)
|
||||
melon = BundleItem(Fruit.melon)
|
||||
poppy = BundleItem(Flower.poppy)
|
||||
radish = BundleItem(Vegetable.radish)
|
||||
summer_spangle = BundleItem(Flower.summer_spangle)
|
||||
sunflower = BundleItem(Flower.sunflower)
|
||||
tomato = BundleItem(Vegetable.tomato)
|
||||
wheat = BundleItem(Vegetable.wheat)
|
||||
hay = BundleItem(Forageable.hay)
|
||||
amaranth = BundleItem(Vegetable.amaranth)
|
||||
bok_choy = BundleItem(Vegetable.bok_choy)
|
||||
cranberries = BundleItem(Fruit.cranberries)
|
||||
eggplant = BundleItem(Vegetable.eggplant)
|
||||
fairy_rose = BundleItem(Flower.fairy_rose)
|
||||
pumpkin = BundleItem(Vegetable.pumpkin)
|
||||
yam = BundleItem(Vegetable.yam)
|
||||
sweet_gem_berry = BundleItem(Fruit.sweet_gem_berry)
|
||||
rhubarb = BundleItem(Fruit.rhubarb)
|
||||
beet = BundleItem(Vegetable.beet)
|
||||
red_cabbage = BundleItem(Vegetable.red_cabbage)
|
||||
starfruit = BundleItem(Fruit.starfruit)
|
||||
artichoke = BundleItem(Vegetable.artichoke)
|
||||
pineapple = BundleItem(Fruit.pineapple, source=BundleItem.Sources.content)
|
||||
taro_root = BundleItem(Vegetable.taro_root, source=BundleItem.Sources.content)
|
||||
dragon_tooth = BundleItem(Forageable.dragon_tooth, source=BundleItem.Sources.content)
|
||||
|
||||
carrot = BundleItem(Vegetable.carrot)
|
||||
summer_squash = BundleItem(Vegetable.summer_squash)
|
||||
broccoli = BundleItem(Vegetable.broccoli)
|
||||
powdermelon = BundleItem(Fruit.powdermelon)
|
||||
|
||||
egg = BundleItem(AnimalProduct.egg)
|
||||
large_egg = BundleItem(AnimalProduct.large_egg)
|
||||
brown_egg = BundleItem(AnimalProduct.brown_egg)
|
||||
large_brown_egg = BundleItem(AnimalProduct.large_brown_egg)
|
||||
wool = BundleItem(AnimalProduct.wool)
|
||||
milk = BundleItem(AnimalProduct.milk)
|
||||
large_milk = BundleItem(AnimalProduct.large_milk)
|
||||
goat_milk = BundleItem(AnimalProduct.goat_milk)
|
||||
large_goat_milk = BundleItem(AnimalProduct.large_goat_milk)
|
||||
truffle = BundleItem(AnimalProduct.truffle)
|
||||
duck_feather = BundleItem(AnimalProduct.duck_feather)
|
||||
duck_egg = BundleItem(AnimalProduct.duck_egg)
|
||||
rabbit_foot = BundleItem(AnimalProduct.rabbit_foot)
|
||||
dinosaur_egg = BundleItem(AnimalProduct.dinosaur_egg)
|
||||
void_egg = BundleItem(AnimalProduct.void_egg)
|
||||
ostrich_egg = BundleItem(AnimalProduct.ostrich_egg, source=BundleItem.Sources.content)
|
||||
golden_egg = BundleItem(AnimalProduct.golden_egg)
|
||||
|
||||
truffle_oil = BundleItem(ArtisanGood.truffle_oil)
|
||||
cloth = BundleItem(ArtisanGood.cloth)
|
||||
goat_cheese = BundleItem(ArtisanGood.goat_cheese)
|
||||
cheese = BundleItem(ArtisanGood.cheese)
|
||||
honey = BundleItem(ArtisanGood.honey)
|
||||
beer = BundleItem(Beverage.beer)
|
||||
mayonnaise = BundleItem(ArtisanGood.mayonnaise)
|
||||
juice = BundleItem(ArtisanGood.juice)
|
||||
mead = BundleItem(ArtisanGood.mead)
|
||||
pale_ale = BundleItem(ArtisanGood.pale_ale)
|
||||
wine = BundleItem(ArtisanGood.wine)
|
||||
jelly = BundleItem(ArtisanGood.jelly)
|
||||
pickles = BundleItem(ArtisanGood.pickles)
|
||||
caviar = BundleItem(ArtisanGood.caviar)
|
||||
aged_roe = BundleItem(ArtisanGood.aged_roe)
|
||||
roe = BundleItem(AnimalProduct.roe)
|
||||
squid_ink = BundleItem(AnimalProduct.squid_ink)
|
||||
coffee = BundleItem(Beverage.coffee)
|
||||
green_tea = BundleItem(ArtisanGood.green_tea)
|
||||
apple = BundleItem(Fruit.apple)
|
||||
apricot = BundleItem(Fruit.apricot)
|
||||
orange = BundleItem(Fruit.orange)
|
||||
peach = BundleItem(Fruit.peach)
|
||||
pomegranate = BundleItem(Fruit.pomegranate)
|
||||
cherry = BundleItem(Fruit.cherry)
|
||||
banana = BundleItem(Fruit.banana, source=BundleItem.Sources.content)
|
||||
mango = BundleItem(Fruit.mango, source=BundleItem.Sources.content)
|
||||
|
||||
basic_fertilizer = BundleItem(Fertilizer.basic, 100)
|
||||
quality_fertilizer = BundleItem(Fertilizer.quality, 20)
|
||||
deluxe_fertilizer = BundleItem(Fertilizer.deluxe, 5, source=BundleItem.Sources.island)
|
||||
basic_retaining_soil = BundleItem(RetainingSoil.basic, 80)
|
||||
quality_retaining_soil = BundleItem(RetainingSoil.quality, 50)
|
||||
deluxe_retaining_soil = BundleItem(RetainingSoil.deluxe, 20, source=BundleItem.Sources.island)
|
||||
speed_gro = BundleItem(SpeedGro.basic, 40)
|
||||
deluxe_speed_gro = BundleItem(SpeedGro.deluxe, 20)
|
||||
hyper_speed_gro = BundleItem(SpeedGro.hyper, 5, source=BundleItem.Sources.qi_board)
|
||||
tree_fertilizer = BundleItem(Fertilizer.tree, 20)
|
||||
|
||||
lobster = BundleItem(Fish.lobster)
|
||||
crab = BundleItem(Fish.crab)
|
||||
shrimp = BundleItem(Fish.shrimp)
|
||||
crayfish = BundleItem(Fish.crayfish)
|
||||
snail = BundleItem(Fish.snail)
|
||||
periwinkle = BundleItem(Fish.periwinkle)
|
||||
trash = BundleItem(Trash.trash)
|
||||
driftwood = BundleItem(Trash.driftwood)
|
||||
soggy_newspaper = BundleItem(Trash.soggy_newspaper)
|
||||
broken_cd = BundleItem(Trash.broken_cd)
|
||||
broken_glasses = BundleItem(Trash.broken_glasses)
|
||||
|
||||
chub = BundleItem(Fish.chub)
|
||||
catfish = BundleItem(Fish.catfish)
|
||||
rainbow_trout = BundleItem(Fish.rainbow_trout)
|
||||
lingcod = BundleItem(Fish.lingcod)
|
||||
walleye = BundleItem(Fish.walleye)
|
||||
perch = BundleItem(Fish.perch)
|
||||
pike = BundleItem(Fish.pike)
|
||||
bream = BundleItem(Fish.bream)
|
||||
salmon = BundleItem(Fish.salmon)
|
||||
sunfish = BundleItem(Fish.sunfish)
|
||||
tiger_trout = BundleItem(Fish.tiger_trout)
|
||||
shad = BundleItem(Fish.shad)
|
||||
smallmouth_bass = BundleItem(Fish.smallmouth_bass)
|
||||
dorado = BundleItem(Fish.dorado)
|
||||
carp = BundleItem(Fish.carp)
|
||||
midnight_carp = BundleItem(Fish.midnight_carp)
|
||||
largemouth_bass = BundleItem(Fish.largemouth_bass)
|
||||
sturgeon = BundleItem(Fish.sturgeon)
|
||||
bullhead = BundleItem(Fish.bullhead)
|
||||
tilapia = BundleItem(Fish.tilapia)
|
||||
pufferfish = BundleItem(Fish.pufferfish)
|
||||
tuna = BundleItem(Fish.tuna)
|
||||
super_cucumber = BundleItem(Fish.super_cucumber)
|
||||
flounder = BundleItem(Fish.flounder)
|
||||
anchovy = BundleItem(Fish.anchovy)
|
||||
sardine = BundleItem(Fish.sardine)
|
||||
red_mullet = BundleItem(Fish.red_mullet)
|
||||
herring = BundleItem(Fish.herring)
|
||||
eel = BundleItem(Fish.eel)
|
||||
octopus = BundleItem(Fish.octopus)
|
||||
red_snapper = BundleItem(Fish.red_snapper)
|
||||
squid = BundleItem(Fish.squid)
|
||||
sea_cucumber = BundleItem(Fish.sea_cucumber)
|
||||
albacore = BundleItem(Fish.albacore)
|
||||
halibut = BundleItem(Fish.halibut)
|
||||
scorpion_carp = BundleItem(Fish.scorpion_carp)
|
||||
sandfish = BundleItem(Fish.sandfish)
|
||||
woodskip = BundleItem(Fish.woodskip)
|
||||
lava_eel = BundleItem(Fish.lava_eel)
|
||||
ice_pip = BundleItem(Fish.ice_pip)
|
||||
stonefish = BundleItem(Fish.stonefish)
|
||||
ghostfish = BundleItem(Fish.ghostfish)
|
||||
|
||||
bouquet = BundleItem(Gift.bouquet)
|
||||
wilted_bouquet = BundleItem(Gift.wilted_bouquet)
|
||||
copper_bar = BundleItem(MetalBar.copper)
|
||||
iron_bar = BundleItem(MetalBar.iron)
|
||||
gold_bar = BundleItem(MetalBar.gold)
|
||||
iridium_bar = BundleItem(MetalBar.iridium)
|
||||
radioactive_bar = BundleItem(MetalBar.radioactive, source=BundleItem.Sources.island)
|
||||
refined_quartz = BundleItem(MetalBar.quartz)
|
||||
coal = BundleItem(Material.coal)
|
||||
iridium_ore = BundleItem(Ore.iridium)
|
||||
gold_ore = BundleItem(Ore.gold)
|
||||
iron_ore = BundleItem(Ore.iron)
|
||||
copper_ore = BundleItem(Ore.copper)
|
||||
radioactive_ore = BundleItem(Ore.radioactive, source=BundleItem.Sources.qi_board)
|
||||
battery_pack = BundleItem(ArtisanGood.battery_pack)
|
||||
|
||||
quartz = BundleItem(Mineral.quartz)
|
||||
fire_quartz = BundleItem(Mineral.fire_quartz)
|
||||
frozen_tear = BundleItem(Mineral.frozen_tear)
|
||||
earth_crystal = BundleItem(Mineral.earth_crystal)
|
||||
emerald = BundleItem(Mineral.emerald)
|
||||
aquamarine = BundleItem(Mineral.aquamarine)
|
||||
ruby = BundleItem(Mineral.ruby)
|
||||
amethyst = BundleItem(Mineral.amethyst)
|
||||
topaz = BundleItem(Mineral.topaz)
|
||||
jade = BundleItem(Mineral.jade)
|
||||
obsidian = BundleItem(Mineral.obsidian)
|
||||
jamborite = BundleItem(Mineral.jamborite)
|
||||
tigerseye = BundleItem(Mineral.tigerseye)
|
||||
opal = BundleItem(Mineral.opal)
|
||||
thunder_egg = BundleItem(Mineral.thunder_egg)
|
||||
ghost_crystal = BundleItem(Mineral.ghost_crystal)
|
||||
kyanite = BundleItem(Mineral.kyanite)
|
||||
lemon_stone = BundleItem(Mineral.lemon_stone)
|
||||
mudstone = BundleItem(Mineral.mudstone)
|
||||
limestone = BundleItem(Mineral.limestone)
|
||||
|
||||
slime = BundleItem(Loot.slime, 99)
|
||||
bug_meat = BundleItem(Loot.bug_meat, 10)
|
||||
bat_wing = BundleItem(Loot.bat_wing, 10)
|
||||
solar_essence = BundleItem(Loot.solar_essence)
|
||||
void_essence = BundleItem(Loot.void_essence)
|
||||
|
||||
petrified_slime = BundleItem(Mineral.petrified_slime)
|
||||
blue_slime_egg = BundleItem(AnimalProduct.slime_egg_blue)
|
||||
red_slime_egg = BundleItem(AnimalProduct.slime_egg_red)
|
||||
purple_slime_egg = BundleItem(AnimalProduct.slime_egg_purple)
|
||||
green_slime_egg = BundleItem(AnimalProduct.slime_egg_green)
|
||||
tiger_slime_egg = BundleItem(AnimalProduct.slime_egg_tiger, source=BundleItem.Sources.island)
|
||||
|
||||
cherry_bomb = BundleItem(Bomb.cherry_bomb, 5)
|
||||
bomb = BundleItem(Bomb.bomb, 2)
|
||||
mega_bomb = BundleItem(Bomb.mega_bomb)
|
||||
explosive_ammo = BundleItem(Craftable.explosive_ammo, 5)
|
||||
|
||||
maki_roll = BundleItem(Meal.maki_roll)
|
||||
fried_egg = BundleItem(Meal.fried_egg)
|
||||
omelet = BundleItem(Meal.omelet)
|
||||
pizza = BundleItem(Meal.pizza)
|
||||
hashbrowns = BundleItem(Meal.hashbrowns)
|
||||
pancakes = BundleItem(Meal.pancakes)
|
||||
bread = BundleItem(Meal.bread)
|
||||
tortilla = BundleItem(Meal.tortilla)
|
||||
triple_shot_espresso = BundleItem(Beverage.triple_shot_espresso)
|
||||
farmer_s_lunch = BundleItem(Meal.farmer_lunch)
|
||||
survival_burger = BundleItem(Meal.survival_burger)
|
||||
dish_o_the_sea = BundleItem(Meal.dish_o_the_sea)
|
||||
miner_s_treat = BundleItem(Meal.miners_treat)
|
||||
roots_platter = BundleItem(Meal.roots_platter)
|
||||
salad = BundleItem(Meal.salad)
|
||||
cheese_cauliflower = BundleItem(Meal.cheese_cauliflower)
|
||||
parsnip_soup = BundleItem(Meal.parsnip_soup)
|
||||
fried_mushroom = BundleItem(Meal.fried_mushroom)
|
||||
salmon_dinner = BundleItem(Meal.salmon_dinner)
|
||||
pepper_poppers = BundleItem(Meal.pepper_poppers)
|
||||
spaghetti = BundleItem(Meal.spaghetti)
|
||||
sashimi = BundleItem(Meal.sashimi)
|
||||
blueberry_tart = BundleItem(Meal.blueberry_tart)
|
||||
algae_soup = BundleItem(Meal.algae_soup)
|
||||
pale_broth = BundleItem(Meal.pale_broth)
|
||||
chowder = BundleItem(Meal.chowder)
|
||||
cookie = BundleItem(Meal.cookie)
|
||||
ancient_doll = BundleItem(Artifact.ancient_doll)
|
||||
ice_cream = BundleItem(Meal.ice_cream)
|
||||
cranberry_candy = BundleItem(Meal.cranberry_candy)
|
||||
ginger_ale = BundleItem(Beverage.ginger_ale, source=BundleItem.Sources.island)
|
||||
pink_cake = BundleItem(Meal.pink_cake)
|
||||
plum_pudding = BundleItem(Meal.plum_pudding)
|
||||
chocolate_cake = BundleItem(Meal.chocolate_cake)
|
||||
rhubarb_pie = BundleItem(Meal.rhubarb_pie)
|
||||
shrimp_cocktail = BundleItem(Meal.shrimp_cocktail)
|
||||
pina_colada = BundleItem(Beverage.pina_colada, source=BundleItem.Sources.island)
|
||||
stuffing = BundleItem(Meal.stuffing)
|
||||
magic_rock_candy = BundleItem(Meal.magic_rock_candy)
|
||||
spicy_eel = BundleItem(Meal.spicy_eel)
|
||||
crab_cakes = BundleItem(Meal.crab_cakes)
|
||||
eggplant_parmesan = BundleItem(Meal.eggplant_parmesan)
|
||||
pumpkin_soup = BundleItem(Meal.pumpkin_soup)
|
||||
lucky_lunch = BundleItem(Meal.lucky_lunch)
|
||||
joja_cola = BundleItem(Trash.joja_cola)
|
||||
strange_bun = BundleItem(Meal.strange_bun)
|
||||
moss_soup = BundleItem(Meal.moss_soup)
|
||||
roasted_hazelnuts = BundleItem(Meal.roasted_hazelnuts)
|
||||
maple_bar = BundleItem(Meal.maple_bar)
|
||||
|
||||
green_algae = BundleItem(WaterItem.green_algae)
|
||||
white_algae = BundleItem(WaterItem.white_algae)
|
||||
geode = BundleItem(Geode.geode)
|
||||
frozen_geode = BundleItem(Geode.frozen)
|
||||
magma_geode = BundleItem(Geode.magma)
|
||||
omni_geode = BundleItem(Geode.omni)
|
||||
sap = BundleItem(Material.sap)
|
||||
|
||||
dwarf_scroll_1 = BundleItem(Artifact.dwarf_scroll_i)
|
||||
dwarf_scroll_2 = BundleItem(Artifact.dwarf_scroll_ii)
|
||||
dwarf_scroll_3 = BundleItem(Artifact.dwarf_scroll_iii)
|
||||
dwarf_scroll_4 = BundleItem(Artifact.dwarf_scroll_iv)
|
||||
elvish_jewelry = BundleItem(Artifact.elvish_jewelry)
|
||||
ancient_drum = BundleItem(Artifact.ancient_drum)
|
||||
dried_starfish = BundleItem(Fossil.dried_starfish)
|
||||
bone_fragment = BundleItem(Fossil.bone_fragment)
|
||||
|
||||
golden_mask = BundleItem(Artifact.golden_mask)
|
||||
golden_relic = BundleItem(Artifact.golden_relic)
|
||||
dwarf_gadget = BundleItem(Artifact.dwarf_gadget)
|
||||
dwarvish_helm = BundleItem(Artifact.dwarvish_helm)
|
||||
prehistoric_handaxe = BundleItem(Artifact.prehistoric_handaxe)
|
||||
bone_flute = BundleItem(Artifact.bone_flute)
|
||||
anchor = BundleItem(Artifact.anchor)
|
||||
prehistoric_tool = BundleItem(Artifact.prehistoric_tool)
|
||||
chicken_statue = BundleItem(Artifact.chicken_statue)
|
||||
rusty_cog = BundleItem(Artifact.rusty_cog)
|
||||
rusty_spur = BundleItem(Artifact.rusty_spur)
|
||||
rusty_spoon = BundleItem(Artifact.rusty_spoon)
|
||||
ancient_sword = BundleItem(Artifact.ancient_sword)
|
||||
ornamental_fan = BundleItem(Artifact.ornamental_fan)
|
||||
chipped_amphora = BundleItem(Artifact.chipped_amphora)
|
||||
strange_doll = BundleItem(Artifact.strange_doll)
|
||||
strange_doll_green = BundleItem(Artifact.strange_doll_green)
|
||||
ancient_seed = BundleItem(Artifact.ancient_seed)
|
||||
rare_disc = BundleItem(Artifact.rare_disc)
|
||||
|
||||
prehistoric_scapula = BundleItem(Fossil.prehistoric_scapula)
|
||||
prehistoric_tibia = BundleItem(Fossil.prehistoric_tibia)
|
||||
prehistoric_skull = BundleItem(Fossil.prehistoric_skull)
|
||||
skeletal_hand = BundleItem(Fossil.skeletal_hand)
|
||||
prehistoric_rib = BundleItem(Fossil.prehistoric_rib)
|
||||
prehistoric_vertebra = BundleItem(Fossil.prehistoric_vertebra)
|
||||
skeletal_tail = BundleItem(Fossil.skeletal_tail)
|
||||
nautilus_fossil = BundleItem(Fossil.nautilus_fossil)
|
||||
amphibian_fossil = BundleItem(Fossil.amphibian_fossil)
|
||||
palm_fossil = BundleItem(Fossil.palm_fossil)
|
||||
trilobite = BundleItem(Fossil.trilobite)
|
||||
snake_vertebrae = BundleItem(Fossil.snake_vertebrae, source=BundleItem.Sources.island)
|
||||
mummified_bat = BundleItem(Fossil.mummified_bat, source=BundleItem.Sources.island)
|
||||
fossilized_tail = BundleItem(Fossil.fossilized_tail, source=BundleItem.Sources.island)
|
||||
|
||||
dinosaur_mayo = BundleItem(ArtisanGood.dinosaur_mayonnaise)
|
||||
void_mayo = BundleItem(ArtisanGood.void_mayonnaise)
|
||||
prismatic_shard = BundleItem(Mineral.prismatic_shard)
|
||||
diamond = BundleItem(Mineral.diamond)
|
||||
ancient_fruit = BundleItem(Fruit.ancient_fruit)
|
||||
void_salmon = BundleItem(Fish.void_salmon)
|
||||
tea_leaves = BundleItem(Vegetable.tea_leaves)
|
||||
blobfish = BundleItem(Fish.blobfish)
|
||||
spook_fish = BundleItem(Fish.spook_fish)
|
||||
lionfish = BundleItem(Fish.lionfish, source=BundleItem.Sources.island)
|
||||
blue_discus = BundleItem(Fish.blue_discus, source=BundleItem.Sources.island)
|
||||
stingray = BundleItem(Fish.stingray, source=BundleItem.Sources.island)
|
||||
spookfish = BundleItem(Fish.spookfish)
|
||||
midnight_squid = BundleItem(Fish.midnight_squid)
|
||||
slimejack = BundleItem(Fish.slimejack)
|
||||
goby = BundleItem(Fish.goby)
|
||||
|
||||
angler = BundleItem(Fish.angler)
|
||||
crimsonfish = BundleItem(Fish.crimsonfish)
|
||||
mutant_carp = BundleItem(Fish.mutant_carp)
|
||||
glacierfish = BundleItem(Fish.glacierfish)
|
||||
legend = BundleItem(Fish.legend)
|
||||
|
||||
spinner = BundleItem(Fishing.spinner)
|
||||
dressed_spinner = BundleItem(Fishing.dressed_spinner)
|
||||
trap_bobber = BundleItem(Fishing.trap_bobber)
|
||||
sonar_bobber = BundleItem(Fishing.sonar_bobber)
|
||||
cork_bobber = BundleItem(Fishing.cork_bobber)
|
||||
lead_bobber = BundleItem(Fishing.lead_bobber)
|
||||
treasure_hunter = BundleItem(Fishing.treasure_hunter)
|
||||
barbed_hook = BundleItem(Fishing.barbed_hook)
|
||||
curiosity_lure = BundleItem(Fishing.curiosity_lure)
|
||||
quality_bobber = BundleItem(Fishing.quality_bobber)
|
||||
bait = BundleItem(Fishing.bait, 100)
|
||||
deluxe_bait = BundleItem(Fishing.deluxe_bait, 50)
|
||||
magnet = BundleItem(Fishing.magnet)
|
||||
wild_bait = BundleItem(Fishing.wild_bait, 20)
|
||||
magic_bait = BundleItem(Fishing.magic_bait, 10, source=BundleItem.Sources.qi_board)
|
||||
pearl = BundleItem(Gift.pearl)
|
||||
challenge_bait = BundleItem(Fishing.challenge_bait, 25, source=BundleItem.Sources.masteries)
|
||||
targeted_bait = BundleItem(ArtisanGood.targeted_bait, 25, source=BundleItem.Sources.content)
|
||||
golden_bobber = BundleItem(Fishing.golden_bobber)
|
||||
|
||||
ginger = BundleItem(Forageable.ginger, source=BundleItem.Sources.content)
|
||||
magma_cap = BundleItem(Mushroom.magma_cap, source=BundleItem.Sources.content)
|
||||
|
||||
wheat_flour = BundleItem(Ingredient.wheat_flour)
|
||||
sugar = BundleItem(Ingredient.sugar)
|
||||
vinegar = BundleItem(Ingredient.vinegar)
|
||||
|
||||
jack_o_lantern = BundleItem(Lighting.jack_o_lantern)
|
||||
prize_ticket = BundleItem(Currency.prize_ticket)
|
||||
mystery_box = BundleItem(Consumable.mystery_box)
|
||||
gold_mystery_box = BundleItem(Consumable.gold_mystery_box, source=BundleItem.Sources.masteries)
|
||||
calico_egg = BundleItem(Currency.calico_egg)
|
||||
golden_tag = BundleItem(Currency.golden_tag)
|
||||
stardrop_tea = BundleItem(ArtisanGood.stardrop_tea)
|
||||
rotten_plant = BundleItem(Decoration.rotten_plant)
|
||||
|
||||
apple_slices = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.apple))
|
||||
|
||||
infinity_crown = BundleItem(Hats.infinity_crown.name, source=BundleItem.Sources.content)
|
||||
bowler_hat = BundleItem(Hats.bowler.name, source=BundleItem.Sources.content)
|
||||
sombrero = BundleItem(Hats.sombrero.name, source=BundleItem.Sources.content)
|
||||
good_ol_cap = BundleItem(Hats.good_ol_cap.name, source=BundleItem.Sources.content)
|
||||
living_hat = BundleItem(Hats.living_hat.name, source=BundleItem.Sources.content)
|
||||
garbage_hat = BundleItem(Hats.garbage_hat.name, source=BundleItem.Sources.content)
|
||||
golden_helmet = BundleItem(Hats.golden_helmet.name, source=BundleItem.Sources.content)
|
||||
laurel_wreath_crown = BundleItem(Hats.laurel_wreath_crown.name, source=BundleItem.Sources.content)
|
||||
joja_cap = BundleItem(Hats.joja_cap.name, source=BundleItem.Sources.content)
|
||||
deluxe_pirate_hat = BundleItem(Hats.deluxe_pirate_hat.name, source=BundleItem.Sources.content)
|
||||
dark_cowboy_hat = BundleItem(Hats.dark_cowboy_hat.name, source=BundleItem.Sources.content)
|
||||
tiger_hat = BundleItem(Hats.tiger_hat.name, source=BundleItem.Sources.content)
|
||||
mystery_hat = BundleItem(Hats.mystery_hat.name, source=BundleItem.Sources.content)
|
||||
dark_ballcap = BundleItem(Hats.dark_ballcap.name, source=BundleItem.Sources.content)
|
||||
goblin_mask = BundleItem(Hats.goblin_mask.name, source=BundleItem.Sources.island)
|
||||
|
||||
vacation_shirt = BundleItem(Shirts.vacation.name)
|
||||
green_jacket_shirt = BundleItem(Shirts.green_jacket.name)
|
||||
|
||||
mermaid_boots = BundleItem(Boots.mermaid_boots)
|
||||
|
||||
lucky_purple_shorts = BundleItem(SpecialItem.lucky_purple_shorts)
|
||||
trimmed_purple_shorts = BundleItem(SpecialItem.trimmed_purple_shorts)
|
||||
|
||||
ancient_fruit_wine = BundleItem(ArtisanGood.specific_wine(Fruit.ancient_fruit))
|
||||
dried_ancient_fruit = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.ancient_fruit))
|
||||
ancient_fruit_jelly = BundleItem(ArtisanGood.specific_jelly(Fruit.ancient_fruit))
|
||||
starfruit_wine = BundleItem(ArtisanGood.specific_wine(Fruit.starfruit))
|
||||
dried_starfruit = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.starfruit))
|
||||
starfruit_jelly = BundleItem(ArtisanGood.specific_jelly(Fruit.starfruit))
|
||||
rhubarb_wine = BundleItem(ArtisanGood.specific_wine(Fruit.rhubarb))
|
||||
dried_rhubarb = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.rhubarb))
|
||||
melon_wine = BundleItem(ArtisanGood.specific_wine(Fruit.melon))
|
||||
dried_melon = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.melon))
|
||||
pineapple_wine = BundleItem(ArtisanGood.specific_wine(Fruit.pineapple), source=BundleItem.Sources.content)
|
||||
dried_pineapple = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.pineapple), source=BundleItem.Sources.content)
|
||||
dried_banana = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.banana), source=BundleItem.Sources.content)
|
||||
strawberry_wine = BundleItem(ArtisanGood.specific_wine(Fruit.strawberry))
|
||||
dried_strawberry = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.strawberry))
|
||||
pumpkin_juice = BundleItem(ArtisanGood.specific_juice(Vegetable.pumpkin))
|
||||
raisins = BundleItem(ArtisanGood.raisins)
|
||||
dried_qi_fruit = BundleItem(ArtisanGood.specific_dried_fruit(Fruit.qi_fruit), source=BundleItem.Sources.content)
|
||||
|
||||
aged_lava_eel_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.lava_eel))
|
||||
aged_crimsonfish_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.crimsonfish))
|
||||
aged_angler_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.angler))
|
||||
legend_roe = BundleItem(AnimalProduct.specific_roe(Fish.legend))
|
||||
aged_legend_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.legend))
|
||||
aged_glacierfish_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.glacierfish))
|
||||
aged_mutant_carp_roe = BundleItem(ArtisanGood.specific_aged_roe(Fish.mutant_carp))
|
||||
midnight_squid_roe = BundleItem(AnimalProduct.specific_roe(Fish.midnight_squid))
|
||||
|
||||
legend_bait = BundleItem(ArtisanGood.specific_bait(Fish.legend))
|
||||
|
||||
smoked_legend = BundleItem(ArtisanGood.specific_smoked_fish(Fish.legend))
|
||||
|
||||
mystic_syrup = BundleItem(ArtisanGood.mystic_syrup)
|
||||
apple_sapling = BundleItem(Sapling.apple)
|
||||
apricot_sapling = BundleItem(Sapling.apricot)
|
||||
banana_sapling = BundleItem(Sapling.banana, source=BundleItem.Sources.content)
|
||||
cherry_sapling = BundleItem(Sapling.cherry)
|
||||
mango_sapling = BundleItem(Sapling.mango, source=BundleItem.Sources.content)
|
||||
orange_sapling = BundleItem(Sapling.orange)
|
||||
peach_sapling = BundleItem(Sapling.peach)
|
||||
pomegranate_sapling = BundleItem(Sapling.pomegranate)
|
||||
|
||||
cookout_kit = BundleItem(Craftable.cookout_kit)
|
||||
tent_kit = BundleItem(Craftable.tent_kit)
|
||||
bug_steak = BundleItem(Edible.bug_steak)
|
||||
|
||||
tea_set = BundleItem(Gift.tea_set)
|
||||
golden_pumpkin = BundleItem(Gift.golden_pumpkin)
|
||||
mermaid_pendant = BundleItem(Gift.mermaid_pendant)
|
||||
void_ghost_pendant = BundleItem(Gift.void_ghost_pendant)
|
||||
advanced_tv_remote = BundleItem(SpecialItem.advanced_tv_remote)
|
||||
|
||||
crystal_ball = BundleItem(CatalogueItem.crystal_ball)
|
||||
amethyst_crystal_ball = BundleItem(CatalogueItem.amethyst_crystal_ball)
|
||||
aquamarine_crystal_ball = BundleItem(CatalogueItem.aquamarine_crystal_ball)
|
||||
emerald_crystal_ball = BundleItem(CatalogueItem.emerald_crystal_ball)
|
||||
ruby_crystal_ball = BundleItem(CatalogueItem.ruby_crystal_ball)
|
||||
topaz_crystal_ball = BundleItem(CatalogueItem.topaz_crystal_ball)
|
||||
flute_block = BundleItem(Furniture.flute_block)
|
||||
candle_lamp = BundleItem(Furniture.candle_lamp)
|
||||
modern_lamp = BundleItem(Furniture.modern_lamp)
|
||||
single_bed = BundleItem(Furniture.single_bed)
|
||||
exotic_double_bed = BundleItem(Furniture.exotic_double_bed, source=BundleItem.Sources.qi_board)
|
||||
statue_of_endless_fortune = BundleItem(Machine.statue_endless_fortune)
|
||||
cursed_mannequin = BundleItem(Furniture.cursed_mannequin)
|
||||
statue_of_blessings = BundleItem(Statue.blessings)
|
||||
crane_house_plant = BundleItem(Furniture.crane_game_house_plant)
|
||||
|
||||
wood_floor = BundleItem(Floor.wood)
|
||||
rustic_plank_floor = BundleItem(Floor.rustic)
|
||||
straw_floor = BundleItem(Floor.straw)
|
||||
weathered_floor = BundleItem(Floor.weathered)
|
||||
crystal_floor = BundleItem(Floor.crystal)
|
||||
stone_floor = BundleItem(Floor.stone)
|
||||
stone_walkway_floor = BundleItem(Floor.stone_walkway)
|
||||
brick_floor = BundleItem(Floor.brick)
|
||||
wood_path = BundleItem(Floor.wood_path)
|
||||
gravel_path = BundleItem(Floor.gravel_path)
|
||||
cobblestone_path = BundleItem(Floor.cobblestone_path)
|
||||
stepping_stone_path = BundleItem(Floor.stepping_stone_path)
|
||||
crystal_path = BundleItem(Floor.crystal_path)
|
||||
|
||||
warp_totem_beach = BundleItem(Consumable.warp_totem_beach)
|
||||
warp_totem_mountains = BundleItem(Consumable.warp_totem_mountains)
|
||||
warp_totem_farm = BundleItem(Consumable.warp_totem_farm)
|
||||
warp_totem_desert = BundleItem(Consumable.warp_totem_desert, source=BundleItem.Sources.content)
|
||||
warp_totem_island = BundleItem(Consumable.warp_totem_island, source=BundleItem.Sources.island)
|
||||
rain_totem = BundleItem(Consumable.rain_totem)
|
||||
treasure_totem = BundleItem(Consumable.treasure_totem, source=BundleItem.Sources.masteries)
|
||||
|
||||
book_of_mysteries = BundleItem(Book.book_of_mysteries)
|
||||
|
||||
far_away_stone = BundleItem(SpecialItem.far_away_stone)
|
||||
|
||||
death = BundleItem(NotReallyAnItem.death)
|
||||
|
||||
camping_stove = BundleItem(MemeItem.camping_stove)
|
||||
decorative_pot = BundleItem(MemeItem.decorative_pot)
|
||||
slime_crate = BundleItem(MemeItem.slime_crate)
|
||||
supply_crate = BundleItem(MemeItem.supply_crate)
|
||||
warp_totem_qis_arena = BundleItem(MemeItem.warp_totem_qis_arena)
|
||||
artifact_spot = BundleItem(MemeItem.artifact_spot)
|
||||
twig = BundleItem(MemeItem.twig)
|
||||
weeds = BundleItem(MemeItem.weeds)
|
||||
lumber = BundleItem(MemeItem.lumber)
|
||||
green_rain_weeds_0 = BundleItem(MemeItem.green_rain_weeds_0)
|
||||
seed_spot = BundleItem(MemeItem.seed_spot)
|
||||
pot_of_gold = BundleItem(MemeItem.pot_of_gold)
|
||||
28
worlds/stardew_valley/data/bundles_data/bundle_set.py
Normal file
28
worlds/stardew_valley/data/bundles_data/bundle_set.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from typing import Dict, List
|
||||
|
||||
from .remixed_anywhere_bundles import community_center_remixed_anywhere
|
||||
from .remixed_bundles import pantry_remixed, crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed, vault_remixed, \
|
||||
abandoned_joja_mart_remixed, giant_stump_remixed
|
||||
from .thematic_bundles import pantry_thematic, crafts_room_thematic, fish_tank_thematic, boiler_room_thematic, bulletin_board_thematic, vault_thematic, \
|
||||
abandoned_joja_mart_thematic, giant_stump_thematic
|
||||
from .vanilla_bundles import crafts_room_vanilla, pantry_vanilla, fish_tank_vanilla, boiler_room_vanilla, \
|
||||
bulletin_board_vanilla, vault_vanilla, abandoned_joja_mart_vanilla, giant_stump_vanilla
|
||||
from ...bundles.bundle_room import BundleRoomTemplate
|
||||
|
||||
|
||||
class BundleSet:
|
||||
bundles_by_room: Dict[str, BundleRoomTemplate]
|
||||
|
||||
def __init__(self, bundle_rooms: List[BundleRoomTemplate]):
|
||||
self.bundles_by_room = {bundle_room.name: bundle_room for bundle_room in bundle_rooms}
|
||||
|
||||
|
||||
vanilla_bundles = BundleSet([pantry_vanilla, crafts_room_vanilla, fish_tank_vanilla, boiler_room_vanilla, bulletin_board_vanilla,
|
||||
vault_vanilla, abandoned_joja_mart_vanilla, giant_stump_vanilla])
|
||||
thematic_bundles = BundleSet([pantry_thematic, crafts_room_thematic, fish_tank_thematic, boiler_room_thematic, bulletin_board_thematic,
|
||||
vault_thematic, abandoned_joja_mart_thematic, giant_stump_thematic])
|
||||
remixed_bundles = BundleSet([pantry_remixed, crafts_room_remixed, fish_tank_remixed, boiler_room_remixed, bulletin_board_remixed,
|
||||
vault_remixed, abandoned_joja_mart_remixed, giant_stump_remixed])
|
||||
remixed_anywhere_bundles = BundleSet([community_center_remixed_anywhere, abandoned_joja_mart_remixed, giant_stump_remixed])
|
||||
|
||||
# shuffled_bundles = BundleSet()
|
||||
378
worlds/stardew_valley/data/bundles_data/meme_bundles.py
Normal file
378
worlds/stardew_valley/data/bundles_data/meme_bundles.py
Normal file
@@ -0,0 +1,378 @@
|
||||
from .bundle_data import all_bundle_items_by_name
|
||||
from .meme_bundles_data.capitalist_bundle import capitalist_items
|
||||
from .remixed_bundles import *
|
||||
from ...bundles.bundle import BureaucracyBundleTemplate, RecursiveBundleTemplate, FixedPriceCurrencyBundleTemplate, \
|
||||
FixedPriceBundleTemplate, FixedPriceDeepBundleTemplate, FixedMultiplierBundleTemplate, FixedSlotsBundleTemplate
|
||||
from ...strings.bundle_names import MemeBundleName
|
||||
from ...strings.currency_names import MemeCurrency
|
||||
from ...strings.flower_names import all_flowers
|
||||
from ...strings.machine_names import Machine
|
||||
from ...strings.meme_item_names import MemeItem
|
||||
from ...strings.quality_names import AnimalProductQuality, CropQuality
|
||||
|
||||
burger_king_items = [survival_burger, joja_cola, apple_slices, ice_cream, strange_doll, strange_doll_green, hashbrowns, infinity_crown]
|
||||
burger_king_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.burger_king, burger_king_items, 6, 3)
|
||||
|
||||
capitalist_bundle = FixedMultiplierBundleTemplate(CCRoom.vault, MemeBundleName.capitalist, capitalist_items, 12, 2)
|
||||
|
||||
romance_items = [lucky_purple_shorts, truffle_oil, super_cucumber, good_ol_cap]
|
||||
romance_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.romance, romance_items, 4, 4)
|
||||
|
||||
hurricane_tortilla_items = [tortilla.as_amount(4)]
|
||||
hurricane_tortilla_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.hurricane_tortilla, hurricane_tortilla_items, 6, 6)
|
||||
|
||||
AAAA_items = [battery_pack.as_amount(12), battery_pack.as_amount(8), battery_pack.as_amount(6)]
|
||||
AAAA_bundle = BundleTemplate(CCRoom.crafts_room, MemeBundleName.AAAA, AAAA_items, 3, 3)
|
||||
|
||||
anything_for_beyonce_items = [beet]
|
||||
anything_for_beyonce_bundle = BundleTemplate(CCRoom.crafts_room, MemeBundleName.anything_for_beyonce, anything_for_beyonce_items, 1, 1)
|
||||
|
||||
crab_rave_items = [crab.as_amount(8)]
|
||||
crab_rave_bundle = BundleTemplate(CCRoom.fish_tank, MemeBundleName.crab_rave, crab_rave_items, 12, 8)
|
||||
|
||||
potato_items = [potato.as_amount(8)]
|
||||
potato_bundle = BundleTemplate(CCRoom.crafts_room, MemeBundleName.potato, potato_items, 12, 8)
|
||||
|
||||
look_at_chickens_items = [duck_egg.as_amount(2)]
|
||||
look_at_chickens_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.look_at_chickens, look_at_chickens_items, 10, 4)
|
||||
|
||||
lemonade_stand_items = [grape]
|
||||
lemonade_stand_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.lemonade_stand, lemonade_stand_items, 3, 1)
|
||||
|
||||
what_the_rock_is_cooking_items = [stone.as_amount(1), cookout_kit, strange_bun]
|
||||
what_the_rock_is_cooking_bundle = FixedPriceBundleTemplate(CCRoom.pantry, MemeBundleName.what_the_rock_is_cooking, what_the_rock_is_cooking_items, 3, 3)
|
||||
|
||||
amons_fall_items = [stone.as_amount(1)]
|
||||
amons_fall_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.amons_fall, amons_fall_items, 7, 7)
|
||||
|
||||
screw_you_items = [tea_set, ostrich_egg.as_quality(AnimalProductQuality.iridium), snake_vertebrae.as_amount(5), mummified_bat.as_amount(5)]
|
||||
screw_you_bundle = BundleTemplate(CCRoom.boiler_room, MemeBundleName.screw_you, screw_you_items, 4, 4)
|
||||
|
||||
sunmaid_items = [raisins.as_amount(28)]
|
||||
sunmaid_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.sunmaid, sunmaid_items, 1, 1)
|
||||
|
||||
rick_items = [pickles]
|
||||
rick_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.rick, rick_items, 1, 1)
|
||||
|
||||
minecraft_items = [coal, copper_ore, iron_ore, quartz, amethyst, emerald, gold_ore, diamond, obsidian]
|
||||
minecraft_bundle = BundleTemplate(CCRoom.boiler_room, MemeBundleName.minecraft, minecraft_items, 9, 8)
|
||||
|
||||
balls_items = [blue_jazz, cauliflower, blueberry, melon, red_cabbage, tomato, powdermelon, cranberries, fairy_rose, grape, pumpkin, ancient_fruit,
|
||||
solar_essence, cherry_bomb, bomb, mega_bomb, coal, iridium_ore, aquamarine, jamborite, geode, magma_geode, ancient_seed, crystal_ball,
|
||||
amethyst_crystal_ball, aquamarine_crystal_ball, emerald_crystal_ball, ruby_crystal_ball, topaz_crystal_ball, apple, pizza, explosive_ammo, peach,
|
||||
orange, apricot, tigerseye, coconut, gold_ore, golden_coconut, pufferfish, lucky_lunch, salad, cactus_fruit, radioactive_ore, opal, broken_cd,
|
||||
void_essence, wild_plum, pomegranate]
|
||||
balls_items = [item.as_amount(1) for item in balls_items]
|
||||
balls_bundle = BundleTemplate(CCRoom.boiler_room, MemeBundleName.balls, balls_items, 12, 6)
|
||||
|
||||
tilesanity_items = [wood_floor.as_amount(100), rustic_plank_floor.as_amount(100), straw_floor.as_amount(100), weathered_floor.as_amount(100),
|
||||
crystal_floor.as_amount(100), stone_floor.as_amount(100), stone_walkway_floor.as_amount(100), brick_floor.as_amount(100),
|
||||
wood_path.as_amount(100), gravel_path.as_amount(100), cobblestone_path.as_amount(100), stepping_stone_path.as_amount(100),
|
||||
crystal_path.as_amount(100)]
|
||||
tilesanity_bundle = BundleTemplate(CCRoom.boiler_room, MemeBundleName.tilesanity, tilesanity_items, 4, 4)
|
||||
|
||||
cap_items = [vacation_shirt, wood.as_amount(999), sap.as_amount(999), pine_cone.as_amount(100), acorn.as_amount(100),
|
||||
maple_seed.as_amount(100), moss.as_amount(500), exotic_double_bed.as_amount(1)]
|
||||
cap_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.cap, cap_items, 8, 4)
|
||||
|
||||
big_grapes_items = [coconut]
|
||||
big_grapes_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.big_grapes, big_grapes_items, 4, 4)
|
||||
|
||||
obelisks_items = [earth_crystal.as_amount(10), clam.as_amount(10), coral.as_amount(10), coconut.as_amount(10), cactus_fruit.as_amount(10),
|
||||
banana.as_amount(10), dragon_tooth.as_amount(10), iridium_bar.as_amount(45)]
|
||||
obelisks_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.obelisks, obelisks_items, 8, 8)
|
||||
|
||||
burger_king_revenge_items = [fossilized_tail, void_salmon, ostrich_egg.as_amount(3), tea_leaves.as_amount(10), purple_slime_egg,
|
||||
moss_soup.as_amount(3), radioactive_ore.as_amount(5), mystic_syrup.as_amount(10), truffle, aged_crimsonfish_roe]
|
||||
burger_king_revenge_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.burger_king_revenge, burger_king_revenge_items, 8, 8)
|
||||
|
||||
trout_items = [golden_tag.as_amount(10), golden_tag.as_amount(20), golden_tag.as_amount(30)]
|
||||
trout_bundle = BundleTemplate(CCRoom.fish_tank, MemeBundleName.trout, trout_items, 1, 1)
|
||||
|
||||
eg_items = [egg, brown_egg, large_egg, large_brown_egg, duck_egg, void_egg, golden_egg, dinosaur_egg, fried_egg, ostrich_egg,
|
||||
thunder_egg, calico_egg, green_slime_egg, blue_slime_egg, purple_slime_egg, tiger_slime_egg, roe, aged_roe]
|
||||
eg_items = [item.as_amount(57) for item in eg_items]
|
||||
eg_bundle = FixedPriceBundleTemplate(CCRoom.pantry, MemeBundleName.eg, eg_items, 8, 2)
|
||||
|
||||
doctor_angler_items = [fish.as_quality(FishQuality.iridium) for fish in legendary_fish_items]
|
||||
doctor_angler_bundle = BundleTemplate(CCRoom.fish_tank, MemeBundleName.doctor_angler, doctor_angler_items, 5, 5)
|
||||
|
||||
smapi_items = [camping_stove, decorative_pot, slime_crate, supply_crate, warp_totem_qis_arena,
|
||||
artifact_spot, twig, weeds, lumber, green_rain_weeds_0, seed_spot, pot_of_gold]
|
||||
smapi_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.smapi, smapi_items, 4, 4)
|
||||
|
||||
chaos_emerald_items = [diamond, emerald, ruby, limestone, obsidian, kyanite, lemon_stone]
|
||||
chaos_emerald_bundle = FixedPriceBundleTemplate(CCRoom.crafts_room, MemeBundleName.chaos_emerald, chaos_emerald_items, 7, 7)
|
||||
|
||||
not_the_bees_items = [BundleItem(ArtisanGood.specific_honey(flower)) for flower in all_flowers]
|
||||
not_the_bees_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.not_the_bees, not_the_bees_items, 4, 4)
|
||||
|
||||
sappy_items = [golden_pumpkin, magic_rock_candy, pearl, prismatic_shard, rabbit_foot, stardrop_tea]
|
||||
sappy_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.sappy, sappy_items, 4, 4)
|
||||
|
||||
honorable_items = [stone.as_amount(1), prismatic_shard.as_amount(1)]
|
||||
honorable_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.honorable, honorable_items, 2, 1)
|
||||
|
||||
caffeinated_items = [coffee_bean.as_amount(500)]
|
||||
caffeinated_bundle = BundleTemplate(CCRoom.crafts_room, MemeBundleName.caffeinated, caffeinated_items, 1, 1)
|
||||
|
||||
hats_off_to_you_items = [living_hat, garbage_hat, golden_helmet, laurel_wreath_crown, joja_cap,
|
||||
deluxe_pirate_hat, dark_cowboy_hat, tiger_hat, mystery_hat, dark_ballcap]
|
||||
hats_off_to_you_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.hats_off_to_you, hats_off_to_you_items, 8, 2)
|
||||
|
||||
speedrunners_items = [parsnip, wine, cheese, sea_urchin, lucky_purple_shorts, mayonnaise]
|
||||
speedrunners_bundle = FixedPriceBundleTemplate(CCRoom.pantry, MemeBundleName.speedrunners, speedrunners_items, 6, 6)
|
||||
|
||||
snitch_items = [lucky_purple_shorts]
|
||||
snitch_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.snitch, snitch_items, 1, 1)
|
||||
|
||||
mermaid_items = [pearl, clam.as_amount(2), mermaid_pendant, mermaid_boots, flute_block.as_amount(5)]
|
||||
mermaid_bundle = FixedPriceBundleTemplate(CCRoom.fish_tank, MemeBundleName.mermaid, mermaid_items, 5, 5)
|
||||
|
||||
commitment_items = [bouquet, mermaid_pendant, wilted_bouquet, ancient_doll.as_amount(2)]
|
||||
commitment_bundle_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.commitment, commitment_items, 4, 4)
|
||||
|
||||
all_simple_items = [all_bundle_items_by_name[bundle_item_name] for bundle_item_name in all_bundle_items_by_name if
|
||||
all_bundle_items_by_name[bundle_item_name].amount == 1 and
|
||||
all_bundle_items_by_name[bundle_item_name].quality.startswith("Basic") and
|
||||
all_bundle_items_by_name[bundle_item_name].flavor is None and
|
||||
bundle_item_name != "Honey"]
|
||||
|
||||
permit_a38_items = [*all_simple_items]
|
||||
permit_a38_bundle = BureaucracyBundleTemplate(CCRoom.vault, MemeBundleName.permit_a38, permit_a38_items, 1, 8)
|
||||
|
||||
journalist_items = [*all_simple_items]
|
||||
journalist_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.journalist, journalist_items, 1, 1)
|
||||
|
||||
trap_items = [BundleItem(MemeItem.trap)]
|
||||
trap_bundle = FixedSlotsBundleTemplate(CCRoom.bulletin_board, MemeBundleName.trap, trap_items, 4, 4)
|
||||
|
||||
off_your_back_items = [BundleItem(MemeItem.worn_hat), BundleItem(MemeItem.worn_shirt), BundleItem(MemeItem.worn_pants),
|
||||
BundleItem(MemeItem.worn_boots), BundleItem(MemeItem.worn_left_ring), BundleItem(MemeItem.worn_right_ring)]
|
||||
off_your_back_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.off_your_back, off_your_back_items, 6, 6)
|
||||
|
||||
sisyphus_items = [stone.as_amount(1)]
|
||||
sisyphus_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.sisyphus, sisyphus_items, 12, 12)
|
||||
|
||||
vocaloid_items = [spring_onion, orange, banana, tuna, wine, ice_cream, carrot, bread, eggplant]
|
||||
vocaloid_items = [item.as_amount(10) for item in vocaloid_items]
|
||||
vocaloid_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.vocaloid, vocaloid_items, 6, 6)
|
||||
|
||||
legendairy_items = [legend, legend_roe, legend_bait, smoked_legend, aged_legend_roe,
|
||||
milk.as_amount(10), cheese.as_amount(10), goat_milk.as_amount(10), goat_cheese.as_amount(10)]
|
||||
legendairy_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.legendairy, legendairy_items, 6, 4)
|
||||
|
||||
kent_c_items = [broken_glasses.as_amount(5), refined_quartz.as_amount(10)]
|
||||
kent_c_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.kent_c, kent_c_items, 2, 2)
|
||||
|
||||
fruit_items = [tomato, pumpkin, summer_squash, eggplant, hot_pepper]
|
||||
fruit_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.fruit, fruit_items, 5, 5)
|
||||
|
||||
reverse_items = [*all_simple_items]
|
||||
reverse_bundle = FixedSlotsBundleTemplate(CCRoom.crafts_room, MemeBundleName.reverse, reverse_items, 4, 4)
|
||||
|
||||
bundle_items = [*all_simple_items]
|
||||
bundle_bundle = RecursiveBundleTemplate(CCRoom.fish_tank, MemeBundleName.bundle, bundle_items, 16, 16, 4)
|
||||
|
||||
bun_dle_items = [strange_bun, bread, tortilla, rabbit_foot]
|
||||
bun_dle_bundle = BundleTemplate(CCRoom.pantry, MemeBundleName.bun_dle, bun_dle_items, 4, 4)
|
||||
|
||||
celeste_items = [strawberry.as_amount(175), strawberry_seeds.as_amount(4), strawberry.as_quality(CropQuality.gold).as_amount(26)]
|
||||
celeste_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.celeste, celeste_items, 3, 3)
|
||||
|
||||
automation_items = [copper_bar.as_amount(15), iron_bar.as_amount(36), iron_bar.as_amount(20), copper_bar.as_amount(10)]
|
||||
automation_bundle = FixedPriceBundleTemplate(CCRoom.boiler_room, MemeBundleName.automation, automation_items, 4, 4)
|
||||
|
||||
animal_well_items = [rare_disc, bone_flute, ruby_crystal_ball, cherry_bomb.as_amount(1), candle_lamp, modern_lamp, advanced_tv_remote]
|
||||
animal_well_bundle = FixedPriceBundleTemplate(CCRoom.pantry, MemeBundleName.animal_well, animal_well_items, 7, 7)
|
||||
|
||||
schrodinger_items = [*all_simple_items]
|
||||
schrodinger_bundle = FixedPriceBundleTemplate(CCRoom.fish_tank, MemeBundleName.schrodinger, schrodinger_items, 2, 1)
|
||||
|
||||
ikea_craftables = [Machine.mayonnaise_machine, Machine.bee_house, Machine.preserves_jar, Machine.cheese_press, Machine.keg, Machine.fish_smoker,
|
||||
Machine.crystalarium, Machine.worm_bin, Furniture.tub_o_flowers]
|
||||
ikea_items = [BundleItem(craftable) for craftable in ikea_craftables]
|
||||
ikea_bundle = FixedPriceBundleTemplate(CCRoom.crafts_room, MemeBundleName.ikea, ikea_items, 1, 1)
|
||||
|
||||
this_is_fine_items = [coffee, fire_quartz, fire_quartz, fire_quartz, fire_quartz, fire_quartz, fire_quartz, fire_quartz]
|
||||
this_is_fine_bundle = FixedPriceBundleTemplate(CCRoom.crafts_room, MemeBundleName.this_is_fine, this_is_fine_items, 8, 8)
|
||||
|
||||
crap_pot_items = [clay, mudstone, truffle, sunflower_seeds, roasted_hazelnuts, plum_pudding, rotten_plant, taro_root]
|
||||
crap_pot_bundle = BundleTemplate(CCRoom.boiler_room, MemeBundleName.crap_pot, crap_pot_items, 4, 4)
|
||||
|
||||
emmalution_items = [garlic, bread, trash, goblin_mask, rain_totem]
|
||||
emmalution_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.emmalution, emmalution_items, 5, 5)
|
||||
|
||||
unused_balls = [fairy_rose, melon, grape, geode, ancient_seed, crystal_ball, peach]
|
||||
yellow_pool_balls = [item.as_amount(1) for item in [solar_essence, topaz_crystal_ball, pizza, apricot, gold_ore, golden_coconut, pufferfish, lucky_lunch]]
|
||||
blue_pool_balls = [item.as_amount(2) for item in [blue_jazz, blueberry, powdermelon, ancient_fruit, iridium_ore, aquamarine, opal, broken_cd]]
|
||||
red_pool_balls = [item.as_amount(3) for item in [tomato, mega_bomb, magma_geode, apple, explosive_ammo, cranberries, cherry_bomb]]
|
||||
purple_pool_balls = [item.as_amount(4) for item in [red_cabbage, pomegranate, void_essence, wild_plum]]
|
||||
orange_pool_balls = [item.as_amount(5) for item in [pumpkin, orange, tigerseye]]
|
||||
green_pool_balls = [item.as_amount(6) for item in [cauliflower, jamborite, salad, cactus_fruit, radioactive_ore]]
|
||||
brown_pool_balls = [item.as_amount(7) for item in [acorn, coconut, hazelnut, maple_bar, maple_syrup, potato, truffle, yam]]
|
||||
black_pool_balls = [item.as_amount(8) for item in [bomb, coal, void_egg]]
|
||||
pool_items = [yellow_pool_balls, blue_pool_balls, red_pool_balls, purple_pool_balls, orange_pool_balls, green_pool_balls, brown_pool_balls, black_pool_balls]
|
||||
pool_bundle = FixedPriceDeepBundleTemplate(CCRoom.boiler_room, MemeBundleName.pool, pool_items, 8, 8)
|
||||
|
||||
argonmatrix_items = [radish.as_amount(32), radish.as_amount(87), melon.as_amount(127), chocolate_cake.as_amount(3), cactus_fruit.as_amount(1)]
|
||||
argonmatrix_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.argonmatrix, argonmatrix_items, 5, 5)
|
||||
|
||||
frazzleduck_items = [duck_egg, duck_feather, eggplant, green_jacket_shirt]
|
||||
frazzleduck_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.frazzleduck, frazzleduck_items, 4, 4)
|
||||
|
||||
loser_club_items = [tuna]
|
||||
loser_club_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.loser_club, loser_club_items, 1, 1)
|
||||
|
||||
ministry_items = [item.as_amount(999) for item in [trash, joja_cola, broken_glasses, broken_cd, soggy_newspaper]]
|
||||
ministry_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.ministry_of_madness, ministry_items, 4, 1)
|
||||
|
||||
pomnut_items = [pomegranate, hazelnut, carrot]
|
||||
pomnut_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.pomnut, pomnut_items, 3, 3)
|
||||
|
||||
blossom_garden_items = [banana.as_amount(18), pizza.as_amount(32), spaghetti, single_bed, pink_cake, wood_floor, triple_shot_espresso, maple_bar, bug_steak, void_essence.as_amount(10), crystal_ball, solar_essence.as_amount(10)]
|
||||
blossom_garden_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.blossom_garden, blossom_garden_items, 12, 6)
|
||||
|
||||
cooperation_items = [*all_simple_items]
|
||||
cooperation_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.cooperation, cooperation_items, 4, 4)
|
||||
|
||||
doctor_items = [apple.as_amount(365)]
|
||||
doctor_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.doctor, doctor_items, 1, 1)
|
||||
|
||||
very_sticky_items = [sap.as_amount(125), sap.as_amount(125), sap.as_amount(125), sap.as_amount(125)]
|
||||
very_sticky_bundle = FixedPriceBundleTemplate(CCRoom.crafts_room, MemeBundleName.very_sticky, very_sticky_items, 4, 4)
|
||||
|
||||
square_hole_items = [*all_simple_items]
|
||||
square_hole_bundle = FixedPriceBundleTemplate(CCRoom.bulletin_board, MemeBundleName.square_hole, square_hole_items, 6, 6)
|
||||
|
||||
distracted_items = [*all_simple_items] # (If you bring more than one item for it, the rest get sent home)
|
||||
distracted_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.distracted, distracted_items, 4, 4)
|
||||
|
||||
algorerhythm_items =[item.as_amount(2) for item in
|
||||
[midnight_squid_roe, tea_set, statue_of_endless_fortune, golden_bobber, dried_qi_fruit, cursed_mannequin,
|
||||
statue_of_blessings, crane_house_plant, book_of_mysteries, far_away_stone, void_ghost_pendant, trimmed_purple_shorts]]
|
||||
algorerhythm_bundle = BundleTemplate(CCRoom.bulletin_board, MemeBundleName.algorerhythm, algorerhythm_items, 12, 4)
|
||||
|
||||
|
||||
red_fish_items = [red_mullet, red_snapper, lava_eel, crimsonfish]
|
||||
blue_fish_items = [anchovy, tuna, sardine, bream, squid, ice_pip, albacore, blue_discus, midnight_squid, spook_fish, glacierfish]
|
||||
other_fish = [pufferfish, largemouth_bass, smallmouth_bass, rainbow_trout, walleye, perch, carp, catfish, pike, sunfish, herring, eel, octopus, sea_cucumber,
|
||||
super_cucumber, ghostfish, stonefish, sandfish, scorpion_carp, flounder, midnight_carp, tigerseye, bullhead, tilapia, chub, dorado, shad,
|
||||
lingcod, halibut, slimejack, stingray, goby, blobfish, angler, legend, mutant_carp]
|
||||
dr_seuss_items = [other_fish, [fish.as_amount(2) for fish in other_fish], red_fish_items, blue_fish_items]
|
||||
dr_seuss_bundle = FixedPriceDeepBundleTemplate(CCRoom.crafts_room, MemeBundleName.dr_seuss, dr_seuss_items, 4, 4)
|
||||
|
||||
pollution_items = [trash, broken_cd, broken_glasses, joja_cola, soggy_newspaper, battery_pack]
|
||||
pollution_bundle = BundleTemplate(CCRoom.fish_tank, MemeBundleName.pollution, pollution_items, 4, 4)
|
||||
|
||||
all_fish_item_names = sorted(list(set([item.item_name for item in [*spring_fish_items, *summer_fish_items, *fall_fish_items, *winter_fish_items]])))
|
||||
all_fish_items = [BundleItem(item).as_amount(1).as_quality(FishQuality.basic) for item in all_fish_item_names]
|
||||
catch_and_release_items = [*all_fish_items]
|
||||
catch_and_release_bundle = BundleTemplate(CCRoom.fish_tank, MemeBundleName.catch_and_release, catch_and_release_items, 4, 4)
|
||||
|
||||
vampire_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.vampire, BundleItem(MemeCurrency.blood, 200))
|
||||
exhaustion_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.exhaustion, BundleItem(MemeCurrency.energy, 400))
|
||||
tick_tock_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.tick_tock, BundleItem(MemeCurrency.time, 1440))
|
||||
archipela_go_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.archipela_go, BundleItem(MemeCurrency.steps, 20000))
|
||||
clique_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.clique, BundleItem(MemeCurrency.clic, 1))
|
||||
cookie_clicker_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.cookie_clicker, BundleItem(MemeCurrency.cookies, 200000))
|
||||
communism_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.communism, BundleItem.money_bundle(1))
|
||||
death_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.death, death)
|
||||
flashbang_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.flashbang, BundleItem.money_bundle(0))
|
||||
connection_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.connection, BundleItem.money_bundle(0))
|
||||
reconnection_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.reconnection, BundleItem.money_bundle(0))
|
||||
nft_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.nft, BundleItem.money_bundle(0))
|
||||
firstborn_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.firstborn, BundleItem(MemeCurrency.child, 1))
|
||||
restraint_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.restraint, BundleItem.money_bundle(0))
|
||||
fast_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.fast, BundleItem(MemeCurrency.time_elapsed, 1000))
|
||||
floor_is_lava_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.floor_is_lava, BundleItem.money_bundle(0))
|
||||
joetg_bundle = CurrencyBundleTemplate(CCRoom.bulletin_board, MemeBundleName.joetg, BundleItem(MemeCurrency.dead_pumpkins, 750))
|
||||
bad_farmer_bundle = CurrencyBundleTemplate(CCRoom.pantry, MemeBundleName.bad_farmer, BundleItem(MemeCurrency.dead_crops, 400))
|
||||
bad_fisherman_bundle = CurrencyBundleTemplate(CCRoom.fish_tank, MemeBundleName.bad_fisherman, BundleItem(MemeCurrency.missed_fish, 20))
|
||||
honeywell_bundle = CurrencyBundleTemplate(CCRoom.bulletin_board, MemeBundleName.honeywell, BundleItem(MemeCurrency.honeywell, 1))
|
||||
gacha_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.gacha, BundleItem.money_bundle(10000))
|
||||
hibernation_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.hibernation, BundleItem(MemeCurrency.sleep_days, 60))
|
||||
crowdfunding_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.crowdfunding, BundleItem(MemeCurrency.bank_money, 10000))
|
||||
clickbait_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.clickbait, BundleItem.money_bundle(100))
|
||||
puzzle_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.puzzle, BundleItem.money_bundle(10))
|
||||
asmr_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.asmr, BundleItem.money_bundle(0))
|
||||
humble_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.humble, BundleItem.money_bundle(5000))
|
||||
deathlink_bundle = CurrencyBundleTemplate(CCRoom.boiler_room, MemeBundleName.deathlink, BundleItem(MemeCurrency.deathlinks, 10))
|
||||
investment_bundle = CurrencyBundleTemplate(CCRoom.vault, MemeBundleName.scam, BundleItem.money_bundle(10000))
|
||||
stanley_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.stanley, BundleItem.money_bundle(9999999))
|
||||
hairy_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.vault, MemeBundleName.hairy, BundleItem.money_bundle(0))
|
||||
# colored_crystals_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.boiler_room, MemeBundleName.colored_crystals, BundleItem.money_bundle(10))
|
||||
hint_bundle = FixedPriceCurrencyBundleTemplate(CCRoom.bulletin_board, MemeBundleName.hint, BundleItem.money_bundle(10))
|
||||
sacrifice_bundle = CurrencyBundleTemplate(CCRoom.boiler_room, MemeBundleName.sacrifice, BundleItem(MemeCurrency.goat, 1))
|
||||
|
||||
# Stopped at 49 responses on the form
|
||||
|
||||
# Todo Bundles
|
||||
# Acrostic Bundle (Asks for a specific word, you need to donate an item for each letter)
|
||||
# Bubbles Bundle
|
||||
# Cipher Bundle (Some sort of code?)
|
||||
# DLC Bundle
|
||||
# Doom Bundle
|
||||
# Dragonball Bundle
|
||||
# Empty Bundle (donate empty inventory spot)
|
||||
# Friendship Bundle (Show some NPCs, gotta donate a loved gift for each of them)
|
||||
# GeoGessr Bundle
|
||||
# Ghost Bundle (it ghosts you)
|
||||
# Joja/Morris Bundle
|
||||
# Leaf Blower Bundle (Leaf Blower Minigame, similar to the cookie clicker one)
|
||||
# Lingo Bundle
|
||||
# Lost Axe Bundle (Donate your axe then talk to Robin)
|
||||
# Maguffin Bundle (Ap items)
|
||||
# Millibelle Bundle (money, run away, find at spa)
|
||||
# Minesweeper bundle (donate bombs on correct spots)
|
||||
# Pico-8 Bundle
|
||||
# Pollution Bundle
|
||||
# QA Bundle (Some sort of bug, not sure yet)
|
||||
# Relay Bundle (Relay Stick passed around the multiworld)
|
||||
# Robin's Lost Axe Bundle (Give your axe, then Robin brings it back to you)
|
||||
# Scavenger Bundle (The bundle moves around the map and you need to keep finding it)
|
||||
# Side Quest Bundle (Sends you on side quests to talk to random NPCs several times)
|
||||
# Therapy Bundle
|
||||
# Torrent Bundle (someone must seed it for you)
|
||||
# Witness Bundle
|
||||
# Change Cap Bundle to forgetting something at home
|
||||
|
||||
|
||||
|
||||
# Bundles that need special Mod Handling:
|
||||
# None
|
||||
|
||||
pantry_bundles_meme = [hurricane_tortilla_bundle, look_at_chickens_bundle, lemonade_stand_bundle, what_the_rock_is_cooking_bundle, sunmaid_bundle,
|
||||
big_grapes_bundle, eg_bundle, not_the_bees_bundle, speedrunners_bundle, bun_dle_bundle, animal_well_bundle, bad_farmer_bundle]
|
||||
pantry_meme = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_meme, 6)
|
||||
|
||||
crafts_room_bundles_meme = [AAAA_bundle, anything_for_beyonce_bundle, potato_bundle, chaos_emerald_bundle, caffeinated_bundle, reverse_bundle,
|
||||
ikea_bundle, this_is_fine_bundle, very_sticky_bundle, dr_seuss_bundle]
|
||||
crafts_room_meme = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_meme, 6)
|
||||
|
||||
fish_tank_bundles_meme = [crab_rave_bundle, trout_bundle, doctor_angler_bundle, mermaid_bundle, legendairy_bundle, kent_c_bundle, bundle_bundle,
|
||||
schrodinger_bundle, bad_fisherman_bundle, pollution_bundle, catch_and_release_bundle]
|
||||
fish_tank_meme = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_meme, 6)
|
||||
|
||||
boiler_room_bundles_meme = [amons_fall_bundle, screw_you_bundle, rick_bundle, minecraft_bundle, balls_bundle, tilesanity_bundle, obelisks_bundle,
|
||||
honorable_bundle, sisyphus_bundle, automation_bundle, crap_pot_bundle, deathlink_bundle, pool_bundle, # colored_crystals_bundle,
|
||||
sacrifice_bundle]
|
||||
boiler_room_meme = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_meme, 3)
|
||||
|
||||
bulletin_board_bundles_meme = [burger_king_bundle, romance_bundle, burger_king_revenge_bundle, smapi_bundle, sappy_bundle, hats_off_to_you_bundle,
|
||||
snitch_bundle, commitment_bundle_bundle, journalist_bundle, trap_bundle, off_your_back_bundle, vocaloid_bundle, fruit_bundle,
|
||||
celeste_bundle, cap_bundle, emmalution_bundle, joetg_bundle, honeywell_bundle, cooperation_bundle, square_hole_bundle,
|
||||
ministry_bundle, loser_club_bundle, frazzleduck_bundle, argonmatrix_bundle, pomnut_bundle, blossom_garden_bundle, doctor_bundle,
|
||||
hint_bundle, algorerhythm_bundle, distracted_bundle]
|
||||
bulletin_board_meme = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_meme, 5)
|
||||
|
||||
vault_bundles_meme = [capitalist_bundle, death_bundle, permit_a38_bundle, vampire_bundle, exhaustion_bundle,
|
||||
tick_tock_bundle, archipela_go_bundle, clique_bundle, cookie_clicker_bundle, communism_bundle,
|
||||
flashbang_bundle, connection_bundle, reconnection_bundle, nft_bundle, firstborn_bundle, restraint_bundle, fast_bundle,
|
||||
floor_is_lava_bundle, gacha_bundle, hibernation_bundle, crowdfunding_bundle, clickbait_bundle,
|
||||
humble_bundle, puzzle_bundle, asmr_bundle, investment_bundle, stanley_bundle, hairy_bundle]
|
||||
vault_meme = BundleRoomTemplate(CCRoom.vault, vault_bundles_meme, 4)
|
||||
|
||||
all_cc_meme_bundles = [*pantry_bundles_meme, *crafts_room_bundles_meme, *fish_tank_bundles_meme,
|
||||
*boiler_room_bundles_meme, *bulletin_board_bundles_meme, *vault_bundles_meme]
|
||||
community_center_meme_bundles = BundleRoomTemplate("Community Center", all_cc_meme_bundles, 30)
|
||||
@@ -0,0 +1,92 @@
|
||||
import math
|
||||
from typing import Dict, List
|
||||
|
||||
from ..bundle_items_data import *
|
||||
from ....bundles.bundle_item import BundleItem
|
||||
from ....strings.quality_names import ArtisanQuality
|
||||
|
||||
capitalist_value = 1000000
|
||||
ancient_fruit_wines = {ArtisanQuality.basic: 2310, ArtisanQuality.silver: 2886, ArtisanQuality.gold: 3465, ArtisanQuality.iridium: 4620}
|
||||
starfruit_wines = {ArtisanQuality.basic: 3150, ArtisanQuality.silver: 3936, ArtisanQuality.gold: 4725, ArtisanQuality.iridium: 6300}
|
||||
rhubarb_wines = {ArtisanQuality.silver: 1155, ArtisanQuality.gold: 1386, ArtisanQuality.iridium: 1848}
|
||||
melon_wines = {ArtisanQuality.basic: 1050, ArtisanQuality.silver: 1311, ArtisanQuality.gold: 1575, ArtisanQuality.iridium: 2100}
|
||||
pineapple_wines = {ArtisanQuality.basic: 1260, ArtisanQuality.silver: 1575, ArtisanQuality.gold: 1890, ArtisanQuality.iridium: 2520}
|
||||
starfruits = {ArtisanQuality.silver: 1030, ArtisanQuality.gold: 1237, ArtisanQuality.iridium: 1650}
|
||||
sweet_gem_berries = {ArtisanQuality.basic: 3000, ArtisanQuality.silver: 3750, ArtisanQuality.gold: 4500, ArtisanQuality.iridium: 6000}
|
||||
|
||||
# These are just too rude I think
|
||||
# cherry_saplings = {ArtisanQuality.silver: 1062, ArtisanQuality.gold: 1275, ArtisanQuality.iridium: 1700}
|
||||
# banana_saplings = {ArtisanQuality.silver: 1062, ArtisanQuality.gold: 1275, ArtisanQuality.iridium: 1700}
|
||||
# mango_saplings = {ArtisanQuality.silver: 1062, ArtisanQuality.gold: 1275, ArtisanQuality.iridium: 1700}
|
||||
# orange_saplings = {ArtisanQuality.silver: 1250, ArtisanQuality.gold: 1500, ArtisanQuality.iridium: 2000}
|
||||
# peach_saplings = {ArtisanQuality.basic: 1500, ArtisanQuality.silver: 1875, ArtisanQuality.gold: 2250, ArtisanQuality.iridium: 3000}
|
||||
# apple_saplings = {ArtisanQuality.silver: 1250, ArtisanQuality.gold: 1500, ArtisanQuality.iridium: 2000}
|
||||
# pomegranate_saplings = {ArtisanQuality.basic: 1500, ArtisanQuality.silver: 1875, ArtisanQuality.gold: 2250, ArtisanQuality.iridium: 3000}
|
||||
|
||||
|
||||
def get_capitalist_item(item: BundleItem, quality: str, value: int) -> BundleItem:
|
||||
amount = math.ceil(capitalist_value / value)
|
||||
assert amount < 1000
|
||||
return item.as_quality(quality).as_amount(amount)
|
||||
|
||||
|
||||
def get_capitalist_items(item: BundleItem, values_by_quality: Dict[str, int]) -> List[BundleItem]:
|
||||
return [get_capitalist_item(item, quality, values_by_quality[quality]) for quality in values_by_quality]
|
||||
|
||||
|
||||
capitalist_items = [
|
||||
*get_capitalist_items(ancient_fruit_wine, ancient_fruit_wines),
|
||||
get_capitalist_item(dried_ancient_fruit, ArtisanQuality.basic, 5810),
|
||||
get_capitalist_item(ancient_fruit_jelly, ArtisanQuality.basic, 1610),
|
||||
get_capitalist_item(ancient_fruit, ArtisanQuality.iridium, 1210),
|
||||
|
||||
*get_capitalist_items(starfruit_wine, starfruit_wines),
|
||||
get_capitalist_item(dried_starfruit, ArtisanQuality.basic, 7910),
|
||||
get_capitalist_item(starfruit_jelly, ArtisanQuality.basic, 2170),
|
||||
*get_capitalist_items(starfruit, starfruits),
|
||||
|
||||
*get_capitalist_items(rhubarb_wine, rhubarb_wines),
|
||||
get_capitalist_item(dried_rhubarb, ArtisanQuality.basic, 2345),
|
||||
*get_capitalist_items(melon_wine, melon_wines),
|
||||
get_capitalist_item(dried_melon, ArtisanQuality.basic, 2660),
|
||||
*get_capitalist_items(pineapple_wine, pineapple_wines),
|
||||
|
||||
get_capitalist_item(dried_pineapple, ArtisanQuality.basic, 3185),
|
||||
get_capitalist_item(dried_banana, ArtisanQuality.basic, 1610),
|
||||
get_capitalist_item(strawberry_wine, ArtisanQuality.iridium, 1008),
|
||||
get_capitalist_item(dried_strawberry, ArtisanQuality.basic, 1295),
|
||||
|
||||
*get_capitalist_items(sweet_gem_berry, sweet_gem_berries),
|
||||
get_capitalist_item(pumpkin_juice, ArtisanQuality.basic, 1008),
|
||||
|
||||
get_capitalist_item(goat_cheese, ArtisanQuality.iridium, 1120),
|
||||
get_capitalist_item(golden_egg, ArtisanQuality.iridium, 1200),
|
||||
get_capitalist_item(dinosaur_mayo, ArtisanQuality.basic, 1120),
|
||||
get_capitalist_item(truffle_oil, ArtisanQuality.basic, 1491),
|
||||
get_capitalist_item(truffle, ArtisanQuality.iridium, 1250),
|
||||
|
||||
get_capitalist_item(aged_lava_eel_roe, ArtisanQuality.basic, 1064),
|
||||
get_capitalist_item(aged_crimsonfish_roe, ArtisanQuality.basic, 2184),
|
||||
get_capitalist_item(aged_angler_roe, ArtisanQuality.basic, 1344),
|
||||
get_capitalist_item(legend_roe, ArtisanQuality.basic, 2530),
|
||||
get_capitalist_item(aged_legend_roe, ArtisanQuality.basic, 7084),
|
||||
get_capitalist_item(aged_glacierfish_roe, ArtisanQuality.basic, 1484),
|
||||
get_capitalist_item(aged_mutant_carp_roe, ArtisanQuality.basic, 1484),
|
||||
|
||||
get_capitalist_item(iridium_bar, ArtisanQuality.basic, 1500),
|
||||
get_capitalist_item(radioactive_bar, ArtisanQuality.basic, 4500),
|
||||
get_capitalist_item(prismatic_shard, ArtisanQuality.basic, 2600),
|
||||
|
||||
get_capitalist_item(mystic_syrup, ArtisanQuality.basic, 1250),
|
||||
|
||||
# *get_capitalist_items(cherry_sapling, cherry_saplings),
|
||||
# *get_capitalist_items(banana_sapling, banana_saplings),
|
||||
# *get_capitalist_items(mango_sapling, mango_saplings),
|
||||
# *get_capitalist_items(orange_sapling, orange_saplings),
|
||||
# *get_capitalist_items(peach_sapling, peach_saplings),
|
||||
# *get_capitalist_items(apple_sapling, apple_saplings),
|
||||
# *get_capitalist_items(pomegranate_sapling, pomegranate_saplings),
|
||||
|
||||
bowler_hat,
|
||||
sombrero,
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
from .remixed_bundles import *
|
||||
|
||||
all_cc_remixed_bundles = [*crafts_room_bundles_remixed, *pantry_bundles_remixed, *fish_tank_bundles_remixed,
|
||||
*boiler_room_bundles_remixed, *bulletin_board_bundles_remixed, *vault_bundles_remixed]
|
||||
community_center_remixed_anywhere = BundleRoomTemplate("Community Center", all_cc_remixed_bundles, 30)
|
||||
245
worlds/stardew_valley/data/bundles_data/remixed_bundles.py
Normal file
245
worlds/stardew_valley/data/bundles_data/remixed_bundles.py
Normal file
@@ -0,0 +1,245 @@
|
||||
from .thematic_bundles import *
|
||||
from ...bundles.bundle import IslandBundleTemplate, FestivalBundleTemplate, CurrencyBundleTemplate
|
||||
from ...bundles.bundle_room import BundleRoomTemplate
|
||||
from ...content import content_packs
|
||||
from ...strings.bundle_names import CCRoom
|
||||
|
||||
# Giant Stump
|
||||
from ...strings.quality_names import ForageQuality, FishQuality
|
||||
|
||||
giant_stump_bundles_remixed = giant_stump_bundles_thematic
|
||||
giant_stump_remixed = BundleRoomTemplate(CCRoom.raccoon_requests, giant_stump_bundles_remixed, 8)
|
||||
|
||||
# Crafts Room
|
||||
|
||||
beach_foraging_items = [nautilus_shell, coral, sea_urchin, rainbow_shell, clam, cockle, mussel, oyster, seaweed]
|
||||
beach_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.beach_foraging, beach_foraging_items, 4, 4)
|
||||
|
||||
mines_foraging_items = [quartz, earth_crystal, frozen_tear, fire_quartz, red_mushroom, purple_mushroom, cave_carrot]
|
||||
mines_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.mines_foraging, mines_foraging_items, 4, 4)
|
||||
|
||||
desert_foraging_items = [cactus_fruit.as_quality(ForageQuality.gold), cactus_fruit.as_amount(5), coconut.as_quality(ForageQuality.gold), coconut.as_amount(5)]
|
||||
desert_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.desert_foraging, desert_foraging_items, 2, 2)
|
||||
|
||||
island_foraging_items = [ginger.as_amount(5), magma_cap.as_quality(ForageQuality.gold), magma_cap.as_amount(5),
|
||||
fiddlehead_fern.as_quality(ForageQuality.gold), fiddlehead_fern.as_amount(5)]
|
||||
island_foraging_bundle = IslandBundleTemplate(CCRoom.crafts_room, BundleName.island_foraging, island_foraging_items, 2, 2)
|
||||
|
||||
sticky_items = [sap.as_amount(500), sap.as_amount(500)]
|
||||
sticky_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.sticky, sticky_items, 1, 1)
|
||||
|
||||
forest_items = [moss.as_amount(10), fiber.as_amount(200), acorn.as_amount(10), maple_seed.as_amount(10), pine_cone.as_amount(10), mahogany_seed,
|
||||
mushroom_tree_seed, mossy_seed.as_amount(5), mystic_tree_seed]
|
||||
forest_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.forest, forest_items, 4, 2)
|
||||
|
||||
wild_medicine_items = [item.as_amount(5) for item in [purple_mushroom, fiddlehead_fern, white_algae, hops, blackberry, dandelion]]
|
||||
wild_medicine_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.wild_medicine, wild_medicine_items, 4, 3)
|
||||
|
||||
quality_foraging_items = sorted({item.as_quality(ForageQuality.gold).as_amount(3)
|
||||
for item in
|
||||
[*spring_foraging_items_thematic, *summer_foraging_items_thematic, *fall_foraging_items_thematic,
|
||||
*winter_foraging_items_thematic, *beach_foraging_items, *desert_foraging_items, magma_cap] if item.can_have_quality})
|
||||
quality_foraging_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.quality_foraging, quality_foraging_items, 4, 3)
|
||||
|
||||
green_rain_items = [moss.as_amount(200), fiber.as_amount(200), mossy_seed.as_amount(20), fiddlehead_fern.as_amount(10)]
|
||||
green_rain_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.green_rain, green_rain_items, 4, 3)
|
||||
|
||||
totems_items = [warp_totem_beach.as_amount(5), warp_totem_mountains.as_amount(5), warp_totem_farm.as_amount(5), warp_totem_desert.as_amount(5),
|
||||
warp_totem_island.as_amount(5), rain_totem.as_amount(5), treasure_totem.as_amount(5)]
|
||||
totems_bundle = BundleTemplate(CCRoom.crafts_room, BundleName.totems, totems_items, 4, 3)
|
||||
|
||||
crafts_room_bundles_remixed = [*crafts_room_bundles_thematic, beach_foraging_bundle, mines_foraging_bundle, desert_foraging_bundle,
|
||||
island_foraging_bundle, sticky_bundle, forest_bundle, wild_medicine_bundle, quality_foraging_bundle, green_rain_bundle]
|
||||
crafts_room_remixed = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_remixed, 6)
|
||||
|
||||
# Pantry
|
||||
|
||||
rare_crops_items = [ancient_fruit, sweet_gem_berry]
|
||||
rare_crops_bundle = BundleTemplate(CCRoom.pantry, BundleName.rare_crops, rare_crops_items, 2, 2)
|
||||
|
||||
# all_specific_roes = [BundleItem(AnimalProduct.roe, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fish]
|
||||
fish_farmer_items = [roe.as_amount(15), aged_roe.as_amount(5), squid_ink, caviar.as_amount(5)]
|
||||
fish_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.fish_farmer, fish_farmer_items, 3, 2)
|
||||
|
||||
garden_items = [tulip, blue_jazz, summer_spangle, sunflower, fairy_rose, poppy, bouquet]
|
||||
garden_bundle = BundleTemplate(CCRoom.pantry, BundleName.garden, garden_items, 5, 4)
|
||||
|
||||
brewer_items = [mead, pale_ale, wine, juice, green_tea, beer]
|
||||
brewer_bundle = BundleTemplate(CCRoom.pantry, BundleName.brewer, brewer_items, 5, 4)
|
||||
|
||||
orchard_items = [apple, apricot, orange, peach, pomegranate, cherry, banana, mango]
|
||||
orchard_bundle = BundleTemplate(CCRoom.pantry, BundleName.orchard, orchard_items, 6, 4)
|
||||
|
||||
island_crops_items = [pineapple, taro_root, banana, mango]
|
||||
island_crops_bundle = IslandBundleTemplate(CCRoom.pantry, BundleName.island_crops, island_crops_items, 3, 3)
|
||||
|
||||
agronomist_items = [basic_fertilizer, quality_fertilizer, deluxe_fertilizer,
|
||||
basic_retaining_soil, quality_retaining_soil, deluxe_retaining_soil,
|
||||
speed_gro, deluxe_speed_gro, hyper_speed_gro, tree_fertilizer]
|
||||
agronomist_bundle = BundleTemplate(CCRoom.pantry, BundleName.agronomist, agronomist_items, 4, 3)
|
||||
|
||||
slime_farmer_items = [slime.as_amount(99), petrified_slime.as_amount(10), blue_slime_egg, red_slime_egg,
|
||||
purple_slime_egg, green_slime_egg, tiger_slime_egg]
|
||||
slime_farmer_bundle = BundleTemplate(CCRoom.pantry, BundleName.slime_farmer, slime_farmer_items, 4, 3)
|
||||
|
||||
sommelier_items = [BundleItem(ArtisanGood.wine, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits]
|
||||
sommelier_bundle = BundleTemplate(CCRoom.pantry, BundleName.sommelier, sommelier_items, 6, 3)
|
||||
|
||||
dry_items = [*[BundleItem(ArtisanGood.dried_fruit, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits],
|
||||
*[BundleItem(ArtisanGood.dried_mushroom, flavor=mushroom, source=BundleItem.Sources.content) for mushroom in all_edible_mushrooms],
|
||||
BundleItem(ArtisanGood.raisins, source=BundleItem.Sources.content)]
|
||||
dry_bundle = BundleTemplate(CCRoom.pantry, BundleName.dry, dry_items, 6, 3)
|
||||
|
||||
pantry_bundles_remixed = [*pantry_bundles_thematic, rare_crops_bundle, fish_farmer_bundle, garden_bundle,
|
||||
brewer_bundle, orchard_bundle, island_crops_bundle, agronomist_bundle, slime_farmer_bundle, sommelier_bundle, dry_bundle]
|
||||
pantry_remixed = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_remixed, 6)
|
||||
|
||||
# Fish Tank
|
||||
trash_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.trash, crab_pot_trash_items, 4, 4)
|
||||
|
||||
spring_fish_items = [herring, halibut, shad, flounder, sunfish, sardine, catfish, anchovy, smallmouth_bass, eel, legend]
|
||||
spring_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.spring_fish, spring_fish_items, 4, 4)
|
||||
|
||||
summer_fish_items = [tuna, pike, red_mullet, sturgeon, red_snapper, super_cucumber, tilapia, pufferfish, rainbow_trout,
|
||||
octopus, dorado, halibut, shad, flounder, sunfish, crimsonfish]
|
||||
summer_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.summer_fish, summer_fish_items, 4, 4)
|
||||
|
||||
fall_fish_items = [red_snapper, super_cucumber, tilapia, shad, sardine, catfish, anchovy, smallmouth_bass, eel, midnight_carp,
|
||||
walleye, sea_cucumber, tiger_trout, albacore, salmon, angler]
|
||||
fall_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.fall_fish, fall_fish_items, 4, 4)
|
||||
|
||||
winter_fish_items = [perch, squid, lingcod, tuna, pike, red_mullet, sturgeon, red_snapper, herring, halibut, sardine,
|
||||
midnight_carp, sea_cucumber, tiger_trout, albacore, glacierfish]
|
||||
winter_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.winter_fish, winter_fish_items, 4, 4)
|
||||
|
||||
rain_fish_items = [red_snapper, shad, catfish, eel, walleye]
|
||||
rain_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.rain_fish, rain_fish_items, 3, 3)
|
||||
|
||||
quality_fish_items = sorted({
|
||||
item.as_quality(FishQuality.gold).as_amount(2)
|
||||
for item in [*river_fish_items_thematic, *lake_fish_items_thematic, *ocean_fish_items_thematic]
|
||||
})
|
||||
quality_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.quality_fish, quality_fish_items, 4, 3)
|
||||
|
||||
master_fisher_items = [lava_eel, scorpion_carp, octopus, blobfish, lingcod, ice_pip, super_cucumber, stingray, void_salmon, pufferfish]
|
||||
master_fisher_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.master_fisher, master_fisher_items, 4, 2)
|
||||
|
||||
legendary_fish_items = [angler, legend, mutant_carp, crimsonfish, glacierfish]
|
||||
legendary_fish_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.legendary_fish, legendary_fish_items, 4, 2)
|
||||
|
||||
island_fish_items = [lionfish, blue_discus, stingray]
|
||||
island_fish_bundle = IslandBundleTemplate(CCRoom.fish_tank, BundleName.island_fish, island_fish_items, 3, 3)
|
||||
|
||||
tackle_items = [spinner, dressed_spinner, trap_bobber, sonar_bobber, cork_bobber, lead_bobber, treasure_hunter, barbed_hook, curiosity_lure, quality_bobber]
|
||||
tackle_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.tackle, tackle_items, 3, 2)
|
||||
|
||||
bait_items = [bait, magnet, wild_bait, magic_bait, challenge_bait, deluxe_bait, targeted_bait]
|
||||
bait_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.bait, bait_items, 3, 2)
|
||||
|
||||
# This bundle could change based on content packs, once the fish are properly in it. Until then, I'm not sure how, so pelican town only
|
||||
specific_bait_items = [BundleItem(ArtisanGood.targeted_bait, flavor=fish.name).as_amount(10) for fish in content_packs.pelican_town.fishes]
|
||||
specific_bait_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.specific_bait, specific_bait_items, 6, 3)
|
||||
|
||||
deep_fishing_items = [blobfish, spook_fish, midnight_squid, sea_cucumber, super_cucumber, octopus, pearl, seaweed]
|
||||
deep_fishing_bundle = FestivalBundleTemplate(CCRoom.fish_tank, BundleName.deep_fishing, deep_fishing_items, 4, 3)
|
||||
|
||||
smokeable_fish = [Fish.largemouth_bass, Fish.bream, Fish.bullhead, Fish.chub, Fish.ghostfish, Fish.flounder, Fish.shad, Fish.rainbow_trout, Fish.tilapia,
|
||||
Fish.red_mullet, Fish.tuna, Fish.midnight_carp, Fish.salmon, Fish.perch]
|
||||
fish_smoker_items = [BundleItem(ArtisanGood.smoked_fish, flavor=fish) for fish in smokeable_fish]
|
||||
fish_smoker_bundle = BundleTemplate(CCRoom.fish_tank, BundleName.fish_smoker, fish_smoker_items, 6, 3)
|
||||
|
||||
fish_tank_bundles_remixed = [*fish_tank_bundles_thematic, spring_fish_bundle, summer_fish_bundle,
|
||||
fall_fish_bundle, winter_fish_bundle, trash_bundle, rain_fish_bundle,
|
||||
quality_fish_bundle, master_fisher_bundle, legendary_fish_bundle,
|
||||
tackle_bundle, bait_bundle, specific_bait_bundle, deep_fishing_bundle,
|
||||
fish_smoker_bundle]
|
||||
|
||||
# In Remixed, the trash items are in the recycling bundle, so we don't use the thematic version of the crab pot bundle that added trash items to it
|
||||
fish_tank_bundles_remixed.remove(crab_pot_bundle_thematic)
|
||||
fish_tank_bundles_remixed.append(crab_pot_bundle_vanilla)
|
||||
|
||||
fish_tank_remixed = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_remixed, 6)
|
||||
|
||||
# Boiler Room
|
||||
|
||||
# Where to put radioactive bar?
|
||||
treasure_hunter_items = [emerald, aquamarine, ruby, amethyst, topaz, jade, diamond]
|
||||
treasure_hunter_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.treasure_hunter, treasure_hunter_items, 6, 5)
|
||||
|
||||
engineer_items = [iridium_ore.as_amount(5), battery_pack, refined_quartz.as_amount(5), diamond]
|
||||
engineer_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.engineer, engineer_items, 3, 3)
|
||||
|
||||
demolition_items = [cherry_bomb, bomb, mega_bomb, explosive_ammo]
|
||||
demolition_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.demolition, demolition_items, 3, 3)
|
||||
|
||||
recycling_items = [stone, coal, iron_ore, wood, cloth, refined_quartz]
|
||||
recycling_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.recycling, recycling_items, 4, 4)
|
||||
|
||||
archaeologist_items = [golden_mask, golden_relic, ancient_drum, dwarf_gadget, dwarvish_helm, prehistoric_handaxe, bone_flute, anchor, prehistoric_tool,
|
||||
chicken_statue, rusty_cog, rusty_spur, rusty_spoon, ancient_sword, ornamental_fan, elvish_jewelry, ancient_doll, chipped_amphora]
|
||||
archaeologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.archaeologist, archaeologist_items, 6, 3)
|
||||
|
||||
paleontologist_items = [prehistoric_scapula, prehistoric_tibia, prehistoric_skull, skeletal_hand, prehistoric_rib, prehistoric_vertebra, skeletal_tail,
|
||||
nautilus_fossil, amphibian_fossil, palm_fossil, trilobite]
|
||||
paleontologist_bundle = BundleTemplate(CCRoom.boiler_room, BundleName.paleontologist, paleontologist_items, 6, 3)
|
||||
|
||||
boiler_room_bundles_remixed = [*boiler_room_bundles_thematic, treasure_hunter_bundle, engineer_bundle,
|
||||
demolition_bundle, recycling_bundle, archaeologist_bundle, paleontologist_bundle]
|
||||
boiler_room_remixed = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_remixed, 3)
|
||||
|
||||
# Bulletin Board
|
||||
children_items = [salmonberry.as_amount(10), cookie, ancient_doll, ice_cream, cranberry_candy, ginger_ale,
|
||||
grape.as_amount(10), pink_cake, snail, fairy_rose, plum_pudding]
|
||||
children_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.children, children_items, 4, 3)
|
||||
|
||||
forager_items = [salmonberry.as_amount(50), blackberry.as_amount(50), wild_plum.as_amount(20), snow_yam.as_amount(20),
|
||||
common_mushroom.as_amount(20), grape.as_amount(20), spring_onion.as_amount(20)]
|
||||
forager_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.forager, forager_items, 3, 2)
|
||||
|
||||
home_cook_items = [egg.as_amount(10), milk.as_amount(10), wheat_flour.as_amount(100), sugar.as_amount(100), vinegar.as_amount(100),
|
||||
chocolate_cake, pancakes, rhubarb_pie]
|
||||
home_cook_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.home_cook, home_cook_items, 3, 3)
|
||||
|
||||
helper_items = [prize_ticket, mystery_box.as_amount(5), gold_mystery_box]
|
||||
helper_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.helper, helper_items, 2, 2)
|
||||
|
||||
spirit_eve_items = [jack_o_lantern, corn.as_amount(10), bat_wing.as_amount(10)]
|
||||
spirit_eve_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.spirit_eve, spirit_eve_items, 3, 3)
|
||||
|
||||
winter_star_items = [holly.as_amount(5), plum_pudding, stuffing, powdermelon.as_amount(5)]
|
||||
winter_star_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.winter_star, winter_star_items, 2, 2)
|
||||
|
||||
bartender_items = [shrimp_cocktail, triple_shot_espresso, ginger_ale, cranberry_candy, beer, pale_ale, pina_colada]
|
||||
bartender_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.bartender, bartender_items, 3, 3)
|
||||
|
||||
calico_items = [calico_egg.as_amount(200), calico_egg.as_amount(200), calico_egg.as_amount(200), calico_egg.as_amount(200),
|
||||
magic_rock_candy, mega_bomb.as_amount(10), mystery_box.as_amount(10), mixed_seeds.as_amount(50),
|
||||
strawberry_seeds.as_amount(20),
|
||||
spicy_eel.as_amount(5), crab_cakes.as_amount(5), eggplant_parmesan.as_amount(5),
|
||||
pumpkin_soup.as_amount(5), lucky_lunch.as_amount(5) ]
|
||||
calico_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.calico, calico_items, 2, 2)
|
||||
|
||||
raccoon_bundle = BundleTemplate(CCRoom.bulletin_board, BundleName.raccoon, raccoon_foraging_items, 4, 4)
|
||||
|
||||
bulletin_board_bundles_remixed = [*bulletin_board_bundles_thematic, children_bundle, forager_bundle, home_cook_bundle,
|
||||
helper_bundle, spirit_eve_bundle, winter_star_bundle, bartender_bundle, calico_bundle, raccoon_bundle]
|
||||
bulletin_board_remixed = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_remixed, 5)
|
||||
|
||||
# Abandoned Joja Mart
|
||||
abandoned_joja_mart_remixed = abandoned_joja_mart_thematic
|
||||
|
||||
# Vault
|
||||
vault_gambler_items = BundleItem(Currency.qi_coin, 10000)
|
||||
vault_gambler_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.gambler, vault_gambler_items)
|
||||
|
||||
vault_carnival_items = BundleItem(Currency.star_token, 2500, source=BundleItem.Sources.festival)
|
||||
vault_carnival_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.carnival, vault_carnival_items)
|
||||
|
||||
vault_walnut_hunter_items = BundleItem(Currency.golden_walnut, 25)
|
||||
vault_walnut_hunter_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.walnut_hunter, vault_walnut_hunter_items)
|
||||
|
||||
vault_qi_helper_items = BundleItem(Currency.qi_gem, 25, source=BundleItem.Sources.island)
|
||||
vault_qi_helper_bundle = CurrencyBundleTemplate(CCRoom.vault, BundleName.qi_helper, vault_qi_helper_items)
|
||||
|
||||
vault_bundles_remixed = [*vault_bundles_vanilla, vault_gambler_bundle, vault_qi_helper_bundle, vault_carnival_bundle] # , vault_walnut_hunter_bundle
|
||||
vault_remixed = BundleRoomTemplate(CCRoom.vault, vault_bundles_remixed, 4)
|
||||
158
worlds/stardew_valley/data/bundles_data/thematic_bundles.py
Normal file
158
worlds/stardew_valley/data/bundles_data/thematic_bundles.py
Normal file
@@ -0,0 +1,158 @@
|
||||
from .vanilla_bundles import *
|
||||
from ...bundles.bundle import BundleTemplate
|
||||
from ...bundles.bundle_room import BundleRoomTemplate
|
||||
from ...strings.bundle_names import CCRoom, BundleName
|
||||
|
||||
# Giant Stump
|
||||
from ...strings.quality_names import ArtisanQuality, FishQuality
|
||||
|
||||
raccoon_fish_items_flat = [*raccoon_crab_pot_fish_items, *raccoon_smoked_fish_items]
|
||||
raccoon_fish_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_fish, raccoon_fish_items_flat, 3, 2)
|
||||
raccoon_artisan_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_artisan, raccoon_artisan_items, 3, 2)
|
||||
|
||||
raccoon_food_items_thematic = [*all_specific_dried_mushrooms, *raccoon_food_items, brown_egg.as_amount(5), large_egg.as_amount(2), large_brown_egg.as_amount(2),
|
||||
green_algae.as_amount(10)]
|
||||
raccoon_food_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_food, raccoon_food_items_thematic, 3, 2)
|
||||
|
||||
raccoon_foraging_bundle_thematic = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_foraging, raccoon_foraging_items, 3, 2)
|
||||
|
||||
giant_stump_bundles_thematic = [raccoon_fish_bundle_thematic, raccoon_artisan_bundle_thematic, raccoon_food_bundle_thematic, raccoon_foraging_bundle_thematic]
|
||||
giant_stump_thematic = BundleRoomTemplate(CCRoom.raccoon_requests, giant_stump_bundles_thematic, 8)
|
||||
|
||||
|
||||
# Crafts Room
|
||||
spring_foraging_items_thematic = [*spring_foraging_items_vanilla, spring_onion, salmonberry, morel]
|
||||
spring_foraging_bundle_thematic = BundleTemplate.extend_from(spring_foraging_bundle_vanilla, spring_foraging_items_thematic)
|
||||
|
||||
summer_foraging_items_thematic = [*summer_foraging_items_vanilla, fiddlehead_fern, red_mushroom, rainbow_shell]
|
||||
summer_foraging_bundle_thematic = BundleTemplate.extend_from(summer_foraging_bundle_vanilla, summer_foraging_items_thematic)
|
||||
|
||||
fall_foraging_items_thematic = [*fall_foraging_items_vanilla, chanterelle]
|
||||
fall_foraging_bundle_thematic = BundleTemplate.extend_from(fall_foraging_bundle_vanilla, fall_foraging_items_thematic)
|
||||
|
||||
winter_foraging_items_thematic = [*winter_foraging_items_vanilla, holly, nautilus_shell]
|
||||
winter_foraging_bundle_thematic = BundleTemplate.extend_from(winter_foraging_bundle_vanilla, winter_foraging_items_thematic)
|
||||
|
||||
construction_items_thematic = [*construction_items_vanilla, clay.as_amount(10), fiber.as_amount(99), sap.as_amount(50)]
|
||||
construction_bundle_thematic = BundleTemplate.extend_from(construction_bundle_vanilla, construction_items_thematic)
|
||||
|
||||
exotic_foraging_items_thematic = [*exotic_foraging_items_vanilla, coral, sea_urchin, clam, cockle, mussel, oyster, seaweed]
|
||||
exotic_foraging_bundle_thematic = BundleTemplate.extend_from(exotic_foraging_bundle_vanilla, exotic_foraging_items_thematic)
|
||||
|
||||
crafts_room_bundles_thematic = [spring_foraging_bundle_thematic, summer_foraging_bundle_thematic, fall_foraging_bundle_thematic,
|
||||
winter_foraging_bundle_thematic, construction_bundle_thematic, exotic_foraging_bundle_thematic]
|
||||
crafts_room_thematic = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_thematic, 6)
|
||||
|
||||
# Pantry
|
||||
spring_crops_items_thematic = [*spring_crops_items_vanilla, blue_jazz, coffee_bean, garlic, kale, rhubarb, strawberry, tulip, unmilled_rice, carrot]
|
||||
spring_crops_bundle_thematic = BundleTemplate.extend_from(spring_crops_bundle_vanilla, spring_crops_items_thematic)
|
||||
|
||||
summer_crops_items_thematic = [*summer_crops_items_vanilla, corn, hops, poppy, radish, red_cabbage, starfruit, summer_spangle, sunflower, wheat, summer_squash]
|
||||
summer_crops_bundle_thematic = BundleTemplate.extend_from(summer_crops_bundle_vanilla, summer_crops_items_thematic)
|
||||
|
||||
fall_crops_items_thematic = [*fall_crops_items_vanilla, amaranth, artichoke, beet, bok_choy, cranberries, fairy_rose, grape,
|
||||
sunflower, wheat, sweet_gem_berry, broccoli]
|
||||
fall_crops_bundle_thematic = BundleTemplate.extend_from(fall_crops_bundle_vanilla, fall_crops_items_thematic)
|
||||
|
||||
all_crops_items = sorted({*spring_crops_items_thematic, *summer_crops_items_thematic, *fall_crops_items_thematic, powdermelon})
|
||||
|
||||
quality_crops_items_thematic = [item.as_quality_crop() for item in all_crops_items]
|
||||
quality_crops_bundle_thematic = BundleTemplate.extend_from(quality_crops_bundle_vanilla, quality_crops_items_thematic)
|
||||
|
||||
animal_items_thematic = [*animal_items_vanilla, egg, brown_egg, milk, goat_milk, truffle,
|
||||
duck_feather, rabbit_foot, dinosaur_egg, void_egg, golden_egg, ostrich_egg]
|
||||
animal_bundle_thematic = BundleTemplate.extend_from(animal_bundle_vanilla, animal_items_thematic)
|
||||
|
||||
artisan_items_thematic = [*artisan_items_vanilla, beer, juice, mead, pale_ale, wine, pickles, caviar, aged_roe, coffee, green_tea, banana, mango]
|
||||
artisan_bundle_thematic = BundleTemplate.extend_from(artisan_bundle_vanilla, artisan_items_thematic)
|
||||
|
||||
pantry_bundles_thematic = [spring_crops_bundle_thematic, summer_crops_bundle_thematic, fall_crops_bundle_thematic,
|
||||
quality_crops_bundle_thematic, animal_bundle_thematic, artisan_bundle_thematic]
|
||||
pantry_thematic = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_thematic, 6)
|
||||
|
||||
# Fish Tank
|
||||
river_fish_items_thematic = [*river_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, pike, bream, salmon, smallmouth_bass, dorado]
|
||||
river_fish_bundle_thematic = BundleTemplate.extend_from(river_fish_bundle_vanilla, river_fish_items_thematic)
|
||||
|
||||
lake_fish_items_thematic = [*lake_fish_items_vanilla, chub, rainbow_trout, lingcod, walleye, perch, midnight_carp]
|
||||
lake_fish_bundle_thematic = BundleTemplate.extend_from(lake_fish_bundle_vanilla, lake_fish_items_thematic)
|
||||
|
||||
ocean_fish_items_thematic = [*ocean_fish_items_vanilla, pufferfish, super_cucumber, flounder, anchovy, red_mullet,
|
||||
herring, eel, octopus, squid, sea_cucumber, albacore, halibut]
|
||||
ocean_fish_bundle_thematic = BundleTemplate.extend_from(ocean_fish_bundle_vanilla, ocean_fish_items_thematic)
|
||||
|
||||
night_fish_items_thematic = [*night_fish_items_vanilla, super_cucumber, squid, midnight_carp, midnight_squid]
|
||||
night_fish_bundle_thematic = BundleTemplate.extend_from(night_fish_bundle_vanilla, night_fish_items_thematic)
|
||||
|
||||
crab_pot_items_thematic = [*crab_pot_items_vanilla, *crab_pot_trash_items]
|
||||
crab_pot_bundle_thematic = BundleTemplate.extend_from(crab_pot_bundle_vanilla, crab_pot_items_thematic)
|
||||
|
||||
specialty_fish_items_thematic = [*specialty_fish_items_vanilla, scorpion_carp, eel, octopus, lava_eel, ice_pip,
|
||||
stonefish, void_salmon, stingray, spookfish, midnight_squid, slimejack, goby]
|
||||
specialty_fish_bundle_thematic = BundleTemplate.extend_from(specialty_fish_bundle_vanilla, specialty_fish_items_thematic)
|
||||
|
||||
fish_tank_bundles_thematic = [river_fish_bundle_thematic, lake_fish_bundle_thematic, ocean_fish_bundle_thematic,
|
||||
night_fish_bundle_thematic, crab_pot_bundle_thematic, specialty_fish_bundle_thematic]
|
||||
fish_tank_thematic = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_thematic, 6)
|
||||
|
||||
# Boiler Room
|
||||
blacksmith_items_thematic = [*blacksmith_items_vanilla, iridium_bar, refined_quartz.as_amount(3), wilted_bouquet]
|
||||
blacksmith_bundle_thematic = BundleTemplate.extend_from(blacksmith_bundle_vanilla, blacksmith_items_thematic)
|
||||
|
||||
geologist_items_thematic = [*geologist_items_vanilla, emerald, aquamarine, ruby, amethyst, topaz, jade, diamond]
|
||||
geologist_bundle_thematic = BundleTemplate.extend_from(geologist_bundle_vanilla, geologist_items_thematic)
|
||||
|
||||
adventurer_items_thematic = [*adventurer_items_vanilla, bug_meat, coal.as_amount(5), bone_fragment.as_amount(10)]
|
||||
adventurer_bundle_thematic = BundleTemplate.extend_from(adventurer_bundle_vanilla, adventurer_items_thematic)
|
||||
|
||||
boiler_room_bundles_thematic = [blacksmith_bundle_thematic, geologist_bundle_thematic, adventurer_bundle_thematic]
|
||||
boiler_room_thematic = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_thematic, 3)
|
||||
|
||||
# Bulletin Board
|
||||
|
||||
# More recipes?
|
||||
chef_items_thematic = [maki_roll, fried_egg, omelet, pizza, hashbrowns, pancakes, bread, tortilla,
|
||||
farmer_s_lunch, survival_burger, dish_o_the_sea, miner_s_treat, roots_platter, salad,
|
||||
cheese_cauliflower, parsnip_soup, fried_mushroom, salmon_dinner, pepper_poppers, spaghetti,
|
||||
sashimi, blueberry_tart, algae_soup, pale_broth, chowder]
|
||||
chef_bundle_thematic = BundleTemplate.extend_from(chef_bundle_vanilla, chef_items_thematic)
|
||||
|
||||
dye_red_items = [cranberries, hot_pepper, radish, rhubarb, spaghetti, strawberry, tomato, tulip, red_mushroom]
|
||||
dye_orange_items = [poppy, pumpkin, apricot, orange, spice_berry, winter_root]
|
||||
dye_yellow_items = [corn, parsnip, summer_spangle, sunflower, starfruit]
|
||||
dye_green_items = [fiddlehead_fern, kale, artichoke, bok_choy, green_bean, cactus_fruit, duck_feather, dinosaur_egg]
|
||||
dye_blue_items = [blueberry, blue_jazz, blackberry, crystal_fruit, aquamarine]
|
||||
dye_purple_items = [beet, crocus, eggplant, red_cabbage, sweet_pea, iridium_bar, sea_urchin, amaranth]
|
||||
dye_items_thematic = [dye_red_items, dye_orange_items, dye_yellow_items, dye_green_items, dye_blue_items, dye_purple_items]
|
||||
dye_bundle_thematic = DeepBundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_thematic, 6, 6)
|
||||
|
||||
field_research_items_thematic = [*field_research_items_vanilla, geode, magma_geode, omni_geode,
|
||||
rainbow_shell, amethyst, bream, carp]
|
||||
field_research_bundle_thematic = BundleTemplate.extend_from(field_research_bundle_vanilla, field_research_items_thematic)
|
||||
|
||||
fodder_items_thematic = [*fodder_items_vanilla, kale.as_amount(3), corn.as_amount(3), green_bean.as_amount(3),
|
||||
potato.as_amount(3), green_algae.as_amount(5), white_algae.as_amount(3)]
|
||||
fodder_bundle_thematic = BundleTemplate.extend_from(fodder_bundle_vanilla, fodder_items_thematic)
|
||||
|
||||
enchanter_items_thematic = [*enchanter_items_vanilla, purple_mushroom, solar_essence,
|
||||
super_cucumber, void_essence, fire_quartz, frozen_tear, jade]
|
||||
enchanter_bundle_thematic = BundleTemplate.extend_from(enchanter_bundle_vanilla, enchanter_items_thematic)
|
||||
|
||||
bulletin_board_bundles_thematic = [chef_bundle_thematic, dye_bundle_thematic, field_research_bundle_thematic, fodder_bundle_thematic, enchanter_bundle_thematic]
|
||||
bulletin_board_thematic = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_thematic, 5)
|
||||
|
||||
# Abandoned Joja Mart
|
||||
missing_bundle_items_thematic = [*missing_bundle_items_vanilla, pale_ale.as_quality(ArtisanQuality.silver), beer.as_quality(ArtisanQuality.silver),
|
||||
mead.as_quality(ArtisanQuality.silver),
|
||||
cheese.as_quality(ArtisanQuality.silver), goat_cheese.as_quality(ArtisanQuality.silver), void_mayo, cloth, green_tea,
|
||||
truffle_oil, diamond,
|
||||
sweet_gem_berry.as_quality_crop(), starfruit.as_quality_crop(),
|
||||
tea_leaves.as_amount(5), lava_eel.as_quality(FishQuality.gold), scorpion_carp.as_quality(FishQuality.gold),
|
||||
blobfish.as_quality(FishQuality.gold)]
|
||||
missing_bundle_thematic = BundleTemplate.extend_from(missing_bundle_vanilla, missing_bundle_items_thematic)
|
||||
abandoned_joja_mart_bundles_thematic = [missing_bundle_thematic]
|
||||
abandoned_joja_mart_thematic = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_thematic, 1)
|
||||
|
||||
# Vault
|
||||
vault_bundles_thematic = vault_bundles_vanilla
|
||||
vault_thematic = BundleRoomTemplate(CCRoom.vault, vault_bundles_thematic, 4)
|
||||
167
worlds/stardew_valley/data/bundles_data/vanilla_bundles.py
Normal file
167
worlds/stardew_valley/data/bundles_data/vanilla_bundles.py
Normal file
@@ -0,0 +1,167 @@
|
||||
from .bundle_items_data import *
|
||||
from ...bundles.bundle import DeepBundleTemplate, BundleTemplate, MoneyBundleTemplate
|
||||
from ...bundles.bundle_item import BundleItem
|
||||
from ...bundles.bundle_room import BundleRoomTemplate
|
||||
from ...content.vanilla.base import all_fruits, all_vegetables
|
||||
from ...strings.artisan_good_names import ArtisanGood
|
||||
from ...strings.bundle_names import CCRoom, BundleName
|
||||
from ...strings.fish_names import Fish
|
||||
from ...strings.forageable_names import all_edible_mushrooms
|
||||
|
||||
# Giant Stump
|
||||
from ...strings.quality_names import ArtisanQuality, FishQuality
|
||||
|
||||
all_specific_jellies = [BundleItem(ArtisanGood.jelly, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits]
|
||||
all_specific_pickles = [BundleItem(ArtisanGood.pickles, flavor=vegetable, source=BundleItem.Sources.content) for vegetable in all_vegetables]
|
||||
all_specific_dried_fruits = [*[BundleItem(ArtisanGood.dried_fruit, flavor=fruit, source=BundleItem.Sources.content) for fruit in all_fruits],
|
||||
BundleItem(ArtisanGood.raisins, source=BundleItem.Sources.content)]
|
||||
all_specific_juices = [BundleItem(ArtisanGood.juice, flavor=vegetable, source=BundleItem.Sources.content) for vegetable in all_vegetables]
|
||||
|
||||
raccoon_crab_pot_fish_items = [periwinkle.as_amount(5), snail.as_amount(5), crayfish.as_amount(5), mussel.as_amount(5),
|
||||
oyster.as_amount(5), cockle.as_amount(5), clam.as_amount(5)]
|
||||
raccoon_smoked_fish_items = [BundleItem(ArtisanGood.smoked_fish, flavor=fish) for fish in
|
||||
[Fish.largemouth_bass, Fish.bream, Fish.bullhead, Fish.chub, Fish.ghostfish, Fish.flounder, Fish.shad,
|
||||
Fish.rainbow_trout, Fish.tilapia, Fish.red_mullet, Fish.tuna, Fish.midnight_carp, Fish.salmon, Fish.perch]]
|
||||
|
||||
raccoon_artisan_items = [*all_specific_jellies, *all_specific_pickles, *all_specific_dried_fruits, *all_specific_juices]
|
||||
raccoon_fish_items_deep = [raccoon_crab_pot_fish_items, raccoon_smoked_fish_items]
|
||||
|
||||
all_specific_dried_mushrooms = [BundleItem(ArtisanGood.dried_mushroom, flavor=mushroom, source=BundleItem.Sources.content) for mushroom in all_edible_mushrooms]
|
||||
raccoon_food_items = [egg.as_amount(5), cave_carrot.as_amount(5), white_algae.as_amount(5)]
|
||||
|
||||
raccoon_foraging_items = [moss.as_amount(10), rusty_spoon, trash.as_amount(5), slime.as_amount(99), bat_wing.as_amount(10), geode.as_amount(8),
|
||||
frozen_geode.as_amount(5), magma_geode.as_amount(3), coral.as_amount(4), sea_urchin.as_amount(2), bug_meat.as_amount(10),
|
||||
diamond, topaz.as_amount(3), ghostfish.as_amount(3)]
|
||||
|
||||
raccoon_fish_bundle_vanilla = DeepBundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_fish, raccoon_fish_items_deep, 2, 2)
|
||||
raccoon_artisan_bundle_vanilla = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_artisan, raccoon_artisan_items, 2, 2)
|
||||
raccoon_food_items_vanilla = [all_specific_dried_mushrooms, raccoon_food_items]
|
||||
raccoon_food_bundle_vanilla = DeepBundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_food, raccoon_food_items_vanilla, 2, 2)
|
||||
raccoon_foraging_bundle_vanilla = BundleTemplate(CCRoom.raccoon_requests, BundleName.raccoon_foraging, raccoon_foraging_items, 2, 2)
|
||||
giant_stump_bundles_vanilla = [raccoon_fish_bundle_vanilla, raccoon_artisan_bundle_vanilla, raccoon_food_bundle_vanilla, raccoon_foraging_bundle_vanilla]
|
||||
giant_stump_vanilla = BundleRoomTemplate(CCRoom.raccoon_requests, giant_stump_bundles_vanilla, 8)
|
||||
|
||||
# Crafts Room
|
||||
spring_foraging_items_vanilla = [wild_horseradish, daffodil, leek, dandelion]
|
||||
spring_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.spring_foraging, spring_foraging_items_vanilla, 4, 4)
|
||||
|
||||
summer_foraging_items_vanilla = [grape, spice_berry, sweet_pea]
|
||||
summer_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.summer_foraging, summer_foraging_items_vanilla, 3, 3)
|
||||
|
||||
fall_foraging_items_vanilla = [common_mushroom, wild_plum, hazelnut, blackberry]
|
||||
fall_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.fall_foraging, fall_foraging_items_vanilla, 4, 4)
|
||||
|
||||
winter_foraging_items_vanilla = [winter_root, crystal_fruit, snow_yam, crocus]
|
||||
winter_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.winter_foraging, winter_foraging_items_vanilla, 4, 4)
|
||||
|
||||
construction_items_vanilla = [wood, stone, hardwood]
|
||||
construction_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.construction, construction_items_vanilla, 4, 4)
|
||||
|
||||
exotic_foraging_items_vanilla = [coconut, cactus_fruit, cave_carrot, red_mushroom, purple_mushroom, maple_syrup, oak_resin, pine_tar, morel]
|
||||
exotic_foraging_bundle_vanilla = BundleTemplate(CCRoom.crafts_room, BundleName.exotic_foraging, exotic_foraging_items_vanilla, 9, 5)
|
||||
|
||||
crafts_room_bundles_vanilla = [spring_foraging_bundle_vanilla, summer_foraging_bundle_vanilla, fall_foraging_bundle_vanilla,
|
||||
winter_foraging_bundle_vanilla, construction_bundle_vanilla, exotic_foraging_bundle_vanilla]
|
||||
crafts_room_vanilla = BundleRoomTemplate(CCRoom.crafts_room, crafts_room_bundles_vanilla, 6)
|
||||
|
||||
# Pantry
|
||||
spring_crops_items_vanilla = [parsnip, green_bean, cauliflower, potato]
|
||||
spring_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.spring_crops, spring_crops_items_vanilla, 4, 4)
|
||||
|
||||
summer_crops_items_vanilla = [tomato, hot_pepper, blueberry, melon]
|
||||
summer_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.summer_crops, summer_crops_items_vanilla, 4, 4)
|
||||
|
||||
fall_crops_items_vanilla = [corn, eggplant, pumpkin, yam]
|
||||
fall_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.fall_crops, fall_crops_items_vanilla, 4, 4)
|
||||
|
||||
quality_crops_items_vanilla = [item.as_quality_crop() for item in [parsnip, melon, pumpkin, corn]]
|
||||
quality_crops_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.quality_crops, quality_crops_items_vanilla, 4, 3)
|
||||
|
||||
animal_items_vanilla = [large_milk, large_brown_egg, large_egg, large_goat_milk, wool, duck_egg]
|
||||
animal_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.animal, animal_items_vanilla, 6, 5)
|
||||
|
||||
artisan_items_vanilla = [truffle_oil, cloth, goat_cheese, cheese, honey, jelly, apple, apricot, orange, peach, pomegranate, cherry]
|
||||
artisan_bundle_vanilla = BundleTemplate(CCRoom.pantry, BundleName.artisan, artisan_items_vanilla, 12, 6)
|
||||
|
||||
pantry_bundles_vanilla = [spring_crops_bundle_vanilla, summer_crops_bundle_vanilla, fall_crops_bundle_vanilla,
|
||||
quality_crops_bundle_vanilla, animal_bundle_vanilla, artisan_bundle_vanilla]
|
||||
pantry_vanilla = BundleRoomTemplate(CCRoom.pantry, pantry_bundles_vanilla, 6)
|
||||
|
||||
# Fish Tank
|
||||
river_fish_items_vanilla = [sunfish, catfish, shad, tiger_trout]
|
||||
river_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.river_fish, river_fish_items_vanilla, 4, 4)
|
||||
|
||||
lake_fish_items_vanilla = [largemouth_bass, carp, bullhead, sturgeon]
|
||||
lake_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.lake_fish, lake_fish_items_vanilla, 4, 4)
|
||||
|
||||
ocean_fish_items_vanilla = [sardine, tuna, red_snapper, tilapia]
|
||||
ocean_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.ocean_fish, ocean_fish_items_vanilla, 4, 4)
|
||||
|
||||
night_fish_items_vanilla = [walleye, bream, eel]
|
||||
night_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.night_fish, night_fish_items_vanilla, 3, 3)
|
||||
|
||||
crab_pot_items_vanilla = [lobster, crayfish, crab, cockle, mussel, shrimp, snail, periwinkle, oyster, clam]
|
||||
crab_pot_trash_items = [trash, driftwood, soggy_newspaper, broken_cd, broken_glasses]
|
||||
crab_pot_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.crab_pot, crab_pot_items_vanilla, 10, 5)
|
||||
|
||||
specialty_fish_items_vanilla = [pufferfish, ghostfish, sandfish, woodskip]
|
||||
specialty_fish_bundle_vanilla = BundleTemplate(CCRoom.fish_tank, BundleName.specialty_fish, specialty_fish_items_vanilla, 4, 4)
|
||||
|
||||
fish_tank_bundles_vanilla = [river_fish_bundle_vanilla, lake_fish_bundle_vanilla, ocean_fish_bundle_vanilla,
|
||||
night_fish_bundle_vanilla, crab_pot_bundle_vanilla, specialty_fish_bundle_vanilla]
|
||||
fish_tank_vanilla = BundleRoomTemplate(CCRoom.fish_tank, fish_tank_bundles_vanilla, 6)
|
||||
|
||||
# Boiler Room
|
||||
blacksmith_items_vanilla = [copper_bar, iron_bar, gold_bar]
|
||||
blacksmith_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.blacksmith, blacksmith_items_vanilla, 3, 3)
|
||||
|
||||
geologist_items_vanilla = [quartz, earth_crystal, frozen_tear, fire_quartz]
|
||||
geologist_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.geologist, geologist_items_vanilla, 4, 4)
|
||||
|
||||
adventurer_items_vanilla = [slime, bat_wing, solar_essence, void_essence]
|
||||
adventurer_bundle_vanilla = BundleTemplate(CCRoom.boiler_room, BundleName.adventurer, adventurer_items_vanilla, 4, 2)
|
||||
|
||||
boiler_room_bundles_vanilla = [blacksmith_bundle_vanilla, geologist_bundle_vanilla, adventurer_bundle_vanilla]
|
||||
boiler_room_vanilla = BundleRoomTemplate(CCRoom.boiler_room, boiler_room_bundles_vanilla, 3)
|
||||
|
||||
# Bulletin Board
|
||||
chef_items_vanilla = [maple_syrup, fiddlehead_fern, truffle, poppy, maki_roll, fried_egg]
|
||||
chef_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.chef, chef_items_vanilla, 6, 6)
|
||||
|
||||
dye_items_vanilla = [red_mushroom, sea_urchin, sunflower, duck_feather, aquamarine, red_cabbage]
|
||||
dye_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.dye, dye_items_vanilla, 6, 6)
|
||||
|
||||
field_research_items_vanilla = [purple_mushroom, nautilus_shell, chub, frozen_geode]
|
||||
field_research_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.field_research, field_research_items_vanilla, 4, 4)
|
||||
|
||||
fodder_items_vanilla = [wheat.as_amount(10), hay.as_amount(10), apple.as_amount(3)]
|
||||
fodder_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.fodder, fodder_items_vanilla, 3, 3)
|
||||
|
||||
enchanter_items_vanilla = [oak_resin, wine, rabbit_foot, pomegranate]
|
||||
enchanter_bundle_vanilla = BundleTemplate(CCRoom.bulletin_board, BundleName.enchanter, enchanter_items_vanilla, 4, 4)
|
||||
|
||||
bulletin_board_bundles_vanilla = [chef_bundle_vanilla, dye_bundle_vanilla, field_research_bundle_vanilla, fodder_bundle_vanilla, enchanter_bundle_vanilla]
|
||||
bulletin_board_vanilla = BundleRoomTemplate(CCRoom.bulletin_board, bulletin_board_bundles_vanilla, 5)
|
||||
|
||||
# Abandoned Joja Mart
|
||||
missing_bundle_items_vanilla = [wine.as_quality(ArtisanQuality.silver), dinosaur_mayo, prismatic_shard, caviar,
|
||||
ancient_fruit.as_quality_crop(), void_salmon.as_quality(FishQuality.gold)]
|
||||
missing_bundle_vanilla = BundleTemplate(CCRoom.abandoned_joja_mart, BundleName.missing_bundle, missing_bundle_items_vanilla, 6, 5)
|
||||
|
||||
abandoned_joja_mart_bundles_vanilla = [missing_bundle_vanilla]
|
||||
abandoned_joja_mart_vanilla = BundleRoomTemplate(CCRoom.abandoned_joja_mart, abandoned_joja_mart_bundles_vanilla, 1)
|
||||
|
||||
|
||||
# Vault
|
||||
vault_2500_gold = BundleItem.money_bundle(2500)
|
||||
vault_5000_gold = BundleItem.money_bundle(5000)
|
||||
vault_10000_gold = BundleItem.money_bundle(10000)
|
||||
vault_25000_gold = BundleItem.money_bundle(25000)
|
||||
|
||||
vault_2500_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_2500, vault_2500_gold)
|
||||
vault_5000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_5000, vault_5000_gold)
|
||||
vault_10000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_10000, vault_10000_gold)
|
||||
vault_25000_bundle = MoneyBundleTemplate(CCRoom.vault, BundleName.money_25000, vault_25000_gold)
|
||||
|
||||
vault_bundles_vanilla = [vault_2500_bundle, vault_5000_bundle, vault_10000_bundle, vault_25000_bundle]
|
||||
vault_vanilla = BundleRoomTemplate(CCRoom.vault, vault_bundles_vanilla, 4)
|
||||
@@ -1,7 +1,8 @@
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List
|
||||
|
||||
from .recipe_source import RecipeSource, StarterSource, QueenOfSauceSource, ShopSource, SkillSource, FriendshipSource, ShopTradeSource, CutsceneSource, \
|
||||
ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource, QuestSource, MasterySource, SkillCraftsanitySource
|
||||
ArchipelagoSource, LogicSource, SpecialOrderSource, FestivalShopSource, QuestSource, MasterySource, SkillCraftsanitySource, ShopWithKnownRecipeSource
|
||||
from ..content.content_packs import ginger_island_content_pack
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
@@ -33,13 +34,13 @@ class CraftingRecipe:
|
||||
item: str
|
||||
ingredients: Dict[str, int]
|
||||
source: RecipeSource
|
||||
mod_name: Optional[str]
|
||||
content_pack: frozenset[str] | None
|
||||
|
||||
def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None):
|
||||
def __init__(self, item: str, ingredients: Dict[str, int], source: RecipeSource, content_pack: frozenset[str] | None = None):
|
||||
self.item = item
|
||||
self.ingredients = ingredients
|
||||
self.source = source
|
||||
self.mod_name = mod_name
|
||||
self.content_pack = content_pack
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.item} (Source: {self.source} |" \
|
||||
@@ -49,9 +50,9 @@ class CraftingRecipe:
|
||||
all_crafting_recipes: List[CraftingRecipe] = []
|
||||
|
||||
|
||||
def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = FriendshipSource(friend, hearts)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def cutscene_recipe(name: str, region: str, friend: str, hearts: int, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
@@ -59,24 +60,29 @@ def cutscene_recipe(name: str, region: str, friend: str, hearts: int, ingredient
|
||||
return create_recipe(name, ingredients, source)
|
||||
|
||||
|
||||
def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = SkillSource(skill, level)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def skill_craftsanity_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
def skill_craftsanity_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = SkillCraftsanitySource(skill, level)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def mastery_recipe(name: str, skill: str, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
def mastery_recipe(name: str, skill: str, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = MasterySource(skill)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = ShopSource(region, price)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def shop_with_known_recipe_recipe(name: str, region: str, price: int, recipe_requirement: str, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = ShopWithKnownRecipeSource(region, price, recipe_requirement)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def festival_shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
@@ -84,9 +90,9 @@ def festival_shop_recipe(name: str, region: str, price: int, ingredients: Dict[s
|
||||
return create_recipe(name, ingredients, source)
|
||||
|
||||
|
||||
def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = ShopTradeSource(region, currency, price)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
@@ -94,14 +100,14 @@ def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredien
|
||||
return create_recipe(name, ingredients, source)
|
||||
|
||||
|
||||
def quest_recipe(name: str, quest: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
def quest_recipe(name: str, quest: str, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = QuestSource(quest)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def special_order_recipe(name: str, special_order: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
def special_order_recipe(name: str, special_order: str, ingredients: Dict[str, int], content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
source = SpecialOrderSource(special_order)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def starter_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
@@ -109,11 +115,11 @@ def starter_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
return create_recipe(name, ingredients, source)
|
||||
|
||||
|
||||
def ap_recipe(name: str, ingredients: Dict[str, int], ap_item: str = None) -> CraftingRecipe:
|
||||
def ap_recipe(name: str, ingredients: Dict[str, int], ap_item: str = None, content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
if ap_item is None:
|
||||
ap_item = f"{name} Recipe"
|
||||
source = ArchipelagoSource(ap_item)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def cellar_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
@@ -121,8 +127,12 @@ def cellar_recipe(name: str, ingredients: Dict[str, int]) -> CraftingRecipe:
|
||||
return create_recipe(name, ingredients, source)
|
||||
|
||||
|
||||
def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None) -> CraftingRecipe:
|
||||
recipe = CraftingRecipe(name, ingredients, source, mod_name)
|
||||
def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, content_pack: List[str] | str | None = None) -> CraftingRecipe:
|
||||
if content_pack is None:
|
||||
content_pack = []
|
||||
if isinstance(content_pack, str):
|
||||
content_pack = [content_pack]
|
||||
recipe = CraftingRecipe(name, ingredients, source, frozenset(content_pack))
|
||||
all_crafting_recipes.append(recipe)
|
||||
return recipe
|
||||
|
||||
@@ -161,11 +171,11 @@ deluxe_fertilizer = ap_recipe(Fertilizer.deluxe, {MetalBar.iridium: 1, Material.
|
||||
|
||||
basic_speed_gro = skill_recipe(SpeedGro.basic, Skill.farming, 3, {ArtisanGood.pine_tar: 1, Material.moss: 5})
|
||||
deluxe_speed_gro = skill_recipe(SpeedGro.deluxe, Skill.farming, 8, {ArtisanGood.oak_resin: 1, Fossil.bone_fragment: 5})
|
||||
hyper_speed_gro = ap_recipe(SpeedGro.hyper, {Ore.radioactive: 1, Fossil.bone_fragment: 3, Loot.solar_essence: 1})
|
||||
hyper_speed_gro = ap_recipe(SpeedGro.hyper, {Ore.radioactive: 1, Fossil.bone_fragment: 3, Loot.solar_essence: 1}, content_pack=ginger_island_content_pack.name)
|
||||
basic_retaining_soil = skill_recipe(RetainingSoil.basic, Skill.farming, 4, {Material.stone: 2})
|
||||
quality_retaining_soil = skill_recipe(RetainingSoil.quality, Skill.farming, 7, {Material.stone: 3, Material.clay: 1})
|
||||
deluxe_retaining_soil = shop_trade_recipe(RetainingSoil.deluxe, Region.island_trader, Currency.cinder_shard, 50,
|
||||
{Material.stone: 5, Material.fiber: 3, Material.clay: 1})
|
||||
{Material.stone: 5, Material.fiber: 3, Material.clay: 1}, content_pack=ginger_island_content_pack.name)
|
||||
tree_fertilizer = skill_recipe(Fertilizer.tree, Skill.foraging, 7, {Material.fiber: 5, Material.stone: 5})
|
||||
|
||||
spring_seeds = skill_recipe(WildSeeds.spring, Skill.foraging, 1,
|
||||
@@ -176,7 +186,7 @@ winter_seeds = skill_recipe(WildSeeds.winter, Skill.foraging, 7,
|
||||
{Forageable.winter_root: 1, Forageable.crystal_fruit: 1, Forageable.snow_yam: 1, Forageable.crocus: 1})
|
||||
ancient_seeds = ap_recipe(WildSeeds.ancient, {Artifact.ancient_seed: 1})
|
||||
grass_starter = shop_recipe(WildSeeds.grass_starter, Region.pierre_store, 1000, {Material.fiber: 10})
|
||||
blue_grass_starter = ap_recipe(WildSeeds.blue_grass_starter, {Material.fiber: 25, Material.moss: 10, ArtisanGood.mystic_syrup: 1})
|
||||
blue_grass_starter = ap_recipe(WildSeeds.blue_grass_starter, {Material.fiber: 25, Material.moss: 10, ArtisanGood.mystic_syrup: 1}, content_pack=ginger_island_content_pack.name)
|
||||
for wild_seeds in [WildSeeds.spring, WildSeeds.summer, WildSeeds.fall, WildSeeds.winter]:
|
||||
tea_sapling = cutscene_recipe(WildSeeds.tea_sapling, Region.sunroom, NPC.caroline, 2, {wild_seeds: 2, Material.fiber: 5, Material.wood: 5})
|
||||
fiber_seeds = special_order_recipe(WildSeeds.fiber, SpecialOrder.community_cleanup, {Seed.mixed: 1, Material.sap: 5, Material.clay: 1})
|
||||
@@ -207,13 +217,13 @@ magnet = skill_recipe(Fishing.magnet, Skill.fishing, 9, {MetalBar.iron: 1})
|
||||
bait = skill_recipe(Fishing.bait, Skill.fishing, 2, {Loot.bug_meat: 1})
|
||||
deluxe_bait = skill_recipe(Fishing.deluxe_bait, Skill.fishing, 4, {Fishing.bait: 5, Material.moss: 2})
|
||||
wild_bait = cutscene_recipe(Fishing.wild_bait, Region.tent, NPC.linus, 4, {Material.fiber: 10, Loot.bug_meat: 5, Loot.slime: 5})
|
||||
magic_bait = ap_recipe(Fishing.magic_bait, {Ore.radioactive: 1, Loot.bug_meat: 3})
|
||||
magic_bait = ap_recipe(Fishing.magic_bait, {Ore.radioactive: 1, Loot.bug_meat: 3}, content_pack=ginger_island_content_pack.name)
|
||||
crab_pot = skill_recipe(Machine.crab_pot, Skill.fishing, 3, {Material.wood: 40, MetalBar.iron: 3})
|
||||
|
||||
sturdy_ring = skill_recipe(Ring.sturdy_ring, Skill.combat, 1, {MetalBar.copper: 2, Loot.bug_meat: 25, Loot.slime: 25})
|
||||
warrior_ring = skill_recipe(Ring.warrior_ring, Skill.combat, 4, {MetalBar.iron: 10, Material.coal: 25, Mineral.frozen_tear: 10})
|
||||
ring_of_yoba = skill_recipe(Ring.ring_of_yoba, Skill.combat, 7, {MetalBar.gold: 5, MetalBar.iron: 5, Mineral.diamond: 1})
|
||||
thorns_ring = skill_recipe(Ring.thorns_ring, Skill.combat, 7, {Fossil.bone_fragment: 50, Material.stone: 50, MetalBar.gold: 1})
|
||||
thorns_ring = skill_recipe(Ring.thorns_ring, Skill.combat, 7, {Fossil.bone_fragment: 50, Material.stone: 50, MetalBar.gold: 1}, content_pack=ginger_island_content_pack.name)
|
||||
glowstone_ring = skill_recipe(Ring.glowstone_ring, Skill.mining, 4, {Loot.solar_essence: 5, MetalBar.iron: 5})
|
||||
iridium_band = skill_recipe(Ring.iridium_band, Skill.combat, 9, {MetalBar.iridium: 5, Loot.solar_essence: 50, Loot.void_essence: 50})
|
||||
wedding_ring = shop_recipe(Ring.wedding_ring, LogicRegion.traveling_cart, 500, {MetalBar.iridium: 5, Mineral.prismatic_shard: 1})
|
||||
@@ -224,14 +234,14 @@ life_elixir = skill_recipe(Edible.life_elixir, Skill.combat, 2, {Mushroom.red: 1
|
||||
oil_of_garlic = skill_recipe(Edible.oil_of_garlic, Skill.combat, 6, {Vegetable.garlic: 10, Ingredient.oil: 1})
|
||||
|
||||
monster_musk = special_order_recipe(Consumable.monster_musk, SpecialOrder.prismatic_jelly, {Loot.bat_wing: 30, Loot.slime: 30})
|
||||
fairy_dust = quest_recipe(Consumable.fairy_dust, Quest.the_pirates_wife, {Mineral.diamond: 1, Flower.fairy_rose: 1})
|
||||
fairy_dust = quest_recipe(Consumable.fairy_dust, Quest.the_pirates_wife, {Mineral.diamond: 1, Flower.fairy_rose: 1}, content_pack=ginger_island_content_pack.name)
|
||||
warp_totem_beach = skill_recipe(Consumable.warp_totem_beach, Skill.foraging, 6, {Material.hardwood: 1, WaterItem.coral: 2, Material.fiber: 10})
|
||||
warp_totem_mountains = skill_recipe(Consumable.warp_totem_mountains, Skill.foraging, 7, {Material.hardwood: 1, MetalBar.iron: 1, Material.stone: 25})
|
||||
warp_totem_farm = skill_recipe(Consumable.warp_totem_farm, Skill.foraging, 8, {Material.hardwood: 1, ArtisanGood.honey: 1, Material.fiber: 20})
|
||||
warp_totem_desert = shop_trade_recipe(Consumable.warp_totem_desert, Region.desert, MetalBar.iridium, 10,
|
||||
{Material.hardwood: 2, Forageable.coconut: 1, Ore.iridium: 4})
|
||||
warp_totem_island = shop_recipe(Consumable.warp_totem_island, Region.volcano_dwarf_shop, 10000,
|
||||
{Material.hardwood: 5, Forageable.dragon_tooth: 1, Forageable.ginger: 1})
|
||||
{Material.hardwood: 5, Forageable.dragon_tooth: 1, Forageable.ginger: 1}, content_pack=ginger_island_content_pack.name)
|
||||
rain_totem = skill_recipe(Consumable.rain_totem, Skill.foraging, 9, {Material.hardwood: 1, ArtisanGood.truffle_oil: 1, ArtisanGood.pine_tar: 5})
|
||||
|
||||
torch = starter_recipe(Lighting.torch, {Material.wood: 1, Material.sap: 2})
|
||||
@@ -259,14 +269,14 @@ crystalarium = skill_recipe(Machine.crystalarium, Skill.mining, 9, {Material.sto
|
||||
furnace = skill_craftsanity_recipe(Machine.furnace, Skill.mining, 1, {Ore.copper: 20, Material.stone: 25})
|
||||
geode_crusher = special_order_recipe(Machine.geode_crusher, SpecialOrder.cave_patrol, {MetalBar.gold: 2, Material.stone: 50, Mineral.diamond: 1})
|
||||
mushroom_log = skill_recipe(Machine.mushroom_log, Skill.foraging, 4, {Material.hardwood: 10, Material.moss: 10})
|
||||
heavy_tapper = ap_recipe(Machine.heavy_tapper, {Material.hardwood: 30, MetalBar.radioactive: 1})
|
||||
heavy_tapper = ap_recipe(Machine.heavy_tapper, {Material.hardwood: 30, MetalBar.radioactive: 1}, content_pack=ginger_island_content_pack.name)
|
||||
lightning_rod = skill_recipe(Machine.lightning_rod, Skill.foraging, 6, {MetalBar.iron: 1, MetalBar.quartz: 1, Loot.bat_wing: 5})
|
||||
ostrich_incubator = ap_recipe(Machine.ostrich_incubator, {Fossil.bone_fragment: 50, Material.hardwood: 50, Currency.cinder_shard: 20})
|
||||
ostrich_incubator = ap_recipe(Machine.ostrich_incubator, {Fossil.bone_fragment: 50, Material.hardwood: 50, Currency.cinder_shard: 20}, content_pack=ginger_island_content_pack.name)
|
||||
recycling_machine = skill_recipe(Machine.recycling_machine, Skill.fishing, 4, {Material.wood: 25, Material.stone: 25, MetalBar.iron: 1})
|
||||
seed_maker = skill_recipe(Machine.seed_maker, Skill.farming, 9, {Material.wood: 25, Material.coal: 10, MetalBar.gold: 1})
|
||||
slime_egg_press = skill_recipe(Machine.slime_egg_press, Skill.combat, 6, {Material.coal: 25, Mineral.fire_quartz: 1, ArtisanGood.battery_pack: 1})
|
||||
slime_incubator = skill_recipe(Machine.slime_incubator, Skill.combat, 8, {MetalBar.iridium: 2, Loot.slime: 100})
|
||||
solar_panel = special_order_recipe(Machine.solar_panel, SpecialOrder.island_ingredients, {MetalBar.quartz: 10, MetalBar.iron: 5, MetalBar.gold: 5})
|
||||
solar_panel = special_order_recipe(Machine.solar_panel, SpecialOrder.island_ingredients, {MetalBar.quartz: 10, MetalBar.iron: 5, MetalBar.gold: 5})#, content_pack=ginger_island_content_pack.name) # If set this as a ginger island only recipe, the rule for battery packs will fail. It does OR on lightning rod and solar panel, even when GI is off
|
||||
|
||||
tapper = skill_recipe(Machine.tapper, Skill.foraging, 4, {Material.wood: 40, MetalBar.copper: 2})
|
||||
|
||||
@@ -282,7 +292,7 @@ drum_block = cutscene_recipe(Furniture.drum_block, Region.carpenter, NPC.robin,
|
||||
chest = starter_recipe(Storage.chest, {Material.wood: 50})
|
||||
stone_chest = special_order_recipe(Storage.stone_chest, SpecialOrder.robins_resource_rush, {Material.stone: 50})
|
||||
big_chest = shop_recipe(Storage.big_chest, Region.carpenter, 5000, {Material.wood: 120, MetalBar.copper: 2})
|
||||
big_stone_chest = shop_recipe(Storage.big_stone_chest, LogicRegion.mines_dwarf_shop, 5000, {Material.stone: 250})
|
||||
big_stone_chest = shop_with_known_recipe_recipe(Storage.big_stone_chest, LogicRegion.mines_dwarf_shop, 5000, Storage.stone_chest, {Material.stone: 250})
|
||||
|
||||
wood_sign = starter_recipe(Sign.wood, {Material.wood: 25})
|
||||
stone_sign = starter_recipe(Sign.stone, {Material.stone: 25})
|
||||
@@ -300,7 +310,7 @@ mini_jukebox = cutscene_recipe(Craftable.mini_jukebox, Region.saloon, NPC.gus, 5
|
||||
mini_obelisk = special_order_recipe(Craftable.mini_obelisk, SpecialOrder.a_curious_substance, {Material.hardwood: 30, Loot.solar_essence: 20, MetalBar.gold: 3})
|
||||
farm_computer = special_order_recipe(Craftable.farm_computer, SpecialOrder.aquatic_overpopulation,
|
||||
{Artifact.dwarf_gadget: 1, ArtisanGood.battery_pack: 1, MetalBar.quartz: 10})
|
||||
hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1})
|
||||
hopper = ap_recipe(Craftable.hopper, {Material.hardwood: 10, MetalBar.iridium: 1, MetalBar.radioactive: 1}, content_pack=ginger_island_content_pack.name)
|
||||
|
||||
cookout_kit = skill_recipe(Craftable.cookout_kit, Skill.foraging, 3, {Material.wood: 15, Material.fiber: 10, Material.coal: 3})
|
||||
tent_kit = skill_recipe(Craftable.tent_kit, Skill.foraging, 8, {Material.hardwood: 10, Material.fiber: 25, ArtisanGood.cloth: 1})
|
||||
@@ -312,81 +322,81 @@ mystic_tree_seed = mastery_recipe(TreeSeed.mystic, Skill.foraging, {TreeSeed.aco
|
||||
treasure_totem = mastery_recipe(Consumable.treasure_totem, Skill.foraging, {Material.hardwood: 5, ArtisanGood.mystic_syrup: 1, Material.moss: 10})
|
||||
challenge_bait = mastery_recipe(Fishing.challenge_bait, Skill.fishing, {Fossil.bone_fragment: 5, Material.moss: 2})
|
||||
anvil = mastery_recipe(Machine.anvil, Skill.combat, {MetalBar.iron: 50})
|
||||
mini_forge = mastery_recipe(Machine.mini_forge, Skill.combat, {Forageable.dragon_tooth: 5, MetalBar.iron: 10, MetalBar.gold: 10, MetalBar.iridium: 5})
|
||||
mini_forge = mastery_recipe(Machine.mini_forge, Skill.combat, {Forageable.dragon_tooth: 5, MetalBar.iron: 10, MetalBar.gold: 10, MetalBar.iridium: 5}, content_pack=ginger_island_content_pack.name)
|
||||
|
||||
travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 250, {Loot.solar_essence: 1, Loot.void_essence: 1}, ModNames.magic)
|
||||
travel_charm = shop_recipe(ModCraftable.travel_core, Region.adventurer_guild, 250, {Loot.solar_essence: 1, Loot.void_essence: 1}, content_pack=ModNames.magic)
|
||||
preservation_chamber = skill_recipe(ModMachine.preservation_chamber, ModSkill.archaeology, 1,
|
||||
{MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 30},
|
||||
{MetalBar.copper: 1, Material.wood: 15, ArtisanGood.oak_resin: 10},
|
||||
ModNames.archaeology)
|
||||
restoration_table = skill_recipe(ModMachine.restoration_table, ModSkill.archaeology, 1, {Material.wood: 15, MetalBar.copper: 1, MetalBar.iron: 1},
|
||||
restoration_table = skill_recipe(ModMachine.restoration_table, ModSkill.archaeology, 1, {Material.wood: 25, MetalBar.quartz: 1, MetalBar.iron: 1},
|
||||
ModNames.archaeology)
|
||||
preservation_chamber_h = skill_recipe(ModMachine.hardwood_preservation_chamber, ModSkill.archaeology, 6, {MetalBar.copper: 1, Material.hardwood: 15,
|
||||
ArtisanGood.oak_resin: 30}, ModNames.archaeology)
|
||||
grinder = skill_recipe(ModMachine.grinder, ModSkill.archaeology, 2, {Artifact.rusty_cog: 10, MetalBar.iron: 5, ArtisanGood.battery_pack: 1},
|
||||
ArtisanGood.oak_resin: 10}, content_pack=ModNames.archaeology)
|
||||
grinder = skill_recipe(ModMachine.grinder, ModSkill.archaeology, 2, {Artifact.rusty_cog: 4, MetalBar.iron: 5, ArtisanGood.battery_pack: 1},
|
||||
ModNames.archaeology)
|
||||
ancient_battery = skill_recipe(ModMachine.ancient_battery, ModSkill.archaeology, 7, {Material.stone: 40, MetalBar.copper: 10, MetalBar.iron: 5},
|
||||
ancient_battery = skill_recipe(ModMachine.ancient_battery, ModSkill.archaeology, 7, {Material.stone: 40, Material.clay: 10, MetalBar.iron: 5},
|
||||
ModNames.archaeology)
|
||||
glass_bazier = skill_recipe(ModCraftable.glass_brazier, ModSkill.archaeology, 4, {Artifact.glass_shards: 10}, ModNames.archaeology)
|
||||
glass_path = skill_recipe(ModFloor.glass_path, ModSkill.archaeology, 3, {Artifact.glass_shards: 1}, ModNames.archaeology)
|
||||
glass_fence = skill_recipe(ModCraftable.glass_fence, ModSkill.archaeology, 7, {Artifact.glass_shards: 5}, ModNames.archaeology)
|
||||
bone_path = skill_recipe(ModFloor.bone_path, ModSkill.archaeology, 4, {Fossil.bone_fragment: 1}, ModNames.archaeology)
|
||||
rust_path = skill_recipe(ModFloor.rusty_path, ModSkill.archaeology, 2, {ModTrash.rusty_scrap: 2}, ModNames.archaeology)
|
||||
glass_brazier = skill_recipe(ModCraftable.glass_brazier, ModSkill.archaeology, 4, {Artifact.glass_shards: 10, Material.coal: 1, Material.fiber: 1}, content_pack=ModNames.archaeology)
|
||||
glass_path = skill_recipe(ModFloor.glass_path, ModSkill.archaeology, 3, {Artifact.glass_shards: 2}, content_pack=ModNames.archaeology)
|
||||
glass_fence = skill_recipe(ModCraftable.glass_fence, ModSkill.archaeology, 7, {Artifact.glass_shards: 2}, content_pack=ModNames.archaeology)
|
||||
bone_path = skill_recipe(ModFloor.bone_path, ModSkill.archaeology, 4, {Fossil.bone_fragment: 2}, content_pack=ModNames.archaeology)
|
||||
rust_path = skill_recipe(ModFloor.rusty_path, ModSkill.archaeology, 2, {ModTrash.rusty_scrap: 2}, content_pack=ModNames.archaeology)
|
||||
rusty_brazier = skill_recipe(ModCraftable.rusty_brazier, ModSkill.archaeology, 3, {ModTrash.rusty_scrap: 10, Material.coal: 1, Material.fiber: 1},
|
||||
ModNames.archaeology)
|
||||
bone_fence = skill_recipe(ModCraftable.bone_fence, ModSkill.archaeology, 8, {Fossil.bone_fragment: 2}, ModNames.archaeology)
|
||||
water_shifter = skill_recipe(ModCraftable.water_shifter, ModSkill.archaeology, 4, {Material.wood: 40, MetalBar.copper: 4}, ModNames.archaeology)
|
||||
wooden_display = skill_recipe(ModCraftable.wooden_display, ModSkill.archaeology, 1, {Material.wood: 25}, ModNames.archaeology)
|
||||
hardwood_display = skill_recipe(ModCraftable.hardwood_display, ModSkill.archaeology, 7, {Material.hardwood: 10}, ModNames.archaeology)
|
||||
bone_fence = skill_recipe(ModCraftable.bone_fence, ModSkill.archaeology, 8, {Fossil.bone_fragment: 2}, content_pack=ModNames.archaeology)
|
||||
water_sifter = skill_recipe(ModCraftable.water_sifter, ModSkill.archaeology, 8, {MetalBar.copper: 4, Material.fiber: 8}, content_pack=ModNames.archaeology)
|
||||
wooden_display = skill_recipe(ModCraftable.wooden_display, ModSkill.archaeology, 1, {Material.wood: 25}, content_pack=ModNames.archaeology)
|
||||
hardwood_display = skill_recipe(ModCraftable.hardwood_display, ModSkill.archaeology, 6, {Material.hardwood: 10}, content_pack=ModNames.archaeology)
|
||||
lucky_ring = skill_recipe(Ring.lucky_ring, ModSkill.archaeology, 8, {Artifact.elvish_jewelry: 1, AnimalProduct.rabbit_foot: 5, Mineral.tigerseye: 1},
|
||||
ModNames.archaeology)
|
||||
volcano_totem = skill_recipe(ModConsumable.volcano_totem, ModSkill.archaeology, 9, {Material.cinder_shard: 5, Artifact.rare_disc: 1, Artifact.dwarf_gadget: 1},
|
||||
ModNames.archaeology)
|
||||
haste_elixir = shop_recipe(ModEdible.haste_elixir, SVERegion.alesia_shop, 35000, {Loot.void_essence: 35, ModLoot.void_soul: 5, Ingredient.sugar: 1,
|
||||
Meal.spicy_eel: 1}, ModNames.sve)
|
||||
Meal.spicy_eel: 1}, content_pack=ModNames.sve)
|
||||
hero_elixir = shop_recipe(ModEdible.hero_elixir, SVERegion.isaac_shop, 65000, {ModLoot.void_pebble: 3, ModLoot.void_soul: 5, Ingredient.oil: 1,
|
||||
Loot.slime: 10}, ModNames.sve)
|
||||
Loot.slime: 10}, content_pack=ModNames.sve)
|
||||
armor_elixir = shop_recipe(ModEdible.armor_elixir, SVERegion.alesia_shop, 50000, {Loot.solar_essence: 30, ModLoot.void_soul: 5, Ingredient.vinegar: 5,
|
||||
Fossil.bone_fragment: 5}, ModNames.sve)
|
||||
Fossil.bone_fragment: 5}, content_pack=ModNames.sve)
|
||||
ginger_tincture = friendship_recipe(ModConsumable.ginger_tincture, ModNPC.goblin, 4, {DistantLandsForageable.brown_amanita: 1, Forageable.ginger: 5,
|
||||
Material.cinder_shard: 1, DistantLandsForageable.swamp_herb: 1},
|
||||
ModNames.distant_lands)
|
||||
content_pack=[ModNames.distant_lands, ginger_island_content_pack.name])
|
||||
|
||||
neanderthal_skeleton = shop_recipe(ModCraftable.neanderthal_skeleton, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.neanderthal_skull: 1, ModFossil.neanderthal_ribs: 1, ModFossil.neanderthal_pelvis: 1,
|
||||
ModFossil.neanderthal_limb_bones: 1,
|
||||
MetalBar.iron: 5, Material.hardwood: 10}, ModNames.boarding_house)
|
||||
MetalBar.iron: 5, Material.hardwood: 10}, content_pack=ModNames.boarding_house)
|
||||
pterodactyl_skeleton_l = shop_recipe(ModCraftable.pterodactyl_skeleton_l, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_skull: 1, ModFossil.pterodactyl_l_wing_bone: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
pterodactyl_skeleton_m = shop_recipe(ModCraftable.pterodactyl_skeleton_m, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_vertebra: 1, ModFossil.pterodactyl_ribs: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
pterodactyl_skeleton_r = shop_recipe(ModCraftable.pterodactyl_skeleton_r, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.pterodactyl_phalange: 1, ModFossil.pterodactyl_claw: 1, ModFossil.pterodactyl_r_wing_bone: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
trex_skeleton_l = shop_recipe(ModCraftable.trex_skeleton_l, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_tooth: 1, ModFossil.dinosaur_skull: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
trex_skeleton_m = shop_recipe(ModCraftable.trex_skeleton_m, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_ribs: 1, ModFossil.dinosaur_claw: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
trex_skeleton_r = shop_recipe(ModCraftable.trex_skeleton_r, LogicRegion.mines_dwarf_shop, 5000,
|
||||
{ModFossil.dinosaur_vertebra: 1, ModFossil.dinosaur_femur: 1, ModFossil.dinosaur_pelvis: 1,
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, ModNames.boarding_house)
|
||||
MetalBar.iron: 10, Material.hardwood: 15}, content_pack=ModNames.boarding_house)
|
||||
|
||||
bouquet = skill_recipe(Gift.bouquet, ModSkill.socializing, 3, {Flower.tulip: 3}, ModNames.socializing_skill)
|
||||
trash_bin = skill_recipe(ModMachine.trash_bin, ModSkill.binning, 2, {Material.stone: 30, MetalBar.iron: 2}, ModNames.binning_skill)
|
||||
composter = skill_recipe(ModMachine.composter, ModSkill.binning, 4, {Material.wood: 70, Material.sap: 20, Material.fiber: 30}, ModNames.binning_skill)
|
||||
recycling_bin = skill_recipe(ModMachine.recycling_bin, ModSkill.binning, 7, {MetalBar.iron: 3, Material.fiber: 10, MetalBar.gold: 2}, ModNames.binning_skill)
|
||||
bouquet = skill_recipe(Gift.bouquet, ModSkill.socializing, 3, {Flower.tulip: 3}, content_pack=ModNames.socializing_skill)
|
||||
trash_bin = skill_recipe(ModMachine.trash_bin, ModSkill.binning, 2, {Material.stone: 30, MetalBar.iron: 2}, content_pack=ModNames.binning_skill)
|
||||
composter = skill_recipe(ModMachine.composter, ModSkill.binning, 4, {Material.wood: 70, Material.sap: 20, Material.fiber: 30}, content_pack=ModNames.binning_skill)
|
||||
recycling_bin = skill_recipe(ModMachine.recycling_bin, ModSkill.binning, 7, {MetalBar.iron: 3, Material.fiber: 10, MetalBar.gold: 2}, content_pack=ModNames.binning_skill)
|
||||
advanced_recycling_machine = skill_recipe(ModMachine.advanced_recycling_machine, ModSkill.binning, 9,
|
||||
{MetalBar.iridium: 5, ArtisanGood.battery_pack: 2, MetalBar.quartz: 10}, ModNames.binning_skill)
|
||||
{MetalBar.iridium: 5, ArtisanGood.battery_pack: 2, MetalBar.quartz: 10}, content_pack=ModNames.binning_skill)
|
||||
|
||||
coppper_slot_machine = skill_recipe(ModMachine.copper_slot_machine, ModSkill.luck, 2, {MetalBar.copper: 15, Material.stone: 1, Material.wood: 1,
|
||||
Material.fiber: 1, Material.sap: 1, Loot.slime: 1,
|
||||
Forageable.salmonberry: 1, Material.clay: 1, Trash.joja_cola: 1}, ModNames.luck_skill)
|
||||
Forageable.salmonberry: 1, Material.clay: 1, Trash.joja_cola: 1}, content_pack=ModNames.luck_skill)
|
||||
|
||||
gold_slot_machine = skill_recipe(ModMachine.gold_slot_machine, ModSkill.luck, 4, {MetalBar.gold: 15, ModMachine.copper_slot_machine: 1}, ModNames.luck_skill)
|
||||
iridium_slot_machine = skill_recipe(ModMachine.iridium_slot_machine, ModSkill.luck, 6, {MetalBar.iridium: 15, ModMachine.gold_slot_machine: 1}, ModNames.luck_skill)
|
||||
radioactive_slot_machine = skill_recipe(ModMachine.radioactive_slot_machine, ModSkill.luck, 8, {MetalBar.radioactive: 15, ModMachine.iridium_slot_machine: 1}, ModNames.luck_skill)
|
||||
gold_slot_machine = skill_recipe(ModMachine.gold_slot_machine, ModSkill.luck, 4, {MetalBar.gold: 15, ModMachine.copper_slot_machine: 1}, content_pack=ModNames.luck_skill)
|
||||
iridium_slot_machine = skill_recipe(ModMachine.iridium_slot_machine, ModSkill.luck, 6, {MetalBar.iridium: 15, ModMachine.gold_slot_machine: 1}, content_pack=ModNames.luck_skill)
|
||||
radioactive_slot_machine = skill_recipe(ModMachine.radioactive_slot_machine, ModSkill.luck, 8, {MetalBar.radioactive: 15, ModMachine.iridium_slot_machine: 1}, content_pack=ModNames.luck_skill)
|
||||
|
||||
all_crafting_recipes_by_name = {recipe.item: recipe for recipe in all_crafting_recipes}
|
||||
|
||||
@@ -2,9 +2,18 @@ from dataclasses import dataclass
|
||||
from typing import Tuple, Union, Optional
|
||||
|
||||
from . import season_data as season
|
||||
from .game_item import Source
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..strings.fish_names import Fish, SVEFish, DistantLandsFish
|
||||
from ..strings.region_names import Region, SVERegion, LogicRegion
|
||||
from ..strings.tool_names import FishingRod
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class FishingSource(Source):
|
||||
region: str
|
||||
minimum_rod: str = FishingRod.training
|
||||
fishing_level: int = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -15,6 +24,7 @@ class FishItem:
|
||||
difficulty: int
|
||||
legendary: bool
|
||||
extended_family: bool
|
||||
minimum_level: int
|
||||
mod_name: Optional[str] = None
|
||||
|
||||
def __repr__(self):
|
||||
@@ -55,11 +65,11 @@ vineyard = (SVERegion.blue_moon_vineyard,)
|
||||
|
||||
|
||||
def create_fish(name: str, locations: Tuple[str, ...], seasons: Union[str, Tuple[str, ...]],
|
||||
difficulty: int, legendary: bool = False, extended_family: bool = False, mod_name: Optional[str] = None) -> FishItem:
|
||||
difficulty: int, legendary: bool = False, extended_family: bool = False, minimum_level: int = 0, mod_name: Optional[str] = None) -> FishItem:
|
||||
if isinstance(seasons, str):
|
||||
seasons = (seasons,)
|
||||
|
||||
fish_item = FishItem(name, locations, seasons, difficulty, legendary, extended_family, mod_name)
|
||||
fish_item = FishItem(name, locations, seasons, difficulty, legendary, extended_family, minimum_level, mod_name)
|
||||
return fish_item
|
||||
|
||||
|
||||
@@ -118,16 +128,16 @@ blobfish = create_fish(Fish.blobfish, night_market, season.winter, 75)
|
||||
midnight_squid = create_fish(Fish.midnight_squid, night_market, season.winter, 55)
|
||||
spook_fish = create_fish(Fish.spook_fish, night_market, season.winter, 60)
|
||||
|
||||
angler = create_fish(Fish.angler, town_river, season.fall, 85, True, False)
|
||||
crimsonfish = create_fish(Fish.crimsonfish, tide_pools, season.summer, 95, True, False)
|
||||
glacierfish = create_fish(Fish.glacierfish, forest_river, season.winter, 100, True, False)
|
||||
legend = create_fish(Fish.legend, mountain_lake, season.spring, 110, True, False)
|
||||
angler = create_fish(Fish.angler, town_river, season.fall, 85, True, False, minimum_level=3)
|
||||
crimsonfish = create_fish(Fish.crimsonfish, tide_pools, season.summer, 95, True, False, minimum_level=5)
|
||||
glacierfish = create_fish(Fish.glacierfish, forest_river, season.winter, 100, True, False, minimum_level=6)
|
||||
legend = create_fish(Fish.legend, mountain_lake, season.spring, 110, True, False, minimum_level=10)
|
||||
mutant_carp = create_fish(Fish.mutant_carp, sewers, season.all_seasons, 80, True, False)
|
||||
|
||||
ms_angler = create_fish(Fish.ms_angler, town_river, season.fall, 85, True, True)
|
||||
son_of_crimsonfish = create_fish(Fish.son_of_crimsonfish, tide_pools, season.summer, 95, True, True)
|
||||
glacierfish_jr = create_fish(Fish.glacierfish_jr, forest_river, season.winter, 100, True, True)
|
||||
legend_ii = create_fish(Fish.legend_ii, mountain_lake, season.spring, 110, True, True)
|
||||
ms_angler = create_fish(Fish.ms_angler, town_river, season.fall, 85, True, True, minimum_level=3)
|
||||
son_of_crimsonfish = create_fish(Fish.son_of_crimsonfish, tide_pools, season.summer, 95, True, True, minimum_level=5)
|
||||
glacierfish_jr = create_fish(Fish.glacierfish_jr, forest_river, season.winter, 100, True, True, minimum_level=6)
|
||||
legend_ii = create_fish(Fish.legend_ii, mountain_lake, season.spring, 110, True, True, minimum_level=10)
|
||||
radioactive_carp = create_fish(Fish.radioactive_carp, sewers, season.all_seasons, 80, True, True)
|
||||
|
||||
baby_lunaloo = create_fish(SVEFish.baby_lunaloo, ginger_island_ocean, season.all_seasons, 15, mod_name=ModNames.sve)
|
||||
|
||||
50
worlds/stardew_valley/data/fish_pond_data.py
Normal file
50
worlds/stardew_valley/data/fish_pond_data.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from typing import Dict
|
||||
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.crop_names import Fruit
|
||||
from ..strings.fish_names import Fish, WaterItem
|
||||
from ..strings.food_names import Meal
|
||||
from ..strings.forageable_names import Forageable
|
||||
from ..strings.metal_names import Mineral, Ore
|
||||
from ..strings.monster_drop_names import Loot
|
||||
from ..strings.seed_names import Seed
|
||||
|
||||
# Some of these are commented out, because they shouldn't be used, because they cause a loop on themselves, even if the loop is one of many ways to complete the quest
|
||||
# I don't know the correct architectural way to fix this. So in the meantime, obtaining these items from fish ponds is not in logic
|
||||
|
||||
# Dictionary of fish pond requests, in the format of Dict[fish_name, Dict[population, Dict[item_name, item_amount]]]
|
||||
fish_pond_quests: Dict[str, Dict[int, Dict[str, int]]] = {
|
||||
Fish.blobfish: {
|
||||
1: {WaterItem.coral: 3, Mineral.frozen_tear: 2, WaterItem.sea_urchin: 2, },
|
||||
3: {Seed.coffee: 5, ArtisanGood.mayonnaise: 1, Meal.pizza: 1, },
|
||||
5: {Meal.cookie: 1, ArtisanGood.green_tea: 1, ArtisanGood.wine: 1, },
|
||||
7: {Forageable.rainbow_shell: 1, Meal.rice_pudding: 1, },
|
||||
},
|
||||
# Fish.lava_eel: {
|
||||
# 1: {Mineral.fire_quartz: 3, },
|
||||
# 3: {"Basalt": 1, Mineral.diamond: 2, Artifact.dwarf_scroll_iii: 1, },
|
||||
# 5: {Bomb.mega_bomb: 2, },
|
||||
# 7: {MetalBar.iridium: 1, },
|
||||
# },
|
||||
Fish.lionfish: {
|
||||
3: {Forageable.ginger: 3, Fruit.pineapple: 1, },
|
||||
5: {Fruit.mango: 1, },
|
||||
},
|
||||
# Fish.octopus: {
|
||||
# 3: {WaterItem.coral: 3, ArtisanGood.honey: 1, Fish.oyster: 1, MetalBar.quartz: 3, },
|
||||
# 5: {Fossil.dried_starfish: 1, Mineral.emerald: 2, Geode.omni: 2, Mushroom.purple: 2, },
|
||||
# 7: {ArtisanGood.green_tea: 1, },
|
||||
# },
|
||||
# Fish.super_cucumber: {
|
||||
# 3: {WaterItem.coral: 3, ArtisanGood.honey: 1, Fish.oyster: 1, Trash.driftwood: 3, MetalBar.quartz: 3, },
|
||||
# 5: {Fossil.dried_starfish: 1, Mineral.emerald: 2, Geode.omni: 2, Mushroom.purple: 2 },
|
||||
# 7: {Mineral.diamond: 1, MetalBar.gold: 3, Ore.iridium: 1, ArtisanGood.jelly: 1, ArtisanGood.pickles: 1, WaterItem.sea_urchin: 2 },
|
||||
# },
|
||||
Fish.void_salmon: {
|
||||
1: {Loot.void_essence: 5, },
|
||||
3: {Loot.bat_wing: 10, },
|
||||
5: {Mineral.diamond: 1, AnimalProduct.void_egg: 1, },
|
||||
7: {Ore.iridium: 1, },
|
||||
},
|
||||
}
|
||||
@@ -2,10 +2,13 @@ import enum
|
||||
from abc import ABC
|
||||
from dataclasses import dataclass, field
|
||||
from types import MappingProxyType
|
||||
from typing import List, Iterable, Set, ClassVar, Tuple, Mapping, Callable, Any
|
||||
from typing import Iterable, ClassVar, Mapping, Callable, TYPE_CHECKING
|
||||
|
||||
from ..stardew_rule.protocol import StardewRule
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..logic.logic import StardewLogic
|
||||
|
||||
DEFAULT_REQUIREMENT_TAGS = MappingProxyType({})
|
||||
|
||||
|
||||
@@ -24,34 +27,47 @@ class ItemTag(enum.Enum):
|
||||
BOOK = enum.auto()
|
||||
BOOK_POWER = enum.auto()
|
||||
BOOK_SKILL = enum.auto()
|
||||
HAT = enum.auto()
|
||||
FORAGE = enum.auto()
|
||||
COOKING = enum.auto()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Source(ABC):
|
||||
add_tags: ClassVar[Tuple[ItemTag]] = ()
|
||||
add_tags: ClassVar[tuple[ItemTag]] = ()
|
||||
|
||||
other_requirements: Tuple[Requirement, ...] = field(kw_only=True, default_factory=tuple)
|
||||
other_requirements: tuple[Requirement, ...] = field(kw_only=True, default=())
|
||||
|
||||
@property
|
||||
def requirement_tags(self) -> Mapping[str, Tuple[ItemTag, ...]]:
|
||||
def requirement_tags(self) -> Mapping[str, tuple[ItemTag, ...]]:
|
||||
return DEFAULT_REQUIREMENT_TAGS
|
||||
|
||||
@property
|
||||
def all_requirements(self) -> Iterable[Requirement]:
|
||||
"""Returns all requirements that are not directly part of the source."""
|
||||
return self.other_requirements
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class GenericSource(Source):
|
||||
regions: Tuple[str, ...] = ()
|
||||
regions: tuple[str, ...] = ()
|
||||
"""No region means it's available everywhere."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AllRegionsSource(Source):
|
||||
regions: tuple[str, ...] = ()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CustomRuleSource(Source):
|
||||
"""Hopefully once everything is migrated to sources, we won't need these custom logic anymore."""
|
||||
create_rule: Callable[[Any], StardewRule]
|
||||
create_rule: "Callable[[StardewLogic], StardewRule]"
|
||||
|
||||
|
||||
class Tag(Source):
|
||||
"""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, ...]
|
||||
tag: tuple[ItemTag, ...]
|
||||
|
||||
def __init__(self, *tag: ItemTag):
|
||||
self.tag = tag # noqa
|
||||
@@ -64,8 +80,8 @@ class Tag(Source):
|
||||
@dataclass(frozen=True)
|
||||
class GameItem:
|
||||
name: str
|
||||
sources: List[Source] = field(default_factory=list)
|
||||
tags: Set[ItemTag] = field(default_factory=set)
|
||||
sources: list[Source] = field(default_factory=list)
|
||||
tags: set[ItemTag] = field(default_factory=set)
|
||||
|
||||
def add_sources(self, sources: Iterable[Source]):
|
||||
self.sources.extend(source for source in sources if type(source) is not Tag)
|
||||
|
||||
@@ -9,6 +9,8 @@ from ..strings.season_names import Season
|
||||
class ForagingSource(Source):
|
||||
regions: Tuple[str, ...]
|
||||
seasons: Tuple[str, ...] = Season.all
|
||||
require_all_regions: bool = False
|
||||
grind_months: int = 0
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
|
||||
160
worlds/stardew_valley/data/hats_data.py
Normal file
160
worlds/stardew_valley/data/hats_data.py
Normal file
@@ -0,0 +1,160 @@
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from typing import List
|
||||
|
||||
from worlds.stardew_valley.strings.ap_names.ap_option_names import HatsanityOptionName
|
||||
|
||||
hat_clarifier = " (Hat)"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HatItem:
|
||||
name: str
|
||||
difficulty: frozenset[str]
|
||||
need_clarifier: bool = False
|
||||
|
||||
def __post_init__(self):
|
||||
all_hats.append(self)
|
||||
|
||||
@cached_property
|
||||
def clarified_name(self) -> str:
|
||||
if self.need_clarifier:
|
||||
return self.name + hat_clarifier
|
||||
return self.name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.name} (Difficulty: {self.difficulty})"
|
||||
|
||||
|
||||
def create_hat(name: str, difficulty: List[str] | str, need_clarifier: bool = False) -> HatItem:
|
||||
if isinstance(difficulty, str):
|
||||
difficulty = [difficulty]
|
||||
return HatItem(name, frozenset(difficulty), need_clarifier)
|
||||
|
||||
|
||||
all_hats: list[HatItem] = []
|
||||
|
||||
|
||||
class Hats:
|
||||
abigails_bow = create_hat("Abigail's Bow", HatsanityOptionName.rng)
|
||||
arcane_hat = create_hat("Arcane Hat", HatsanityOptionName.near_perfection)
|
||||
archers_cap = create_hat("Archer's Cap", HatsanityOptionName.near_perfection)
|
||||
beanie = create_hat("Beanie", HatsanityOptionName.tailoring)
|
||||
blobfish_mask = create_hat("Blobfish Mask", HatsanityOptionName.tailoring)
|
||||
blue_bonnet = create_hat("Blue Bonnet", HatsanityOptionName.medium)
|
||||
blue_bow = create_hat("Blue Bow", HatsanityOptionName.easy)
|
||||
blue_cowboy_hat = create_hat("Blue Cowboy Hat", HatsanityOptionName.rng)
|
||||
blue_ribbon = create_hat("Blue Ribbon", HatsanityOptionName.medium)
|
||||
bluebird_mask = create_hat("Bluebird Mask", HatsanityOptionName.medium)
|
||||
bowler = create_hat("Bowler Hat", HatsanityOptionName.difficult)
|
||||
bridal_veil = create_hat("Bridal Veil", HatsanityOptionName.tailoring)
|
||||
bucket_hat = create_hat("Bucket Hat", HatsanityOptionName.medium)
|
||||
butterfly_bow = create_hat("Butterfly Bow", HatsanityOptionName.easy)
|
||||
cat_ears = create_hat("Cat Ears", HatsanityOptionName.medium)
|
||||
chef_hat = create_hat("Chef Hat", HatsanityOptionName.near_perfection)
|
||||
chicken_mask = create_hat("Chicken Mask", HatsanityOptionName.near_perfection)
|
||||
concerned_ape_mask = create_hat("???", HatsanityOptionName.post_perfection)
|
||||
cone_hat = create_hat("Cone Hat", HatsanityOptionName.easy)
|
||||
cool_cap = create_hat("Cool Cap", HatsanityOptionName.medium)
|
||||
copper_pan_hat = create_hat("Copper Pan", HatsanityOptionName.easy, need_clarifier=True)
|
||||
cowboy = create_hat("Cowboy Hat", HatsanityOptionName.near_perfection)
|
||||
cowgal_hat = create_hat("Cowgal Hat", HatsanityOptionName.difficult)
|
||||
cowpoke_hat = create_hat("Cowpoke Hat", HatsanityOptionName.difficult)
|
||||
daisy = create_hat("Daisy", HatsanityOptionName.easy)
|
||||
dark_ballcap = create_hat("Dark Ballcap", HatsanityOptionName.rng)
|
||||
dark_cowboy_hat = create_hat("Dark Cowboy Hat", HatsanityOptionName.rng)
|
||||
dark_velvet_bow = create_hat("Dark Velvet Bow", HatsanityOptionName.easy)
|
||||
delicate_bow = create_hat("Delicate Bow", HatsanityOptionName.easy)
|
||||
deluxe_cowboy_hat = create_hat("Deluxe Cowboy Hat", HatsanityOptionName.medium)
|
||||
deluxe_pirate_hat = create_hat("Deluxe Pirate Hat", HatsanityOptionName.rng)
|
||||
dinosaur_hat = create_hat("Dinosaur Hat", HatsanityOptionName.tailoring)
|
||||
earmuffs = create_hat("Earmuffs", HatsanityOptionName.medium)
|
||||
elegant_turban = create_hat("Elegant Turban", HatsanityOptionName.post_perfection)
|
||||
emilys_magic_hat = create_hat("Emily's Magic Hat", HatsanityOptionName.medium)
|
||||
eye_patch = create_hat("Eye Patch", HatsanityOptionName.near_perfection)
|
||||
fashion_hat = create_hat("Fashion Hat", HatsanityOptionName.tailoring)
|
||||
fedora = create_hat("Fedora", HatsanityOptionName.easy)
|
||||
fishing_hat = create_hat("Fishing Hat", HatsanityOptionName.tailoring)
|
||||
flat_topped_hat = create_hat("Flat Topped Hat", HatsanityOptionName.tailoring)
|
||||
floppy_beanie = create_hat("Floppy Beanie", HatsanityOptionName.tailoring)
|
||||
foragers_hat = create_hat("Forager's Hat", HatsanityOptionName.tailoring)
|
||||
frog_hat = create_hat("Frog Hat", HatsanityOptionName.medium)
|
||||
garbage_hat = create_hat("Garbage Hat", HatsanityOptionName.rng)
|
||||
gils_hat = create_hat("Gil's Hat", HatsanityOptionName.difficult)
|
||||
gnomes_cap = create_hat("Gnome's Cap", HatsanityOptionName.near_perfection)
|
||||
goblin_mask = create_hat("Goblin Mask", HatsanityOptionName.near_perfection)
|
||||
goggles = create_hat("Goggles", HatsanityOptionName.tailoring)
|
||||
gold_pan_hat = create_hat("Gold Pan", HatsanityOptionName.easy, need_clarifier=True)
|
||||
golden_helmet = create_hat("Golden Helmet", HatsanityOptionName.rng)
|
||||
golden_mask = create_hat("Golden Mask", HatsanityOptionName.tailoring, need_clarifier=True)
|
||||
good_ol_cap = create_hat("Good Ol' Cap", HatsanityOptionName.easy)
|
||||
governors_hat = create_hat("Governor's Hat", HatsanityOptionName.medium)
|
||||
green_turban = create_hat("Green Turban", HatsanityOptionName.medium)
|
||||
hair_bone = create_hat("Hair Bone", HatsanityOptionName.tailoring)
|
||||
hard_hat = create_hat("Hard Hat", HatsanityOptionName.difficult)
|
||||
hunters_cap = create_hat("Hunter's Cap", HatsanityOptionName.medium)
|
||||
infinity_crown = create_hat("Infinity Crown", HatsanityOptionName.difficult)
|
||||
iridium_pan_hat = create_hat("Iridium Pan", HatsanityOptionName.easy, need_clarifier=True)
|
||||
jester_hat = create_hat("Jester Hat", HatsanityOptionName.easy)
|
||||
joja_cap = create_hat("Joja Cap", HatsanityOptionName.rng)
|
||||
junimo_hat = create_hat("Junimo Hat", HatsanityOptionName.post_perfection)
|
||||
knights_helmet = create_hat("Knight's Helmet", HatsanityOptionName.near_perfection)
|
||||
laurel_wreath_crown = create_hat("Laurel Wreath Crown", HatsanityOptionName.rng)
|
||||
leprechaun_hat = create_hat("Leprechaun Hat", HatsanityOptionName.easy)
|
||||
living_hat = create_hat("Living Hat", HatsanityOptionName.rng)
|
||||
logo_cap = create_hat("Logo Cap", HatsanityOptionName.tailoring)
|
||||
lucky_bow = create_hat("Lucky Bow", HatsanityOptionName.medium)
|
||||
magic_cowboy_hat = create_hat("Magic Cowboy Hat", HatsanityOptionName.difficult)
|
||||
magic_turban = create_hat("Magic Turban", HatsanityOptionName.difficult)
|
||||
mouse_ears = create_hat("Mouse Ears", HatsanityOptionName.easy)
|
||||
mr_qis_hat = create_hat("Mr. Qi's Hat", HatsanityOptionName.medium)
|
||||
mummy_mask = create_hat("Mummy Mask", HatsanityOptionName.easy)
|
||||
mushroom_cap = create_hat("Mushroom Cap", HatsanityOptionName.rng)
|
||||
mystery_hat = create_hat("Mystery Hat", HatsanityOptionName.rng)
|
||||
official_cap = create_hat("Official Cap", HatsanityOptionName.medium)
|
||||
pageboy_cap = create_hat("Pageboy Cap", HatsanityOptionName.near_perfection)
|
||||
panda_hat = create_hat("Panda Hat", "Impossible")
|
||||
paper_hat = create_hat("Paper Hat", HatsanityOptionName.easy)
|
||||
party_hat_blue = create_hat("Party Hat (Blue)", HatsanityOptionName.tailoring)
|
||||
party_hat_green = create_hat("Party Hat (Green)", HatsanityOptionName.tailoring)
|
||||
party_hat_red = create_hat("Party Hat (Red)", HatsanityOptionName.tailoring)
|
||||
pink_bow = create_hat("Pink Bow", HatsanityOptionName.easy)
|
||||
pirate_hat = create_hat("Pirate Hat", HatsanityOptionName.tailoring)
|
||||
plum_chapeau = create_hat("Plum Chapeau", HatsanityOptionName.difficult)
|
||||
polka_bow = create_hat("Polka Bow", HatsanityOptionName.medium)
|
||||
propeller_hat = create_hat("Propeller Hat", HatsanityOptionName.tailoring)
|
||||
pumpkin_mask = create_hat("Pumpkin Mask", HatsanityOptionName.tailoring)
|
||||
qi_mask = create_hat("Qi Mask", HatsanityOptionName.tailoring)
|
||||
raccoon_hat = create_hat("Raccoon Hat", HatsanityOptionName.medium)
|
||||
radioactive_goggles = create_hat("Radioactive Goggles", HatsanityOptionName.tailoring)
|
||||
red_cowboy_hat = create_hat("Red Cowboy Hat", HatsanityOptionName.rng)
|
||||
red_fez = create_hat("Red Fez", HatsanityOptionName.medium)
|
||||
sailors_cap = create_hat("Sailor's Cap", HatsanityOptionName.easy)
|
||||
santa_hat = create_hat("Santa Hat", HatsanityOptionName.medium)
|
||||
skeleton_mask = create_hat("Skeleton Mask", HatsanityOptionName.medium)
|
||||
small_cap = create_hat("Small Cap", HatsanityOptionName.medium)
|
||||
sombrero = create_hat("Sombrero", HatsanityOptionName.near_perfection)
|
||||
souwester = create_hat("Sou'wester", HatsanityOptionName.easy)
|
||||
space_helmet = create_hat("Space Helmet", HatsanityOptionName.difficult)
|
||||
sports_cap = create_hat("Sports Cap", HatsanityOptionName.medium)
|
||||
spotted_headscarf = create_hat("Spotted Headscarf", HatsanityOptionName.tailoring)
|
||||
squid_hat = create_hat("Squid Hat", HatsanityOptionName.medium)
|
||||
squires_helmet = create_hat("Squire's Helmet", HatsanityOptionName.rng)
|
||||
star_helmet = create_hat("Star Helmet", HatsanityOptionName.tailoring)
|
||||
steel_pan_hat = create_hat("Steel Pan", HatsanityOptionName.easy, need_clarifier=True)
|
||||
straw = create_hat("Straw Hat", HatsanityOptionName.medium)
|
||||
sunglasses = create_hat("Sunglasses", HatsanityOptionName.tailoring)
|
||||
swashbuckler_hat = create_hat("Swashbuckler Hat", HatsanityOptionName.tailoring)
|
||||
tiara = create_hat("Tiara", HatsanityOptionName.easy)
|
||||
tiger_hat = create_hat("Tiger Hat", HatsanityOptionName.rng)
|
||||
top_hat = create_hat("Top Hat", HatsanityOptionName.easy)
|
||||
totem_mask = create_hat("Totem Mask", HatsanityOptionName.tailoring)
|
||||
tricorn = create_hat("Tricorn Hat", HatsanityOptionName.rng)
|
||||
tropiclip = create_hat("Tropiclip", HatsanityOptionName.easy)
|
||||
trucker_hat = create_hat("Trucker Hat", HatsanityOptionName.medium)
|
||||
warrior_helmet = create_hat("Warrior Helmet", HatsanityOptionName.tailoring)
|
||||
watermelon_band = create_hat("Watermelon Band", HatsanityOptionName.difficult)
|
||||
wearable_dwarf_helm = create_hat("Wearable Dwarf Helm", HatsanityOptionName.tailoring)
|
||||
white_bow = create_hat("White Bow", HatsanityOptionName.difficult)
|
||||
white_turban = create_hat("White Turban", HatsanityOptionName.tailoring)
|
||||
witch_hat = create_hat("Witch Hat", HatsanityOptionName.tailoring)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Tuple, Dict, Set, Callable
|
||||
from typing import List, Tuple, Dict, Callable
|
||||
|
||||
from .game_item import Source
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..mods.mod_monster_locations import modded_monsters_locations
|
||||
from ..strings.monster_names import Monster, MonsterCategory
|
||||
@@ -12,7 +13,7 @@ from ..strings.region_names import Region
|
||||
class StardewMonster:
|
||||
name: str
|
||||
category: str
|
||||
locations: Tuple[str]
|
||||
locations: Tuple[str, ...]
|
||||
difficulty: str
|
||||
|
||||
def __repr__(self):
|
||||
@@ -20,6 +21,12 @@ class StardewMonster:
|
||||
f" Difficulty: {self.difficulty}) |"
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class MonsterSource(Source):
|
||||
monsters: Tuple[StardewMonster, ...]
|
||||
amount_tier: int = 0
|
||||
|
||||
|
||||
slime_hutch = (Region.slime_hutch,)
|
||||
mines_floor_20 = (Region.mines_floor_20,)
|
||||
mines_floor_60 = (Region.mines_floor_60,)
|
||||
@@ -97,6 +104,8 @@ armored_bug = create_monster(Monster.armored_bug, MonsterCategory.cave_insects,
|
||||
armored_bug_dangerous = create_monster(Monster.armored_bug_dangerous, MonsterCategory.cave_insects, skull_cavern,
|
||||
Performance.good) # Requires 'Bug Killer' enchantment
|
||||
|
||||
metal_head = create_monster(Monster.metal_head, MonsterCategory.metal_heads, mines_floor_100, Performance.good)
|
||||
|
||||
duggy = create_monster(Monster.duggy, MonsterCategory.duggies, mines_floor_20, Performance.basic)
|
||||
duggy_dangerous = create_monster(Monster.duggy_dangerous, MonsterCategory.duggies, dangerous_mines_20, Performance.great)
|
||||
magma_duggy = create_monster(Monster.magma_duggy, MonsterCategory.duggies, volcano, Performance.galaxy)
|
||||
@@ -122,6 +131,8 @@ royal_serpent = create_monster(Monster.royal_serpent, MonsterCategory.serpents,
|
||||
magma_sprite = create_monster(Monster.magma_sprite, MonsterCategory.magma_sprites, volcano, Performance.galaxy)
|
||||
magma_sparker = create_monster(Monster.magma_sparker, MonsterCategory.magma_sprites, volcano_high, Performance.galaxy)
|
||||
|
||||
haunted_skull = create_monster(Monster.haunted_skull, MonsterCategory.none, quarry_mine, Performance.great)
|
||||
|
||||
register_monster_modification(ModNames.sve, shadow_brute_dangerous, update_monster_locations)
|
||||
register_monster_modification(ModNames.sve, shadow_sniper, update_monster_locations)
|
||||
register_monster_modification(ModNames.sve, shadow_shaman_dangerous, update_monster_locations)
|
||||
@@ -145,7 +156,7 @@ register_monster_modification(ModNames.boarding_house, grub, update_monster_loca
|
||||
register_monster_modification(ModNames.boarding_house, bug, update_monster_locations)
|
||||
|
||||
|
||||
def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster]:
|
||||
def all_monsters_by_name_given_content_packs(mods: set[str]) -> dict[str, StardewMonster]:
|
||||
monsters_by_name = {}
|
||||
for monster in all_monsters:
|
||||
current_monster = monster
|
||||
@@ -158,7 +169,7 @@ def all_monsters_by_name_given_mods(mods: Set[str]) -> Dict[str, StardewMonster]
|
||||
return monsters_by_name
|
||||
|
||||
|
||||
def all_monsters_by_category_given_mods(mods: Set[str]) -> Dict[str, Tuple[StardewMonster, ...]]:
|
||||
def all_monsters_by_category_given_content_packs(mods: set[str]) -> dict[str, Tuple[StardewMonster, ...]]:
|
||||
monsters_by_category = {}
|
||||
for monster in all_monsters:
|
||||
current_monster = monster
|
||||
|
||||
99
worlds/stardew_valley/data/movies.py
Normal file
99
worlds/stardew_valley/data/movies.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from typing import List
|
||||
|
||||
from ..strings.season_names import Season
|
||||
from ..strings.villager_names import NPC
|
||||
|
||||
movies_by_name = dict()
|
||||
snacks_by_name = dict()
|
||||
npc_snacks = dict()
|
||||
|
||||
|
||||
def movie(movie_name: str, season: str, loving_npcs: List[str]):
|
||||
movie = Movie(movie_name, season, loving_npcs)
|
||||
movies_by_name[movie_name] = movie
|
||||
return movie
|
||||
|
||||
|
||||
def snack(snack_name: str, category: str, loving_npcs: List[str]):
|
||||
snack = Snack(snack_name, category, loving_npcs)
|
||||
snacks_by_name[snack_name] = snack
|
||||
for npc in loving_npcs:
|
||||
if npc not in npc_snacks:
|
||||
npc_snacks[npc] = []
|
||||
npc_snacks[npc].append(snack)
|
||||
return snack
|
||||
|
||||
|
||||
class Movie:
|
||||
name: str
|
||||
season: str
|
||||
loving_npcs: List[str]
|
||||
|
||||
def __init__(self, name: str, season: str, loving_npcs: List[str]):
|
||||
self.name = name
|
||||
self.season = season
|
||||
self.loving_npcs = loving_npcs
|
||||
|
||||
|
||||
class Snack:
|
||||
name: str
|
||||
category: str
|
||||
loving_npcs: List[str]
|
||||
|
||||
def __init__(self, name: str, category: str, loving_npcs: List[str]):
|
||||
self.name = name
|
||||
self.category = category
|
||||
self.loving_npcs = loving_npcs
|
||||
|
||||
|
||||
class MovieName:
|
||||
brave_sapling = movie("The Brave Little Sapling", Season.spring, [NPC.caroline, NPC.dwarf, NPC.jas, NPC.penny, NPC.sandy, NPC.vincent])
|
||||
prairie_king = movie("Journey Of The Prairie King: The Motion Picture", Season.summer, [NPC.caroline, NPC.dwarf, NPC.jas, NPC.robin, NPC.sandy, NPC.vincent])
|
||||
mysterium = movie("Mysterium", Season.fall, [NPC.abigail, NPC.dwarf, NPC.elliott, NPC.leah, NPC.sandy, NPC.sebastian, NPC.wizard])
|
||||
miracle_coldstar_ranch = movie("The Miracle At Coldstar Ranch", Season.winter, [NPC.dwarf, NPC.emily, NPC.evelyn, NPC.gus, NPC.harvey, NPC.marnie, NPC.sandy])
|
||||
natural_wonders = movie("Natural Wonders: Exploring Our Vibrant World", Season.spring, [NPC.demetrius, NPC.dwarf, NPC.jas, NPC.leo, NPC.lewis, NPC.maru, NPC.sandy])
|
||||
wumbus = movie("Wumbus", Season.summer, [NPC.alex, NPC.demetrius, NPC.dwarf, NPC.gus, NPC.jas, NPC.maru, NPC.pierre, NPC.sam, NPC.sandy, NPC.shane, NPC.vincent])
|
||||
howls_in_rain = movie("It Howls In The Rain", Season.fall, [NPC.abigail, NPC.alex, NPC.dwarf, NPC.sandy, NPC.sebastian, NPC.shane])
|
||||
zuzu_city_express = movie("The Zuzu City Express", Season.winter, [NPC.dwarf, NPC.evelyn, NPC.george, NPC.harvey, NPC.jodi, NPC.sandy])
|
||||
|
||||
|
||||
class SnackCategory:
|
||||
salty = "Movie Salty Snacks"
|
||||
sweet = "Movie Sweet Snacks"
|
||||
drinks = "Movie Drinks"
|
||||
meals = "Movie Meals"
|
||||
|
||||
|
||||
class SnackName:
|
||||
apple_slices = snack("Apple Slices", SnackCategory.sweet, [NPC.harvey])
|
||||
black_licorice = snack("Black Licorice", SnackCategory.sweet, [NPC.george, NPC.krobus, NPC.wizard])
|
||||
cappuccino_mousse_cake = snack("Cappuccino Mousse Cake", SnackCategory.sweet, [NPC.elliott, NPC.evelyn, NPC.gus, NPC.haley])
|
||||
chocolate_popcorn = snack("Chocolate Popcorn", SnackCategory.sweet, [NPC.jodi])
|
||||
cotton_candy = snack("Cotton Candy", SnackCategory.sweet, [NPC.penny, NPC.sandy])
|
||||
fries = snack("Fries", SnackCategory.salty, [NPC.clint])
|
||||
hummus_snack_pack = snack("Hummus Snack Pack", SnackCategory.salty, [NPC.shane])
|
||||
ice_cream_sandwich = snack("Ice Cream Sandwich", SnackCategory.sweet, [NPC.marnie])
|
||||
jasmine_tea = snack("Jasmine Tea", SnackCategory.drinks, [NPC.caroline, NPC.harvey, NPC.lewis, NPC.sebastian])
|
||||
jawbreaker = snack("Jawbreaker", SnackCategory.sweet, [NPC.vincent])
|
||||
joja_cola = snack("Joja Cola", SnackCategory.drinks, [NPC.shane])
|
||||
jojacorn = snack("JojaCorn", SnackCategory.salty, [NPC.shane])
|
||||
kale_smoothie = snack("Kale Smoothie", SnackCategory.drinks, [NPC.emily])
|
||||
nachos = snack("Nachos", SnackCategory.meals, [NPC.pam, NPC.shane])
|
||||
panzanella_salad = snack("Panzanella Salad", SnackCategory.meals, [NPC.gus, NPC.leah])
|
||||
personal_pizza = snack("Personal Pizza", SnackCategory.meals, [NPC.pierre, NPC.sam, NPC.shane])
|
||||
popcorn = snack("Popcorn", SnackCategory.salty, [NPC.demetrius, NPC.kent])
|
||||
rock_candy = snack("Rock Candy", SnackCategory.sweet, [NPC.abigail, NPC.dwarf])
|
||||
salmon_burger = snack("Salmon Burger", SnackCategory.meals, [NPC.alex, NPC.linus, NPC.willy])
|
||||
salted_peanuts = snack("Salted Peanuts", SnackCategory.salty, [NPC.robin])
|
||||
sour_slimes = snack("Sour Slimes", SnackCategory.sweet, [NPC.jas])
|
||||
star_cookie = snack("Star Cookie", SnackCategory.sweet, [NPC.evelyn, NPC.maru, NPC.wizard])
|
||||
stardrop_sorbet = snack("Stardrop Sorbet", SnackCategory.sweet, [NPC.alex, NPC.harvey, NPC.sam, NPC.sebastian, NPC.shane, NPC.abigail, NPC.emily, NPC.haley,
|
||||
NPC.leah, NPC.maru, NPC.penny, NPC.caroline, NPC.clint, NPC.demetrius, NPC.dwarf, NPC.evelyn,
|
||||
NPC.george, NPC.gus, NPC.jas, NPC.jodi, NPC.kent, NPC.lewis, NPC.linus, NPC.marnie, NPC.pam,
|
||||
NPC.pierre, NPC.robin, NPC.sandy, NPC.vincent, NPC.willy, NPC.wizard])
|
||||
truffle_popcorn = snack("Truffle Popcorn", SnackCategory.salty, [NPC.caroline, NPC.elliott, NPC.gus])
|
||||
|
||||
|
||||
# For some unknown reason, Leo doesn't love ANY snack
|
||||
npc_snacks[NPC.leo] = []
|
||||
|
||||
@@ -15,7 +15,7 @@ from ..strings.region_names import Region
|
||||
@dataclass(frozen=True)
|
||||
class MuseumItem:
|
||||
item_name: str
|
||||
locations: Tuple[str, ...]
|
||||
artifact_spot_locations: Tuple[str, ...]
|
||||
geodes: Tuple[str, ...]
|
||||
monsters: Tuple[str, ...]
|
||||
difficulty: float
|
||||
@@ -23,11 +23,11 @@ class MuseumItem:
|
||||
@staticmethod
|
||||
def of(item_name: str,
|
||||
difficulty: float,
|
||||
locations: Union[str, Tuple[str, ...]],
|
||||
artifact_spot_locations: Union[str, Tuple[str, ...]],
|
||||
geodes: Union[str, Tuple[str, ...]],
|
||||
monsters: Union[str, Tuple[str, ...]]) -> MuseumItem:
|
||||
if isinstance(locations, str):
|
||||
locations = (locations,)
|
||||
if isinstance(artifact_spot_locations, str):
|
||||
artifact_spot_locations = (artifact_spot_locations,)
|
||||
|
||||
if isinstance(geodes, str):
|
||||
geodes = (geodes,)
|
||||
@@ -35,10 +35,10 @@ class MuseumItem:
|
||||
if isinstance(monsters, str):
|
||||
monsters = (monsters,)
|
||||
|
||||
return MuseumItem(item_name, locations, geodes, monsters, difficulty)
|
||||
return MuseumItem(item_name, artifact_spot_locations, geodes, monsters, difficulty)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.item_name} (Locations: {self.locations} |" \
|
||||
return f"{self.item_name} (Artifact Spot Locations: {self.artifact_spot_locations} |" \
|
||||
f" Geodes: {self.geodes} |" \
|
||||
f" Monsters: {self.monsters}) "
|
||||
|
||||
@@ -53,17 +53,17 @@ all_museum_items: List[MuseumItem] = []
|
||||
|
||||
def create_artifact(name: str,
|
||||
difficulty: float,
|
||||
locations: Union[str, Tuple[str, ...]] = (),
|
||||
artifact_spot_locations: Union[str, Tuple[str, ...]] = (),
|
||||
geodes: Union[str, Tuple[str, ...]] = (),
|
||||
monsters: Union[str, Tuple[str, ...]] = ()) -> MuseumItem:
|
||||
artifact_item = MuseumItem.of(name, difficulty, locations, geodes, monsters)
|
||||
artifact_item = MuseumItem.of(name, difficulty, artifact_spot_locations, geodes, monsters)
|
||||
all_museum_artifacts.append(artifact_item)
|
||||
all_museum_items.append(artifact_item)
|
||||
return artifact_item
|
||||
|
||||
|
||||
def create_mineral(name: str,
|
||||
locations: Union[str, Tuple[str, ...]] = (),
|
||||
artifact_spot_locations: Union[str, Tuple[str, ...]] = (),
|
||||
geodes: Union[str, Tuple[str, ...]] = (),
|
||||
monsters: Union[str, Tuple[str, ...]] = (),
|
||||
difficulty: Optional[float] = None) -> MuseumItem:
|
||||
@@ -80,7 +80,7 @@ def create_mineral(name: str,
|
||||
if "Fishing Chest" in geodes:
|
||||
difficulty += 4.3
|
||||
|
||||
mineral_item = MuseumItem.of(name, difficulty, locations, geodes, monsters)
|
||||
mineral_item = MuseumItem.of(name, difficulty, artifact_spot_locations, geodes, monsters)
|
||||
all_museum_minerals.append(mineral_item)
|
||||
all_museum_items.append(mineral_item)
|
||||
return mineral_item
|
||||
@@ -168,7 +168,7 @@ class Artifact:
|
||||
geodes=WaterChest.fishing_chest)
|
||||
palm_fossil = create_artifact("Palm Fossil", 10.2,
|
||||
(Region.dig_site, Region.desert, Region.forest, Region.beach))
|
||||
trilobite = create_artifact("Trilobite", 7.4, (Region.dig_site, Region.desert, Region.forest, Region.beach))
|
||||
trilobite = create_artifact(Fossil.trilobite, 7.4, (Region.dig_site, Region.desert, Region.forest, Region.beach))
|
||||
|
||||
|
||||
class Mineral:
|
||||
@@ -267,15 +267,15 @@ class Mineral:
|
||||
geodes=(Geode.geode, Geode.omni))
|
||||
basalt = create_mineral("Basalt",
|
||||
geodes=(Geode.magma, Geode.omni))
|
||||
limestone = create_mineral("Limestone",
|
||||
limestone = create_mineral(Mineral.limestone,
|
||||
geodes=(Geode.geode, Geode.omni))
|
||||
soapstone = create_mineral("Soapstone",
|
||||
geodes=(Geode.frozen, Geode.omni))
|
||||
hematite = create_mineral("Hematite",
|
||||
geodes=(Geode.frozen, Geode.omni))
|
||||
mudstone = create_mineral("Mudstone",
|
||||
mudstone = create_mineral(Mineral.mudstone,
|
||||
geodes=(Geode.geode, Geode.omni))
|
||||
obsidian = create_mineral("Obsidian",
|
||||
obsidian = create_mineral(Mineral.obsidian,
|
||||
geodes=(Geode.magma, Geode.omni))
|
||||
slate = create_mineral("Slate", geodes=(Geode.geode, Geode.omni))
|
||||
fairy_stone = create_mineral("Fairy Stone", geodes=(Geode.frozen, Geode.omni))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from typing import Dict, List, Optional
|
||||
from typing import List
|
||||
|
||||
from .recipe_source import RecipeSource, FriendshipSource, SkillSource, QueenOfSauceSource, ShopSource, StarterSource, ShopTradeSource, ShopFriendshipSource
|
||||
from ..content.content_packs import ginger_island_content_pack
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
@@ -23,15 +24,15 @@ from ..strings.villager_names import NPC, ModNPC
|
||||
|
||||
class CookingRecipe:
|
||||
meal: str
|
||||
ingredients: Dict[str, int]
|
||||
ingredients: dict[str, int]
|
||||
source: RecipeSource
|
||||
mod_name: Optional[str] = None
|
||||
content_pack: str | None
|
||||
|
||||
def __init__(self, meal: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None):
|
||||
def __init__(self, meal: str, ingredients: dict[str, int], source: RecipeSource, content_pack: str | None):
|
||||
self.meal = meal
|
||||
self.ingredients = ingredients
|
||||
self.source = source
|
||||
self.mod_name = mod_name
|
||||
self.content_pack = content_pack
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.meal} (Source: {self.source} |" \
|
||||
@@ -41,44 +42,44 @@ class CookingRecipe:
|
||||
all_cooking_recipes: List[CookingRecipe] = []
|
||||
|
||||
|
||||
def friendship_recipe(name: str, friend: str, hearts: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe:
|
||||
def friendship_recipe(name: str, friend: str, hearts: int, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = FriendshipSource(friend, hearts)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def friendship_and_shop_recipe(name: str, friend: str, hearts: int, region: str, price: int, ingredients: Dict[str, int],
|
||||
mod_name: Optional[str] = None) -> CookingRecipe:
|
||||
def friendship_and_shop_recipe(name: str, friend: str, hearts: int, region: str, price: int, ingredients: dict[str, int],
|
||||
/, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = ShopFriendshipSource(friend, hearts, region, price)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def skill_recipe(name: str, skill: str, level: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe:
|
||||
def skill_recipe(name: str, skill: str, level: int, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = SkillSource(skill, level)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def shop_recipe(name: str, region: str, price: int, ingredients: Dict[str, int], mod_name: Optional[str] = None) -> CookingRecipe:
|
||||
def shop_recipe(name: str, region: str, price: int, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = ShopSource(region, price)
|
||||
return create_recipe(name, ingredients, source, mod_name)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: Dict[str, int]) -> CookingRecipe:
|
||||
def shop_trade_recipe(name: str, region: str, currency: str, price: int, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = ShopTradeSource(region, currency, price)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredients: Dict[str, int]) -> CookingRecipe:
|
||||
def queen_of_sauce_recipe(name: str, year: int, season: str, day: int, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = QueenOfSauceSource(year, season, day)
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def starter_recipe(name: str, ingredients: Dict[str, int]) -> CookingRecipe:
|
||||
def starter_recipe(name: str, ingredients: dict[str, int], /, *, content_pack: str | None = None) -> CookingRecipe:
|
||||
source = StarterSource()
|
||||
return create_recipe(name, ingredients, source)
|
||||
return create_recipe(name, ingredients, source, content_pack)
|
||||
|
||||
|
||||
def create_recipe(name: str, ingredients: Dict[str, int], source: RecipeSource, mod_name: Optional[str] = None) -> CookingRecipe:
|
||||
recipe = CookingRecipe(name, ingredients, source, mod_name)
|
||||
def create_recipe(name: str, ingredients: dict[str, int], source: RecipeSource, content_pack: str | None = None) -> CookingRecipe:
|
||||
recipe = CookingRecipe(name, ingredients, source, content_pack)
|
||||
all_cooking_recipes.append(recipe)
|
||||
return recipe
|
||||
|
||||
@@ -88,7 +89,8 @@ artichoke_dip = queen_of_sauce_recipe(Meal.artichoke_dip, 1, Season.fall, 28, {V
|
||||
autumn_bounty = friendship_recipe(Meal.autumn_bounty, NPC.demetrius, 7, {Vegetable.yam: 1, Vegetable.pumpkin: 1})
|
||||
baked_fish = queen_of_sauce_recipe(Meal.baked_fish, 1, Season.summer, 7, {Fish.sunfish: 1, Fish.bream: 1, Ingredient.wheat_flour: 1})
|
||||
banana_pudding = shop_trade_recipe(Meal.banana_pudding, Region.island_trader, Fossil.bone_fragment, 30,
|
||||
{Fruit.banana: 1, AnimalProduct.cow_milk: 1, Ingredient.sugar: 1})
|
||||
{Fruit.banana: 1, AnimalProduct.cow_milk: 1, Ingredient.sugar: 1},
|
||||
content_pack=ginger_island_content_pack.name)
|
||||
bean_hotpot = friendship_recipe(Meal.bean_hotpot, NPC.clint, 7, {Vegetable.green_bean: 2})
|
||||
blackberry_cobbler_ingredients = {Forageable.blackberry: 2, Ingredient.sugar: 1, Ingredient.wheat_flour: 1}
|
||||
blackberry_cobbler_qos = queen_of_sauce_recipe(Meal.blackberry_cobbler, 2, Season.fall, 14, blackberry_cobbler_ingredients)
|
||||
@@ -122,7 +124,8 @@ fried_eel = friendship_recipe(Meal.fried_eel, NPC.george, 3, {Fish.eel: 1, Ingre
|
||||
fried_egg = starter_recipe(Meal.fried_egg, {AnimalProduct.chicken_egg: 1})
|
||||
fried_mushroom = friendship_recipe(Meal.fried_mushroom, NPC.demetrius, 3, {Mushroom.common: 1, Mushroom.morel: 1, Ingredient.oil: 1})
|
||||
fruit_salad = queen_of_sauce_recipe(Meal.fruit_salad, 2, Season.fall, 7, {Fruit.blueberry: 1, Fruit.melon: 1, Fruit.apricot: 1})
|
||||
ginger_ale = shop_recipe(Beverage.ginger_ale, Region.volcano_dwarf_shop, 1000, {Forageable.ginger: 3, Ingredient.sugar: 1})
|
||||
ginger_ale = shop_recipe(Beverage.ginger_ale, Region.volcano_dwarf_shop, 1000, {Forageable.ginger: 3, Ingredient.sugar: 1},
|
||||
content_pack=ginger_island_content_pack.name)
|
||||
glazed_yams = queen_of_sauce_recipe(Meal.glazed_yams, 1, Season.fall, 21, {Vegetable.yam: 1, Ingredient.sugar: 1})
|
||||
hashbrowns = queen_of_sauce_recipe(Meal.hashbrowns, 2, Season.spring, 14, {Vegetable.potato: 1, Ingredient.oil: 1})
|
||||
ice_cream = friendship_recipe(Meal.ice_cream, NPC.jodi, 7, {AnimalProduct.cow_milk: 1, Ingredient.sugar: 1})
|
||||
@@ -131,7 +134,8 @@ lobster_bisque_friend = friendship_recipe(Meal.lobster_bisque, NPC.willy, 9, lob
|
||||
lobster_bisque_qos = queen_of_sauce_recipe(Meal.lobster_bisque, 2, Season.winter, 14, lobster_bisque_ingredients)
|
||||
lucky_lunch = queen_of_sauce_recipe(Meal.lucky_lunch, 2, Season.spring, 28, {Fish.sea_cucumber: 1, Meal.tortilla: 1, Flower.blue_jazz: 1})
|
||||
maki_roll = queen_of_sauce_recipe(Meal.maki_roll, 1, Season.summer, 21, {Fish.any: 1, WaterItem.seaweed: 1, Ingredient.rice: 1})
|
||||
mango_sticky_rice = friendship_recipe(Meal.mango_sticky_rice, NPC.leo, 7, {Fruit.mango: 1, Forageable.coconut: 1, Ingredient.rice: 1})
|
||||
mango_sticky_rice = friendship_recipe(Meal.mango_sticky_rice, NPC.leo, 7, {Fruit.mango: 1, Forageable.coconut: 1, Ingredient.rice: 1},
|
||||
content_pack=ginger_island_content_pack.name)
|
||||
maple_bar = queen_of_sauce_recipe(Meal.maple_bar, 2, Season.summer, 14, {ArtisanGood.maple_syrup: 1, Ingredient.sugar: 1, Ingredient.wheat_flour: 1})
|
||||
miners_treat = skill_recipe(Meal.miners_treat, Skill.mining, 3, {Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.cow_milk: 1})
|
||||
moss_soup = skill_recipe(Meal.moss_soup, Skill.foraging, 3, {Material.moss: 20})
|
||||
@@ -146,7 +150,7 @@ pizza_ingredients = {Ingredient.wheat_flour: 1, Vegetable.tomato: 1, ArtisanGood
|
||||
pizza_qos = queen_of_sauce_recipe(Meal.pizza, 2, Season.spring, 7, pizza_ingredients)
|
||||
pizza_saloon = shop_recipe(Meal.pizza, Region.saloon, 150, pizza_ingredients)
|
||||
plum_pudding = queen_of_sauce_recipe(Meal.plum_pudding, 1, Season.winter, 7, {Forageable.wild_plum: 2, Ingredient.wheat_flour: 1, Ingredient.sugar: 1})
|
||||
poi = friendship_recipe(Meal.poi, NPC.leo, 3, {Vegetable.taro_root: 4})
|
||||
poi = friendship_recipe(Meal.poi, NPC.leo, 3, {Vegetable.taro_root: 4}, content_pack=ginger_island_content_pack.name)
|
||||
poppyseed_muffin = queen_of_sauce_recipe(Meal.poppyseed_muffin, 2, Season.winter, 7, {Flower.poppy: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1})
|
||||
pumpkin_pie_ingredients = {Vegetable.pumpkin: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1, AnimalProduct.cow_milk: 1}
|
||||
pumpkin_pie_qos = queen_of_sauce_recipe(Meal.pumpkin_pie, 1, Season.winter, 21, pumpkin_pie_ingredients)
|
||||
@@ -177,55 +181,59 @@ tortilla_ingredients = {Vegetable.corn: 1}
|
||||
tortilla_qos = queen_of_sauce_recipe(Meal.tortilla, 1, Season.fall, 7, tortilla_ingredients)
|
||||
tortilla_saloon = shop_recipe(Meal.tortilla, Region.saloon, 100, tortilla_ingredients)
|
||||
triple_shot_espresso = shop_recipe(Beverage.triple_shot_espresso, Region.saloon, 5000, {Beverage.coffee: 3})
|
||||
tropical_curry = shop_recipe(Meal.tropical_curry, Region.island_resort, 2000, {Forageable.coconut: 1, Fruit.pineapple: 1, Fruit.hot_pepper: 1})
|
||||
tropical_curry = shop_recipe(Meal.tropical_curry, Region.island_resort, 2000, {Forageable.coconut: 1, Fruit.pineapple: 1, Fruit.hot_pepper: 1},
|
||||
content_pack=ginger_island_content_pack.name)
|
||||
trout_soup = queen_of_sauce_recipe(Meal.trout_soup, 1, Season.fall, 14, {Fish.rainbow_trout: 1, WaterItem.green_algae: 1})
|
||||
vegetable_medley = friendship_recipe(Meal.vegetable_medley, NPC.caroline, 7, {Vegetable.tomato: 1, Vegetable.beet: 1})
|
||||
|
||||
magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Mushroom.purple: 1}, ModNames.magic)
|
||||
magic_elixir = shop_recipe(ModEdible.magic_elixir, Region.adventurer_guild, 3000, {Edible.life_elixir: 1, Mushroom.purple: 1}, content_pack=ModNames.magic)
|
||||
|
||||
baked_berry_oatmeal = shop_recipe(SVEMeal.baked_berry_oatmeal, SVERegion.bear_shop, 0, {Forageable.salmonberry: 15, Forageable.blackberry: 15,
|
||||
Ingredient.sugar: 1, Ingredient.wheat_flour: 2}, ModNames.sve)
|
||||
Ingredient.sugar: 1, Ingredient.wheat_flour: 2},
|
||||
content_pack=ModNames.sve)
|
||||
big_bark_burger = friendship_and_shop_recipe(SVEMeal.big_bark_burger, NPC.gus, 5, Region.saloon, 5500,
|
||||
{SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, ModNames.sve)
|
||||
{SVEFish.puppyfish: 1, Meal.bread: 1, Ingredient.oil: 1}, content_pack=ModNames.sve)
|
||||
flower_cookie = shop_recipe(SVEMeal.flower_cookie, SVERegion.bear_shop, 0, {SVEForage.ferngill_primrose: 1, SVEForage.goldenrod: 1,
|
||||
SVEForage.winter_star_rose: 1, Ingredient.wheat_flour: 1, Ingredient.sugar: 1,
|
||||
AnimalProduct.large_egg: 1}, ModNames.sve)
|
||||
frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1}, ModNames.sve)
|
||||
AnimalProduct.large_egg: 1}, content_pack=ModNames.sve)
|
||||
frog_legs = shop_recipe(SVEMeal.frog_legs, Region.adventurer_guild, 2000, {SVEFish.frog: 1, Ingredient.oil: 1, Ingredient.wheat_flour: 1},
|
||||
content_pack=ModNames.sve)
|
||||
glazed_butterfish = friendship_and_shop_recipe(SVEMeal.glazed_butterfish, NPC.gus, 10, Region.saloon, 4000,
|
||||
{SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, ModNames.sve)
|
||||
{SVEFish.butterfish: 1, Ingredient.wheat_flour: 1, Ingredient.oil: 1}, content_pack=ModNames.sve)
|
||||
mixed_berry_pie = shop_recipe(SVEMeal.mixed_berry_pie, Region.saloon, 3500, {Fruit.strawberry: 6, SVEFruit.salal_berry: 6, Forageable.blackberry: 6,
|
||||
SVEForage.bearberry: 6, Ingredient.sugar: 1, Ingredient.wheat_flour: 1},
|
||||
ModNames.sve)
|
||||
content_pack=ModNames.sve)
|
||||
mushroom_berry_rice = friendship_and_shop_recipe(SVEMeal.mushroom_berry_rice, ModNPC.marlon, 6, Region.adventurer_guild, 1500,
|
||||
{SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10, Ingredient.rice: 1, Ingredient.sugar: 2},
|
||||
ModNames.sve)
|
||||
{SVEForage.poison_mushroom: 3, SVEForage.red_baneberry: 10,
|
||||
Ingredient.rice: 1, Ingredient.sugar: 2}, content_pack=ModNames.sve)
|
||||
seaweed_salad = shop_recipe(SVEMeal.seaweed_salad, Region.fish_shop, 1250, {SVEWaterItem.dulse_seaweed: 2, WaterItem.seaweed: 2, Ingredient.oil: 1},
|
||||
ModNames.sve)
|
||||
content_pack=ModNames.sve)
|
||||
void_delight = friendship_and_shop_recipe(SVEMeal.void_delight, NPC.krobus, 10, Region.sewer, 5000,
|
||||
{SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, ModNames.sve)
|
||||
{SVEFish.void_eel: 1, Loot.void_essence: 50, Loot.solar_essence: 20}, content_pack=ModNames.sve)
|
||||
void_salmon_sushi = friendship_and_shop_recipe(SVEMeal.void_salmon_sushi, NPC.krobus, 10, Region.sewer, 5000,
|
||||
{Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, ModNames.sve)
|
||||
{Fish.void_salmon: 1, ArtisanGood.void_mayonnaise: 1, WaterItem.seaweed: 3}, content_pack=ModNames.sve)
|
||||
|
||||
mushroom_kebab = friendship_recipe(DistantLandsMeal.mushroom_kebab, ModNPC.goblin, 2, {Mushroom.chanterelle: 1, Mushroom.common: 1,
|
||||
Mushroom.red: 1, Material.wood: 1}, ModNames.distant_lands)
|
||||
void_mint_tea = friendship_recipe(DistantLandsMeal.void_mint_tea, ModNPC.goblin, 4, {DistantLandsCrop.void_mint: 1}, ModNames.distant_lands)
|
||||
Mushroom.red: 1, Material.wood: 1}, content_pack=ModNames.distant_lands)
|
||||
void_mint_tea = friendship_recipe(DistantLandsMeal.void_mint_tea, ModNPC.goblin, 4, {DistantLandsCrop.void_mint: 1}, content_pack=ModNames.distant_lands)
|
||||
crayfish_soup = friendship_recipe(DistantLandsMeal.crayfish_soup, ModNPC.goblin, 6, {Forageable.cave_carrot: 1, Fish.crayfish: 1,
|
||||
DistantLandsFish.purple_algae: 1, WaterItem.white_algae: 1},
|
||||
ModNames.distant_lands)
|
||||
content_pack=ModNames.distant_lands)
|
||||
pemmican = friendship_recipe(DistantLandsMeal.pemmican, ModNPC.goblin, 8, {Loot.bug_meat: 1, Fish.any: 1, Forageable.salmonberry: 3,
|
||||
Material.stone: 2}, ModNames.distant_lands)
|
||||
Material.stone: 2}, content_pack=ModNames.distant_lands)
|
||||
|
||||
special_pumpkin_soup = friendship_recipe(BoardingHouseMeal.special_pumpkin_soup, ModNPC.joel, 6, {Vegetable.pumpkin: 2, AnimalProduct.large_goat_milk: 1,
|
||||
Vegetable.garlic: 1}, ModNames.boarding_house)
|
||||
Vegetable.garlic: 1}, content_pack=ModNames.boarding_house)
|
||||
diggers_delight = skill_recipe(ArchaeologyMeal.diggers_delight, ModSkill.archaeology, 3,
|
||||
{Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.milk: 1}, ModNames.archaeology)
|
||||
{Forageable.cave_carrot: 2, Ingredient.sugar: 1, AnimalProduct.milk: 1}, content_pack=ModNames.archaeology)
|
||||
rocky_root = skill_recipe(ArchaeologyMeal.rocky_root, ModSkill.archaeology, 7, {Forageable.cave_carrot: 3, Seed.coffee: 1, Material.stone: 1},
|
||||
ModNames.archaeology)
|
||||
content_pack=ModNames.archaeology)
|
||||
ancient_jello = skill_recipe(ArchaeologyMeal.ancient_jello, ModSkill.archaeology, 9,
|
||||
{WaterItem.cave_jelly: 6, Ingredient.sugar: 5, AnimalProduct.egg: 1, AnimalProduct.milk: 1, Artifact.chipped_amphora: 1},
|
||||
ModNames.archaeology)
|
||||
content_pack=ModNames.archaeology)
|
||||
|
||||
grilled_cheese = skill_recipe(TrashyMeal.grilled_cheese, ModSkill.binning, 1, {Meal.bread: 1, ArtisanGood.cheese: 1}, ModNames.binning_skill)
|
||||
fish_casserole = skill_recipe(TrashyMeal.fish_casserole, ModSkill.binning, 8, {Fish.any: 1, AnimalProduct.milk: 1, Vegetable.carrot: 1}, ModNames.binning_skill)
|
||||
grilled_cheese = skill_recipe(TrashyMeal.grilled_cheese, ModSkill.binning, 1, {Meal.bread: 1, ArtisanGood.cheese: 1}, content_pack=ModNames.binning_skill)
|
||||
fish_casserole = skill_recipe(TrashyMeal.fish_casserole, ModSkill.binning, 8, {Fish.any: 1, AnimalProduct.milk: 1, Vegetable.carrot: 1},
|
||||
content_pack=ModNames.binning_skill)
|
||||
|
||||
all_cooking_recipes_by_name = {recipe.meal: recipe for recipe in all_cooking_recipes}
|
||||
|
||||
@@ -121,6 +121,17 @@ class ShopSource(RecipeSource):
|
||||
return f"ShopSource at {self.region} costing {self.price}g"
|
||||
|
||||
|
||||
class ShopWithKnownRecipeSource(ShopSource):
|
||||
recipe_required: str
|
||||
|
||||
def __init__(self, region: str, price: int, recipe_required: str):
|
||||
super().__init__(region, price)
|
||||
self.recipe_required = recipe_required
|
||||
|
||||
def __repr__(self):
|
||||
return f"ShopSource at {self.region} costing {self.price}g"
|
||||
|
||||
|
||||
class ShopFriendshipSource(RecipeSource):
|
||||
friend: str
|
||||
hearts: int
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Tuple
|
||||
|
||||
from .game_item import Requirement
|
||||
from ..strings.tool_names import ToolMaterial
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HasItemRequirement(Requirement):
|
||||
item: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BookRequirement(Requirement):
|
||||
book: str
|
||||
@@ -47,8 +53,19 @@ class QuestRequirement(Requirement):
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RelationshipRequirement(Requirement):
|
||||
class MeetRequirement(Requirement):
|
||||
npc: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SpecificFriendRequirement(Requirement):
|
||||
npc: str
|
||||
hearts: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NumberOfFriendsRequirement(Requirement):
|
||||
friends: int
|
||||
hearts: int
|
||||
|
||||
|
||||
@@ -60,3 +77,125 @@ class FishingRequirement(Requirement):
|
||||
@dataclass(frozen=True)
|
||||
class WalnutRequirement(Requirement):
|
||||
amount: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TotalEarningsRequirement(Requirement):
|
||||
amount: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GrangeDisplayRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EggHuntRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FishingCompetitionRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LuauDelightRequirementRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MovieRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ForgeInfinityWeaponRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CaughtFishRequirement(Requirement):
|
||||
number_fish: int
|
||||
unique: bool = field(kw_only=True)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MuseumCompletionRequirement(Requirement):
|
||||
number_donated: int = 95
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FullShipmentRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BuildingRequirement(Requirement):
|
||||
building: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CookedRecipesRequirement(Requirement):
|
||||
number_of_recipes: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CraftedItemsRequirement(Requirement):
|
||||
number_of_recipes: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HelpWantedRequirement(Requirement):
|
||||
number_of_quests: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ShipOneCropRequirement(Requirement):
|
||||
number: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReceivedRaccoonsRequirement(Requirement):
|
||||
number_of_raccoons: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PrizeMachineRequirement(Requirement):
|
||||
number_of_tickets: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AllAchievementsRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PerfectionPercentRequirement(Requirement):
|
||||
percent: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReadAllBooksRequirement(Requirement):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MinesRequirement(Requirement):
|
||||
floor: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DangerousMinesRequirement(Requirement):
|
||||
floor: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MonsterKillRequirement(Requirement):
|
||||
monsters: Tuple[str, ...]
|
||||
amount: int = 1
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CatalogueRequirement(Requirement):
|
||||
catalogue: str
|
||||
|
||||
76
worlds/stardew_valley/data/secret_note_data.py
Normal file
76
worlds/stardew_valley/data/secret_note_data.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Tuple, Dict, List
|
||||
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.crop_names import Vegetable, Fruit
|
||||
from ..strings.flower_names import Flower
|
||||
from ..strings.food_names import Meal, Beverage
|
||||
from ..strings.forageable_names import Forageable
|
||||
from ..strings.metal_names import Mineral, MetalBar
|
||||
from ..strings.villager_names import NPC
|
||||
|
||||
|
||||
class SecretNote:
|
||||
note_1 = "Secret Note #1: A Page From Abigail's Diary"
|
||||
note_2 = "Secret Note #2: Sam's Holiday Shopping List"
|
||||
note_3 = "Secret Note #3: Leah's Perfect Dinner"
|
||||
note_4 = "Secret Note #4: Maru's Greatest Invention Yet"
|
||||
note_5 = "Secret Note #5: Penny gets everyone something they love"
|
||||
note_6 = "Secret Note #6: Stardrop Saloon Special Orders"
|
||||
note_7 = "Secret Note #7: Older Bachelors In Town"
|
||||
note_8 = "Secret Note #8: To Haley And Emily"
|
||||
note_9 = "Secret Note #9: Alex's Strength Training Diet"
|
||||
note_10 = "Secret Note #10: Cryptic Note"
|
||||
note_11 = "Secret Note #11: Marnie's Memory"
|
||||
note_12 = "Secret Note #12: Good Things In Garbage Cans"
|
||||
note_13 = "Secret Note #13: Junimo Plush"
|
||||
note_14 = "Secret Note #14: Stone Junimo"
|
||||
note_15 = "Secret Note #15: Mermaid Show"
|
||||
note_16 = "Secret Note #16: Treasure Chest"
|
||||
note_17 = "Secret Note #17: Green Strange Doll"
|
||||
note_18 = "Secret Note #18: Yellow Strange Doll"
|
||||
note_19_part_1 = "Secret Note #19: Solid Gold Lewis"
|
||||
note_19_part_2 = "Secret Note #19: In Town For All To See"
|
||||
note_20 = "Secret Note #20: Special Charm"
|
||||
note_21 = "Secret Note #21: A Date In Nature"
|
||||
note_22 = "Secret Note #22: The Mysterious Qi"
|
||||
note_23 = "Secret Note #23: Strange Note"
|
||||
note_24 = "Secret Note #24: M. Jasper's Book On Junimos"
|
||||
note_25 = "Secret Note #25: Ornate Necklace"
|
||||
note_26 = "Secret Note #26: Ancient Farming Secrets"
|
||||
note_27 = "Secret Note #27: A Compendium Of My Greatest Discoveries"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RequiredGifts:
|
||||
npc: str
|
||||
gifts: Tuple[str, ...]
|
||||
|
||||
|
||||
gift_requirements: Dict[str, List[RequiredGifts]] = {
|
||||
SecretNote.note_1: [RequiredGifts(NPC.abigail, (Vegetable.pumpkin, Mineral.amethyst, Meal.chocolate_cake, Meal.spicy_eel, Meal.blackberry_cobbler,)), ],
|
||||
SecretNote.note_2: [RequiredGifts(NPC.sebastian, (Mineral.frozen_tear, Meal.sashimi,)),
|
||||
RequiredGifts(NPC.penny, (Mineral.emerald, Flower.poppy,)),
|
||||
RequiredGifts(NPC.vincent, (Fruit.grape, Meal.cranberry_candy,)),
|
||||
RequiredGifts(NPC.jodi, (Meal.crispy_bass, Meal.pancakes,)),
|
||||
RequiredGifts(NPC.kent, (Meal.fiddlehead_risotto, Meal.roasted_hazelnuts,)),
|
||||
RequiredGifts(NPC.sam, (Forageable.cactus_fruit, Meal.maple_bar, Meal.pizza,)), ],
|
||||
SecretNote.note_3: [RequiredGifts(NPC.leah, (Meal.salad, ArtisanGood.goat_cheese, AnimalProduct.truffle, ArtisanGood.wine,)), ],
|
||||
SecretNote.note_4: [RequiredGifts(NPC.maru, (MetalBar.gold, MetalBar.iridium, ArtisanGood.battery_pack, Mineral.diamond, Fruit.strawberry,)), ],
|
||||
SecretNote.note_5: [RequiredGifts(NPC.pam, (Vegetable.parsnip, Meal.glazed_yams,)),
|
||||
RequiredGifts(NPC.jas, (Flower.fairy_rose, Meal.plum_pudding,)),
|
||||
RequiredGifts(NPC.vincent, (Meal.pink_cake, Fruit.grape,)),
|
||||
RequiredGifts(NPC.george, (Forageable.leek, Meal.fried_mushroom,)),
|
||||
RequiredGifts(NPC.evelyn, (Vegetable.beet, Flower.tulip,)), ],
|
||||
SecretNote.note_6: [RequiredGifts(NPC.lewis, (Meal.autumn_bounty,)),
|
||||
RequiredGifts(NPC.marnie, (Meal.pumpkin_pie,)),
|
||||
RequiredGifts(NPC.demetrius, (Meal.bean_hotpot,)),
|
||||
RequiredGifts(NPC.caroline, (Meal.fish_taco,)), ],
|
||||
SecretNote.note_7: [RequiredGifts(NPC.harvey, (Beverage.coffee, ArtisanGood.pickles,)),
|
||||
RequiredGifts(NPC.elliott, (Meal.crab_cakes, Fruit.pomegranate,)),
|
||||
RequiredGifts(NPC.shane, (Beverage.beer, Meal.pizza, Meal.pepper_poppers,)), ],
|
||||
SecretNote.note_8: [RequiredGifts(NPC.haley, (Meal.pink_cake, Flower.sunflower,)),
|
||||
RequiredGifts(NPC.emily, (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.jade, Mineral.ruby, Mineral.topaz, AnimalProduct.wool,)), ],
|
||||
SecretNote.note_9: [RequiredGifts(NPC.alex, (Meal.complete_breakfast, Meal.salmon_dinner,)), ],
|
||||
}
|
||||
33
worlds/stardew_valley/data/shirt_data.py
Normal file
33
worlds/stardew_valley/data/shirt_data.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from typing import List
|
||||
|
||||
from worlds.stardew_valley.strings.animal_product_names import AnimalProduct
|
||||
from worlds.stardew_valley.strings.forageable_names import Forageable
|
||||
|
||||
all_shirts = []
|
||||
all_considered_shirts = []
|
||||
|
||||
|
||||
class Shirt:
|
||||
name: str
|
||||
required_items: List[str]
|
||||
|
||||
def __init__(self, name: str, items: List[str]):
|
||||
self.name = name
|
||||
self.required_items = items
|
||||
|
||||
|
||||
# consider_in_logic exists as a temporary measure because I don't feel like writing out the logic for every single shirt at this stage,
|
||||
# and I only need some of them for the meme bundle
|
||||
def shirt(name: str, items: str | List[str], consider_in_logic: bool = True) -> Shirt:
|
||||
if isinstance(items, str):
|
||||
items = [items]
|
||||
new_shirt = Shirt(name, items)
|
||||
all_shirts.append(new_shirt)
|
||||
if consider_in_logic:
|
||||
all_considered_shirts.append(new_shirt)
|
||||
return new_shirt
|
||||
|
||||
|
||||
class Shirts:
|
||||
vacation = shirt("Vacation Shirt", Forageable.coconut)
|
||||
green_jacket = shirt("Green Jacket Shirt", AnimalProduct.duck_egg)
|
||||
@@ -1,21 +1,23 @@
|
||||
from collections.abc import Iterable
|
||||
from dataclasses import dataclass
|
||||
from typing import Tuple, Optional
|
||||
|
||||
from .game_item import Source
|
||||
from .game_item import Source, Requirement
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.season_names import Season
|
||||
|
||||
ItemPrice = Tuple[int, str]
|
||||
ItemPrice = tuple[int, str]
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class ShopSource(Source):
|
||||
shop_region: str
|
||||
money_price: Optional[int] = None
|
||||
items_price: Optional[Tuple[ItemPrice, ...]] = None
|
||||
seasons: Tuple[str, ...] = Season.all
|
||||
price: int | None = None
|
||||
items_price: tuple[ItemPrice, ...] | None = None
|
||||
seasons: tuple[str, ...] = Season.all
|
||||
currency: str = Currency.money
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.money_price is not None or self.items_price is not None, "At least money price or items price need to be defined."
|
||||
assert self.price is not None or self.items_price is not None, "At least money price or items price need to be defined."
|
||||
assert self.items_price is None or all(isinstance(p, tuple) for p in self.items_price), "Items price should be a tuple."
|
||||
|
||||
|
||||
@@ -37,3 +39,13 @@ class PrizeMachineSource(Source):
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class FishingTreasureChestSource(Source):
|
||||
amount: int
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class HatMouseSource(Source):
|
||||
price: int | None = None
|
||||
unlock_requirements: tuple[Requirement, ...] | None = None
|
||||
|
||||
@property
|
||||
def all_requirements(self) -> Iterable[Requirement]:
|
||||
return self.other_requirements + (self.unlock_requirements or ())
|
||||
|
||||
@@ -4,7 +4,8 @@ from typing import Tuple, Optional
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..strings.food_names import Beverage
|
||||
from ..strings.generic_names import Generic
|
||||
from ..strings.region_names import Region, SVERegion, AlectoRegion, BoardingHouseRegion, LaceyRegion, LogicRegion
|
||||
from ..strings.metal_names import Mineral, Fossil
|
||||
from ..strings.region_names import Region, SVERegion, AlectoRegion, BoardingHouseRegion, LaceyRegion, LogicRegion, RileyRegion
|
||||
from ..strings.season_names import Season
|
||||
from ..strings.villager_names import NPC, ModNPC
|
||||
|
||||
@@ -43,6 +44,16 @@ sewers = (Region.sewer,)
|
||||
island = (Region.island_east,)
|
||||
secret_woods = (Region.secret_woods,)
|
||||
wizard_tower = (Region.wizard_tower,)
|
||||
sam_house = (Region.sam_house,)
|
||||
pierre_shop = (Region.pierre_store,)
|
||||
haley_house = (Region.haley_house,)
|
||||
saloon = (Region.saloon,)
|
||||
blacksmith = (Region.blacksmith,)
|
||||
trailer = (Region.trailer,)
|
||||
leah_house = (Region.leah_house,)
|
||||
linus_tent = (Region.tent,)
|
||||
lewis_house = (Region.mayor_house,)
|
||||
fish_shop = (Region.fish_shop,)
|
||||
|
||||
# Stardew Valley Expanded Locations
|
||||
adventurer = (Region.adventurer_guild,)
|
||||
@@ -53,6 +64,8 @@ museum = (Region.museum,)
|
||||
jojamart = (Region.jojamart,)
|
||||
railroad = (Region.railroad,)
|
||||
junimo = (SVERegion.junimo_woods,)
|
||||
olivia_house = (SVERegion.jenkins_residence,)
|
||||
andy_house = (SVERegion.fairhaven_farm,)
|
||||
|
||||
# Stray Locations
|
||||
witch_swamp = (Region.witch_swamp,)
|
||||
@@ -60,6 +73,7 @@ witch_attic = (AlectoRegion.witch_attic,)
|
||||
hat_house = (LaceyRegion.hat_house,)
|
||||
the_lost_valley = (BoardingHouseRegion.the_lost_valley,)
|
||||
boarding_house = (BoardingHouseRegion.boarding_house_first,)
|
||||
riley_house = (RileyRegion.riley_house,)
|
||||
|
||||
golden_pumpkin = ("Golden Pumpkin",)
|
||||
# magic_rock_candy = ("Magic Rock Candy",)
|
||||
@@ -90,7 +104,7 @@ pizza = ("Pizza",)
|
||||
tigerseye = ("Tigerseye",)
|
||||
sam_loves = cactus_fruit + maple_bar + pizza + tigerseye
|
||||
frozen_tear = ("Frozen Tear",)
|
||||
obsidian = ("Obsidian",)
|
||||
obsidian = (Mineral.obsidian,)
|
||||
# pumpkin_soup = ("Pumpkin Soup",)
|
||||
# sashimi = ("Sashimi",)
|
||||
void_egg = ("Void Egg",)
|
||||
@@ -252,7 +266,7 @@ energy_tonic = ("Energy Tonic",)
|
||||
kale = ("Kale",)
|
||||
muscle_remedy = ("Muscle Remedy",)
|
||||
vegetable_medley = ("Vegetable Medley",)
|
||||
trilobite = ("Trilobite",)
|
||||
trilobite = (Fossil.trilobite,)
|
||||
golden_mask = ("Golden Mask",)
|
||||
rainbow_shell = ("Rainbow Shell",)
|
||||
blue_jazz = ("Blue Jazz",)
|
||||
@@ -361,39 +375,39 @@ def villager(name: str, bachelor: bool, locations: Tuple[str, ...], birthday: st
|
||||
return Villager(name, bachelor, locations, birthday, gifts, available, mod_name)
|
||||
|
||||
|
||||
josh = villager(NPC.alex, True, town + alex_house, Season.summer, universal_loves + complete_breakfast + salmon_dinner, True)
|
||||
elliott = villager(NPC.elliott, True, town + beach + elliott_house, Season.fall, universal_loves + elliott_loves, True)
|
||||
harvey = villager(NPC.harvey, True, town + hospital, Season.winter, universal_loves + harvey_loves, True)
|
||||
sam = villager(NPC.sam, True, town, Season.summer, universal_loves + sam_loves, True)
|
||||
josh = villager(NPC.alex, True, alex_house, Season.summer, universal_loves + complete_breakfast + salmon_dinner, True)
|
||||
elliott = villager(NPC.elliott, True, beach + elliott_house, Season.fall, universal_loves + elliott_loves, True)
|
||||
harvey = villager(NPC.harvey, True, hospital, Season.winter, universal_loves + harvey_loves, True)
|
||||
sam = villager(NPC.sam, True, sam_house, Season.summer, universal_loves + sam_loves, True)
|
||||
sebastian = villager(NPC.sebastian, True, carpenter, Season.winter, universal_loves + sebastian_loves, True)
|
||||
shane = villager(NPC.shane, True, ranch, Season.spring, universal_loves + shane_loves, True)
|
||||
abigail = villager(NPC.abigail, True, town, Season.fall, universal_loves + abigail_loves, True)
|
||||
emily = villager(NPC.emily, True, town, Season.spring, universal_loves + emily_loves, True)
|
||||
haley = villager(NPC.haley, True, town, Season.spring, universal_loves_no_prismatic_shard + haley_loves, True)
|
||||
leah = villager(NPC.leah, True, forest, Season.winter, universal_loves + leah_loves, True)
|
||||
maru = villager(NPC.maru, True, carpenter + hospital + town, Season.summer, universal_loves + maru_loves, True)
|
||||
penny = villager(NPC.penny, True, town, Season.fall, universal_loves_no_rabbit_foot + penny_loves, True)
|
||||
caroline = villager(NPC.caroline, False, town, Season.winter, universal_loves + caroline_loves, True)
|
||||
clint = villager(NPC.clint, False, town, Season.winter, universal_loves + clint_loves, True)
|
||||
abigail = villager(NPC.abigail, True, pierre_shop, Season.fall, universal_loves + abigail_loves, True)
|
||||
emily = villager(NPC.emily, True, haley_house, Season.spring, universal_loves + emily_loves, True)
|
||||
haley = villager(NPC.haley, True, haley_house, Season.spring, universal_loves_no_prismatic_shard + haley_loves, True)
|
||||
leah = villager(NPC.leah, True, forest + leah_house, Season.winter, universal_loves + leah_loves, True)
|
||||
maru = villager(NPC.maru, True, carpenter + hospital, Season.summer, universal_loves + maru_loves, True)
|
||||
penny = villager(NPC.penny, True, trailer, Season.fall, universal_loves_no_rabbit_foot + penny_loves, True)
|
||||
caroline = villager(NPC.caroline, False, pierre_shop, Season.winter, universal_loves + caroline_loves, True)
|
||||
clint = villager(NPC.clint, False, blacksmith, Season.winter, universal_loves + clint_loves, True)
|
||||
demetrius = villager(NPC.demetrius, False, carpenter, Season.summer, universal_loves + demetrius_loves, True)
|
||||
dwarf = villager(NPC.dwarf, False, mines_dwarf_shop, Season.summer, universal_loves + dwarf_loves, False)
|
||||
evelyn = villager(NPC.evelyn, False, town, Season.winter, universal_loves + evelyn_loves, True)
|
||||
george = villager(NPC.george, False, town, Season.fall, universal_loves + george_loves, True)
|
||||
gus = villager(NPC.gus, False, town, Season.summer, universal_loves + gus_loves, True)
|
||||
evelyn = villager(NPC.evelyn, False, alex_house, Season.winter, universal_loves + evelyn_loves, True)
|
||||
george = villager(NPC.george, False, alex_house, Season.fall, universal_loves + george_loves, True)
|
||||
gus = villager(NPC.gus, False, saloon, Season.summer, universal_loves + gus_loves, True)
|
||||
jas = villager(NPC.jas, False, ranch, Season.summer, universal_loves + jas_loves, True)
|
||||
jodi = villager(NPC.jodi, False, town, Season.fall, universal_loves + jodi_loves, True)
|
||||
kent = villager(NPC.kent, False, town, Season.spring, universal_loves + kent_loves, False)
|
||||
jodi = villager(NPC.jodi, False, sam_house, Season.fall, universal_loves + jodi_loves, True)
|
||||
kent = villager(NPC.kent, False, sam_house, Season.spring, universal_loves + kent_loves, False)
|
||||
krobus = villager(NPC.krobus, False, sewers, Season.winter, universal_loves + krobus_loves, False)
|
||||
leo = villager(NPC.leo, False, island, Season.summer, universal_loves + leo_loves, False)
|
||||
lewis = villager(NPC.lewis, False, town, Season.spring, universal_loves + lewis_loves, True)
|
||||
linus = villager(NPC.linus, False, mountain, Season.winter, universal_loves + linus_loves, True)
|
||||
lewis = villager(NPC.lewis, False, lewis_house, Season.spring, universal_loves + lewis_loves, True)
|
||||
linus = villager(NPC.linus, False, mountain + linus_tent, Season.winter, universal_loves + linus_loves, True)
|
||||
marnie = villager(NPC.marnie, False, ranch, Season.fall, universal_loves + marnie_loves, True)
|
||||
pam = villager(NPC.pam, False, town, Season.spring, universal_loves + pam_loves, True)
|
||||
pierre = villager(NPC.pierre, False, town, Season.spring, universal_loves + pierre_loves, True)
|
||||
pam = villager(NPC.pam, False, trailer, Season.spring, universal_loves + pam_loves, True)
|
||||
pierre = villager(NPC.pierre, False, pierre_shop, Season.spring, universal_loves + pierre_loves, True)
|
||||
robin = villager(NPC.robin, False, carpenter, Season.fall, universal_loves + robin_loves, True)
|
||||
sandy = villager(NPC.sandy, False, oasis, Season.fall, universal_loves + sandy_loves, False)
|
||||
vincent = villager(NPC.vincent, False, town, Season.spring, universal_loves + vincent_loves, True)
|
||||
willy = villager(NPC.willy, False, beach, Season.summer, universal_loves + willy_loves, True)
|
||||
vincent = villager(NPC.vincent, False, sam_house, Season.spring, universal_loves + vincent_loves, True)
|
||||
willy = villager(NPC.willy, False, beach + fish_shop, Season.summer, universal_loves + willy_loves, True)
|
||||
wizard = villager(NPC.wizard, False, wizard_tower, Season.winter, universal_loves + wizard_loves, True)
|
||||
|
||||
# Custom NPCs
|
||||
@@ -401,13 +415,13 @@ alec = villager(ModNPC.alec, True, forest, Season.winter, universal_loves + tril
|
||||
ayeisha = villager(ModNPC.ayeisha, False, town, Season.summer, universal_loves + ayeisha_loves, True, ModNames.ayeisha)
|
||||
delores = villager(ModNPC.delores, True, forest, Season.winter, universal_loves + delores_loves, True, ModNames.delores)
|
||||
eugene = villager(ModNPC.eugene, True, forest, Season.spring, universal_loves + eugene_loves, True, ModNames.eugene)
|
||||
jasper = villager(ModNPC.jasper, True, town, Season.fall, universal_loves + jasper_loves, True, ModNames.jasper)
|
||||
jasper = villager(ModNPC.jasper, True, museum, Season.fall, universal_loves + jasper_loves, True, ModNames.jasper)
|
||||
juna = villager(ModNPC.juna, False, forest, Season.summer, universal_loves + juna_loves, True, ModNames.juna)
|
||||
kitty = villager(ModNPC.mr_ginger, False, forest, Season.summer, universal_loves + mister_ginger_loves, True, ModNames.ginger)
|
||||
shiko = villager(ModNPC.shiko, True, town, Season.winter, universal_loves + shiko_loves, True, ModNames.shiko)
|
||||
wellwick = villager(ModNPC.wellwick, True, forest, Season.winter, universal_loves + wellwick_loves, True, ModNames.wellwick)
|
||||
shiko = villager(ModNPC.shiko, True, saloon, Season.winter, universal_loves + shiko_loves, True, ModNames.shiko)
|
||||
wellwick = villager(ModNPC.wellwick, True, wizard_tower, Season.winter, universal_loves + wellwick_loves, True, ModNames.wellwick)
|
||||
yoba = villager(ModNPC.yoba, False, secret_woods, Season.spring, universal_loves + yoba_loves, False, ModNames.yoba)
|
||||
riley = villager(ModNPC.riley, True, town, Season.spring, universal_loves, True, ModNames.riley)
|
||||
riley = villager(ModNPC.riley, True, riley_house, Season.spring, universal_loves, True, ModNames.riley)
|
||||
zic = villager(ModNPC.goblin, False, witch_swamp, Season.fall, void_mayonnaise, False, ModNames.distant_lands)
|
||||
alecto = villager(ModNPC.alecto, False, witch_attic, Generic.any, universal_loves, False, ModNames.alecto)
|
||||
lacey = villager(ModNPC.lacey, True, forest, Season.spring, universal_loves, True, ModNames.lacey)
|
||||
@@ -420,15 +434,15 @@ joel = villager(ModNPC.joel, False, boarding_house, Season.winter, universal_lov
|
||||
# SVE Villagers
|
||||
claire = villager(ModNPC.claire, True, town + jojamart, Season.fall, universal_loves + claire_loves, True, ModNames.sve)
|
||||
lance = villager(ModNPC.lance, True, adventurer + highlands + island, Season.spring, lance_loves, False, ModNames.sve)
|
||||
mommy = villager(ModNPC.olivia, True, town, Season.spring, universal_loves_no_rabbit_foot + olivia_loves, True, ModNames.sve)
|
||||
mommy = villager(ModNPC.olivia, True, olivia_house, Season.spring, universal_loves_no_rabbit_foot + olivia_loves, True, ModNames.sve)
|
||||
sophia = villager(ModNPC.sophia, True, bluemoon, Season.winter, universal_loves_no_rabbit_foot + sophia_loves, True, ModNames.sve)
|
||||
victor = villager(ModNPC.victor, True, town, Season.summer, universal_loves + victor_loves, True, ModNames.sve)
|
||||
andy = villager(ModNPC.andy, False, forest, Season.spring, universal_loves + andy_loves, True, ModNames.sve)
|
||||
victor = villager(ModNPC.victor, True, olivia_house, Season.summer, universal_loves + victor_loves, True, ModNames.sve)
|
||||
andy = villager(ModNPC.andy, False, andy_house, Season.spring, universal_loves + andy_loves, True, ModNames.sve)
|
||||
apples = villager(ModNPC.apples, False, aurora + junimo, Generic.any, starfruit, False, ModNames.sve)
|
||||
gunther = villager(ModNPC.gunther, False, museum, Season.winter, universal_loves + gunther_loves, True, ModNames.sve)
|
||||
martin = villager(ModNPC.martin, False, town + jojamart, Season.summer, universal_loves + martin_loves, True, ModNames.sve)
|
||||
marlon = villager(ModNPC.marlon, False, adventurer, Season.winter, universal_loves + marlon_loves, False, ModNames.sve)
|
||||
morgan = villager(ModNPC.morgan, False, forest, Season.fall, universal_loves_no_rabbit_foot + morgan_loves, False, ModNames.sve)
|
||||
morgan = villager(ModNPC.morgan, False, wizard_tower, Season.fall, universal_loves_no_rabbit_foot + morgan_loves, False, ModNames.sve)
|
||||
scarlett = villager(ModNPC.scarlett, False, bluemoon, Season.summer, universal_loves + scarlett_loves, False, ModNames.sve)
|
||||
susan = villager(ModNPC.susan, False, railroad, Season.fall, universal_loves + susan_loves, False, ModNames.sve)
|
||||
morris = villager(ModNPC.morris, False, jojamart, Season.spring, universal_loves + morris_loves, True, ModNames.sve)
|
||||
|
||||
@@ -36,10 +36,12 @@ The player can choose from a number of goals, using their YAML options.
|
||||
- Become a [Craft Master](https://stardewvalleywiki.com/Crafting) by crafting every item
|
||||
- Earn the title of [Legend](https://stardewvalleywiki.com/Gold) by earning 10 000 000g
|
||||
- Solve the [Mystery of the Stardrops](https://stardewvalleywiki.com/Stardrop) by finding every stardrop
|
||||
- Find and wear every [Hat](https://stardewvalleywiki.com/Hats) in the game.
|
||||
- Find and eat every item in the game.
|
||||
- Finish 100% of your randomizer slot with Allsanity: Complete every check in your slot
|
||||
- Achieve [Perfection](https://stardewvalleywiki.com/Perfection) in your save file
|
||||
|
||||
The following goals [Community Center, Master Angler, Protector of the Valley, Full Shipment and Gourmet Chef] will adapt
|
||||
The following goals [Community Center, Master Angler, Protector of the Valley, Full Shipment, Gourmet Chef and Mad Hatter] will adapt
|
||||
to other options in your slots, and are therefore customizable in duration and difficulty. For example, if you set "Fishsanity"
|
||||
to "Exclude Legendaries", and pick the Master Angler goal, you will not need to catch the legendaries to complete the goal.
|
||||
|
||||
@@ -78,6 +80,12 @@ There also are a number of location checks that are optional, and individual pla
|
||||
- [Shipsanity](https://stardewvalleywiki.com/Shipping): Shipping individual items
|
||||
- [Booksanity](https://stardewvalleywiki.com/Books): Reading individual books
|
||||
- [Walnutsanity](https://stardewvalleywiki.com/Golden_Walnut): Collecting Walnuts on Ginger Island
|
||||
- [Hatsanity](https://stardewvalleywiki.com/Hats): Wear individual Hats
|
||||
- [Secretsanity](https://stardewvalleywiki.com/Secrets): Find secrets and easter eggs
|
||||
- [Moviesanity](https://stardewvalleywiki.com/Movie_Theater): Watch movies with villagers and optionally share snacks with them
|
||||
- Eatsanity: Eat every item in the game
|
||||
|
||||
And more!
|
||||
|
||||
## Which items can be in another player's world?
|
||||
|
||||
@@ -138,12 +146,11 @@ This means that, for these specific mods, if you decide to include them in your
|
||||
with the assumption that you will install and play with these mods. The multiworld will contain related items and locations
|
||||
for these mods, the specifics will vary from mod to mod
|
||||
|
||||
[Supported Mods Documentation](https://github.com/agilbert1412/StardewArchipelago/blob/6.x.x/Documentation/Supported%20Mods.md)
|
||||
[Supported Mods Documentation](https://github.com/agilbert1412/StardewArchipelago/blob/7.x.x/Documentation/Supported%20Mods.md)
|
||||
|
||||
List of supported mods:
|
||||
|
||||
- General
|
||||
- [Stardew Valley Expanded](https://www.nexusmods.com/stardewvalley/mods/3753)
|
||||
- [Skull Cavern Elevator](https://www.nexusmods.com/stardewvalley/mods/963)
|
||||
- [Bigger Backpack](https://www.nexusmods.com/stardewvalley/mods/1845)
|
||||
- [Tractor Mod](https://www.nexusmods.com/stardewvalley/mods/1401)
|
||||
|
||||
@@ -3,35 +3,49 @@
|
||||
## Required Software
|
||||
|
||||
- Stardew Valley 1.6 on PC (Recommended: [Steam version](https://store.steampowered.com/app/413150/Stardew_Valley/))
|
||||
- SMAPI ([Mod loader for Stardew Valley](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files))
|
||||
- [StardewArchipelago Mod Release 6.x.x](https://github.com/agilbert1412/StardewArchipelago/releases)
|
||||
- It is important to use a mod release of version 6.x.x to play seeds that have been generated here. Later releases
|
||||
- SMAPI ([Mod loader for Stardew Valley](https://smapi.io/) ([Nexus](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files) | [Github](https://github.com/Pathoschild/SMAPI/releases))
|
||||
- [StardewArchipelago Mod Release 7.x.x](https://github.com/agilbert1412/StardewArchipelago/releases)
|
||||
- It is important to use a mod release of version 7.x.x to play seeds that have been generated here. Later releases
|
||||
can only be used with later releases of the world generator, that are not hosted on archipelago.gg yet.
|
||||
|
||||
## Optional Software
|
||||
- Archipelago from the [Archipelago Releases Page](https://github.com/ArchipelagoMW/Archipelago/releases)
|
||||
* (Only for the TextClient)
|
||||
* This provides access to various built-in tools, text client, and local generation and hosting
|
||||
- [Universal Tracker](https://github.com/FarisTheAncient/Archipelago/releases?q=Tracker)
|
||||
* If you installed Archipelago, you can use a custom Stardew Tracker that depends on Universal Tracker.
|
||||
- Other Stardew Valley Mods [Nexus Mods](https://www.nexusmods.com/stardewvalley)
|
||||
* There are [supported mods](https://github.com/agilbert1412/StardewArchipelago/blob/6.x.x/Documentation/Supported%20Mods.md)
|
||||
* There are [supported mods](https://github.com/agilbert1412/StardewArchipelago/blob/7.x.x/Documentation/Supported%20Mods.md)
|
||||
that you can add to your yaml to include them with the Archipelago randomization
|
||||
|
||||
* It is **not** recommended to further mod Stardew Valley with unsupported mods, although it is possible to do so.
|
||||
Mod interactions can be unpredictable, and no support will be offered for related bugs.
|
||||
* The more unsupported mods you have, and the bigger they are, the more likely things are to break.
|
||||
|
||||
## Configuring your YAML file
|
||||
## Configuring your Multiworld
|
||||
|
||||
### What is a YAML file and why do I need one?
|
||||
### Customizing my options
|
||||
|
||||
You can customize your options by visiting the [Stardew Valley Player Options Page](/games/Stardew%20Valley/player-options)
|
||||
|
||||
From there, you can customize all your options, or use a preset. Then, you can either Generate a single player game, or export a yaml file.
|
||||
|
||||
### What is a YAML file and do I need one?
|
||||
|
||||
A yaml file serves to configure your game in the multiworld. If you play a solo game, you can skip it entirely.
|
||||
|
||||
If you intend to play in a multiworld, you will need to provide your yaml file to the person who is hosting the multiworld.
|
||||
|
||||
See the guide on setting up a basic YAML at the Archipelago setup
|
||||
guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en)
|
||||
|
||||
### Where do I get a YAML file?
|
||||
### Creating a room
|
||||
|
||||
You can customize your options by visiting the [Stardew Valley Player Options Page](/games/Stardew%20Valley/player-options)
|
||||
If you hosted your own game, you can now click "Create Room" and your multiworld will be ready for play!
|
||||
|
||||
## Joining a MultiWorld Game
|
||||
|
||||
Note that even if you play a solo game, you still connect to a server to play. Hosting on archipelago.gg is free and the easiest option, but you can also host it locally.
|
||||
|
||||
### Installing the mod
|
||||
|
||||
- Install [SMAPI](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files) by following the instructions on the mod page
|
||||
@@ -41,7 +55,7 @@ your Stardew Valley "Mods" folder
|
||||
- Otherwise just launch "StardewModdingAPI.exe" in your installation folder directly
|
||||
- Stardew Valley should launch itself alongside a console which allows you to read mod information and interact with some of them.
|
||||
|
||||
### Connect to the MultiServer
|
||||
### Connect to the Multiworld
|
||||
|
||||
Launch Stardew Valley with SMAPI. Once you have reached the Stardew Valley title screen, create a new farm.
|
||||
|
||||
@@ -51,7 +65,7 @@ On the new character creation page, you will see 3 new fields, used to link your
|
||||
|
||||
You can customize your farm and character as much as desired.
|
||||
|
||||
The Server text box needs to have both the address and the port, and your slotname is the name specified in your yaml
|
||||
The Server text box needs to have both the address and the port, and your slotname is the name specified in your options. You can also see the name on the room page.
|
||||
|
||||
`archipelago.gg:38281`
|
||||
|
||||
@@ -62,13 +76,7 @@ The password is optional.
|
||||
Your game will connect automatically to Archipelago, and reconnect automatically when loading the save, later.
|
||||
|
||||
You will never need to enter this information again for this character, unless your room changes its ip or port.
|
||||
If the room's ip or port **does** change, you can follow these instructions to modify the connection information of your save file
|
||||
- Launch modded Stardew Valley
|
||||
- While **on the main menu** of the game, enter the follow command **in the SMAPI console**:
|
||||
- `connect_override ip:port slot password`
|
||||
- Example: `connect_override archipelago.gg:38281 StardewPlayer`
|
||||
- Load your save game. The new connection information will be used, instead of the saved one
|
||||
- Play a full day, sleep, and save the game. This connection information will overwrite the previous one and become permanent.
|
||||
If the room's ip or port **does** change, you will be prompted, after the connection fails, to enter new values and try again.
|
||||
|
||||
### Interacting with the MultiWorld from in-game
|
||||
|
||||
@@ -82,14 +90,14 @@ Lastly, you can also run Archipelago commands `!help` from the in game chat box,
|
||||
items, or check missing locations.
|
||||
|
||||
It is important to note that the Stardew Valley chat is fairly limited in its capabilities. For example, it doesn't allow
|
||||
scrolling up to see history that has been pushed off screen. The SMAPI console running alonside your game will have the
|
||||
scrolling up to see history that has been pushed off screen. The SMAPI console running alongside your game will have the
|
||||
full history as well and may be better suited to read older messages.
|
||||
For a better chat experience, you can also use the official Archipelago Text Client, altough it will not allow you to run
|
||||
For a better chat experience, you can also use the official Archipelago Text Client, although it will not allow you to run
|
||||
Stardew-exclusive commands.
|
||||
|
||||
### Playing with supported mods
|
||||
|
||||
See the [Supported mods documentation](https://github.com/agilbert1412/StardewArchipelago/blob/6.x.x/Documentation/Supported%20Mods.md)
|
||||
See the [Supported mods documentation](https://github.com/agilbert1412/StardewArchipelago/blob/7.x.x/Documentation/Supported%20Mods.md)
|
||||
|
||||
### Multiplayer
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
- Stardew Valley 1.6 sur PC (Recommandé: [Steam](https://store.steampowered.com/app/413150/Stardew_Valley/))
|
||||
- SMAPI ([Mod loader pour Stardew Valley](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files))
|
||||
- [StardewArchipelago Version 6.x.x](https://github.com/agilbert1412/StardewArchipelago/releases)
|
||||
- Il est important d'utiliser une release en 6.x.x pour jouer sur des seeds générées ici. Les versions ultérieures peuvent uniquement être utilisées pour des release ultérieures du générateur de mondes, qui ne sont pas encore hébergées sur archipelago.gg
|
||||
- [StardewArchipelago Version 7.x.x](https://github.com/agilbert1412/StardewArchipelago/releases)
|
||||
- Il est important d'utiliser une release en 7.x.x pour jouer sur des seeds générées ici. Les versions ultérieures peuvent uniquement être utilisées pour des release ultérieures du générateur de mondes, qui ne sont pas encore hébergées sur archipelago.gg
|
||||
|
||||
## Logiciels optionnels
|
||||
|
||||
- Launcher Archipelago à partir de la [page des versions d'Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases)
|
||||
- (Uniquement pour le client textuel)
|
||||
- Autres [mods supportés](https://github.com/agilbert1412/StardewArchipelago/blob/6.x.x/Documentation/Supported%20Mods.md) que vous pouvez ajouter au yaml pour les inclure dans la randomization d'Archipelago
|
||||
- Autres [mods supportés](https://github.com/agilbert1412/StardewArchipelago/blob/7.x.x/Documentation/Supported%20Mods.md) que vous pouvez ajouter au yaml pour les inclure dans la randomization d'Archipelago
|
||||
|
||||
- Il n'est **pas** recommandé de modder Stardew Valley avec des mods non supportés, même s'il est possible de le faire.
|
||||
Les interactions entre mods peuvent être imprévisibles, et aucune aide ne sera fournie pour les bugs qui y sont liés.
|
||||
@@ -80,7 +80,7 @@ Pour une meilleure expérience avec le chat, vous pouvez aussi utiliser le clien
|
||||
|
||||
### Jouer avec des mods supportés
|
||||
|
||||
Voir la [documentation des mods supportés](https://github.com/agilbert1412/StardewArchipelago/blob/6.x.x/Documentation/Supported%20Mods.md) (en Anglais).
|
||||
Voir la [documentation des mods supportés](https://github.com/agilbert1412/StardewArchipelago/blob/7.x.x/Documentation/Supported%20Mods.md) (en Anglais).
|
||||
|
||||
### Multijoueur
|
||||
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
from .early_items import setup_early_items
|
||||
from .fillers import generate_filler_choice_pool
|
||||
from .item_creation import create_items
|
||||
from .item_data import item_table, ItemData, Group, items_by_group, load_item_csv
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
from random import Random
|
||||
|
||||
from . import options as stardew_options
|
||||
from .content import StardewContent
|
||||
from .strings.ap_names.ap_weapon_names import APWeapon
|
||||
from .strings.ap_names.transport_names import Transportation
|
||||
from .strings.building_names import Building
|
||||
from .strings.region_names import Region
|
||||
from .strings.season_names import Season
|
||||
from .strings.skill_names import Skill
|
||||
from .strings.tv_channel_names import Channel
|
||||
from .strings.wallet_item_names import Wallet
|
||||
from .. import options as stardew_options
|
||||
from ..content import StardewContent
|
||||
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from ..strings.ap_names.ap_option_names import ChefsanityOptionName, StartWithoutOptionName
|
||||
from ..strings.ap_names.ap_weapon_names import APWeapon
|
||||
from ..strings.ap_names.transport_names import Transportation
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.season_names import Season
|
||||
from ..strings.skill_names import Skill
|
||||
from ..strings.tv_channel_names import Channel
|
||||
from ..strings.wallet_item_names import Wallet
|
||||
|
||||
early_candidate_rate = 4
|
||||
always_early_candidates = [Region.greenhouse, Transportation.desert_obelisk, Wallet.rusty_key]
|
||||
@@ -47,7 +49,7 @@ def setup_early_items(multiworld, options: stardew_options.StardewValleyOptions,
|
||||
if options.special_order_locations & stardew_options.SpecialOrderLocations.option_board:
|
||||
early_candidates.append("Special Order Board")
|
||||
|
||||
if options.cooksanity != stardew_options.Cooksanity.option_none or options.chefsanity & stardew_options.Chefsanity.option_queen_of_sauce:
|
||||
if options.cooksanity != stardew_options.Cooksanity.option_none or ChefsanityOptionName.queen_of_sauce in options.chefsanity:
|
||||
early_candidates.append(Channel.queen_of_sauce)
|
||||
|
||||
if options.craftsanity != stardew_options.Craftsanity.option_none:
|
||||
@@ -58,8 +60,9 @@ def setup_early_items(multiworld, options: stardew_options.StardewValleyOptions,
|
||||
else:
|
||||
early_candidates.append(APWeapon.sword)
|
||||
|
||||
if options.exclude_ginger_island == stardew_options.ExcludeGingerIsland.option_false:
|
||||
if content.is_enabled(ginger_island_content_pack):
|
||||
early_candidates.append(Transportation.island_obelisk)
|
||||
early_candidates.append(Transportation.boat_repair)
|
||||
|
||||
if options.walnutsanity.value:
|
||||
early_candidates.append("Island North Turtle")
|
||||
@@ -68,6 +71,14 @@ def setup_early_items(multiworld, options: stardew_options.StardewValleyOptions,
|
||||
if options.museumsanity != stardew_options.Museumsanity.option_none or options.shipsanity >= stardew_options.Shipsanity.option_full_shipment:
|
||||
early_candidates.append(Wallet.metal_detector)
|
||||
|
||||
if StartWithoutOptionName.landslide in options.start_without:
|
||||
early_candidates.append("Landslide Removed")
|
||||
|
||||
if StartWithoutOptionName.community_center in options.start_without:
|
||||
early_candidates.append("Forest Magic")
|
||||
early_candidates.append("Community Center Key")
|
||||
early_candidates.append("Wizard Invitation")
|
||||
|
||||
early_forced.extend(random.sample(early_candidates, len(early_candidates) // early_candidate_rate))
|
||||
|
||||
for item_name in early_forced:
|
||||
181
worlds/stardew_valley/items/fillers.py
Normal file
181
worlds/stardew_valley/items/fillers.py
Normal file
@@ -0,0 +1,181 @@
|
||||
from random import Random
|
||||
from typing import List
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .filters import remove_excluded, remove_limited_amount_resource_packs, remove_already_included
|
||||
from .item_data import items_by_group, Group, ItemData, StardewItemFactory, item_table
|
||||
from ..content.game_content import StardewContent
|
||||
from ..options import StardewValleyOptions, FestivalLocations
|
||||
from ..strings.ap_names.ap_option_names import BuffOptionName, AllowedFillerOptionName
|
||||
from ..strings.ap_names.buff_names import Buff
|
||||
|
||||
AllowedFillerTypesMap = {
|
||||
AllowedFillerOptionName.farming: Group.FILLER_FARMING,
|
||||
AllowedFillerOptionName.fishing: Group.FILLER_FISHING,
|
||||
AllowedFillerOptionName.fruit_trees: Group.FILLER_FRUIT_TREES,
|
||||
AllowedFillerOptionName.food: Group.FILLER_FOOD,
|
||||
AllowedFillerOptionName.buff_food: Group.FILLER_BUFF_FOOD,
|
||||
AllowedFillerOptionName.consumables: Group.FILLER_CONSUMABLE,
|
||||
AllowedFillerOptionName.machines: Group.FILLER_MACHINE,
|
||||
AllowedFillerOptionName.storage: Group.FILLER_STORAGE,
|
||||
AllowedFillerOptionName.quality_of_life: Group.FILLER_QUALITY_OF_LIFE,
|
||||
AllowedFillerOptionName.materials: Group.FILLER_MATERIALS,
|
||||
AllowedFillerOptionName.currencies: Group.FILLER_CURRENCY,
|
||||
AllowedFillerOptionName.money: Group.FILLER_MONEY,
|
||||
AllowedFillerOptionName.hats: Group.FILLER_HAT,
|
||||
AllowedFillerOptionName.decorations: Group.FILLER_DECORATION,
|
||||
AllowedFillerOptionName.rings: Group.FILLER_RING,
|
||||
}
|
||||
|
||||
|
||||
def generate_filler_choice_pool(options: StardewValleyOptions, content: StardewContent) -> list[str]:
|
||||
available_filler = get_all_filler_items(options)
|
||||
available_filler = remove_excluded(available_filler, content, options)
|
||||
available_filler = remove_limited_amount_resource_packs(available_filler)
|
||||
|
||||
return [item.name for item in available_filler]
|
||||
|
||||
|
||||
def get_all_filler_items(options: StardewValleyOptions) -> list[ItemData]:
|
||||
all_filler_items = []
|
||||
allowed_filler_types = sorted(list(options.allowed_filler_items.value))
|
||||
for allowed_filler_type in allowed_filler_types:
|
||||
allowed_filler_group = AllowedFillerTypesMap[allowed_filler_type]
|
||||
all_filler_items.extend([pack for pack in items_by_group[allowed_filler_group]])
|
||||
all_filler_items.extend(items_by_group[Group.TRASH])
|
||||
all_filler_items.extend(get_player_buffs(options))
|
||||
all_filler_items.extend(get_traps(options))
|
||||
|
||||
return all_filler_items
|
||||
|
||||
|
||||
def get_filler_weights(options: StardewValleyOptions, all_filler_packs: list[ItemData]) -> list[int]:
|
||||
weights = []
|
||||
for filler in all_filler_packs:
|
||||
if filler.name in options.trap_distribution:
|
||||
num = options.trap_distribution[filler.name]
|
||||
else:
|
||||
num = options.trap_distribution.default_weight
|
||||
weights.append(num)
|
||||
return weights
|
||||
|
||||
|
||||
def generate_unique_filler_items(item_factory: StardewItemFactory, content: StardewContent, options: StardewValleyOptions, random: Random,
|
||||
available_item_slots: int) -> list[Item]:
|
||||
items = create_filler_festival_rewards(item_factory, content, options)
|
||||
|
||||
if len(items) > available_item_slots:
|
||||
items = random.sample(items, available_item_slots)
|
||||
return items
|
||||
|
||||
|
||||
def create_filler_festival_rewards(item_factory: StardewItemFactory, content: StardewContent, options: StardewValleyOptions) -> list[Item]:
|
||||
if options.festival_locations == FestivalLocations.option_disabled:
|
||||
return []
|
||||
filler_rewards = [item for item in items_by_group[Group.FESTIVAL] if item.classification == ItemClassification.filler]
|
||||
filler_rewards = remove_excluded(filler_rewards, content, options)
|
||||
return [item_factory(item) for item in filler_rewards]
|
||||
|
||||
|
||||
def generate_resource_packs_and_traps(item_factory: StardewItemFactory,
|
||||
options: StardewValleyOptions,
|
||||
content: StardewContent,
|
||||
random: Random,
|
||||
already_added_items: list[Item],
|
||||
available_item_slots: int) -> list[Item]:
|
||||
def filler_factory(item: ItemData):
|
||||
# Yes some fillers are progression. We add multiple fruit tree saplings for instance.
|
||||
if ItemClassification.progression in item.classification:
|
||||
return item_factory(item,
|
||||
classification_pre_fill=ItemClassification.filler,
|
||||
classification_post_fill=ItemClassification.progression_skip_balancing)
|
||||
return item_factory(item)
|
||||
|
||||
already_added_items_names = {item.name for item in already_added_items}
|
||||
|
||||
priority_fillers = get_priority_fillers(options)
|
||||
priority_fillers = remove_excluded(priority_fillers, content, options)
|
||||
priority_fillers = remove_already_included(priority_fillers, already_added_items_names)
|
||||
|
||||
if available_item_slots < len(priority_fillers):
|
||||
return [filler_factory(priority_filler)
|
||||
for priority_filler in random.sample(priority_fillers, available_item_slots)]
|
||||
|
||||
chosen_fillers = []
|
||||
chosen_fillers.extend([filler_factory(priority_filler) for priority_filler in priority_fillers])
|
||||
available_item_slots -= len(priority_fillers)
|
||||
already_added_items_names |= {priority_item.name for priority_item in priority_fillers}
|
||||
|
||||
all_fillers = get_all_filler_items(options)
|
||||
all_fillers = remove_excluded(all_fillers, content, options)
|
||||
all_fillers = remove_already_included(all_fillers, already_added_items_names)
|
||||
|
||||
filler_weights = get_filler_weights(options, all_fillers)
|
||||
|
||||
while available_item_slots > 0:
|
||||
resource_pack = random.choices(all_fillers, weights=filler_weights, k=1)[0]
|
||||
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
while exactly_2 and available_item_slots == 1:
|
||||
# We roll another filler since there is no place for the second one
|
||||
resource_pack = random.choices(all_fillers, weights=filler_weights, k=1)[0]
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
|
||||
chosen_fillers.append(filler_factory(resource_pack))
|
||||
available_item_slots -= 1
|
||||
if exactly_2:
|
||||
chosen_fillers.append(filler_factory(resource_pack))
|
||||
available_item_slots -= 1
|
||||
|
||||
if resource_pack.has_limited_amount():
|
||||
index = all_fillers.index(resource_pack)
|
||||
all_fillers.pop(index)
|
||||
filler_weights.pop(index)
|
||||
|
||||
return chosen_fillers
|
||||
|
||||
|
||||
def get_priority_fillers(options: StardewValleyOptions) -> list[ItemData]:
|
||||
buffs = get_player_buffs(options)
|
||||
traps = get_traps(options)
|
||||
|
||||
return buffs + traps
|
||||
|
||||
|
||||
def get_player_buffs(options: StardewValleyOptions) -> List[ItemData]:
|
||||
buff_option = options.enabled_filler_buffs
|
||||
allowed_buffs = []
|
||||
if BuffOptionName.luck in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.luck])
|
||||
if BuffOptionName.damage in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.damage])
|
||||
if BuffOptionName.defense in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.defense])
|
||||
if BuffOptionName.immunity in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.immunity])
|
||||
if BuffOptionName.health in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.health])
|
||||
if BuffOptionName.energy in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.energy])
|
||||
if BuffOptionName.bite in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.bite_rate])
|
||||
if BuffOptionName.fish_trap in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.fish_trap])
|
||||
if BuffOptionName.fishing_bar in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.fishing_bar])
|
||||
if BuffOptionName.quality in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.quality])
|
||||
if BuffOptionName.glow in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.glow])
|
||||
return allowed_buffs
|
||||
|
||||
|
||||
def get_traps(options: StardewValleyOptions) -> list[ItemData]:
|
||||
if not options.trap_difficulty.include_traps():
|
||||
return []
|
||||
|
||||
return [
|
||||
trap
|
||||
for trap in items_by_group[Group.TRAP]
|
||||
if trap.name not in options.trap_distribution or options.trap_distribution[trap.name] > 0
|
||||
]
|
||||
31
worlds/stardew_valley/items/filters.py
Normal file
31
worlds/stardew_valley/items/filters.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from typing import Iterable
|
||||
|
||||
from .item_data import ItemData, Group, FILLER_GROUPS
|
||||
from ..content import StardewContent
|
||||
from ..options import StardewValleyOptions, Hatsanity
|
||||
|
||||
|
||||
def remove_excluded(items: Iterable[ItemData], content: StardewContent, options: StardewValleyOptions) -> list[ItemData]:
|
||||
filtered_items = [
|
||||
item for item in items
|
||||
if Group.DEPRECATED not in item.groups and content.are_all_enabled(item.content_packs)
|
||||
]
|
||||
if options.hatsanity == Hatsanity.preset_none:
|
||||
return filtered_items
|
||||
return [item for item in filtered_items if Group.FILLER_HAT not in item.groups]
|
||||
|
||||
|
||||
def remove_limited_amount_resource_packs(packs: Iterable[ItemData]) -> list[ItemData]:
|
||||
return [
|
||||
resource_pack
|
||||
for resource_pack in packs
|
||||
if not resource_pack.has_limited_amount()
|
||||
]
|
||||
|
||||
|
||||
def remove_already_included(items: Iterable[ItemData], already_added_items: set[str]) -> list[ItemData]:
|
||||
return [
|
||||
item
|
||||
for item in items
|
||||
if item.name not in already_added_items or (item.has_any_group(*FILLER_GROUPS, Group.TRAP) and Group.MAXIMUM_ONE not in item.groups)
|
||||
]
|
||||
@@ -1,30 +1,34 @@
|
||||
import logging
|
||||
from random import Random
|
||||
from typing import List, Set
|
||||
from typing import List
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .fillers import generate_resource_packs_and_traps, generate_unique_filler_items
|
||||
from .filters import remove_excluded
|
||||
from .item_data import StardewItemFactory, items_by_group, Group, item_table, ItemData
|
||||
from ..content.feature import friendsanity
|
||||
from ..content.game_content import StardewContent
|
||||
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from ..content.vanilla.qi_board import qi_board_content_pack
|
||||
from ..data.game_item import ItemTag
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..options import StardewValleyOptions, FestivalLocations, ExcludeGingerIsland, SpecialOrderLocations, SeasonRandomization, Museumsanity, \
|
||||
from ..options import StardewValleyOptions, FestivalLocations, SpecialOrderLocations, SeasonRandomization, Museumsanity, \
|
||||
ElevatorProgression, BackpackProgression, ArcadeMachineLocations, Monstersanity, Goal, \
|
||||
Chefsanity, Craftsanity, BundleRandomization, EntranceRandomization, Shipsanity, Walnutsanity, EnabledFillerBuffs, TrapDifficulty
|
||||
from ..strings.ap_names.ap_option_names import BuffOptionName, WalnutsanityOptionName
|
||||
Chefsanity, Craftsanity, BundleRandomization, EntranceRandomization, Shipsanity, Walnutsanity, Moviesanity
|
||||
from ..options.options import IncludeEndgameLocations, Friendsanity
|
||||
from ..strings.ap_names.ap_option_names import WalnutsanityOptionName, SecretsanityOptionName, EatsanityOptionName, ChefsanityOptionName, StartWithoutOptionName
|
||||
from ..strings.ap_names.ap_weapon_names import APWeapon
|
||||
from ..strings.ap_names.buff_names import Buff
|
||||
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade
|
||||
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade, Bookseller
|
||||
from ..strings.ap_names.mods.mod_items import SVEQuestItem
|
||||
from ..strings.backpack_tiers import Backpack
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.tool_names import Tool
|
||||
from ..strings.wallet_item_names import Wallet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def get_too_many_items_error_message(locations_count: int, items_count: int) -> str:
|
||||
return f"There should be at least as many locations [{locations_count}] as there are mandatory items [{items_count}]"
|
||||
|
||||
|
||||
def create_items(item_factory: StardewItemFactory, locations_count: int, items_to_exclude: List[Item],
|
||||
options: StardewValleyOptions, content: StardewContent, random: Random) -> List[Item]:
|
||||
@@ -38,21 +42,25 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t
|
||||
items += unique_items
|
||||
logger.debug(f"Created {len(unique_items)} unique items")
|
||||
|
||||
unique_filler_items = create_unique_filler_items(item_factory, options, random, locations_count - len(items))
|
||||
unique_filler_items = generate_unique_filler_items(item_factory, content, options, random, locations_count - len(items))
|
||||
items += unique_filler_items
|
||||
logger.debug(f"Created {len(unique_filler_items)} unique filler items")
|
||||
|
||||
resource_pack_items = fill_with_resource_packs_and_traps(item_factory, options, random, items + items_to_exclude, locations_count - len(items))
|
||||
resource_pack_items = generate_resource_packs_and_traps(item_factory, options, content, random, items + items_to_exclude, locations_count - len(items))
|
||||
items += resource_pack_items
|
||||
logger.debug(f"Created {len(resource_pack_items)} resource packs")
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def remove_items(items_to_remove, items):
|
||||
for item in items_to_remove:
|
||||
if item in items:
|
||||
items.remove(item)
|
||||
def remove_items(items_to_remove: List[Item], items: List[Item]):
|
||||
for item_to_remove in items_to_remove:
|
||||
for i, item_candidate in enumerate(items):
|
||||
if item_to_remove != item_candidate:
|
||||
continue
|
||||
if item_to_remove.classification == item_candidate.classification and item_to_remove.advancement == item_candidate.advancement:
|
||||
items.pop(i)
|
||||
break
|
||||
|
||||
|
||||
def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count: int, random: Random):
|
||||
@@ -66,7 +74,9 @@ def remove_items_if_no_room_for_them(unique_items: List[Item], locations_count:
|
||||
removable_items = [item for item in unique_items if not item.classification & ItemClassification.progression]
|
||||
else:
|
||||
logger.debug(f"Player has more items than locations, trying to remove {number_of_items_to_remove} random filler items")
|
||||
assert len(removable_items) >= number_of_items_to_remove, get_too_many_items_error_message(locations_count, len(unique_items))
|
||||
count = len(unique_items)
|
||||
assert len(removable_items) >= number_of_items_to_remove, \
|
||||
f"There should be at least as many locations [{locations_count}] as there are mandatory items [{count - len(removable_items)}]"
|
||||
items_to_remove = random.sample(removable_items, number_of_items_to_remove)
|
||||
remove_items(items_to_remove, unique_items)
|
||||
|
||||
@@ -79,20 +89,20 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley
|
||||
create_raccoons(item_factory, options, items)
|
||||
items.append(item_factory(Wallet.metal_detector)) # Always offer at least one metal detector
|
||||
|
||||
create_backpack_items(item_factory, options, items)
|
||||
create_weapons(item_factory, options, items)
|
||||
create_backpack_items(item_factory, options, content, items)
|
||||
create_weapons(item_factory, options, content, items)
|
||||
items.append(item_factory("Skull Key"))
|
||||
create_elevators(item_factory, options, items)
|
||||
create_elevators(item_factory, options, content, items)
|
||||
create_tools(item_factory, content, items)
|
||||
create_skills(item_factory, content, items)
|
||||
create_wizard_buildings(item_factory, options, items)
|
||||
create_carpenter_buildings(item_factory, content, items)
|
||||
create_wizard_buildings(item_factory, options, content, items)
|
||||
create_carpenter_buildings(item_factory, options, content, items)
|
||||
items.append(item_factory("Railroad Boulder Removed"))
|
||||
items.append(item_factory(CommunityUpgrade.fruit_bats))
|
||||
items.append(item_factory(CommunityUpgrade.mushroom_boxes))
|
||||
items.append(item_factory("Beach Bridge"))
|
||||
create_tv_channels(item_factory, options, items)
|
||||
create_quest_rewards(item_factory, options, items)
|
||||
create_quest_rewards(item_factory, options, content, items)
|
||||
create_stardrops(item_factory, options, content, items)
|
||||
create_museum_items(item_factory, options, items)
|
||||
create_arcade_machine_items(item_factory, options, items)
|
||||
@@ -104,84 +114,105 @@ def create_unique_items(item_factory: StardewItemFactory, options: StardewValley
|
||||
create_friendsanity_items(item_factory, options, content, items, random)
|
||||
create_festival_rewards(item_factory, options, items)
|
||||
create_special_order_board_rewards(item_factory, options, items)
|
||||
create_special_order_qi_rewards(item_factory, options, items)
|
||||
create_walnuts(item_factory, options, items)
|
||||
create_walnut_purchase_rewards(item_factory, options, items)
|
||||
create_crafting_recipes(item_factory, options, items)
|
||||
create_cooking_recipes(item_factory, options, items)
|
||||
create_special_order_qi_rewards(item_factory, options, content, items)
|
||||
create_walnuts(item_factory, options, content, items)
|
||||
create_walnut_purchase_rewards(item_factory, content, items)
|
||||
create_crafting_recipes(item_factory, options, content, items)
|
||||
create_cooking_recipes(item_factory, options, content, items)
|
||||
create_shipsanity_items(item_factory, options, items)
|
||||
create_booksanity_items(item_factory, content, items)
|
||||
create_booksanity_items(item_factory, options, content, items)
|
||||
create_movie_items(item_factory, options, items)
|
||||
create_secrets_items(item_factory, content, options, items)
|
||||
create_eatsanity_enzyme_items(item_factory, options, items)
|
||||
create_endgame_locations_items(item_factory, options, items)
|
||||
|
||||
create_goal_items(item_factory, options, items)
|
||||
items.append(item_factory("Golden Egg"))
|
||||
items.append(item_factory(CommunityUpgrade.mr_qi_plane_ride))
|
||||
|
||||
create_sve_special_items(item_factory, options, items)
|
||||
create_magic_mod_spells(item_factory, options, items)
|
||||
create_deepwoods_pendants(item_factory, options, items)
|
||||
create_archaeology_items(item_factory, options, items)
|
||||
items.append(item_factory(Wallet.mens_locker_key))
|
||||
items.append(item_factory(Wallet.womens_locker_key))
|
||||
|
||||
create_sve_special_items(item_factory, content, items)
|
||||
create_magic_mod_spells(item_factory, content, items)
|
||||
create_deepwoods_pendants(item_factory, content, items)
|
||||
create_archaeology_items(item_factory, content, items)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def create_raccoons(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
number_progressive_raccoons = 9
|
||||
if options.bundle_per_room.value < 0:
|
||||
number_progressive_raccoons -= options.bundle_per_room.value
|
||||
if options.quest_locations.has_no_story_quests():
|
||||
number_progressive_raccoons = number_progressive_raccoons - 1
|
||||
|
||||
items.extend(item_factory(item) for item in [CommunityUpgrade.raccoon] * number_progressive_raccoons)
|
||||
|
||||
|
||||
def create_backpack_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if (options.backpack_progression == BackpackProgression.option_progressive or
|
||||
options.backpack_progression == BackpackProgression.option_early_progressive):
|
||||
items.extend(item_factory(item) for item in ["Progressive Backpack"] * 2)
|
||||
if ModNames.big_backpack in options.mods:
|
||||
items.append(item_factory("Progressive Backpack"))
|
||||
def create_backpack_items(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
if options.backpack_progression == BackpackProgression.option_vanilla:
|
||||
return
|
||||
num_per_tier = options.backpack_size.count_per_tier()
|
||||
backpack_tier_names = Backpack.get_purchasable_tiers(ModNames.big_backpack in content.registered_packs, StartWithoutOptionName.backpack in options.start_without)
|
||||
num_backpacks = len(backpack_tier_names) * num_per_tier
|
||||
|
||||
items.extend(item_factory(item) for item in ["Progressive Backpack"] * num_backpacks)
|
||||
|
||||
|
||||
def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
weapons = weapons_count(options)
|
||||
def create_footwear(item_factory: StardewItemFactory, number: int) -> List[Item]:
|
||||
return [item_factory(APWeapon.footwear) for _ in range(number)]
|
||||
|
||||
|
||||
def create_weapons(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
weapons = weapons_count(content)
|
||||
items.extend(item_factory(item) for item in [APWeapon.slingshot] * 2)
|
||||
monstersanity = options.monstersanity
|
||||
|
||||
ring_classification = ItemClassification.progression if options.bundle_randomization == BundleRandomization.option_meme else ItemClassification.useful
|
||||
rings_items = [item for item in items_by_group[Group.FILLER_RING] if item.classification is not ItemClassification.filler]
|
||||
|
||||
if monstersanity == Monstersanity.option_none: # Without monstersanity, might not be enough checks to split the weapons
|
||||
items.extend(item_factory(item) for item in [APWeapon.weapon] * weapons)
|
||||
items.extend(item_factory(item) for item in [APWeapon.footwear] * 3) # 1-2 | 3-4 | 6-7-8
|
||||
items.extend(create_footwear(item_factory, 3)) # 1-2 | 3-4 | 6-7-8
|
||||
rings_items = [item for item in rings_items if item.classification is ItemClassification.progression]
|
||||
items.extend(item_factory(item, classification_pre_fill=ring_classification) for item in rings_items)
|
||||
return
|
||||
|
||||
items.extend(item_factory(item) for item in [APWeapon.sword] * weapons)
|
||||
items.extend(item_factory(item) for item in [APWeapon.club] * weapons)
|
||||
items.extend(item_factory(item) for item in [APWeapon.dagger] * weapons)
|
||||
items.extend(item_factory(item) for item in [APWeapon.footwear] * 4) # 1-2 | 3-4 | 6-7-8 | 11-13
|
||||
items.extend(create_footwear(item_factory, 4)) # 1-2 | 3-4 | 6-7-8 | 11-13
|
||||
|
||||
items.extend(item_factory(item, classification_pre_fill=ring_classification) for item in rings_items)
|
||||
if monstersanity == Monstersanity.option_goals or monstersanity == Monstersanity.option_one_per_category or \
|
||||
monstersanity == Monstersanity.option_short_goals or monstersanity == Monstersanity.option_very_short_goals:
|
||||
return
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
rings_items = [item for item in items_by_group[Group.RING] if item.classification is not ItemClassification.filler]
|
||||
else:
|
||||
rings_items = [item for item in items_by_group[Group.RING]]
|
||||
items.extend(item_factory(item) for item in rings_items)
|
||||
|
||||
|
||||
def create_elevators(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
def create_elevators(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
if options.elevator_progression == ElevatorProgression.option_vanilla:
|
||||
return
|
||||
|
||||
items.extend([item_factory(item) for item in ["Progressive Mine Elevator"] * 24])
|
||||
if ModNames.deepwoods in options.mods:
|
||||
if ModNames.deepwoods in content.registered_packs:
|
||||
items.extend([item_factory(item) for item in ["Progressive Woods Obelisk Sigils"] * 10])
|
||||
if ModNames.skull_cavern_elevator in options.mods:
|
||||
if ModNames.skull_cavern_elevator in content.registered_packs:
|
||||
items.extend([item_factory(item) for item in ["Progressive Skull Cavern Elevator"] * 8])
|
||||
|
||||
|
||||
def create_tools(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
tool_progression = content.features.tool_progression
|
||||
for tool, count in tool_progression.tool_distribution.items():
|
||||
item = item_table[tool_progression.to_progressive_item(tool)]
|
||||
item = item_table[tool_progression.to_progressive_item_name(tool)]
|
||||
|
||||
# Trash can is only used in tool upgrade logic, so the last trash can is not progression because it basically does not unlock anything.
|
||||
if tool == Tool.trash_can:
|
||||
count -= 1
|
||||
items.append(item_factory(item, ItemClassification.useful))
|
||||
items.append(item_factory(item,
|
||||
classification_pre_fill=ItemClassification.useful,
|
||||
classification_post_fill=ItemClassification.progression_skip_balancing))
|
||||
|
||||
items.extend([item_factory(item) for _ in range(count)])
|
||||
|
||||
@@ -201,49 +232,53 @@ def create_skills(item_factory: StardewItemFactory, content: StardewContent, ite
|
||||
items.append(item_factory(Wallet.mastery_of_the_five_ways))
|
||||
|
||||
|
||||
def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
useless_buildings_classification = ItemClassification.progression_skip_balancing if world_is_perfection(options) else ItemClassification.useful
|
||||
items.append(item_factory("Earth Obelisk", useless_buildings_classification))
|
||||
items.append(item_factory("Water Obelisk", useless_buildings_classification))
|
||||
def create_wizard_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
useful_buildings_classification = ItemClassification.progression_skip_balancing if goal_is_perfection(options) else ItemClassification.useful
|
||||
items.append(item_factory("Earth Obelisk", classification_pre_fill=useful_buildings_classification))
|
||||
items.append(item_factory("Water Obelisk", classification_pre_fill=useful_buildings_classification))
|
||||
items.append(item_factory("Desert Obelisk"))
|
||||
items.append(item_factory("Junimo Hut"))
|
||||
items.append(item_factory("Gold Clock", useless_buildings_classification))
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_false:
|
||||
items.append(item_factory("Gold Clock", classification_pre_fill=useful_buildings_classification))
|
||||
if content.is_enabled(ginger_island_content_pack):
|
||||
items.append(item_factory("Island Obelisk"))
|
||||
if ModNames.deepwoods in options.mods:
|
||||
if content.is_enabled(ModNames.deepwoods):
|
||||
items.append(item_factory("Woods Obelisk"))
|
||||
|
||||
|
||||
def create_carpenter_buildings(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
def create_carpenter_buildings(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
building_progression = content.features.building_progression
|
||||
if not building_progression.is_progressive:
|
||||
return
|
||||
|
||||
for building in content.farm_buildings.values():
|
||||
item_name, _ = building_progression.to_progressive_item(building.name)
|
||||
if item_name in [Building.stable, Building.well] and options.bundle_randomization != BundleRandomization.option_meme:
|
||||
items.append(item_factory(item_name, classification_pre_fill=ItemClassification.useful))
|
||||
else:
|
||||
items.append(item_factory(item_name))
|
||||
|
||||
|
||||
def create_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
create_special_quest_rewards(item_factory, options, items)
|
||||
def create_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
create_special_quest_rewards(item_factory, options, content, items)
|
||||
create_help_wanted_quest_rewards(item_factory, options, items)
|
||||
|
||||
create_quest_rewards_sve(item_factory, options, items)
|
||||
create_quest_rewards_sve(item_factory, options, content, items)
|
||||
|
||||
|
||||
def create_special_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
def create_special_quest_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
if options.quest_locations.has_no_story_quests():
|
||||
return
|
||||
# items.append(item_factory("Adventurer's Guild")) # Now unlocked always!
|
||||
items.append(item_factory(Wallet.club_card))
|
||||
items.append(item_factory(Wallet.magnifying_glass))
|
||||
if ModNames.sve in options.mods:
|
||||
items.append(item_factory(Wallet.magic_ink))
|
||||
items.append(item_factory(Wallet.iridium_snake_milk))
|
||||
if ModNames.sve in content.registered_packs:
|
||||
items.append(item_factory(Wallet.bears_knowledge))
|
||||
else:
|
||||
items.append(item_factory(Wallet.bears_knowledge, ItemClassification.useful)) # Not necessary outside of SVE
|
||||
items.append(item_factory(Wallet.iridium_snake_milk))
|
||||
items.append(item_factory(Wallet.bears_knowledge, classification_pre_fill=ItemClassification.useful)) # Not necessary outside of SVE
|
||||
items.append(item_factory("Dark Talisman"))
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_false:
|
||||
if content.is_enabled(ginger_island_content_pack):
|
||||
items.append(item_factory("Fairy Dust Recipe"))
|
||||
|
||||
|
||||
@@ -259,22 +294,24 @@ def create_help_wanted_quest_rewards(item_factory: StardewItemFactory, options:
|
||||
|
||||
def create_stardrops(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
stardrops_classification = get_stardrop_classification(options)
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # The Mines level 100
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # Old Master Cannoli
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # Krobus Stardrop
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=stardrops_classification)) # The Mines level 100
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=stardrops_classification)) # Krobus Stardrop
|
||||
if content.features.fishsanity.is_enabled:
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # Master Angler Stardrop
|
||||
if ModNames.deepwoods in options.mods:
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # Petting the Unicorn
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=stardrops_classification)) # Master Angler Stardrop
|
||||
if ModNames.deepwoods in content.registered_packs:
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=stardrops_classification)) # Petting the Unicorn
|
||||
if content.features.friendsanity.is_enabled:
|
||||
items.append(item_factory("Stardrop", stardrops_classification)) # Spouse Stardrop
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=stardrops_classification)) # Spouse Stardrop
|
||||
if SecretsanityOptionName.easy in options.secretsanity:
|
||||
# Always Progression as a different secret requires a stardrop
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=ItemClassification.progression)) # Old Master Cannoli.
|
||||
|
||||
|
||||
def create_museum_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
items.append(item_factory(Wallet.rusty_key))
|
||||
items.append(item_factory(Wallet.dwarvish_translation_guide))
|
||||
items.append(item_factory("Ancient Seeds Recipe"))
|
||||
items.append(item_factory("Stardrop", get_stardrop_classification(options)))
|
||||
items.append(item_factory("Stardrop", classification_pre_fill=get_stardrop_classification(options)))
|
||||
if options.museumsanity == Museumsanity.option_none:
|
||||
return
|
||||
items.extend(item_factory(item) for item in ["Magic Rock Candy"] * 10)
|
||||
@@ -292,13 +329,10 @@ def create_friendsanity_items(item_factory: StardewItemFactory, options: Stardew
|
||||
item_name = friendsanity.to_item_name(villager.name)
|
||||
|
||||
for _ in content.features.friendsanity.get_randomized_hearts(villager):
|
||||
items.append(item_factory(item_name, ItemClassification.progression))
|
||||
|
||||
need_pet = options.goal == Goal.option_grandpa_evaluation
|
||||
pet_item_classification = ItemClassification.progression_skip_balancing if need_pet else ItemClassification.useful
|
||||
items.append(item_factory(item_name))
|
||||
|
||||
for _ in content.features.friendsanity.get_pet_randomized_hearts():
|
||||
items.append(item_factory(friendsanity.pet_heart_item_name, pet_item_classification))
|
||||
items.append(item_factory(friendsanity.pet_heart_item_name, classification_pre_fill=ItemClassification.progression_skip_balancing))
|
||||
|
||||
|
||||
def create_babies(item_factory: StardewItemFactory, items: List[Item], random: Random):
|
||||
@@ -359,12 +393,12 @@ def create_festival_rewards(item_factory: StardewItemFactory, options: StardewVa
|
||||
return
|
||||
|
||||
festival_rewards = [item_factory(item) for item in items_by_group[Group.FESTIVAL] if item.classification != ItemClassification.filler]
|
||||
items.extend([*festival_rewards, item_factory("Stardrop", get_stardrop_classification(options))])
|
||||
items.extend([*festival_rewards, item_factory("Stardrop", classification_pre_fill=get_stardrop_classification(options))])
|
||||
|
||||
|
||||
def create_walnuts(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
def create_walnuts(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
walnutsanity = options.walnutsanity
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true or walnutsanity == Walnutsanity.preset_none:
|
||||
if not content.is_enabled(ginger_island_content_pack) or walnutsanity == Walnutsanity.preset_none:
|
||||
return
|
||||
|
||||
# Give baseline walnuts just to be nice
|
||||
@@ -391,8 +425,8 @@ def create_walnuts(item_factory: StardewItemFactory, options: StardewValleyOptio
|
||||
items.extend([item_factory(item) for item in ["5 Golden Walnuts"] * num_penta_walnuts])
|
||||
|
||||
|
||||
def create_walnut_purchase_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
def create_walnut_purchase_rewards(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
if not content.is_enabled(ginger_island_content_pack):
|
||||
return
|
||||
|
||||
items.extend([item_factory("Boat Repair"),
|
||||
@@ -420,15 +454,15 @@ def special_order_board_item_classification(item: ItemData, need_all_recipes: bo
|
||||
return ItemClassification.useful
|
||||
|
||||
|
||||
def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
def create_special_order_qi_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
if not content.is_enabled(ginger_island_content_pack):
|
||||
return
|
||||
qi_gem_rewards = []
|
||||
if options.bundle_randomization >= BundleRandomization.option_remixed:
|
||||
qi_gem_rewards.append("15 Qi Gems")
|
||||
qi_gem_rewards.append("15 Qi Gems")
|
||||
|
||||
if options.special_order_locations & SpecialOrderLocations.value_qi:
|
||||
if content.is_enabled(qi_board_content_pack):
|
||||
qi_gem_rewards.extend(["100 Qi Gems", "10 Qi Gems", "40 Qi Gems", "25 Qi Gems", "25 Qi Gems",
|
||||
"40 Qi Gems", "20 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems"])
|
||||
|
||||
@@ -443,33 +477,33 @@ def create_tv_channels(item_factory: StardewItemFactory, options: StardewValleyO
|
||||
items.extend([item_factory(item) for item in channels])
|
||||
|
||||
|
||||
def create_crafting_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
def create_crafting_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
has_craftsanity = options.craftsanity == Craftsanity.option_all
|
||||
crafting_recipes = []
|
||||
crafting_recipes.extend([recipe for recipe in items_by_group[Group.QI_CRAFTING_RECIPE]])
|
||||
if has_craftsanity:
|
||||
crafting_recipes.extend([recipe for recipe in items_by_group[Group.CRAFTSANITY]])
|
||||
crafting_recipes = remove_excluded_items(crafting_recipes, options)
|
||||
crafting_recipes = remove_excluded(crafting_recipes, content, options)
|
||||
items.extend([item_factory(item) for item in crafting_recipes])
|
||||
|
||||
|
||||
def create_cooking_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
def create_cooking_recipes(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
chefsanity = options.chefsanity
|
||||
if chefsanity == Chefsanity.option_none:
|
||||
if chefsanity == Chefsanity.preset_none:
|
||||
return
|
||||
|
||||
chefsanity_recipes_by_name = {recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_STARTER]} # Dictionary to not make duplicates
|
||||
|
||||
if chefsanity & Chefsanity.option_queen_of_sauce:
|
||||
if ChefsanityOptionName.queen_of_sauce in chefsanity:
|
||||
chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_QOS]})
|
||||
if chefsanity & Chefsanity.option_purchases:
|
||||
if ChefsanityOptionName.purchases in chefsanity:
|
||||
chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_PURCHASE]})
|
||||
if chefsanity & Chefsanity.option_friendship:
|
||||
if ChefsanityOptionName.friendship in chefsanity:
|
||||
chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_FRIENDSHIP]})
|
||||
if chefsanity & Chefsanity.option_skills:
|
||||
if ChefsanityOptionName.skills in chefsanity:
|
||||
chefsanity_recipes_by_name.update({recipe.name: recipe for recipe in items_by_group[Group.CHEFSANITY_SKILL]})
|
||||
|
||||
filtered_chefsanity_recipes = remove_excluded_items(list(chefsanity_recipes_by_name.values()), options)
|
||||
filtered_chefsanity_recipes = remove_excluded(list(chefsanity_recipes_by_name.values()), content, options)
|
||||
items.extend([item_factory(item) for item in filtered_chefsanity_recipes])
|
||||
|
||||
|
||||
@@ -481,14 +515,95 @@ def create_shipsanity_items(item_factory: StardewItemFactory, options: StardewVa
|
||||
items.append(item_factory(Wallet.metal_detector))
|
||||
|
||||
|
||||
def create_booksanity_items(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
def create_booksanity_items(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
create_bookseller_items(item_factory, options, content, items)
|
||||
booksanity = content.features.booksanity
|
||||
if not booksanity.is_enabled:
|
||||
return
|
||||
|
||||
items.extend(item_factory(item_table[booksanity.to_item_name(book.name)]) for book in content.find_tagged_items(ItemTag.BOOK_POWER))
|
||||
progressive_lost_book = item_table[booksanity.progressive_lost_book]
|
||||
items.extend(item_factory(progressive_lost_book) for _ in content.features.booksanity.get_randomized_lost_books())
|
||||
# We do -1 here because the first lost book spawns freely in the museum
|
||||
num_lost_books = len([book for book in content.features.booksanity.get_randomized_lost_books()]) - 1
|
||||
items.extend(item_factory(progressive_lost_book) for _ in range(num_lost_books))
|
||||
|
||||
|
||||
def create_bookseller_items(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
needs_books = options.shipsanity == Shipsanity.option_everything or content.features.booksanity.is_enabled or content.features.hatsanity.is_enabled
|
||||
book_items = []
|
||||
book_items.extend(item_factory(item_table[Bookseller.days]) for _ in range(4 if needs_books else 1))
|
||||
if not needs_books:
|
||||
book_items.extend(item_factory(item_table[Bookseller.days], classification_pre_fill=ItemClassification.filler) for _ in range(3))
|
||||
book_items.extend(item_factory(item_table[Bookseller.stock_rare_books]) for _ in range(2 if needs_books else 1))
|
||||
book_items.append(item_factory(item_table[Bookseller.stock_permanent_books]))
|
||||
book_items.append(item_factory(item_table[Bookseller.stock_experience_books]))
|
||||
if needs_books:
|
||||
book_items.extend(item_factory(item_table[Bookseller.stock_experience_books], classification_pre_fill=ItemClassification.filler) for _ in range(2))
|
||||
|
||||
items.extend(book_items)
|
||||
|
||||
|
||||
def create_movie_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if options.moviesanity.value < Moviesanity.option_all_movies:
|
||||
return
|
||||
|
||||
items.extend(item_factory(item) for item in items_by_group[Group.MOVIESANITY])
|
||||
|
||||
|
||||
def create_secrets_items(item_factory: StardewItemFactory, content: StardewContent, options: StardewValleyOptions, items: List[Item]):
|
||||
if not options.secretsanity:
|
||||
return
|
||||
secret_items = []
|
||||
if SecretsanityOptionName.easy in options.secretsanity:
|
||||
secret_items.extend(items_by_group[Group.EASY_SECRET])
|
||||
# if SecretsanityOptionName.fishing in options.secretsanity:
|
||||
# secret_items.extend(items_by_group[Group.FISHING_SECRET]) # There are no longer any of these items, they are now part of FILLER_DECORATION
|
||||
# if SecretsanityOptionName.difficult in options.secretsanity:
|
||||
# items.extend(item_factory(item) for item in items_by_group[Group.DIFFICULT_SECRET])
|
||||
if SecretsanityOptionName.secret_notes in options.secretsanity:
|
||||
secret_items.extend(items_by_group[Group.SECRET_NOTES_SECRET])
|
||||
if options.quest_locations.has_no_story_quests():
|
||||
secret_items.append(item_table[Wallet.club_card])
|
||||
secret_items.append(item_table[Wallet.iridium_snake_milk])
|
||||
filtered_secret_items = remove_excluded(list(secret_items), content, options)
|
||||
items.extend([item_factory(item) for item in filtered_secret_items])
|
||||
|
||||
|
||||
def create_eatsanity_enzyme_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if EatsanityOptionName.lock_effects not in options.eatsanity:
|
||||
return
|
||||
|
||||
# These items unlock progressively stronger ability to digest food items that give the associated buff
|
||||
# Upon receiving the enzyme, you also get a temporary buff of whatever the effect is
|
||||
# Stamina and Health items can go beyond their original max value, but the buffs cannot.
|
||||
items.extend(item_factory(item) for item in ["Stamina Enzyme"]*10)
|
||||
items.extend(item_factory(item) for item in ["Health Enzyme"]*10)
|
||||
items.extend(item_factory(item) for item in ["Speed Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Luck Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Farming Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Foraging Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Fishing Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Mining Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Magnetism Enzyme"]*2)
|
||||
items.extend(item_factory(item) for item in ["Defense Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Attack Enzyme"]*5)
|
||||
items.extend(item_factory(item) for item in ["Max Stamina Enzyme"]*3)
|
||||
items.extend(item_factory(item) for item in ["Squid Ink Enzyme"])
|
||||
items.extend(item_factory(item) for item in ["Monster Musk Enzyme"])
|
||||
items.extend(item_factory(item) for item in ["Oil Of Garlic Enzyme"])
|
||||
items.extend(item_factory(item) for item in ["Tipsy Enzyme"])
|
||||
|
||||
|
||||
def create_endgame_locations_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if options.include_endgame_locations == IncludeEndgameLocations.option_false:
|
||||
return
|
||||
|
||||
items_to_add = []
|
||||
items_to_add.extend(items_by_group[Group.ENDGAME_LOCATION_ITEMS])
|
||||
if options.friendsanity != Friendsanity.option_all_with_marriage:
|
||||
for portrait in items_by_group[Group.REQUIRES_FRIENDSANITY_MARRIAGE]:
|
||||
items_to_add.remove(portrait)
|
||||
items.extend(item_factory(item) for item in items_to_add)
|
||||
|
||||
|
||||
def create_goal_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
@@ -499,233 +614,66 @@ def create_goal_items(item_factory: StardewItemFactory, options: StardewValleyOp
|
||||
items.append(item_factory(Wallet.metal_detector))
|
||||
|
||||
|
||||
def create_archaeology_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
mods = options.mods
|
||||
if ModNames.archaeology not in mods:
|
||||
def create_archaeology_items(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
if ModNames.archaeology not in content.registered_packs:
|
||||
return
|
||||
|
||||
items.append(item_factory(Wallet.metal_detector))
|
||||
|
||||
|
||||
def create_filler_festival_rewards(item_factory: StardewItemFactory, options: StardewValleyOptions) -> List[Item]:
|
||||
if options.festival_locations == FestivalLocations.option_disabled:
|
||||
return []
|
||||
|
||||
return [item_factory(item) for item in items_by_group[Group.FESTIVAL] if
|
||||
item.classification == ItemClassification.filler]
|
||||
|
||||
|
||||
def create_magic_mod_spells(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if ModNames.magic not in options.mods:
|
||||
def create_magic_mod_spells(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
if ModNames.magic not in content.registered_packs:
|
||||
return
|
||||
items.extend([item_factory(item) for item in items_by_group[Group.MAGIC_SPELL]])
|
||||
|
||||
|
||||
def create_deepwoods_pendants(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if ModNames.deepwoods not in options.mods:
|
||||
def create_deepwoods_pendants(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
if ModNames.deepwoods not in content.registered_packs:
|
||||
return
|
||||
items.extend([item_factory(item) for item in ["Pendant of Elders", "Pendant of Community", "Pendant of Depths"]])
|
||||
|
||||
|
||||
def create_sve_special_items(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if ModNames.sve not in options.mods:
|
||||
def create_sve_special_items(item_factory: StardewItemFactory, content: StardewContent, items: List[Item]):
|
||||
if ModNames.sve not in content.registered_packs:
|
||||
return
|
||||
|
||||
items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP] if item.mod_name == ModNames.sve])
|
||||
items.extend([item_factory(item) for item in items_by_group[Group.MOD_WARP] if ModNames.sve in item.content_packs])
|
||||
|
||||
|
||||
def create_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, items: List[Item]):
|
||||
if ModNames.sve not in options.mods:
|
||||
def create_quest_rewards_sve(item_factory: StardewItemFactory, options: StardewValleyOptions, content: StardewContent, items: List[Item]):
|
||||
if not content.is_enabled(ModNames.sve):
|
||||
return
|
||||
|
||||
exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true
|
||||
ginger_island_included = content.is_enabled(ginger_island_content_pack)
|
||||
items.extend([item_factory(item) for item in SVEQuestItem.sve_always_quest_items])
|
||||
if not exclude_ginger_island:
|
||||
if ginger_island_included:
|
||||
items.extend([item_factory(item) for item in SVEQuestItem.sve_always_quest_items_ginger_island])
|
||||
|
||||
if options.quest_locations.has_no_story_quests():
|
||||
return
|
||||
|
||||
items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items])
|
||||
if exclude_ginger_island:
|
||||
if not ginger_island_included:
|
||||
return
|
||||
items.extend([item_factory(item) for item in SVEQuestItem.sve_quest_items_ginger_island])
|
||||
|
||||
|
||||
def create_unique_filler_items(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random,
|
||||
available_item_slots: int) -> List[Item]:
|
||||
items = []
|
||||
|
||||
items.extend(create_filler_festival_rewards(item_factory, options))
|
||||
|
||||
if len(items) > available_item_slots:
|
||||
items = random.sample(items, available_item_slots)
|
||||
return items
|
||||
|
||||
|
||||
def weapons_count(options: StardewValleyOptions):
|
||||
def weapons_count(content: StardewContent):
|
||||
weapon_count = 5
|
||||
if ModNames.sve in options.mods:
|
||||
if ModNames.sve in content.registered_packs:
|
||||
weapon_count += 1
|
||||
return weapon_count
|
||||
|
||||
|
||||
def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random,
|
||||
items_already_added: List[Item],
|
||||
available_item_slots: int) -> List[Item]:
|
||||
include_traps = options.trap_difficulty != TrapDifficulty.option_no_traps
|
||||
items_already_added_names = [item.name for item in items_already_added]
|
||||
useful_resource_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK_USEFUL]
|
||||
if pack.name not in items_already_added_names]
|
||||
trap_items = [trap for trap in items_by_group[Group.TRAP]
|
||||
if trap.name not in items_already_added_names and
|
||||
Group.DEPRECATED not in trap.groups and
|
||||
(trap.mod_name is None or trap.mod_name in options.mods) and
|
||||
options.trap_distribution[trap.name] > 0]
|
||||
player_buffs = get_allowed_player_buffs(options.enabled_filler_buffs)
|
||||
|
||||
priority_filler_items = []
|
||||
priority_filler_items.extend(useful_resource_packs)
|
||||
priority_filler_items.extend(player_buffs)
|
||||
|
||||
if include_traps:
|
||||
priority_filler_items.extend(trap_items)
|
||||
|
||||
exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true
|
||||
all_filler_packs = remove_excluded_items(get_all_filler_items(include_traps, exclude_ginger_island), options)
|
||||
all_filler_packs.extend(player_buffs)
|
||||
priority_filler_items = remove_excluded_items(priority_filler_items, options)
|
||||
|
||||
number_priority_items = len(priority_filler_items)
|
||||
if available_item_slots < number_priority_items:
|
||||
chosen_priority_items = [item_factory(resource_pack) for resource_pack in
|
||||
random.sample(priority_filler_items, available_item_slots)]
|
||||
return chosen_priority_items
|
||||
|
||||
items = []
|
||||
chosen_priority_items = [item_factory(resource_pack,
|
||||
ItemClassification.trap if resource_pack.classification == ItemClassification.trap else ItemClassification.useful)
|
||||
for resource_pack in priority_filler_items]
|
||||
items.extend(chosen_priority_items)
|
||||
available_item_slots -= number_priority_items
|
||||
all_filler_packs = [filler_pack for filler_pack in all_filler_packs
|
||||
if Group.MAXIMUM_ONE not in filler_pack.groups or
|
||||
(filler_pack.name not in [priority_item.name for priority_item in
|
||||
priority_filler_items] and filler_pack.name not in items_already_added_names)]
|
||||
|
||||
filler_weights = get_filler_weights(options, all_filler_packs)
|
||||
|
||||
while available_item_slots > 0:
|
||||
resource_pack = random.choices(all_filler_packs, weights=filler_weights, k=1)[0]
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
while exactly_2 and available_item_slots == 1:
|
||||
resource_pack = random.choices(all_filler_packs, weights=filler_weights, k=1)[0]
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
classification = ItemClassification.useful if resource_pack.classification == ItemClassification.progression else resource_pack.classification
|
||||
items.append(item_factory(resource_pack, classification))
|
||||
available_item_slots -= 1
|
||||
if exactly_2:
|
||||
items.append(item_factory(resource_pack, classification))
|
||||
available_item_slots -= 1
|
||||
if exactly_2 or Group.MAXIMUM_ONE in resource_pack.groups:
|
||||
index = all_filler_packs.index(resource_pack)
|
||||
all_filler_packs.pop(index)
|
||||
filler_weights.pop(index)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def get_filler_weights(options: StardewValleyOptions, all_filler_packs: List[ItemData]):
|
||||
weights = []
|
||||
for filler in all_filler_packs:
|
||||
if filler.name in options.trap_distribution:
|
||||
num = options.trap_distribution[filler.name]
|
||||
else:
|
||||
num = options.trap_distribution.default_weight
|
||||
weights.append(num)
|
||||
return weights
|
||||
|
||||
|
||||
def filter_deprecated_items(items: List[ItemData]) -> List[ItemData]:
|
||||
return [item for item in items if Group.DEPRECATED not in item.groups]
|
||||
|
||||
|
||||
def filter_ginger_island_items(exclude_island: bool, items: List[ItemData]) -> List[ItemData]:
|
||||
return [item for item in items if not exclude_island or Group.GINGER_ISLAND not in item.groups]
|
||||
|
||||
|
||||
def filter_mod_items(mods: Set[str], items: List[ItemData]) -> List[ItemData]:
|
||||
return [item for item in items if item.mod_name is None or item.mod_name in mods]
|
||||
|
||||
|
||||
def remove_excluded_items(items, options: StardewValleyOptions):
|
||||
return remove_excluded_items_island_mods(items, options.exclude_ginger_island == ExcludeGingerIsland.option_true, options.mods.value)
|
||||
|
||||
|
||||
def remove_excluded_items_island_mods(items, exclude_ginger_island: bool, mods: Set[str]):
|
||||
deprecated_filter = filter_deprecated_items(items)
|
||||
ginger_island_filter = filter_ginger_island_items(exclude_ginger_island, deprecated_filter)
|
||||
mod_filter = filter_mod_items(mods, ginger_island_filter)
|
||||
return mod_filter
|
||||
|
||||
|
||||
def generate_filler_choice_pool(options: StardewValleyOptions) -> list[str]:
|
||||
include_traps = options.trap_difficulty != TrapDifficulty.option_no_traps
|
||||
exclude_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true
|
||||
|
||||
available_filler = get_all_filler_items(include_traps, exclude_island)
|
||||
available_filler = remove_limited_amount_packs(available_filler)
|
||||
|
||||
return [item.name for item in available_filler]
|
||||
|
||||
|
||||
def remove_limited_amount_packs(packs):
|
||||
return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.AT_LEAST_TWO not in pack.groups]
|
||||
|
||||
|
||||
def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool) -> List[ItemData]:
|
||||
all_filler_items = [pack for pack in items_by_group[Group.RESOURCE_PACK]]
|
||||
all_filler_items.extend(items_by_group[Group.TRASH])
|
||||
if include_traps:
|
||||
all_filler_items.extend(items_by_group[Group.TRAP])
|
||||
all_filler_items = remove_excluded_items_island_mods(all_filler_items, exclude_ginger_island, set())
|
||||
return all_filler_items
|
||||
|
||||
|
||||
def get_allowed_player_buffs(buff_option: EnabledFillerBuffs) -> List[ItemData]:
|
||||
allowed_buffs = []
|
||||
if BuffOptionName.luck in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.luck])
|
||||
if BuffOptionName.damage in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.damage])
|
||||
if BuffOptionName.defense in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.defense])
|
||||
if BuffOptionName.immunity in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.immunity])
|
||||
if BuffOptionName.health in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.health])
|
||||
if BuffOptionName.energy in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.energy])
|
||||
if BuffOptionName.bite in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.bite_rate])
|
||||
if BuffOptionName.fish_trap in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.fish_trap])
|
||||
if BuffOptionName.fishing_bar in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.fishing_bar])
|
||||
if BuffOptionName.quality in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.quality])
|
||||
if BuffOptionName.glow in buff_option:
|
||||
allowed_buffs.append(item_table[Buff.glow])
|
||||
return allowed_buffs
|
||||
|
||||
|
||||
def get_stardrop_classification(options) -> ItemClassification:
|
||||
return ItemClassification.progression_skip_balancing if world_is_perfection(options) or world_is_stardrops(options) else ItemClassification.useful
|
||||
return ItemClassification.progression_skip_balancing \
|
||||
if goal_is_perfection(options) or goal_is_stardrops(options) or EatsanityOptionName.shop in options.eatsanity \
|
||||
else ItemClassification.useful
|
||||
|
||||
|
||||
def world_is_perfection(options) -> bool:
|
||||
def goal_is_perfection(options) -> bool:
|
||||
return options.goal == Goal.option_perfection
|
||||
|
||||
|
||||
def world_is_stardrops(options) -> bool:
|
||||
def goal_is_stardrops(options) -> bool:
|
||||
return options.goal == Goal.option_mystery_of_the_stardrops
|
||||
|
||||
@@ -1,27 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import enum
|
||||
from dataclasses import dataclass, field
|
||||
from functools import reduce
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Protocol, Union, Set, Optional
|
||||
from typing import Protocol
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from BaseClasses import ItemClassification, Item
|
||||
from .. import data
|
||||
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from ..logic.logic_event import all_events
|
||||
|
||||
ITEM_CODE_OFFSET = 717000
|
||||
|
||||
world_folder = Path(__file__).parent
|
||||
|
||||
class StardewItemFactory(Protocol):
|
||||
def __call__(self, item: str | ItemData, /, *, classification_pre_fill: ItemClassification = None,
|
||||
classification_post_fill: ItemClassification = None) -> Item:
|
||||
"""
|
||||
:param item: The item to create. Can be the name of the item or the item data.
|
||||
:param classification_pre_fill: The classification to use for the item before the fill. If None, the basic classification of the item is used.
|
||||
:param classification_post_fill: The classification to use for the item after the fill. If None, the pre_fill classification will be used.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Group(enum.Enum):
|
||||
RESOURCE_PACK = enum.auto()
|
||||
FRIENDSHIP_PACK = enum.auto()
|
||||
COMMUNITY_REWARD = enum.auto()
|
||||
TRASH_BEAR = enum.auto()
|
||||
TRASH = enum.auto()
|
||||
FOOTWEAR = enum.auto()
|
||||
HATS = enum.auto()
|
||||
RING = enum.auto()
|
||||
WEAPON = enum.auto()
|
||||
WEAPON_GENERIC = enum.auto()
|
||||
WEAPON_SWORD = enum.auto()
|
||||
@@ -41,7 +50,6 @@ class Group(enum.Enum):
|
||||
GEODE = enum.auto()
|
||||
ORE = enum.auto()
|
||||
FERTILIZER = enum.auto()
|
||||
SEED = enum.auto()
|
||||
CROPSANITY = enum.auto()
|
||||
FISHING_RESOURCE = enum.auto()
|
||||
SEASON = enum.auto()
|
||||
@@ -55,7 +63,6 @@ class Group(enum.Enum):
|
||||
MAXIMUM_ONE = enum.auto()
|
||||
AT_LEAST_TWO = enum.auto()
|
||||
DEPRECATED = enum.auto()
|
||||
RESOURCE_PACK_USEFUL = enum.auto()
|
||||
SPECIAL_ORDER_BOARD = enum.auto()
|
||||
SPECIAL_ORDER_QI = enum.auto()
|
||||
BABY = enum.auto()
|
||||
@@ -73,35 +80,70 @@ class Group(enum.Enum):
|
||||
BOOK_POWER = enum.auto()
|
||||
LOST_BOOK = enum.auto()
|
||||
PLAYER_BUFF = enum.auto()
|
||||
EASY_SECRET = enum.auto()
|
||||
FISHING_SECRET = enum.auto()
|
||||
SECRET_NOTES_SECRET = enum.auto()
|
||||
MOVIESANITY = enum.auto()
|
||||
TRINKET = enum.auto()
|
||||
EATSANITY_ENZYME = enum.auto()
|
||||
ENDGAME_LOCATION_ITEMS = enum.auto()
|
||||
REQUIRES_FRIENDSANITY_MARRIAGE = enum.auto()
|
||||
BOOKSELLER = enum.auto()
|
||||
|
||||
# Types of filler
|
||||
FILLER_FARMING = enum.auto()
|
||||
FILLER_FISHING = enum.auto()
|
||||
FILLER_FRUIT_TREES = enum.auto()
|
||||
FILLER_FOOD = enum.auto()
|
||||
FILLER_BUFF_FOOD = enum.auto()
|
||||
FILLER_CONSUMABLE = enum.auto()
|
||||
FILLER_MACHINE = enum.auto()
|
||||
FILLER_STORAGE = enum.auto()
|
||||
FILLER_QUALITY_OF_LIFE = enum.auto()
|
||||
FILLER_MATERIALS = enum.auto()
|
||||
FILLER_CURRENCY = enum.auto()
|
||||
FILLER_MONEY = enum.auto()
|
||||
FILLER_HAT = enum.auto()
|
||||
FILLER_DECORATION = enum.auto()
|
||||
FILLER_RING = enum.auto()
|
||||
|
||||
# Mods
|
||||
MAGIC_SPELL = enum.auto()
|
||||
MOD_WARP = enum.auto()
|
||||
|
||||
|
||||
FILLER_GROUPS = [Group.FILLER_FARMING, Group.FILLER_FISHING, Group.FILLER_FRUIT_TREES, Group.FILLER_FOOD, Group.FILLER_BUFF_FOOD,
|
||||
Group.FILLER_CONSUMABLE, Group.FILLER_MACHINE, Group.FILLER_STORAGE, Group.FILLER_QUALITY_OF_LIFE, Group.FILLER_MATERIALS,
|
||||
Group.FILLER_CURRENCY, Group.FILLER_MONEY, Group.FILLER_HAT, Group.FILLER_DECORATION, Group.FILLER_RING, ]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ItemData:
|
||||
code_without_offset: Optional[int]
|
||||
code_without_offset: int | None
|
||||
name: str
|
||||
classification: ItemClassification
|
||||
mod_name: Optional[str] = None
|
||||
groups: Set[Group] = field(default_factory=frozenset)
|
||||
content_packs: frozenset[str] = frozenset()
|
||||
"""All the content packs required for this item to be available."""
|
||||
groups: set[Group] = field(default_factory=frozenset)
|
||||
|
||||
def __post_init__(self):
|
||||
if not isinstance(self.groups, frozenset):
|
||||
super().__setattr__("groups", frozenset(self.groups))
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
def code(self) -> int | None:
|
||||
return ITEM_CODE_OFFSET + self.code_without_offset if self.code_without_offset is not None else None
|
||||
|
||||
def has_any_group(self, *group: Group) -> bool:
|
||||
groups = set(group)
|
||||
return bool(groups.intersection(self.groups))
|
||||
|
||||
def has_all_groups(self, *group: Group) -> bool:
|
||||
groups = set(group)
|
||||
return bool(groups.issubset(self.groups))
|
||||
|
||||
class StardewItemFactory(Protocol):
|
||||
def __call__(self, name: Union[str, ItemData], override_classification: ItemClassification = None) -> Item:
|
||||
raise NotImplementedError
|
||||
def has_limited_amount(self) -> bool:
|
||||
return self.has_any_group(Group.MAXIMUM_ONE, Group.AT_LEAST_TWO)
|
||||
|
||||
|
||||
def load_item_csv():
|
||||
@@ -111,11 +153,21 @@ def load_item_csv():
|
||||
with files(data).joinpath("items.csv").open() as file:
|
||||
item_reader = csv.DictReader(file)
|
||||
for item in item_reader:
|
||||
id = int(item["id"]) if item["id"] else None
|
||||
item_id = int(item["id"]) if item["id"] else None
|
||||
item_name = item["name"]
|
||||
classification = reduce((lambda a, b: a | b), {ItemClassification[str_classification] for str_classification in item["classification"].split(",")})
|
||||
groups = {Group[group] for group in item["groups"].split(",") if group}
|
||||
mod_name = str(item["mod_name"]) if item["mod_name"] else None
|
||||
items.append(ItemData(id, item["name"], classification, mod_name, groups))
|
||||
csv_groups = [Group[group] for group in item["groups"].split(",") if group]
|
||||
groups = set(csv_groups)
|
||||
csv_content_packs = [cp for cp in item["content_packs"].split(",") if cp]
|
||||
content_packs = frozenset(csv_content_packs)
|
||||
|
||||
assert len(csv_groups) == len(groups), f"Item '{item_name}' has duplicate groups: {csv_groups}"
|
||||
assert len(csv_content_packs) == len(content_packs)
|
||||
|
||||
if Group.GINGER_ISLAND in groups:
|
||||
content_packs |= {ginger_island_content_pack.name}
|
||||
|
||||
items.append(ItemData(item_id, item_name, classification, content_packs, groups))
|
||||
return items
|
||||
|
||||
|
||||
@@ -124,9 +176,9 @@ events = [
|
||||
for e in sorted(all_events)
|
||||
]
|
||||
|
||||
all_items: List[ItemData] = load_item_csv() + events
|
||||
item_table: Dict[str, ItemData] = {}
|
||||
items_by_group: Dict[Group, List[ItemData]] = {}
|
||||
all_items: list[ItemData] = load_item_csv() + events
|
||||
item_table: dict[str, ItemData] = {}
|
||||
items_by_group: dict[Group, list[ItemData]] = {}
|
||||
|
||||
|
||||
def initialize_groups():
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import csv
|
||||
import enum
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from random import Random
|
||||
from typing import Optional, Dict, Protocol, List, FrozenSet, Iterable
|
||||
from typing import Optional, Dict, Protocol, List, Iterable
|
||||
|
||||
from . import data
|
||||
from .bundles.bundle_room import BundleRoom
|
||||
from .content.game_content import StardewContent
|
||||
from .content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from .content.vanilla.qi_board import qi_board_content_pack
|
||||
from .data.game_item import ItemTag
|
||||
from .data.museum_data import all_museum_items
|
||||
from .mods.mod_data import ModNames
|
||||
from .options import ExcludeGingerIsland, ArcadeMachineLocations, SpecialOrderLocations, Museumsanity, \
|
||||
from .options import ArcadeMachineLocations, SpecialOrderLocations, Museumsanity, \
|
||||
FestivalLocations, ElevatorProgression, BackpackProgression, FarmType
|
||||
from .options import StardewValleyOptions, Craftsanity, Chefsanity, Cooksanity, Shipsanity, Monstersanity
|
||||
from .options.options import BackpackSize, Moviesanity, Eatsanity, IncludeEndgameLocations, Friendsanity
|
||||
from .strings.ap_names.ap_option_names import WalnutsanityOptionName, SecretsanityOptionName, EatsanityOptionName, ChefsanityOptionName, StartWithoutOptionName
|
||||
from .strings.backpack_tiers import Backpack
|
||||
from .strings.goal_names import Goal
|
||||
from .strings.quest_names import ModQuest, Quest
|
||||
from .strings.region_names import Region, LogicRegion
|
||||
@@ -20,10 +26,13 @@ from .strings.villager_names import NPC
|
||||
|
||||
LOCATION_CODE_OFFSET = 717000
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LocationTags(enum.Enum):
|
||||
MANDATORY = enum.auto()
|
||||
BUNDLE = enum.auto()
|
||||
TRASH_BEAR = enum.auto()
|
||||
COMMUNITY_CENTER_BUNDLE = enum.auto()
|
||||
CRAFTS_ROOM_BUNDLE = enum.auto()
|
||||
PANTRY_BUNDLE = enum.auto()
|
||||
@@ -33,7 +42,10 @@ class LocationTags(enum.Enum):
|
||||
VAULT_BUNDLE = enum.auto()
|
||||
COMMUNITY_CENTER_ROOM = enum.auto()
|
||||
RACCOON_BUNDLES = enum.auto()
|
||||
MEME_BUNDLE = enum.auto()
|
||||
BACKPACK = enum.auto()
|
||||
BACKPACK_TIER = enum.auto()
|
||||
SPLIT_BACKPACK = enum.auto()
|
||||
TOOL_UPGRADE = enum.auto()
|
||||
HOE_UPGRADE = enum.auto()
|
||||
PICKAXE_UPGRADE = enum.auto()
|
||||
@@ -42,6 +54,7 @@ class LocationTags(enum.Enum):
|
||||
TRASH_CAN_UPGRADE = enum.auto()
|
||||
FISHING_ROD_UPGRADE = enum.auto()
|
||||
PAN_UPGRADE = enum.auto()
|
||||
STARTING_TOOLS = enum.auto()
|
||||
THE_MINES_TREASURE = enum.auto()
|
||||
CROPSANITY = enum.auto()
|
||||
ELEVATOR = enum.auto()
|
||||
@@ -67,6 +80,7 @@ class LocationTags(enum.Enum):
|
||||
FESTIVAL = enum.auto()
|
||||
FESTIVAL_HARD = enum.auto()
|
||||
DESERT_FESTIVAL_CHEF = enum.auto()
|
||||
DESERT_FESTIVAL_CHEF_MEAL = enum.auto()
|
||||
SPECIAL_ORDER_BOARD = enum.auto()
|
||||
SPECIAL_ORDER_QI = enum.auto()
|
||||
REQUIRES_QI_ORDERS = enum.auto()
|
||||
@@ -97,10 +111,42 @@ class LocationTags(enum.Enum):
|
||||
CHEFSANITY_SKILL = enum.auto()
|
||||
CHEFSANITY_STARTER = enum.auto()
|
||||
CRAFTSANITY = enum.auto()
|
||||
CRAFTSANITY_CRAFT = enum.auto()
|
||||
CRAFTSANITY_RECIPE = enum.auto()
|
||||
BOOKSANITY = enum.auto()
|
||||
BOOKSANITY_POWER = enum.auto()
|
||||
BOOKSANITY_SKILL = enum.auto()
|
||||
BOOKSANITY_LOST = enum.auto()
|
||||
SECRETSANITY = enum.auto()
|
||||
EASY_SECRET = enum.auto()
|
||||
FISHING_SECRET = enum.auto()
|
||||
DIFFICULT_SECRET = enum.auto()
|
||||
SECRET_NOTE = enum.auto()
|
||||
REPLACES_PREVIOUS_LOCATION = enum.auto()
|
||||
ANY_MOVIE = enum.auto()
|
||||
MOVIE = enum.auto()
|
||||
MOVIE_SNACK = enum.auto()
|
||||
HATSANITY = enum.auto()
|
||||
HAT_EASY = enum.auto()
|
||||
HAT_TAILORING = enum.auto()
|
||||
HAT_MEDIUM = enum.auto()
|
||||
HAT_DIFFICULT = enum.auto()
|
||||
HAT_RNG = enum.auto()
|
||||
HAT_NEAR_PERFECTION = enum.auto()
|
||||
HAT_POST_PERFECTION = enum.auto()
|
||||
HAT_IMPOSSIBLE = enum.auto()
|
||||
EATSANITY = enum.auto()
|
||||
EATSANITY_CROP = enum.auto()
|
||||
EATSANITY_COOKING = enum.auto()
|
||||
EATSANITY_FISH = enum.auto()
|
||||
EATSANITY_ARTISAN = enum.auto()
|
||||
EATSANITY_SHOP = enum.auto()
|
||||
EATSANITY_POISONOUS = enum.auto()
|
||||
ENDGAME_LOCATIONS = enum.auto()
|
||||
REQUIRES_FRIENDSANITY = enum.auto()
|
||||
REQUIRES_FRIENDSANITY_MARRIAGE = enum.auto()
|
||||
|
||||
BEACH_FARM = enum.auto()
|
||||
# Mods
|
||||
# Skill Mods
|
||||
LUCK_LEVEL = enum.auto()
|
||||
@@ -115,14 +161,15 @@ class LocationTags(enum.Enum):
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LocationData:
|
||||
code_without_offset: Optional[int]
|
||||
code_without_offset: int | None
|
||||
region: str
|
||||
name: str
|
||||
mod_name: Optional[str] = None
|
||||
tags: FrozenSet[LocationTags] = frozenset()
|
||||
content_packs: frozenset[str] = frozenset()
|
||||
"""All the content packs required for this location to be active."""
|
||||
tags: frozenset[LocationTags] = frozenset()
|
||||
|
||||
@property
|
||||
def code(self) -> Optional[int]:
|
||||
def code(self) -> int | None:
|
||||
return LOCATION_CODE_OFFSET + self.code_without_offset if self.code_without_offset is not None else None
|
||||
|
||||
|
||||
@@ -134,16 +181,28 @@ class StardewLocationCollector(Protocol):
|
||||
def load_location_csv() -> List[LocationData]:
|
||||
from importlib.resources import files
|
||||
|
||||
locations = []
|
||||
with files(data).joinpath("locations.csv").open() as file:
|
||||
reader = csv.DictReader(file)
|
||||
return [LocationData(int(location["id"]) if location["id"] else None,
|
||||
location["region"],
|
||||
location["name"],
|
||||
str(location["mod_name"]) if location["mod_name"] else None,
|
||||
frozenset(LocationTags[group]
|
||||
for group in location["tags"].split(",")
|
||||
if group))
|
||||
for location in reader]
|
||||
location_reader = csv.DictReader(file)
|
||||
for location in location_reader:
|
||||
location_id = int(location["id"]) if location["id"] else None
|
||||
location_name = location["name"]
|
||||
csv_tags = [LocationTags[tag] for tag in location["tags"].split(",") if tag]
|
||||
tags = frozenset(csv_tags)
|
||||
csv_content_packs = [cp for cp in location["content_packs"].split(",") if cp]
|
||||
content_packs = frozenset(csv_content_packs)
|
||||
|
||||
assert len(csv_tags) == len(tags), f"Location '{location_name}' has duplicate tags: {csv_tags}"
|
||||
assert len(csv_content_packs) == len(content_packs)
|
||||
|
||||
if LocationTags.GINGER_ISLAND in tags:
|
||||
content_packs |= {ginger_island_content_pack.name}
|
||||
if LocationTags.SPECIAL_ORDER_QI in tags or LocationTags.REQUIRES_QI_ORDERS in tags:
|
||||
content_packs |= {qi_board_content_pack.name}
|
||||
|
||||
locations.append(LocationData(location_id, location["region"], location_name, content_packs, tags))
|
||||
|
||||
return locations
|
||||
|
||||
|
||||
events_locations = [
|
||||
@@ -161,6 +220,8 @@ events_locations = [
|
||||
LocationData(None, Region.farm, Goal.craft_master),
|
||||
LocationData(None, LogicRegion.shipping, Goal.legend),
|
||||
LocationData(None, Region.farm, Goal.mystery_of_the_stardrops),
|
||||
LocationData(None, Region.farm, Goal.mad_hatter),
|
||||
LocationData(None, Region.farm, Goal.ultimate_foodie),
|
||||
LocationData(None, Region.farm, Goal.allsanity),
|
||||
LocationData(None, Region.qi_walnut_room, Goal.perfection),
|
||||
]
|
||||
@@ -296,10 +357,12 @@ def extend_hard_festival_locations(randomized_locations: List[LocationData], opt
|
||||
|
||||
|
||||
def extend_desert_festival_chef_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, random: Random):
|
||||
festival_chef_locations = locations_by_tag[LocationTags.DESERT_FESTIVAL_CHEF]
|
||||
number_to_add = 5 if options.festival_locations == FestivalLocations.option_easy else 10
|
||||
locations_to_add = random.sample(festival_chef_locations, number_to_add)
|
||||
randomized_locations.extend(locations_to_add)
|
||||
if options.festival_locations == FestivalLocations.option_easy:
|
||||
randomized_locations.append(location_table["Desert Chef"])
|
||||
elif options.festival_locations == FestivalLocations.option_hard:
|
||||
festival_chef_locations = locations_by_tag[LocationTags.DESERT_FESTIVAL_CHEF_MEAL]
|
||||
location_to_add = random.choice(festival_chef_locations)
|
||||
randomized_locations.append(location_to_add)
|
||||
|
||||
|
||||
def extend_special_order_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
@@ -307,16 +370,15 @@ def extend_special_order_locations(randomized_locations: List[LocationData], opt
|
||||
board_locations = filter_disabled_locations(options, content, locations_by_tag[LocationTags.SPECIAL_ORDER_BOARD])
|
||||
randomized_locations.extend(board_locations)
|
||||
|
||||
include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false
|
||||
if options.special_order_locations & SpecialOrderLocations.value_qi and include_island:
|
||||
if content.is_enabled(qi_board_content_pack):
|
||||
include_arcade = options.arcade_machine_locations != ArcadeMachineLocations.option_disabled
|
||||
qi_orders = [location for location in locations_by_tag[LocationTags.SPECIAL_ORDER_QI] if
|
||||
include_arcade or LocationTags.JUNIMO_KART not in location.tags]
|
||||
randomized_locations.extend(qi_orders)
|
||||
|
||||
|
||||
def extend_walnut_purchase_locations(randomized_locations: List[LocationData], options: StardewValleyOptions):
|
||||
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
def extend_walnut_purchase_locations(randomized_locations: List[LocationData], content: StardewContent):
|
||||
if not content.is_enabled(ginger_island_content_pack):
|
||||
return
|
||||
randomized_locations.append(location_table["Repair Ticket Machine"])
|
||||
randomized_locations.append(location_table["Repair Boat Hull"])
|
||||
@@ -332,14 +394,14 @@ def extend_mandatory_locations(randomized_locations: List[LocationData], options
|
||||
randomized_locations.extend(filtered_mandatory_locations)
|
||||
|
||||
|
||||
def extend_situational_quest_locations(randomized_locations: List[LocationData], options: StardewValleyOptions):
|
||||
def extend_situational_quest_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.quest_locations.has_no_story_quests():
|
||||
return
|
||||
if ModNames.distant_lands in options.mods:
|
||||
if ModNames.alecto in options.mods:
|
||||
randomized_locations.append(location_table[ModQuest.WitchOrder])
|
||||
if ModNames.distant_lands in content.registered_packs:
|
||||
if ModNames.alecto in content.registered_packs:
|
||||
randomized_locations.append(location_table[f"Quest: {ModQuest.WitchOrder}"])
|
||||
else:
|
||||
randomized_locations.append(location_table[ModQuest.CorruptedCropsTask])
|
||||
randomized_locations.append(location_table[f"Quest: {ModQuest.CorruptedCropsTask}"])
|
||||
|
||||
|
||||
def extend_bundle_locations(randomized_locations: List[LocationData], bundle_rooms: List[BundleRoom]):
|
||||
@@ -351,19 +413,35 @@ def extend_bundle_locations(randomized_locations: List[LocationData], bundle_roo
|
||||
randomized_locations.append(location_table[bundle.name])
|
||||
|
||||
|
||||
def extend_backpack_locations(randomized_locations: List[LocationData], options: StardewValleyOptions):
|
||||
def extend_trash_bear_locations(randomized_locations: List[LocationData], trash_bear_requests: Dict[str, List[str]]):
|
||||
for request_type in trash_bear_requests:
|
||||
randomized_locations.append(location_table[f"Trash Bear {request_type}"])
|
||||
|
||||
|
||||
def extend_backpack_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.backpack_progression == BackpackProgression.option_vanilla:
|
||||
return
|
||||
backpack_locations = [location for location in locations_by_tag[LocationTags.BACKPACK]]
|
||||
filtered_backpack_locations = filter_modded_locations(options, backpack_locations)
|
||||
|
||||
no_start_backpack = StartWithoutOptionName.backpack in options.start_without
|
||||
if options.backpack_size == BackpackSize.option_12:
|
||||
backpack_locations = [location for location in locations_by_tag[LocationTags.BACKPACK_TIER] if no_start_backpack or LocationTags.STARTING_TOOLS not in location.tags]
|
||||
else:
|
||||
num_per_tier = options.backpack_size.count_per_tier()
|
||||
backpack_tier_names = Backpack.get_purchasable_tiers(ModNames.big_backpack in content.registered_packs, no_start_backpack)
|
||||
backpack_locations = []
|
||||
for tier in backpack_tier_names:
|
||||
for i in range(1, num_per_tier + 1):
|
||||
backpack_locations.append(location_table[f"{tier} {i}"])
|
||||
|
||||
filtered_backpack_locations = filter_modded_locations(backpack_locations, content)
|
||||
randomized_locations.extend(filtered_backpack_locations)
|
||||
|
||||
|
||||
def extend_elevator_locations(randomized_locations: List[LocationData], options: StardewValleyOptions):
|
||||
def extend_elevator_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.elevator_progression == ElevatorProgression.option_vanilla:
|
||||
return
|
||||
elevator_locations = [location for location in locations_by_tag[LocationTags.ELEVATOR]]
|
||||
filtered_elevator_locations = filter_modded_locations(options, elevator_locations)
|
||||
filtered_elevator_locations = filter_modded_locations(elevator_locations, content)
|
||||
randomized_locations.extend(filtered_elevator_locations)
|
||||
|
||||
|
||||
@@ -396,14 +474,14 @@ def extend_shipsanity_locations(randomized_locations: List[LocationData], option
|
||||
randomized_locations.extend(filtered_ship_locations)
|
||||
return
|
||||
shipsanity_locations = set()
|
||||
if shipsanity == Shipsanity.option_fish or shipsanity == Shipsanity.option_full_shipment_with_fish:
|
||||
if shipsanity == Shipsanity.option_fish or shipsanity == Shipsanity.option_crops_and_fish or shipsanity == Shipsanity.option_full_shipment_with_fish:
|
||||
shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FISH]})
|
||||
if shipsanity == Shipsanity.option_crops:
|
||||
if shipsanity == Shipsanity.option_crops or shipsanity == Shipsanity.option_crops_and_fish:
|
||||
shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_CROP]})
|
||||
if shipsanity == Shipsanity.option_full_shipment or shipsanity == Shipsanity.option_full_shipment_with_fish:
|
||||
shipsanity_locations = shipsanity_locations.union({location for location in locations_by_tag[LocationTags.SHIPSANITY_FULL_SHIPMENT]})
|
||||
|
||||
filtered_shipsanity_locations = filter_disabled_locations(options, content, list(shipsanity_locations))
|
||||
filtered_shipsanity_locations = filter_disabled_locations(options, content, sorted(list(shipsanity_locations), key=lambda x: x.name))
|
||||
randomized_locations.extend(filtered_shipsanity_locations)
|
||||
|
||||
|
||||
@@ -422,18 +500,18 @@ def extend_cooksanity_locations(randomized_locations: List[LocationData], option
|
||||
|
||||
def extend_chefsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
chefsanity = options.chefsanity
|
||||
if chefsanity == Chefsanity.option_none:
|
||||
if chefsanity == Chefsanity.preset_none:
|
||||
return
|
||||
|
||||
chefsanity_locations_by_name = {} # Dictionary to not make duplicates
|
||||
|
||||
if chefsanity & Chefsanity.option_queen_of_sauce:
|
||||
if ChefsanityOptionName.queen_of_sauce in chefsanity:
|
||||
chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_QOS]})
|
||||
if chefsanity & Chefsanity.option_purchases:
|
||||
if ChefsanityOptionName.purchases in chefsanity:
|
||||
chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_PURCHASE]})
|
||||
if chefsanity & Chefsanity.option_friendship:
|
||||
if ChefsanityOptionName.friendship in chefsanity:
|
||||
chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_FRIENDSHIP]})
|
||||
if chefsanity & Chefsanity.option_skills:
|
||||
if ChefsanityOptionName.skills in chefsanity:
|
||||
chefsanity_locations_by_name.update({location.name: location for location in locations_by_tag[LocationTags.CHEFSANITY_SKILL]})
|
||||
|
||||
filtered_chefsanity_locations = filter_disabled_locations(options, content, list(chefsanity_locations_by_name.values()))
|
||||
@@ -468,18 +546,141 @@ def extend_walnutsanity_locations(randomized_locations: List[LocationData], opti
|
||||
if not options.walnutsanity:
|
||||
return
|
||||
|
||||
if "Puzzles" in options.walnutsanity:
|
||||
if WalnutsanityOptionName.puzzles in options.walnutsanity:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.WALNUTSANITY_PUZZLE])
|
||||
if "Bushes" in options.walnutsanity:
|
||||
if WalnutsanityOptionName.bushes in options.walnutsanity:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.WALNUTSANITY_BUSH])
|
||||
if "Dig Spots" in options.walnutsanity:
|
||||
if WalnutsanityOptionName.dig_spots in options.walnutsanity:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.WALNUTSANITY_DIG])
|
||||
if "Repeatables" in options.walnutsanity:
|
||||
if WalnutsanityOptionName.repeatables in options.walnutsanity:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.WALNUTSANITY_REPEATABLE])
|
||||
|
||||
|
||||
def extend_movies_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.moviesanity == Moviesanity.option_none:
|
||||
return
|
||||
|
||||
locations = []
|
||||
if options.moviesanity == Moviesanity.option_one:
|
||||
locations.extend(locations_by_tag[LocationTags.ANY_MOVIE])
|
||||
if options.moviesanity >= Moviesanity.option_all_movies:
|
||||
locations.extend(locations_by_tag[LocationTags.MOVIE])
|
||||
if options.moviesanity >= Moviesanity.option_all_movies_and_all_snacks:
|
||||
locations.extend(locations_by_tag[LocationTags.MOVIE_SNACK])
|
||||
filtered_locations = filter_disabled_locations(options, content, locations)
|
||||
randomized_locations.extend(filtered_locations)
|
||||
|
||||
|
||||
def extend_secrets_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if not options.secretsanity:
|
||||
return
|
||||
|
||||
locations = []
|
||||
if SecretsanityOptionName.easy in options.secretsanity:
|
||||
locations.extend(locations_by_tag[LocationTags.EASY_SECRET])
|
||||
if SecretsanityOptionName.fishing in options.secretsanity:
|
||||
locations.extend(locations_by_tag[LocationTags.FISHING_SECRET])
|
||||
if SecretsanityOptionName.difficult in options.secretsanity:
|
||||
locations.extend(locations_by_tag[LocationTags.DIFFICULT_SECRET])
|
||||
if SecretsanityOptionName.secret_notes in options.secretsanity:
|
||||
locations.extend(locations_by_tag[LocationTags.SECRET_NOTE])
|
||||
for location_dupe in locations_by_tag[LocationTags.REPLACES_PREVIOUS_LOCATION]:
|
||||
second_part_of_name = location_dupe.name.split(":")[-1]
|
||||
for location in randomized_locations:
|
||||
second_part_of_dupe_name = location.name.split(":")[-1]
|
||||
if second_part_of_name == second_part_of_dupe_name:
|
||||
randomized_locations.remove(location)
|
||||
filtered_locations = filter_disabled_locations(options, content, locations)
|
||||
randomized_locations.extend(filtered_locations)
|
||||
|
||||
|
||||
def extend_hats_locations(randomized_locations: List[LocationData], content: StardewContent):
|
||||
hatsanity = content.features.hatsanity
|
||||
if not hatsanity.is_enabled:
|
||||
return
|
||||
|
||||
for hat in content.hats.values():
|
||||
if not hatsanity.is_included(hat):
|
||||
continue
|
||||
|
||||
randomized_locations.append(location_table[hatsanity.to_location_name(hat)])
|
||||
|
||||
|
||||
def eatsanity_item_is_included(location: LocationData, options: StardewValleyOptions, content: StardewContent) -> bool:
|
||||
eat_prefix = "Eat "
|
||||
drink_prefix = "Drink "
|
||||
if location.name.startswith(eat_prefix):
|
||||
item_name = location.name[len(eat_prefix):]
|
||||
elif location.name.startswith(drink_prefix):
|
||||
item_name = location.name[len(drink_prefix):]
|
||||
else:
|
||||
raise Exception(f"Eatsanity Location does not have a recognized prefix: '{location.name}'")
|
||||
|
||||
# if not item_name in content.game_items:
|
||||
# return False
|
||||
if EatsanityOptionName.poisonous in options.eatsanity.value:
|
||||
return True
|
||||
if location in locations_by_tag[LocationTags.EATSANITY_POISONOUS]:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def extend_eatsanity_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.eatsanity.value == Eatsanity.preset_none:
|
||||
return
|
||||
|
||||
eatsanity_locations = []
|
||||
if EatsanityOptionName.crops in options.eatsanity:
|
||||
eatsanity_locations.extend(locations_by_tag[LocationTags.EATSANITY_CROP])
|
||||
if EatsanityOptionName.cooking in options.eatsanity:
|
||||
eatsanity_locations.extend(locations_by_tag[LocationTags.EATSANITY_COOKING])
|
||||
if EatsanityOptionName.fish in options.eatsanity:
|
||||
eatsanity_locations.extend(locations_by_tag[LocationTags.EATSANITY_FISH])
|
||||
if EatsanityOptionName.artisan in options.eatsanity:
|
||||
eatsanity_locations.extend(locations_by_tag[LocationTags.EATSANITY_ARTISAN])
|
||||
if EatsanityOptionName.shop in options.eatsanity:
|
||||
eatsanity_locations.extend(locations_by_tag[LocationTags.EATSANITY_SHOP])
|
||||
|
||||
eatsanity_locations = [location for location in eatsanity_locations if eatsanity_item_is_included(location, options, content)]
|
||||
eatsanity_locations = filter_disabled_locations(options, content, eatsanity_locations)
|
||||
randomized_locations.extend(eatsanity_locations)
|
||||
|
||||
|
||||
def extend_endgame_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
if options.include_endgame_locations.value == IncludeEndgameLocations.option_false:
|
||||
return
|
||||
|
||||
has_friendsanity_marriage = options.friendsanity == Friendsanity.option_all_with_marriage
|
||||
has_friendsanity = (not has_friendsanity_marriage) and options.friendsanity != Friendsanity.option_none
|
||||
|
||||
endgame_locations = []
|
||||
endgame_locations.extend(locations_by_tag[LocationTags.ENDGAME_LOCATIONS])
|
||||
|
||||
endgame_locations = [location for location in endgame_locations if
|
||||
LocationTags.REQUIRES_FRIENDSANITY_MARRIAGE not in location.tags or has_friendsanity_marriage]
|
||||
endgame_locations = [location for location in endgame_locations if LocationTags.REQUIRES_FRIENDSANITY not in location.tags or has_friendsanity]
|
||||
endgame_locations = filter_disabled_locations(options, content, endgame_locations)
|
||||
randomized_locations.extend(endgame_locations)
|
||||
|
||||
|
||||
def extend_filler_locations(randomized_locations: List[LocationData], options: StardewValleyOptions, content: StardewContent):
|
||||
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||
i = 1
|
||||
while len(randomized_locations) < 90:
|
||||
location_name = f"Traveling Merchant Sunday Item {i}"
|
||||
while any(location.name == location_name for location in randomized_locations):
|
||||
i += 1
|
||||
location_name = f"Traveling Merchant Sunday Item {i}"
|
||||
logger.debug(f"Player too few locations, adding Traveling Merchant Items #{i}")
|
||||
for day in days:
|
||||
location_name = f"Traveling Merchant {day} Item {i}"
|
||||
randomized_locations.append(location_table[location_name])
|
||||
|
||||
|
||||
|
||||
def create_locations(location_collector: StardewLocationCollector,
|
||||
bundle_rooms: List[BundleRoom],
|
||||
trash_bear_requests: Dict[str, List[str]],
|
||||
options: StardewValleyOptions,
|
||||
content: StardewContent,
|
||||
random: Random):
|
||||
@@ -487,12 +688,13 @@ def create_locations(location_collector: StardewLocationCollector,
|
||||
|
||||
extend_mandatory_locations(randomized_locations, options, content)
|
||||
extend_bundle_locations(randomized_locations, bundle_rooms)
|
||||
extend_backpack_locations(randomized_locations, options)
|
||||
extend_trash_bear_locations(randomized_locations, trash_bear_requests)
|
||||
extend_backpack_locations(randomized_locations, options, content)
|
||||
|
||||
if content.features.tool_progression.is_progressive:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.TOOL_UPGRADE])
|
||||
|
||||
extend_elevator_locations(randomized_locations, options)
|
||||
extend_elevator_locations(randomized_locations, options, content)
|
||||
|
||||
skill_progression = content.features.skill_progression
|
||||
if skill_progression.is_progressive:
|
||||
@@ -516,7 +718,7 @@ def create_locations(location_collector: StardewLocationCollector,
|
||||
|
||||
extend_festival_locations(randomized_locations, options, random)
|
||||
extend_special_order_locations(randomized_locations, options, content)
|
||||
extend_walnut_purchase_locations(randomized_locations, options)
|
||||
extend_walnut_purchase_locations(randomized_locations, content)
|
||||
|
||||
extend_monstersanity_locations(randomized_locations, options, content)
|
||||
extend_shipsanity_locations(randomized_locations, options, content)
|
||||
@@ -526,9 +728,16 @@ def create_locations(location_collector: StardewLocationCollector,
|
||||
extend_quests_locations(randomized_locations, options, content)
|
||||
extend_book_locations(randomized_locations, content)
|
||||
extend_walnutsanity_locations(randomized_locations, options)
|
||||
extend_movies_locations(randomized_locations, options, content)
|
||||
extend_secrets_locations(randomized_locations, options, content)
|
||||
extend_hats_locations(randomized_locations, content)
|
||||
extend_eatsanity_locations(randomized_locations, options, content)
|
||||
extend_endgame_locations(randomized_locations, options, content)
|
||||
|
||||
# Mods
|
||||
extend_situational_quest_locations(randomized_locations, options)
|
||||
extend_situational_quest_locations(randomized_locations, options, content)
|
||||
|
||||
extend_filler_locations(randomized_locations, options, content)
|
||||
|
||||
for location_data in randomized_locations:
|
||||
location_collector(location_data.name, location_data.code, location_data.region)
|
||||
@@ -538,21 +747,34 @@ def filter_deprecated_locations(locations: Iterable[LocationData]) -> Iterable[L
|
||||
return [location for location in locations if LocationTags.DEPRECATED not in location.tags]
|
||||
|
||||
|
||||
def filter_farm_type(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
def filter_animals_quest(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
# On Meadowlands, "Feeding Animals" replaces "Raising Animals"
|
||||
if options.farm_type == FarmType.option_meadowlands:
|
||||
return (location for location in locations if location.name != Quest.raising_animals)
|
||||
return (location for location in locations if location.name != f"Quest: {Quest.raising_animals}")
|
||||
else:
|
||||
return (location for location in locations if location.name != Quest.feeding_animals)
|
||||
return (location for location in locations if location.name != f"Quest: {Quest.feeding_animals}")
|
||||
|
||||
|
||||
def filter_ginger_island(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
include_island = options.exclude_ginger_island == ExcludeGingerIsland.option_false
|
||||
def filter_farm_exclusives(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
# Some locations are only on specific farms
|
||||
if options.farm_type != FarmType.option_beach:
|
||||
return (location for location in locations if LocationTags.BEACH_FARM not in location.tags)
|
||||
return locations
|
||||
|
||||
|
||||
def filter_farm_type(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
animals_filter = filter_animals_quest(options, locations)
|
||||
exclusives_filter = filter_farm_exclusives(options, animals_filter)
|
||||
return exclusives_filter
|
||||
|
||||
|
||||
def filter_ginger_island(content: StardewContent, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
include_island = content.is_enabled(ginger_island_content_pack)
|
||||
return (location for location in locations if include_island or LocationTags.GINGER_ISLAND not in location.tags)
|
||||
|
||||
|
||||
def filter_qi_order_locations(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
include_qi_orders = options.special_order_locations & SpecialOrderLocations.value_qi
|
||||
def filter_qi_order_locations(content: StardewContent, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
include_qi_orders = content.is_enabled(qi_board_content_pack)
|
||||
return (location for location in locations if include_qi_orders or LocationTags.REQUIRES_QI_ORDERS not in location.tags)
|
||||
|
||||
|
||||
@@ -563,15 +785,15 @@ def filter_masteries_locations(content: StardewContent, locations: Iterable[Loca
|
||||
return (location for location in locations if LocationTags.REQUIRES_MASTERIES not in location.tags)
|
||||
|
||||
|
||||
def filter_modded_locations(options: StardewValleyOptions, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
return (location for location in locations if location.mod_name is None or location.mod_name in options.mods)
|
||||
def filter_modded_locations(locations: Iterable[LocationData], content: StardewContent) -> Iterable[LocationData]:
|
||||
return (location for location in locations if content.are_all_enabled(location.content_packs))
|
||||
|
||||
|
||||
def filter_disabled_locations(options: StardewValleyOptions, content: StardewContent, locations: Iterable[LocationData]) -> Iterable[LocationData]:
|
||||
locations_deprecated_filter = filter_deprecated_locations(locations)
|
||||
locations_farm_filter = filter_farm_type(options, locations_deprecated_filter)
|
||||
locations_island_filter = filter_ginger_island(options, locations_farm_filter)
|
||||
locations_qi_filter = filter_qi_order_locations(options, locations_island_filter)
|
||||
locations_island_filter = filter_ginger_island(content, locations_farm_filter)
|
||||
locations_qi_filter = filter_qi_order_locations(content, locations_island_filter)
|
||||
locations_masteries_filter = filter_masteries_locations(content, locations_qi_filter)
|
||||
locations_mod_filter = filter_modded_locations(options, locations_masteries_filter)
|
||||
locations_mod_filter = filter_modded_locations(locations_masteries_filter, content)
|
||||
return locations_mod_filter
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..options import FarmType
|
||||
from ..stardew_rule import StardewRule, False_, True_
|
||||
from ..strings.ap_names.ap_option_names import CustomLogicOptionName
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.skill_names import Skill, ModSkill
|
||||
from ..strings.tool_names import ToolMaterial, Tool
|
||||
from ..strings.tool_names import ToolMaterial, Tool, FishingRod
|
||||
|
||||
|
||||
class AbilityLogicMixin(BaseLogicMixin):
|
||||
@@ -12,6 +14,13 @@ class AbilityLogicMixin(BaseLogicMixin):
|
||||
|
||||
|
||||
class AbilityLogic(BaseLogic):
|
||||
|
||||
def can_mine_stone(self) -> StardewRule:
|
||||
can_reach_any_mining_region = self.logic.region.can_reach_any(Region.mines, Region.skull_cavern, Region.volcano, Region.quarry_mine)
|
||||
if self.options.farm_type in [FarmType.option_hill_top, FarmType.option_four_corners]:
|
||||
can_reach_any_mining_region = can_reach_any_mining_region | self.logic.region.can_reach(Region.farm)
|
||||
return self.logic.tool.has_tool(Tool.pickaxe) & can_reach_any_mining_region
|
||||
|
||||
def can_mine_perfectly(self) -> StardewRule:
|
||||
return self.logic.mine.can_progress_in_the_mines_from_floor(160)
|
||||
|
||||
@@ -20,15 +29,17 @@ class AbilityLogic(BaseLogic):
|
||||
self.logic.region.can_reach(Region.skull_cavern))
|
||||
|
||||
def can_farm_perfectly(self) -> StardewRule:
|
||||
tool_rule = self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.logic.tool.can_water(4)
|
||||
tool_rule = self.logic.tool.has_tool(Tool.hoe, ToolMaterial.iridium) & self.logic.tool.can_water(5)
|
||||
return tool_rule & self.logic.skill.has_farming_level(10)
|
||||
|
||||
def can_fish_perfectly(self) -> StardewRule:
|
||||
skill_rule = self.logic.skill.has_level(Skill.fishing, 10)
|
||||
return skill_rule & self.logic.tool.has_fishing_rod(4)
|
||||
return skill_rule & self.logic.tool.has_fishing_rod(FishingRod.iridium)
|
||||
|
||||
def can_chop_trees(self) -> StardewRule:
|
||||
return self.logic.tool.has_tool(Tool.axe) & self.logic.region.can_reach(Region.forest)
|
||||
can_reach_any_tree_region = self.logic.region.can_reach_any(Region.forest, Region.backwoods, Region.bus_stop, Region.mountain, Region.desert,
|
||||
Region.island_west, Region.island_north)
|
||||
return self.logic.tool.has_tool(Tool.axe) & can_reach_any_tree_region
|
||||
|
||||
def can_chop_perfectly(self) -> StardewRule:
|
||||
magic_rule = (self.logic.magic.can_use_clear_debris_instead_of_tool_level(3)) & self.logic.mod.skill.has_mod_level(ModSkill.magic, 10)
|
||||
@@ -36,3 +47,20 @@ class AbilityLogic(BaseLogic):
|
||||
foraging_rule = self.logic.skill.has_level(Skill.foraging, 10)
|
||||
region_rule = self.logic.region.can_reach(Region.forest)
|
||||
return region_rule & ((tool_rule & foraging_rule) | magic_rule)
|
||||
|
||||
def can_scythe_vines(self) -> StardewRule:
|
||||
can_reach_any_vine_region = self.logic.region.can_reach_any(Region.forest, Region.railroad)
|
||||
return self.logic.tool.has_scythe() & can_reach_any_vine_region & self.logic.season.has_any_not_winter()
|
||||
|
||||
def can_chair_skip(self) -> StardewRule:
|
||||
if CustomLogicOptionName.chair_skips not in self.options.custom_logic:
|
||||
return False_()
|
||||
|
||||
if CustomLogicOptionName.critical_free_samples in self.options.custom_logic:
|
||||
if self.options.farm_type == FarmType.option_standard or \
|
||||
self.options.farm_type == FarmType.option_riverland or \
|
||||
self.options.farm_type == FarmType.option_forest or \
|
||||
self.options.farm_type == FarmType.option_beach:
|
||||
return True_()
|
||||
|
||||
return self.logic.money.can_spend_at(Region.carpenter, 350)
|
||||
|
||||
@@ -3,8 +3,10 @@ from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from ..stardew_rule import StardewRule, True_
|
||||
from ..strings.generic_names import Generic
|
||||
from ..strings.geode_names import Geode
|
||||
from ..strings.metal_names import Mineral
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.tool_names import Tool
|
||||
from ..strings.season_names import Season
|
||||
from ..strings.tv_channel_names import Channel
|
||||
|
||||
|
||||
class ActionLogicMixin(BaseLogicMixin):
|
||||
@@ -19,10 +21,13 @@ class ActionLogic(BaseLogic):
|
||||
tv_rule = True_()
|
||||
if channel is None:
|
||||
return tv_rule
|
||||
if channel == Channel.sinister_signal:
|
||||
sacrifice_rule = self.logic.relationship.has_children(1) & self.logic.region.can_reach(Region.witch_hut) & self.logic.has(Mineral.prismatic_shard)
|
||||
return self.logic.received(channel) & tv_rule & sacrifice_rule & self.logic.season.has(Season.fall)
|
||||
return self.logic.received(channel) & tv_rule
|
||||
|
||||
def can_pan_at(self, region: str, material: str) -> StardewRule:
|
||||
return self.logic.region.can_reach(region) & self.logic.tool.has_tool(Tool.pan, material)
|
||||
return self.logic.region.can_reach(region) & self.logic.tool.has_pan(material)
|
||||
|
||||
@cache_self1
|
||||
def can_open_geode(self, geode: str) -> StardewRule:
|
||||
@@ -31,3 +36,6 @@ class ActionLogic(BaseLogic):
|
||||
if geode == Generic.any:
|
||||
return blacksmith_access & self.logic.or_(*(self.logic.has(geode_type) for geode_type in geodes))
|
||||
return blacksmith_access & self.logic.has(geode)
|
||||
|
||||
def can_speak_junimo(self) -> StardewRule:
|
||||
return self.logic.received("Forest Magic")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import typing
|
||||
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.building_names import Building
|
||||
|
||||
@@ -2,9 +2,12 @@ from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from ..data.artisan import MachineSource
|
||||
from ..data.game_item import ItemTag
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.crop_names import Vegetable, Fruit
|
||||
from ..strings.fish_names import Fish, all_fish
|
||||
from ..strings.flower_names import all_flowers
|
||||
from ..strings.forageable_names import Mushroom
|
||||
from ..strings.generic_names import Generic
|
||||
from ..strings.machine_names import Machine
|
||||
@@ -21,6 +24,9 @@ class ArtisanLogic(BaseLogic):
|
||||
# TODO remove this one too once fish are converted to sources
|
||||
self.registry.artisan_good_rules.update({ArtisanGood.specific_smoked_fish(fish): self.can_smoke(fish) for fish in all_fish})
|
||||
self.registry.artisan_good_rules.update({ArtisanGood.specific_bait(fish): self.can_bait(fish) for fish in all_fish})
|
||||
self.registry.artisan_good_rules.update({AnimalProduct.specific_roe(fish): self.can_get_roe(fish) for fish in all_fish})
|
||||
self.registry.artisan_good_rules.update({ArtisanGood.specific_aged_roe(fish): self.can_preserves_jar(AnimalProduct.specific_roe(fish)) for fish in all_fish})
|
||||
self.registry.artisan_good_rules.update({ArtisanGood.specific_honey(flower): self.can_get_honey(flower) for flower in all_flowers})
|
||||
|
||||
def has_jelly(self) -> StardewRule:
|
||||
return self.logic.artisan.can_preserves_jar(Fruit.any)
|
||||
@@ -73,6 +79,10 @@ class ArtisanLogic(BaseLogic):
|
||||
machine_rule = self.logic.has(Machine.fish_smoker)
|
||||
return machine_rule & self.logic.has(item)
|
||||
|
||||
def can_get_roe(self, item: str) -> StardewRule:
|
||||
machine_rule = self.logic.building.has_building(Building.fish_pond)
|
||||
return machine_rule & self.logic.has(item)
|
||||
|
||||
def can_bait(self, item: str) -> StardewRule:
|
||||
machine_rule = self.logic.has(Machine.bait_maker)
|
||||
return machine_rule & self.logic.has(item)
|
||||
@@ -87,3 +97,11 @@ class ArtisanLogic(BaseLogic):
|
||||
if item == Mushroom.any_edible:
|
||||
return machine_rule & self.logic.has_any(*(mushroom.name for mushroom in self.content.find_tagged_items(ItemTag.EDIBLE_MUSHROOM)))
|
||||
return machine_rule & self.logic.has(item)
|
||||
|
||||
def can_get_honey(self, flower: str) -> StardewRule:
|
||||
machine_rule = self.logic.has(Machine.bee_house)
|
||||
flower_rule = self.logic.has(flower)
|
||||
return machine_rule & flower_rule
|
||||
|
||||
def can_replicate_gem(self, gem: str) -> StardewRule:
|
||||
return self.logic.has(Machine.crystalarium) & self.logic.has(gem)
|
||||
|
||||
@@ -25,6 +25,8 @@ class LogicRegistry:
|
||||
self.festival_rules: Dict[str, StardewRule] = {}
|
||||
self.quest_rules: Dict[str, StardewRule] = {}
|
||||
self.special_order_rules: Dict[str, StardewRule] = {}
|
||||
self.meme_item_rules: Dict[str, StardewRule] = {}
|
||||
self.shirt_rules: Dict[str, StardewRule] = {}
|
||||
|
||||
self.sve_location_rules: Dict[str, StardewRule] = {}
|
||||
|
||||
|
||||
@@ -2,8 +2,13 @@ from functools import cached_property
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from ..stardew_rule import StardewRule, true_
|
||||
from ..strings.building_names import Building
|
||||
from ..stardew_rule import StardewRule, true_, false_
|
||||
from ..strings.building_names import Building, WizardBuilding
|
||||
from ..strings.crop_names import Fruit
|
||||
from ..strings.fish_names import Fish, WaterItem
|
||||
from ..strings.forageable_names import Forageable
|
||||
from ..strings.material_names import Material
|
||||
from ..strings.metal_names import MetalBar, Mineral
|
||||
from ..strings.region_names import Region
|
||||
|
||||
AUTO_BUILDING_BUILDINGS = {Building.shipping_bin, Building.pet_bowl, Building.farm_house}
|
||||
@@ -41,12 +46,33 @@ class BuildingLogic(BaseLogic):
|
||||
|
||||
# Those buildings are special. The mod auto-builds them when received, no need to go to Robin.
|
||||
if building_name in AUTO_BUILDING_BUILDINGS:
|
||||
return self.logic.received(Building.shipping_bin)
|
||||
return self.logic.received(building_name)
|
||||
|
||||
carpenter_rule = self.logic.building.can_construct_buildings
|
||||
item, count = building_progression.to_progressive_item(building_name)
|
||||
return self.logic.received(item, count) & carpenter_rule
|
||||
|
||||
@cache_self1
|
||||
def has_wizard_building(self, building_name: str) -> StardewRule:
|
||||
return self.logic.region.can_reach(Region.wizard_tower) & self.logic.received(building_name)
|
||||
|
||||
@cached_property
|
||||
def can_construct_buildings(self) -> StardewRule:
|
||||
return self.logic.region.can_reach(Region.carpenter)
|
||||
|
||||
def can_purchase_wizard_blueprint(self, building_name: str) -> StardewRule:
|
||||
# This rule is part of the region, so not needed here
|
||||
# rule = self.logic.region.can_reach(Region.wizard_tower) & self.logic.quest.has_magic_ink()
|
||||
if building_name == WizardBuilding.earth_obelisk:
|
||||
return self.logic.money.can_spend(500_000) & self.logic.has_all(MetalBar.iridium, Mineral.earth_crystal)
|
||||
if building_name == WizardBuilding.water_obelisk:
|
||||
return self.logic.money.can_spend(500_000) & self.logic.has_all(MetalBar.iridium, Fish.clam, WaterItem.coral)
|
||||
if building_name == WizardBuilding.desert_obelisk:
|
||||
return self.logic.money.can_spend(1_000_000) & self.logic.has_all(MetalBar.iridium, Forageable.coconut, Forageable.cactus_fruit)
|
||||
if building_name == WizardBuilding.island_obelisk:
|
||||
return self.logic.money.can_spend(1_000_000) & self.logic.has_all(MetalBar.iridium, Forageable.dragon_tooth, Fruit.banana)
|
||||
if building_name == WizardBuilding.junimo_hut:
|
||||
return self.logic.money.can_spend(20_000) & self.logic.has_all(MetalBar.iridium, Material.stone, Fruit.starfruit, Material.fiber)
|
||||
if building_name == WizardBuilding.gold_clock:
|
||||
return self.logic.money.can_spend(10_000_000)
|
||||
return false_
|
||||
|
||||
@@ -5,6 +5,8 @@ from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..bundles.bundle import Bundle
|
||||
from ..stardew_rule import StardewRule, True_
|
||||
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.bundle_names import MemeBundleName
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.machine_names import Machine
|
||||
from ..strings.quality_names import CropQuality, ForageQuality, FishQuality, ArtisanQuality
|
||||
@@ -24,19 +26,31 @@ class BundleLogic(BaseLogic):
|
||||
item_rules = []
|
||||
qualities = []
|
||||
time_to_grind = 0
|
||||
can_speak_junimo = self.logic.region.can_reach(Region.wizard_tower)
|
||||
building_rule = self.logic.true_
|
||||
can_speak_junimo = self.logic.action.can_speak_junimo()
|
||||
number_items_required = bundle.number_required
|
||||
for bundle_item in bundle.items:
|
||||
if Currency.is_currency(bundle_item.get_item()):
|
||||
return can_speak_junimo & self.logic.money.can_trade(bundle_item.get_item(), bundle_item.amount)
|
||||
|
||||
item_rules.append(bundle_item.get_item())
|
||||
item = bundle_item.get_item()
|
||||
if Currency.is_currency(item):
|
||||
return can_speak_junimo & self.logic.money.can_trade(item, bundle_item.amount)
|
||||
if item == Building.well:
|
||||
building_rule = self.logic.building.has_building(item)
|
||||
number_items_required -= 1
|
||||
else:
|
||||
item_rules.append(item)
|
||||
if bundle_item.amount > 50:
|
||||
time_to_grind = bundle_item.amount // 50
|
||||
qualities.append(bundle_item.quality)
|
||||
quality_rules = self.get_quality_rules(qualities)
|
||||
item_rules = self.logic.has_n(*item_rules, count=bundle.number_required)
|
||||
item_rules = self.logic.has_n(*item_rules, count=number_items_required)
|
||||
time_rule = self.logic.time.has_lived_months(time_to_grind)
|
||||
return can_speak_junimo & item_rules & quality_rules & time_rule
|
||||
special_rule = self.get_special_bundle_requirement(bundle)
|
||||
return can_speak_junimo & item_rules & quality_rules & time_rule & building_rule & special_rule
|
||||
|
||||
def get_special_bundle_requirement(self, bundle: Bundle) -> StardewRule:
|
||||
if bundle.name == MemeBundleName.pomnut:
|
||||
return self.logic.building.has_building(Building.stable)
|
||||
return self.logic.true_
|
||||
|
||||
def get_quality_rules(self, qualities: List[str]) -> StardewRule:
|
||||
crop_quality = CropQuality.get_highest(qualities)
|
||||
@@ -72,3 +86,8 @@ class BundleLogic(BaseLogic):
|
||||
# 1 - Break the tree
|
||||
# 2 - Build the house, which summons the bundle racoon. This one is done manually if quests are turned off
|
||||
return self.logic.received(CommunityUpgrade.raccoon, 2)
|
||||
|
||||
def can_feed_trash_bear(self, *items: str) -> StardewRule:
|
||||
return (self.logic.received("Trash Bear Arrival") &
|
||||
self.logic.region.can_reach(Region.forest) &
|
||||
self.logic.has_all(*items))
|
||||
|
||||
@@ -2,9 +2,13 @@ from functools import cached_property
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..options import Monstersanity
|
||||
from ..stardew_rule import StardewRule, False_
|
||||
from ..strings.ap_names.ap_weapon_names import APWeapon
|
||||
from ..strings.ap_names.event_names import Event
|
||||
from ..strings.boot_names import tier_by_boots
|
||||
from ..strings.performance_names import Performance
|
||||
from ..strings.region_names import Region
|
||||
|
||||
valid_weapons = (APWeapon.weapon, APWeapon.sword, APWeapon.club, APWeapon.dagger)
|
||||
|
||||
@@ -34,24 +38,31 @@ class CombatLogic(BaseLogic):
|
||||
|
||||
@cached_property
|
||||
def has_any_weapon(self) -> StardewRule:
|
||||
return self.logic.received_any(*valid_weapons)
|
||||
return self.logic.received(Event.received_progressive_weapon)
|
||||
|
||||
@cached_property
|
||||
def has_decent_weapon(self) -> StardewRule:
|
||||
return self.logic.or_(*(self.logic.received(weapon, 2) for weapon in valid_weapons))
|
||||
return self.logic.received(Event.received_progressive_weapon, 2)
|
||||
|
||||
@cached_property
|
||||
def has_good_weapon(self) -> StardewRule:
|
||||
return self.logic.or_(*(self.logic.received(weapon, 3) for weapon in valid_weapons))
|
||||
return self.logic.received(Event.received_progressive_weapon, 3)
|
||||
|
||||
@cached_property
|
||||
def has_great_weapon(self) -> StardewRule:
|
||||
return self.logic.or_(*(self.logic.received(weapon, 4) for weapon in valid_weapons))
|
||||
return self.logic.received(Event.received_progressive_weapon, 4)
|
||||
|
||||
@cached_property
|
||||
def has_galaxy_weapon(self) -> StardewRule:
|
||||
return self.logic.or_(*(self.logic.received(weapon, 5) for weapon in valid_weapons))
|
||||
return self.logic.received(Event.received_progressive_weapon, 5)
|
||||
|
||||
@cached_property
|
||||
def has_slingshot(self) -> StardewRule:
|
||||
return self.logic.received(APWeapon.slingshot)
|
||||
|
||||
@cache_self1
|
||||
def has_specific_boots(self, boots: str) -> StardewRule:
|
||||
tier = tier_by_boots[boots]
|
||||
if tier >= 4 and self.options.monstersanity == Monstersanity.option_none:
|
||||
tier = 3 # no tier 4 boots in the pool, instead tier 4 boots can be purchased after tier 3 is received
|
||||
return self.logic.received(APWeapon.footwear, tier) & self.logic.region.can_reach(Region.adventurer_guild)
|
||||
|
||||
@@ -3,13 +3,14 @@ from functools import cached_property
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..data.recipe_data import RecipeSource, StarterSource, ShopSource, SkillSource, FriendshipSource, \
|
||||
QueenOfSauceSource, CookingRecipe, ShopFriendshipSource
|
||||
QueenOfSauceSource, CookingRecipe, ShopFriendshipSource, all_cooking_recipes
|
||||
from ..data.recipe_source import CutsceneSource, ShopTradeSource
|
||||
from ..options import Chefsanity
|
||||
from ..stardew_rule import StardewRule, True_, False_
|
||||
from ..strings.ap_names.ap_option_names import ChefsanityOptionName
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.craftable_names import Craftable
|
||||
from ..strings.region_names import LogicRegion
|
||||
from ..strings.skill_names import Skill
|
||||
from ..strings.tv_channel_names import Channel
|
||||
|
||||
|
||||
@@ -22,13 +23,15 @@ class CookingLogicMixin(BaseLogicMixin):
|
||||
class CookingLogic(BaseLogic):
|
||||
@cached_property
|
||||
def can_cook_in_kitchen(self) -> StardewRule:
|
||||
return self.logic.building.has_building(Building.kitchen) | self.logic.skill.has_level(Skill.foraging, 9)
|
||||
return self.logic.building.has_building(Building.kitchen) | self.logic.has(Craftable.cookout_kit)
|
||||
|
||||
# Should be cached
|
||||
def can_cook(self, recipe: CookingRecipe = None) -> StardewRule:
|
||||
def can_cook(self, recipe: CookingRecipe | str = None) -> StardewRule:
|
||||
cook_rule = self.logic.region.can_reach(LogicRegion.kitchen)
|
||||
if recipe is None:
|
||||
return cook_rule
|
||||
if isinstance(recipe, str):
|
||||
recipe = next(filter(lambda x: x.meal == recipe, all_cooking_recipes))
|
||||
|
||||
recipe_rule = self.logic.cooking.knows_recipe(recipe.source, recipe.meal)
|
||||
ingredients_rule = self.logic.has_all(*sorted(recipe.ingredients))
|
||||
@@ -36,23 +39,23 @@ class CookingLogic(BaseLogic):
|
||||
|
||||
# Should be cached
|
||||
def knows_recipe(self, source: RecipeSource, meal_name: str) -> StardewRule:
|
||||
if self.options.chefsanity == Chefsanity.option_none:
|
||||
if self.options.chefsanity == Chefsanity.preset_none:
|
||||
return self.logic.cooking.can_learn_recipe(source)
|
||||
if isinstance(source, StarterSource):
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, ShopTradeSource) and self.options.chefsanity & Chefsanity.option_purchases:
|
||||
if isinstance(source, ShopTradeSource) and ChefsanityOptionName.purchases in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, ShopSource) and self.options.chefsanity & Chefsanity.option_purchases:
|
||||
if isinstance(source, ShopSource) and ChefsanityOptionName.purchases in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, SkillSource) and self.options.chefsanity & Chefsanity.option_skills:
|
||||
if isinstance(source, SkillSource) and ChefsanityOptionName.skills in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, CutsceneSource) and self.options.chefsanity & Chefsanity.option_friendship:
|
||||
if isinstance(source, CutsceneSource) and ChefsanityOptionName.friendship in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, FriendshipSource) and self.options.chefsanity & Chefsanity.option_friendship:
|
||||
if isinstance(source, FriendshipSource) and ChefsanityOptionName.friendship in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, QueenOfSauceSource) and self.options.chefsanity & Chefsanity.option_queen_of_sauce:
|
||||
if isinstance(source, QueenOfSauceSource) and ChefsanityOptionName.queen_of_sauce in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
if isinstance(source, ShopFriendshipSource) and self.options.chefsanity & Chefsanity.option_purchases:
|
||||
if isinstance(source, ShopFriendshipSource) and ChefsanityOptionName.purchases in self.options.chefsanity:
|
||||
return self.logic.cooking.received_recipe(meal_name)
|
||||
return self.logic.cooking.can_learn_recipe(source)
|
||||
|
||||
@@ -79,3 +82,14 @@ class CookingLogic(BaseLogic):
|
||||
@cache_self1
|
||||
def received_recipe(self, meal_name: str):
|
||||
return self.logic.received(f"{meal_name} Recipe")
|
||||
|
||||
def can_have_cooked_recipes(self, number: int) -> StardewRule:
|
||||
if number <= 0:
|
||||
return self.logic.true_
|
||||
recipe_rules = []
|
||||
for recipe in all_cooking_recipes:
|
||||
if recipe.content_pack and not self.content.is_enabled(recipe.content_pack):
|
||||
continue
|
||||
recipe_rules.append(self.can_cook(recipe))
|
||||
number = min(len(recipe_rules), number)
|
||||
return self.logic.count(number, *recipe_rules)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from .. import options
|
||||
from ..data.craftable_data import CraftingRecipe
|
||||
from ..data.craftable_data import CraftingRecipe, all_crafting_recipes, all_crafting_recipes_by_name
|
||||
from ..data.recipe_source import CutsceneSource, ShopTradeSource, ArchipelagoSource, LogicSource, SpecialOrderSource, \
|
||||
FestivalShopSource, QuestSource, StarterSource, ShopSource, SkillSource, MasterySource, FriendshipSource, SkillCraftsanitySource
|
||||
FestivalShopSource, QuestSource, StarterSource, ShopSource, SkillSource, MasterySource, FriendshipSource, SkillCraftsanitySource, ShopWithKnownRecipeSource
|
||||
from ..options import Craftsanity, SpecialOrderLocations
|
||||
from ..stardew_rule import StardewRule, True_, False_
|
||||
from ..strings.region_names import Region
|
||||
@@ -55,6 +55,8 @@ class CraftingLogic(BaseLogic):
|
||||
return self.logic.received_all(*recipe.source.ap_item)
|
||||
if isinstance(recipe.source, ShopTradeSource):
|
||||
return self.logic.money.can_trade_at(recipe.source.region, recipe.source.currency, recipe.source.price)
|
||||
if isinstance(recipe.source, ShopWithKnownRecipeSource):
|
||||
return self.knows_recipe(all_crafting_recipes_by_name[recipe.source.recipe_required]) & self.logic.money.can_spend_at(recipe.source.region, recipe.source.price)
|
||||
if isinstance(recipe.source, ShopSource):
|
||||
return self.logic.money.can_spend_at(recipe.source.region, recipe.source.price)
|
||||
if isinstance(recipe.source, SkillCraftsanitySource):
|
||||
@@ -83,3 +85,14 @@ class CraftingLogic(BaseLogic):
|
||||
@cache_self1
|
||||
def received_recipe(self, item_name: str):
|
||||
return self.logic.received(f"{item_name} Recipe")
|
||||
|
||||
def can_have_crafted_recipes(self, number: int) -> StardewRule:
|
||||
if number <= 0:
|
||||
return self.logic.true_
|
||||
recipe_rules = []
|
||||
for recipe in all_crafting_recipes:
|
||||
if recipe.content_pack is not None and not self.content.are_all_enabled(recipe.content_pack):
|
||||
continue
|
||||
recipe_rules.append(self.can_craft(recipe))
|
||||
number = min(len(recipe_rules), number)
|
||||
return self.logic.count(number, *recipe_rules)
|
||||
|
||||
@@ -3,8 +3,10 @@ from typing import Union, Tuple
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from .. import options
|
||||
from ..stardew_rule import StardewRule, True_, false_
|
||||
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.ap_names.ap_option_names import CustomLogicOptionName
|
||||
from ..strings.craftable_names import Bomb
|
||||
from ..strings.fertilizer_names import Fertilizer
|
||||
from ..strings.region_names import Region, LogicRegion
|
||||
from ..strings.season_names import Season
|
||||
@@ -27,17 +29,30 @@ class FarmingLogicMixin(BaseLogicMixin):
|
||||
class FarmingLogic(BaseLogic):
|
||||
|
||||
@cached_property
|
||||
def has_farming_tools(self) -> StardewRule:
|
||||
return self.logic.tool.has_tool(Tool.hoe) & self.logic.tool.can_water(0)
|
||||
def has_farming_tools_and_water(self) -> StardewRule:
|
||||
if CustomLogicOptionName.rain_watering in self.options.custom_logic:
|
||||
return self.has_hoeing_tool
|
||||
return self.has_hoeing_tool & self.logic.tool.can_water()
|
||||
|
||||
@cached_property
|
||||
def has_farming_and_watering_tools(self) -> StardewRule:
|
||||
return self.has_hoeing_tool & self.logic.tool.can_water()
|
||||
|
||||
@cached_property
|
||||
def has_hoeing_tool(self) -> StardewRule:
|
||||
if CustomLogicOptionName.bomb_hoeing in self.options.custom_logic:
|
||||
return self.logic.tool.has_tool(Tool.hoe) | self.logic.has_any(Bomb.cherry_bomb, Bomb.bomb, Bomb.mega_bomb)
|
||||
return self.logic.tool.has_tool(Tool.hoe)
|
||||
|
||||
def has_fertilizer(self, tier: int) -> StardewRule:
|
||||
if tier <= 0:
|
||||
return True_()
|
||||
assert 0 <= tier <= 3
|
||||
if tier == 0:
|
||||
return self.logic.true_
|
||||
if tier == 1:
|
||||
return self.logic.has(Fertilizer.basic)
|
||||
if tier == 2:
|
||||
return self.logic.has(Fertilizer.quality)
|
||||
if tier >= 3:
|
||||
if tier == 3:
|
||||
return self.logic.has(Fertilizer.deluxe)
|
||||
|
||||
return self.logic.false_
|
||||
@@ -45,7 +60,8 @@ class FarmingLogic(BaseLogic):
|
||||
@cache_self1
|
||||
def can_plant_and_grow_item(self, seasons: Union[str, Tuple[str]]) -> StardewRule:
|
||||
if seasons == (): # indoor farming
|
||||
return (self.logic.region.can_reach(Region.greenhouse) | self.logic.farming.has_island_farm()) & self.logic.farming.has_farming_tools
|
||||
return (self.logic.region.can_reach(Region.greenhouse) & self.logic.farming.has_farming_and_watering_tools) |\
|
||||
(self.logic.farming.has_island_farm() & self.logic.farming.has_farming_tools_and_water)
|
||||
|
||||
if isinstance(seasons, str):
|
||||
seasons = (seasons,)
|
||||
@@ -53,6 +69,6 @@ class FarmingLogic(BaseLogic):
|
||||
return self.logic.or_(*(self.logic.region.can_reach(farming_region_by_season[season]) for season in seasons))
|
||||
|
||||
def has_island_farm(self) -> StardewRule:
|
||||
if self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_false:
|
||||
if self.content.is_enabled(ginger_island_content_pack):
|
||||
return self.logic.region.can_reach(Region.island_west)
|
||||
return false_
|
||||
return self.logic.false_
|
||||
|
||||
@@ -3,15 +3,16 @@ from ..options import FestivalLocations
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.book_names import Book
|
||||
from ..strings.craftable_names import Fishing
|
||||
from ..strings.crop_names import Fruit, Vegetable
|
||||
from ..strings.festival_check_names import FestivalCheck
|
||||
from ..strings.fish_names import Fish
|
||||
from ..strings.forageable_names import Forageable
|
||||
from ..strings.generic_names import Generic
|
||||
from ..strings.gift_names import Gift
|
||||
from ..strings.machine_names import Machine
|
||||
from ..strings.monster_names import Monster
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.season_names import Season
|
||||
|
||||
|
||||
class FestivalLogicMixin(BaseLogicMixin):
|
||||
@@ -42,7 +43,7 @@ class FestivalLogic(BaseLogic):
|
||||
FestivalCheck.rarecrow_2: self.logic.money.can_spend(5000),
|
||||
FestivalCheck.fishing_competition: self.logic.festival.can_win_fishing_competition(),
|
||||
FestivalCheck.rarecrow_4: self.logic.money.can_spend(5000),
|
||||
FestivalCheck.mermaid_pearl: self.logic.has(Forageable.secret_note),
|
||||
FestivalCheck.mermaid_show: self.logic.true_,
|
||||
FestivalCheck.cone_hat: self.logic.money.can_spend(2500),
|
||||
FestivalCheck.iridium_fireplace: self.logic.money.can_spend(15000),
|
||||
FestivalCheck.rarecrow_7: self.logic.money.can_spend(5000) & self.logic.museum.can_donate_museum_artifacts(20),
|
||||
@@ -94,25 +95,24 @@ class FestivalLogic(BaseLogic):
|
||||
FestivalCheck.willy_challenge: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.scorpion_carp]),
|
||||
FestivalCheck.desert_scholar: self.logic.true_,
|
||||
FestivalCheck.squidfest_day_1_copper: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]),
|
||||
FestivalCheck.squidfest_day_1_iron: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.has(Fishing.bait),
|
||||
FestivalCheck.squidfest_day_1_gold: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.has(Fishing.deluxe_bait),
|
||||
FestivalCheck.squidfest_day_1_iridium: self.logic.festival.can_squidfest_day_1_iridium_reward(),
|
||||
FestivalCheck.squidfest_day_1_iron: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.fishing.can_use_any_bait(),
|
||||
FestivalCheck.squidfest_day_1_gold: self.logic.festival.can_squidfest_iridium_reward(),
|
||||
FestivalCheck.squidfest_day_1_iridium: self.logic.festival.can_squidfest_iridium_reward(),
|
||||
FestivalCheck.squidfest_day_2_copper: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]),
|
||||
FestivalCheck.squidfest_day_2_iron: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.has(Fishing.bait),
|
||||
FestivalCheck.squidfest_day_2_gold: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.has(Fishing.deluxe_bait),
|
||||
FestivalCheck.squidfest_day_2_iridium: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) &
|
||||
self.logic.fishing.has_specific_bait(self.content.fishes[Fish.squid]),
|
||||
FestivalCheck.squidfest_day_2_iron: self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.fishing.can_use_any_bait(),
|
||||
FestivalCheck.squidfest_day_2_gold: self.logic.festival.can_squidfest_iridium_reward(),
|
||||
FestivalCheck.squidfest_day_2_iridium: self.logic.festival.can_squidfest_iridium_reward(),
|
||||
})
|
||||
for i in range(1, 11):
|
||||
check_name = f"{FestivalCheck.trout_derby_reward_pattern}{i}"
|
||||
self.registry.festival_rules[check_name] = self.logic.fishing.can_catch_fish(self.content.fishes[Fish.rainbow_trout])
|
||||
|
||||
def can_squidfest_day_1_iridium_reward(self) -> StardewRule:
|
||||
return self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.fishing.has_specific_bait(self.content.fishes[Fish.squid])
|
||||
def can_squidfest_iridium_reward(self) -> StardewRule:
|
||||
return self.logic.fishing.can_catch_fish(self.content.fishes[Fish.squid]) & self.logic.fishing.can_use_specific_bait(Fish.squid)
|
||||
|
||||
def has_squidfest_day_1_iridium_reward(self) -> StardewRule:
|
||||
if self.options.festival_locations == FestivalLocations.option_disabled:
|
||||
return self.logic.festival.can_squidfest_day_1_iridium_reward()
|
||||
return self.logic.festival.can_squidfest_iridium_reward()
|
||||
else:
|
||||
return self.logic.received(f"Book: {Book.the_art_o_crabbing}")
|
||||
|
||||
@@ -122,6 +122,9 @@ class FestivalLogic(BaseLogic):
|
||||
def can_succeed_luau_soup(self) -> StardewRule:
|
||||
if self.options.festival_locations != FestivalLocations.option_hard:
|
||||
return self.logic.true_
|
||||
return self.can_get_luau_soup_delight()
|
||||
|
||||
def can_get_luau_soup_delight(self) -> StardewRule:
|
||||
eligible_fish = (Fish.blobfish, Fish.crimsonfish, Fish.ice_pip, Fish.lava_eel, Fish.legend, Fish.angler, Fish.catfish, Fish.glacierfish,
|
||||
Fish.mutant_carp, Fish.spookfish, Fish.stingray, Fish.sturgeon, Fish.super_cucumber)
|
||||
fish_rule = self.logic.has_any(*(f for f in eligible_fish if f in self.content.fishes)) # To filter stingray
|
||||
@@ -137,7 +140,9 @@ class FestivalLogic(BaseLogic):
|
||||
def can_succeed_grange_display(self) -> StardewRule:
|
||||
if self.options.festival_locations != FestivalLocations.option_hard:
|
||||
return self.logic.true_
|
||||
return self.can_get_grange_display_max_score()
|
||||
|
||||
def can_get_grange_display_max_score(self) -> StardewRule:
|
||||
# Other animal products are not counted in the animal product category
|
||||
good_animal_products = [
|
||||
AnimalProduct.duck_egg, AnimalProduct.duck_feather, AnimalProduct.egg, AnimalProduct.goat_milk, AnimalProduct.golden_egg, AnimalProduct.large_egg,
|
||||
@@ -157,7 +162,7 @@ class FestivalLogic(BaseLogic):
|
||||
fish_rule = self.logic.fishing.can_fish_anywhere(50)
|
||||
|
||||
# Hazelnut always available since the grange display is in fall
|
||||
forage_rule = self.logic.region.can_reach_any((Region.forest, Region.backwoods))
|
||||
forage_rule = self.logic.region.can_reach_any(Region.forest, Region.backwoods)
|
||||
|
||||
# More than half the minerals are good enough
|
||||
mineral_rule = self.logic.action.can_open_geode(Generic.any)
|
||||
@@ -186,3 +191,8 @@ class FestivalLogic(BaseLogic):
|
||||
for rarecrow_number in range(1, 9):
|
||||
rules.append(self.logic.received(f"Rarecrow #{rarecrow_number}"))
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
def has_golden_pumpkin(self) -> StardewRule:
|
||||
if self.options.festival_locations == FestivalLocations.option_disabled:
|
||||
return self.logic.season.has(Season.fall)
|
||||
return self.logic.received(Gift.golden_pumpkin) & self.logic.season.has(Season.fall)
|
||||
|
||||
50
worlds/stardew_valley/logic/fish_pond_logic.py
Normal file
50
worlds/stardew_valley/logic/fish_pond_logic.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from ..data.fish_pond_data import fish_pond_quests
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.fish_names import Fish
|
||||
|
||||
|
||||
class FishPondLogicMixin(BaseLogicMixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fish_pond = FishPondLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class FishPondLogic(BaseLogic):
|
||||
|
||||
def can_get_fish_pond_reward(self, fish: str, population: int, desired_item: str) -> StardewRule:
|
||||
building_rule = self.logic.building.has_building(Building.fish_pond)
|
||||
if fish == Fish.any:
|
||||
return self.logic.fishing.can_fish_anywhere() & building_rule
|
||||
|
||||
fish_rule = self.logic.has(fish)
|
||||
|
||||
if population <= 1:
|
||||
return building_rule & fish_rule
|
||||
|
||||
assert fish in fish_pond_quests, f"Cannot raise the population of {fish} to {population} in a fish pond to get {desired_item} without knowing the required quest items"
|
||||
# if fish not in fish_pond_quests:
|
||||
# return building_rule & fish_rule
|
||||
|
||||
item_rules = []
|
||||
fish_quests = fish_pond_quests[fish]
|
||||
for i in range(0, population):
|
||||
if i not in fish_quests:
|
||||
continue
|
||||
quests_for_that_level = fish_quests[i]
|
||||
num_quests = len(quests_for_that_level)
|
||||
if num_quests <= 0:
|
||||
continue
|
||||
|
||||
level_rules = []
|
||||
for quest_item in quests_for_that_level:
|
||||
if quest_item == desired_item:
|
||||
continue
|
||||
level_rules.append(self.logic.has(quest_item))
|
||||
if num_quests <= 2:
|
||||
item_rules.append(self.logic.count(num_quests, *level_rules))
|
||||
else:
|
||||
item_rules.append(self.logic.count(num_quests - 1, *level_rules))
|
||||
|
||||
return building_rule & fish_rule & self.logic.and_(*item_rules)
|
||||
@@ -2,10 +2,11 @@ from functools import cached_property
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..content.vanilla.qi_board import qi_board_content_pack
|
||||
from ..data import fish_data
|
||||
from ..data.fish_data import FishItem
|
||||
from ..options import ExcludeGingerIsland, SpecialOrderLocations
|
||||
from ..stardew_rule import StardewRule, True_, False_
|
||||
from ..stardew_rule import StardewRule, True_
|
||||
from ..strings.ap_names.ap_option_names import CustomLogicOptionName
|
||||
from ..strings.ap_names.mods.mod_items import SVEQuestItem
|
||||
from ..strings.craftable_names import Fishing
|
||||
from ..strings.fish_names import SVEFish
|
||||
@@ -13,8 +14,7 @@ from ..strings.machine_names import Machine
|
||||
from ..strings.quality_names import FishQuality
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.skill_names import Skill
|
||||
|
||||
fishing_regions = (Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west)
|
||||
from ..strings.tool_names import FishingRod
|
||||
|
||||
|
||||
class FishingLogicMixin(BaseLogicMixin):
|
||||
@@ -24,48 +24,80 @@ class FishingLogicMixin(BaseLogicMixin):
|
||||
|
||||
|
||||
class FishingLogic(BaseLogic):
|
||||
|
||||
@cached_property
|
||||
def can_reach_any_fishing_regions(self) -> StardewRule:
|
||||
return self.logic.region.can_reach_any(Region.beach, Region.town, Region.forest, Region.mountain, Region.island_south, Region.island_west)
|
||||
|
||||
@cache_self1
|
||||
def can_fish_anywhere(self, difficulty: int = 0) -> StardewRule:
|
||||
return self.logic.fishing.can_fish(difficulty) & self.logic.region.can_reach_any(fishing_regions)
|
||||
return self.logic.fishing.can_fish(difficulty) & self.logic.fishing.can_reach_any_fishing_regions
|
||||
|
||||
def can_fish_in_freshwater(self) -> StardewRule:
|
||||
return self.logic.fishing.can_fish() & self.logic.region.can_reach_any((Region.forest, Region.town, Region.mountain))
|
||||
return self.logic.fishing.can_fish() & self.logic.region.can_reach_any(Region.forest, Region.town, Region.mountain)
|
||||
|
||||
@cached_property
|
||||
def has_max_fishing(self) -> StardewRule:
|
||||
return self.logic.tool.has_fishing_rod(4) & self.logic.skill.has_level(Skill.fishing, 10)
|
||||
# Advanced Iridium is not necessary for max fishing
|
||||
return self.logic.tool.has_fishing_rod(FishingRod.iridium) & self.logic.skill.has_level(Skill.fishing, 10)
|
||||
|
||||
@cached_property
|
||||
def can_fish_chests(self) -> StardewRule:
|
||||
return self.logic.tool.has_fishing_rod(4) & self.logic.skill.has_level(Skill.fishing, 6)
|
||||
return self.logic.tool.has_fishing_rod(FishingRod.iridium) & self.logic.skill.has_level(Skill.fishing, 6)
|
||||
|
||||
@cache_self1
|
||||
def can_fish_at(self, region: str) -> StardewRule:
|
||||
return self.logic.fishing.can_fish() & self.logic.region.can_reach(region)
|
||||
|
||||
@cache_self1
|
||||
def can_fish(self, difficulty: int = 0) -> StardewRule:
|
||||
skill_required = min(10, max(0, int((difficulty / 10) - 1)))
|
||||
def can_fish_with_cast_distance(self, region: str, distance: int) -> StardewRule:
|
||||
if distance >= 7:
|
||||
required_levels = 15
|
||||
elif distance >= 6:
|
||||
required_levels = 8
|
||||
elif distance >= 5:
|
||||
required_levels = 4
|
||||
elif distance >= 4:
|
||||
required_levels = 1
|
||||
else:
|
||||
required_levels = 0
|
||||
return self.logic.fishing.can_fish_at(region) & self.logic.skill.has_level(Skill.fishing, required_levels)
|
||||
|
||||
def can_fish(self, difficulty: int = 0, minimum_level: int = 0) -> StardewRule:
|
||||
skill_required = int((difficulty / 10) - 1)
|
||||
if difficulty <= 40:
|
||||
skill_required = 0
|
||||
|
||||
if CustomLogicOptionName.extreme_fishing in self.options.custom_logic:
|
||||
skill_required -= 4
|
||||
elif CustomLogicOptionName.hard_fishing in self.options.custom_logic:
|
||||
skill_required -= 2
|
||||
elif CustomLogicOptionName.easy_fishing in self.options.custom_logic and difficulty > 20:
|
||||
skill_required += 2
|
||||
|
||||
skill_required = min(10, max(minimum_level, skill_required))
|
||||
|
||||
skill_rule = self.logic.skill.has_level(Skill.fishing, skill_required)
|
||||
# Training rod only works with fish < 50. Fiberglass does not help you to catch higher difficulty fish, so it's skipped in logic.
|
||||
number_fishing_rod_required = 1 if difficulty < 50 else (2 if difficulty < 80 else 4)
|
||||
return self.logic.tool.has_fishing_rod(number_fishing_rod_required) & skill_rule
|
||||
if difficulty < 50:
|
||||
fishing_rod_required = FishingRod.training
|
||||
elif difficulty < 80:
|
||||
fishing_rod_required = FishingRod.bamboo
|
||||
else:
|
||||
fishing_rod_required = FishingRod.iridium
|
||||
return self.logic.tool.has_fishing_rod(fishing_rod_required) & skill_rule
|
||||
|
||||
@cache_self1
|
||||
def can_catch_fish(self, fish: FishItem) -> StardewRule:
|
||||
quest_rule = True_()
|
||||
if fish.extended_family:
|
||||
quest_rule = self.logic.fishing.can_start_extended_family_quest()
|
||||
region_rule = self.logic.region.can_reach_any(fish.locations)
|
||||
region_rule = self.logic.region.can_reach_any(*fish.locations)
|
||||
season_rule = self.logic.season.has_any(fish.seasons)
|
||||
|
||||
if fish.difficulty == -1:
|
||||
difficulty_rule = self.logic.fishing.can_crab_pot
|
||||
else:
|
||||
difficulty_rule = self.logic.fishing.can_fish(120 if fish.legendary else fish.difficulty)
|
||||
difficulty_rule = self.logic.fishing.can_fish(120 if fish.legendary else fish.difficulty, fish.minimum_level)
|
||||
|
||||
if fish.name == SVEFish.kittyfish:
|
||||
item_rule = self.logic.received(SVEQuestItem.kittyfish_spell)
|
||||
@@ -80,18 +112,17 @@ class FishingLogic(BaseLogic):
|
||||
return self.logic.fishing.can_catch_fish(fish)
|
||||
|
||||
def can_start_extended_family_quest(self) -> StardewRule:
|
||||
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
return False_()
|
||||
if not self.options.special_order_locations & SpecialOrderLocations.value_qi:
|
||||
return False_()
|
||||
if self.content.is_enabled(qi_board_content_pack):
|
||||
return (self.logic.region.can_reach(Region.qi_walnut_room) &
|
||||
self.logic.and_(*(self.logic.fishing.can_catch_fish(fish) for fish in fish_data.vanilla_legendary_fish)))
|
||||
|
||||
return self.logic.false_
|
||||
|
||||
def can_catch_quality_fish(self, fish_quality: str) -> StardewRule:
|
||||
if fish_quality == FishQuality.basic:
|
||||
return True_()
|
||||
return self.logic.true_
|
||||
if fish_quality == FishQuality.silver:
|
||||
return self.logic.tool.has_fishing_rod(2)
|
||||
return self.logic.tool.has_fishing_rod(FishingRod.bamboo)
|
||||
if fish_quality == FishQuality.gold:
|
||||
return self.logic.skill.has_level(Skill.fishing, 4) & self.can_use_tackle(Fishing.quality_bobber)
|
||||
if fish_quality == FishQuality.iridium:
|
||||
@@ -100,7 +131,7 @@ class FishingLogic(BaseLogic):
|
||||
raise ValueError(f"Quality {fish_quality} is unknown.")
|
||||
|
||||
def can_use_tackle(self, tackle: str) -> StardewRule:
|
||||
return self.logic.tool.has_fishing_rod(4) & self.logic.has(tackle)
|
||||
return self.logic.tool.has_fishing_rod(FishingRod.iridium) & self.logic.has(tackle)
|
||||
|
||||
def can_catch_every_fish(self) -> StardewRule:
|
||||
rules = [self.has_max_fishing]
|
||||
@@ -112,12 +143,27 @@ class FishingLogic(BaseLogic):
|
||||
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
def can_catch_many_fish(self, number: int) -> StardewRule:
|
||||
rules = [
|
||||
self.logic.fishing.can_catch_fish(fish)
|
||||
for fish in self.content.fishes.values()
|
||||
]
|
||||
if number > len(rules):
|
||||
number = len(rules)
|
||||
return self.logic.count(number, *rules)
|
||||
|
||||
def has_specific_bait(self, fish: FishItem) -> StardewRule:
|
||||
return self.can_catch_fish(fish) & self.logic.has(Machine.bait_maker)
|
||||
|
||||
def can_use_specific_bait(self, fish_name: str) -> StardewRule:
|
||||
return self.has_specific_bait(self.content.fishes[fish_name]) & self.logic.tool.has_fishing_rod(FishingRod.fiberglass)
|
||||
|
||||
def can_use_any_bait(self) -> StardewRule:
|
||||
return self.logic.has(Fishing.bait) & self.logic.tool.has_fishing_rod(FishingRod.fiberglass)
|
||||
|
||||
@cached_property
|
||||
def can_crab_pot_anywhere(self) -> StardewRule:
|
||||
return self.logic.fishing.can_crab_pot & self.logic.region.can_reach_any(fishing_regions)
|
||||
return self.logic.fishing.can_crab_pot & self.can_reach_any_fishing_regions
|
||||
|
||||
@cache_self1
|
||||
def can_crab_pot_at(self, region: str) -> StardewRule:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from functools import cached_property
|
||||
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from ..data.secret_note_data import RequiredGifts
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.gift_names import Gift
|
||||
@@ -17,3 +18,32 @@ class GiftLogic(BaseLogic):
|
||||
@cached_property
|
||||
def has_any_universal_love(self) -> StardewRule:
|
||||
return self.logic.has_any(Gift.golden_pumpkin, Gift.pearl, "Prismatic Shard", AnimalProduct.rabbit_foot)
|
||||
|
||||
def can_gift_to(self, npc: str, item: str) -> StardewRule:
|
||||
return self.logic.relationship.can_meet(npc) & self.logic.has(item)
|
||||
|
||||
def can_gift_any_to(self, npc: str, *items: str) -> StardewRule:
|
||||
return self.logic.relationship.can_meet(npc) & self.logic.has_any(*items)
|
||||
|
||||
def can_fulfill(self, required_gifts: RequiredGifts | list[RequiredGifts]) -> StardewRule:
|
||||
if isinstance(required_gifts, RequiredGifts):
|
||||
return self.can_gift_all_to(required_gifts)
|
||||
return self.can_gift_all_to_all(required_gifts)
|
||||
|
||||
def can_gift_all_to(self, required_gifts: RequiredGifts) -> StardewRule:
|
||||
return self.logic.relationship.can_meet(required_gifts.npc) & self.logic.has_all(*required_gifts.gifts)
|
||||
|
||||
def can_gift_all_to_all(self, required_gifts: list[RequiredGifts]) -> StardewRule:
|
||||
items = [gift for required_gift in required_gifts for gift in required_gift.gifts]
|
||||
return self.logic.relationship.can_meet_all(*[required_gift.npc for required_gift in required_gifts]) & self.logic.has_all(*items)
|
||||
|
||||
def can_give_loved_gifts_to_everyone(self) -> StardewRule:
|
||||
rules = []
|
||||
|
||||
for npc in self.content.villagers:
|
||||
meet_rule = self.logic.relationship.can_meet(npc)
|
||||
rules.append(meet_rule)
|
||||
|
||||
rules.append(self.has_any_universal_love)
|
||||
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
@@ -5,8 +5,11 @@ from ..locations import LocationTags, locations_by_tag
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..options import options
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.ap_names.ap_option_names import SecretsanityOptionName
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.crop_names import Fruit
|
||||
from ..strings.quest_names import Quest
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.season_names import Season
|
||||
from ..strings.wallet_item_names import Wallet
|
||||
|
||||
@@ -97,11 +100,8 @@ class GoalLogic(BaseLogic):
|
||||
def can_complete_gourmet_chef(self) -> StardewRule:
|
||||
cooksanity_prefix = "Cook "
|
||||
all_recipes_names = []
|
||||
exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true
|
||||
for location in locations_by_tag[LocationTags.COOKSANITY]:
|
||||
if exclude_island and LocationTags.GINGER_ISLAND in location.tags:
|
||||
continue
|
||||
if location.mod_name and location.mod_name not in self.options.mods:
|
||||
if not self.content.are_all_enabled(location.content_packs):
|
||||
continue
|
||||
all_recipes_names.append(location.name[len(cooksanity_prefix):])
|
||||
all_recipes = [all_cooking_recipes_by_name[recipe_name] for recipe_name in all_recipes_names]
|
||||
@@ -110,17 +110,14 @@ class GoalLogic(BaseLogic):
|
||||
def can_complete_craft_master(self) -> StardewRule:
|
||||
craftsanity_prefix = "Craft "
|
||||
all_recipes_names = []
|
||||
exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true
|
||||
exclude_masteries = not self.content.features.skill_progression.are_masteries_shuffled
|
||||
for location in locations_by_tag[LocationTags.CRAFTSANITY]:
|
||||
if not location.name.startswith(craftsanity_prefix):
|
||||
continue
|
||||
if exclude_island and LocationTags.GINGER_ISLAND in location.tags:
|
||||
continue
|
||||
# FIXME Remove when recipes are in content packs
|
||||
if exclude_masteries and LocationTags.REQUIRES_MASTERIES in location.tags:
|
||||
continue
|
||||
if location.mod_name and location.mod_name not in self.options.mods:
|
||||
if not self.content.are_all_enabled(location.content_packs):
|
||||
continue
|
||||
all_recipes_names.append(location.name[len(craftsanity_prefix):])
|
||||
all_recipes = [all_crafting_recipes_by_name[recipe_name] for recipe_name in all_recipes_names]
|
||||
@@ -133,7 +130,6 @@ class GoalLogic(BaseLogic):
|
||||
other_rules = []
|
||||
number_of_stardrops_to_receive = 0
|
||||
number_of_stardrops_to_receive += 1 # The Mines level 100
|
||||
number_of_stardrops_to_receive += 1 # Old Master Cannoli
|
||||
number_of_stardrops_to_receive += 1 # Museum Stardrop
|
||||
number_of_stardrops_to_receive += 1 # Krobus Stardrop
|
||||
|
||||
@@ -154,11 +150,41 @@ class GoalLogic(BaseLogic):
|
||||
else:
|
||||
other_rules.append(self.logic.relationship.has_hearts_with_any_bachelor(13))
|
||||
|
||||
if ModNames.deepwoods in self.options.mods: # Petting the Unicorn
|
||||
# Old Master Cannoli
|
||||
if SecretsanityOptionName.easy in self.options.secretsanity:
|
||||
number_of_stardrops_to_receive += 1
|
||||
else:
|
||||
other_rules.append(self.logic.has(Fruit.sweet_gem_berry) & self.logic.region.can_reach(Region.secret_woods))
|
||||
|
||||
if self.content.is_enabled(ModNames.deepwoods): # Petting the Unicorn
|
||||
number_of_stardrops_to_receive += 1
|
||||
|
||||
return self.logic.received("Stardrop", number_of_stardrops_to_receive) & self.logic.and_(*other_rules, allow_empty=True)
|
||||
|
||||
def can_complete_mad_hatter(self, all_location_names_in_slot: list[str]) -> StardewRule:
|
||||
if not self.content.features.hatsanity.is_enabled:
|
||||
raise Exception("Cannot play Mad Hatter Goal without Hatsanity")
|
||||
|
||||
rules = []
|
||||
|
||||
for hatsanity_location in locations_by_tag[LocationTags.HATSANITY]:
|
||||
if hatsanity_location.name not in all_location_names_in_slot:
|
||||
continue
|
||||
rules.append(self.logic.region.can_reach_location(hatsanity_location.name))
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
def can_complete_ultimate_foodie(self, all_location_names_in_slot: list[str]) -> StardewRule:
|
||||
if not self.options.eatsanity.value:
|
||||
raise Exception("Cannot play Ultimate Foodie Goal without Eatsanity")
|
||||
|
||||
rules = []
|
||||
|
||||
for eatsanity_location in locations_by_tag[LocationTags.EATSANITY]:
|
||||
if eatsanity_location.name not in all_location_names_in_slot:
|
||||
continue
|
||||
rules.append(self.logic.region.can_reach_location(eatsanity_location.name))
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
def can_complete_allsanity(self) -> StardewRule:
|
||||
return self.logic.has_progress_percent(100)
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
from typing import Union, TYPE_CHECKING
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from .book_logic import BookLogicMixin
|
||||
from .has_logic import HasLogicMixin
|
||||
from .received_logic import ReceivedLogicMixin
|
||||
from .region_logic import RegionLogicMixin
|
||||
from .time_logic import TimeLogicMixin
|
||||
from ..options import ExcludeGingerIsland
|
||||
from ..stardew_rule import StardewRule, HasProgressionPercent
|
||||
from ..strings.book_names import Book
|
||||
from ..strings.craftable_names import Consumable
|
||||
@@ -17,11 +11,6 @@ from ..strings.material_names import Material
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.tool_names import Tool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .tool_logic import ToolLogicMixin
|
||||
else:
|
||||
ToolLogicMixin = object
|
||||
|
||||
MIN_MEDIUM_ITEMS = 10
|
||||
MAX_MEDIUM_ITEMS = 999
|
||||
PERCENT_REQUIRED_FOR_MAX_MEDIUM_ITEM = 24
|
||||
@@ -29,7 +18,7 @@ PERCENT_REQUIRED_FOR_MAX_MEDIUM_ITEM = 24
|
||||
EASY_ITEMS = {Material.wood, Material.stone, Material.fiber, Material.sap}
|
||||
MIN_EASY_ITEMS = 300
|
||||
MAX_EASY_ITEMS = 2997
|
||||
PERCENT_REQUIRED_FOR_MAX_EASY_ITEM = 6
|
||||
PERCENT_REQUIRED_FOR_MAX_EASY_ITEM = 8
|
||||
|
||||
|
||||
class GrindLogicMixin(BaseLogicMixin):
|
||||
@@ -59,9 +48,8 @@ class GrindLogic(BaseLogic):
|
||||
|
||||
def can_grind_prize_tickets(self, quantity: int) -> StardewRule:
|
||||
claiming_rule = self.logic.region.can_reach(Region.mayor_house)
|
||||
return self.logic.and_(claiming_rule, self.logic.has(Currency.prize_ticket),
|
||||
# Assuming two per month if the player does not grind it.
|
||||
self.logic.time.has_lived_months(quantity // 2))
|
||||
help_wanted_rules = self.logic.quest.can_complete_help_wanteds(quantity * 3)
|
||||
return self.logic.and_(claiming_rule, self.logic.has(Currency.prize_ticket), help_wanted_rules)
|
||||
|
||||
def can_grind_fishing_treasure_chests(self, quantity: int) -> StardewRule:
|
||||
return self.logic.and_(self.logic.has(WaterChest.fishing_chest),
|
||||
@@ -73,12 +61,23 @@ class GrindLogic(BaseLogic):
|
||||
# Assuming twelve per month if the player does not grind it.
|
||||
self.logic.time.has_lived_months(quantity // 12))
|
||||
|
||||
def can_grind_weeds(self, quantity: int) -> StardewRule:
|
||||
regions = [Region.farm, Region.town, Region.forest, Region.secret_woods, Region.backwoods, Region.mountain, Region.railroad, Region.mutant_bug_lair]
|
||||
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_false:
|
||||
regions.extend([Region.island_east, Region.island_west])
|
||||
return self.logic.and_(self.logic.tool.has_scythe(),
|
||||
self.logic.region.can_reach_all(*regions),
|
||||
# Assuming 1000 per month if the player does not grind it
|
||||
self.logic.time.has_lived_months(quantity // 1000))
|
||||
|
||||
def can_grind_item(self, quantity: int, item: str | None = None) -> StardewRule:
|
||||
if item in EASY_ITEMS:
|
||||
return self.logic.grind.can_grind_easy_item(quantity)
|
||||
else:
|
||||
if item is None:
|
||||
return self.logic.grind.can_grind_medium_item(quantity)
|
||||
|
||||
if item in EASY_ITEMS:
|
||||
return self.logic.grind.can_grind_easy_item(quantity) & self.logic.has(item)
|
||||
return self.logic.grind.can_grind_medium_item(quantity) & self.logic.has(item)
|
||||
|
||||
@cache_self1
|
||||
def can_grind_medium_item(self, quantity: int) -> StardewRule:
|
||||
if quantity <= MIN_MEDIUM_ITEMS:
|
||||
|
||||
@@ -27,8 +27,14 @@ class HarvestingLogic(BaseLogic):
|
||||
@cache_self1
|
||||
def can_forage_from(self, source: ForagingSource) -> StardewRule:
|
||||
seasons_rule = self.logic.season.has_any(source.seasons)
|
||||
regions_rule = self.logic.region.can_reach_any(source.regions)
|
||||
if source.require_all_regions:
|
||||
regions_rule = self.logic.region.can_reach_all(*source.regions)
|
||||
else:
|
||||
regions_rule = self.logic.region.can_reach_any(*source.regions)
|
||||
if source.grind_months == 0:
|
||||
return seasons_rule & regions_rule
|
||||
else:
|
||||
return seasons_rule & regions_rule & self.logic.time.has_lived_months(source.grind_months)
|
||||
|
||||
@cache_self1
|
||||
def can_harvest_tree_from(self, source: HarvestFruitTreeSource) -> StardewRule:
|
||||
|
||||
28
worlds/stardew_valley/logic/hats_logic.py
Normal file
28
worlds/stardew_valley/logic/hats_logic.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from functools import cached_property
|
||||
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..data.hats_data import HatItem
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.fish_names import Fish
|
||||
from ..strings.region_names import LogicRegion
|
||||
|
||||
|
||||
class HatLogicMixin(BaseLogicMixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.hat = HatLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class HatLogic(BaseLogic):
|
||||
|
||||
@cached_property
|
||||
def can_get_unlikely_hat_at_outfit_services(self) -> StardewRule:
|
||||
return self.logic.region.can_reach(LogicRegion.desert_festival) & self.logic.time.has_lived_months(12)
|
||||
|
||||
@cached_property
|
||||
def has_bucket_hat(self) -> StardewRule:
|
||||
trout_derby_rule = self.logic.region.can_reach(LogicRegion.trout_derby) & self.logic.fishing.can_catch_fish(self.content.fishes[Fish.rainbow_trout])
|
||||
return trout_derby_rule
|
||||
|
||||
def can_wear(self, hat: HatItem) -> StardewRule:
|
||||
return self.logic.has(hat.clarified_name)
|
||||
@@ -17,16 +17,20 @@ from .cooking_logic import CookingLogicMixin
|
||||
from .crafting_logic import CraftingLogicMixin
|
||||
from .farming_logic import FarmingLogicMixin
|
||||
from .festival_logic import FestivalLogicMixin
|
||||
from .fish_pond_logic import FishPondLogicMixin
|
||||
from .fishing_logic import FishingLogicMixin
|
||||
from .gift_logic import GiftLogicMixin
|
||||
from .goal_logic import GoalLogicMixin
|
||||
from .grind_logic import GrindLogicMixin
|
||||
from .harvesting_logic import HarvestingLogicMixin
|
||||
from .has_logic import HasLogicMixin
|
||||
from .logic_event import all_logic_events
|
||||
from .hats_logic import HatLogicMixin
|
||||
from .logic_event import all_item_events
|
||||
from .meme_items_logic import MemeItemsLogicMixin
|
||||
from .mine_logic import MineLogicMixin
|
||||
from .money_logic import MoneyLogicMixin
|
||||
from .monster_logic import MonsterLogicMixin
|
||||
from .movie_logic import MovieLogicMixin
|
||||
from .museum_logic import MuseumLogicMixin
|
||||
from .pet_logic import PetLogicMixin
|
||||
from .quality_logic import QualityLogicMixin
|
||||
@@ -37,28 +41,34 @@ from .relationship_logic import RelationshipLogicMixin
|
||||
from .requirement_logic import RequirementLogicMixin
|
||||
from .season_logic import SeasonLogicMixin
|
||||
from .shipping_logic import ShippingLogicMixin
|
||||
from .shirts_logic import ShirtLogicMixin
|
||||
from .skill_logic import SkillLogicMixin
|
||||
from .source_logic import SourceLogicMixin
|
||||
from .special_items_logic import SpecialItemsLogicMixin
|
||||
from .special_order_logic import SpecialOrderLogicMixin
|
||||
from .tailoring_logic import TailoringLogicMixin
|
||||
from .time_logic import TimeLogicMixin
|
||||
from .tool_logic import ToolLogicMixin
|
||||
from .traveling_merchant_logic import TravelingMerchantLogicMixin
|
||||
from .wallet_logic import WalletLogicMixin
|
||||
from .walnut_logic import WalnutLogicMixin
|
||||
from ..content.game_content import StardewContent
|
||||
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||
from ..data.craftable_data import all_crafting_recipes
|
||||
from ..data.museum_data import all_museum_items
|
||||
from ..data.recipe_data import all_cooking_recipes
|
||||
from ..mods.logic.magic_logic import MagicLogicMixin
|
||||
from ..mods.logic.mod_logic import ModLogicMixin
|
||||
from ..options import ExcludeGingerIsland, StardewValleyOptions
|
||||
from ..stardew_rule import False_, True_, StardewRule
|
||||
from ..options import StardewValleyOptions, BundleRandomization, IncludeEndgameLocations
|
||||
from ..stardew_rule import False_, StardewRule, Or, Reach
|
||||
from ..strings.animal_names import Animal
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.boot_names import tier_by_boots
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.craftable_names import Consumable, Ring, Fishing, Lighting, WildSeeds
|
||||
from ..strings.catalogue_names import items_by_catalogue
|
||||
from ..strings.craftable_names import Consumable, Ring, Fishing, Lighting, WildSeeds, Furniture
|
||||
from ..strings.crop_names import Fruit, Vegetable
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.decoration_names import Decoration
|
||||
@@ -73,16 +83,16 @@ from ..strings.gift_names import Gift
|
||||
from ..strings.ingredient_names import Ingredient
|
||||
from ..strings.machine_names import Machine
|
||||
from ..strings.material_names import Material
|
||||
from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil, Artifact
|
||||
from ..strings.metal_names import Ore, MetalBar, Mineral, Fossil
|
||||
from ..strings.monster_drop_names import Loot
|
||||
from ..strings.monster_names import Monster
|
||||
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
|
||||
from ..strings.special_item_names import SpecialItem
|
||||
from ..strings.tool_names import Tool, ToolMaterial, FishingRod
|
||||
from ..strings.villager_names import NPC
|
||||
from ..strings.wallet_item_names import Wallet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -93,7 +103,8 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin,
|
||||
SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin,
|
||||
SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin,
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, FestivalLogicMixin, WalnutLogicMixin, GoalLogicMixin):
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, FestivalLogicMixin, WalnutLogicMixin, GoalLogicMixin, SpecialItemsLogicMixin,
|
||||
MovieLogicMixin, MemeItemsLogicMixin, HatLogicMixin, ShirtLogicMixin, TailoringLogicMixin, FishPondLogicMixin):
|
||||
player: int
|
||||
options: StardewValleyOptions
|
||||
content: StardewContent
|
||||
@@ -107,15 +118,16 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
self.registry.museum_rules.update({donation.item_name: self.museum.can_find_museum_item(donation) for donation in all_museum_items})
|
||||
|
||||
for recipe in all_cooking_recipes:
|
||||
if recipe.mod_name and recipe.mod_name not in self.options.mods:
|
||||
if recipe.content_pack and not self.content.is_enabled(recipe.content_pack):
|
||||
continue
|
||||
|
||||
can_cook_rule = self.cooking.can_cook(recipe)
|
||||
if recipe.meal in self.registry.cooking_rules:
|
||||
can_cook_rule = can_cook_rule | self.registry.cooking_rules[recipe.meal]
|
||||
self.registry.cooking_rules[recipe.meal] = can_cook_rule
|
||||
|
||||
for recipe in all_crafting_recipes:
|
||||
if recipe.mod_name and recipe.mod_name not in self.options.mods:
|
||||
if recipe.content_pack is not None and not self.content.are_all_enabled(recipe.content_pack):
|
||||
continue
|
||||
can_craft_rule = self.crafting.can_craft(recipe)
|
||||
if recipe.item in self.registry.crafting_rules:
|
||||
@@ -145,11 +157,14 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
"Junimo Kart Small Buff": self.arcade.has_junimo_kart_power_level(2),
|
||||
"Magic Rock Candy": self.region.can_reach(Region.desert) & self.has("Prismatic Shard"),
|
||||
"Muscle Remedy": self.money.can_spend_at(Region.hospital, 1000),
|
||||
"Stardrop": self.received("Stardrop"),
|
||||
"Iridium Snake Milk": self.quest.can_drink_snake_milk(),
|
||||
# self.has(Ingredient.vinegar)),
|
||||
# self.received("Deluxe Fertilizer Recipe") & self.has(MetalBar.iridium) & self.has(SVItem.sap),
|
||||
# | (self.ability.can_cook() & self.relationship.has_hearts(NPC.emily, 3) & self.has(Forageable.leek) & self.has(Forageable.dandelion) &
|
||||
# | (self.ability.can_cook() & self.relationship.has_hearts(NPC.jodi, 7) & self.has(AnimalProduct.cow_milk) & self.has(Ingredient.sugar)),
|
||||
AnimalProduct.any_egg: self.has_any(AnimalProduct.chicken_egg, AnimalProduct.duck_egg),
|
||||
AnimalProduct.any_milk: self.has_any(AnimalProduct.cow_milk, AnimalProduct.goat_milk),
|
||||
AnimalProduct.brown_egg: self.animal.has_animal(Animal.chicken),
|
||||
AnimalProduct.chicken_egg: self.has_any(AnimalProduct.egg, AnimalProduct.brown_egg, AnimalProduct.large_egg, AnimalProduct.large_brown_egg),
|
||||
AnimalProduct.cow_milk: self.has_any(AnimalProduct.milk, AnimalProduct.large_milk),
|
||||
@@ -164,9 +179,8 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
AnimalProduct.large_milk: self.animal.has_happy_animal(Animal.cow),
|
||||
AnimalProduct.milk: self.animal.has_animal(Animal.cow),
|
||||
AnimalProduct.rabbit_foot: self.animal.has_happy_animal(Animal.rabbit),
|
||||
AnimalProduct.roe: self.fishing.can_fish_anywhere() & self.building.has_building(Building.fish_pond),
|
||||
AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | (self.building.has_building(Building.fish_pond) & self.has(Fish.squid)),
|
||||
AnimalProduct.sturgeon_roe: self.has(Fish.sturgeon) & self.building.has_building(Building.fish_pond),
|
||||
AnimalProduct.roe: self.fish_pond.can_get_fish_pond_reward(Fish.any, 1, AnimalProduct.roe),
|
||||
AnimalProduct.squid_ink: self.mine.can_mine_in_the_mines_floor_81_120() | self.fish_pond.can_get_fish_pond_reward(Fish.squid, 1, AnimalProduct.squid_ink) | self.fish_pond.can_get_fish_pond_reward(Fish.midnight_squid, 1, AnimalProduct.squid_ink),
|
||||
AnimalProduct.truffle: self.animal.has_animal(Animal.pig) & self.season.has_any_not_winter(),
|
||||
AnimalProduct.void_egg: self.has(AnimalProduct.void_egg_starter), # Should also check void chicken if there was an alternative to obtain it without void egg
|
||||
AnimalProduct.wool: self.animal.has_animal(Animal.rabbit) | self.animal.has_animal(Animal.sheep),
|
||||
@@ -174,18 +188,17 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
AnimalProduct.slime_egg_blue: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(3),
|
||||
AnimalProduct.slime_egg_red: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(6),
|
||||
AnimalProduct.slime_egg_purple: self.has(Machine.slime_egg_press) & self.has(Loot.slime) & self.time.has_lived_months(9),
|
||||
AnimalProduct.slime_egg_tiger: self.can_fish_pond(Fish.lionfish, *(Forageable.ginger, Fruit.pineapple, Fruit.mango)) & self.time.has_lived_months(12) &
|
||||
AnimalProduct.slime_egg_tiger: self.fish_pond.can_get_fish_pond_reward(Fish.lionfish, 9, AnimalProduct.slime_egg_tiger) & self.time.has_lived_months(12) &
|
||||
self.building.has_building(Building.slime_hutch) & self.monster.can_kill(Monster.tiger_slime),
|
||||
AnimalProduct.duck_egg_starter: self.logic.false_, # It could be purchased at the Feast of the Winter Star, but it's random every year, so not considering it yet...
|
||||
AnimalProduct.dinosaur_egg_starter: self.logic.false_, # Dinosaur eggs are also part of the museum rules, and I don't want to touch them yet.
|
||||
AnimalProduct.egg_starter: self.logic.false_, # It could be purchased at the Desert Festival, but festival logic is quite a mess, so not considering it yet...
|
||||
AnimalProduct.golden_egg_starter: self.received(AnimalProduct.golden_egg) & (self.money.can_spend_at(Region.ranch, 100000) | self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 100)),
|
||||
AnimalProduct.void_egg_starter: self.money.can_spend_at(Region.sewer, 5000) | (self.building.has_building(Building.fish_pond) & self.has(Fish.void_salmon)),
|
||||
AnimalProduct.void_egg_starter: self.money.can_spend_at(Region.sewer, 5000),
|
||||
ArtisanGood.aged_roe: self.artisan.can_preserves_jar(AnimalProduct.roe),
|
||||
ArtisanGood.battery_pack: (self.has(Machine.lightning_rod) & self.season.has_any_not_winter()) | self.has(Machine.solar_panel),
|
||||
ArtisanGood.caviar: self.artisan.can_preserves_jar(AnimalProduct.sturgeon_roe),
|
||||
ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.region.can_reach(Region.desert) & self.has(Mineral.emerald)),
|
||||
ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.region.can_reach(Region.desert) & self.has(Mineral.aquamarine)),
|
||||
ArtisanGood.cheese: (self.has(AnimalProduct.cow_milk) & self.has(Machine.cheese_press)) | (self.region.can_reach(Region.desert) & self.artisan.can_replicate_gem(Mineral.emerald)),
|
||||
ArtisanGood.cloth: (self.has(AnimalProduct.wool) & self.has(Machine.loom)) | (self.region.can_reach(Region.desert) & self.artisan.can_replicate_gem(Mineral.aquamarine)),
|
||||
ArtisanGood.dinosaur_mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.dinosaur_egg),
|
||||
ArtisanGood.duck_mayonnaise: self.artisan.can_mayonnaise(AnimalProduct.duck_egg),
|
||||
ArtisanGood.goat_cheese: self.has(AnimalProduct.goat_milk) & self.has(Machine.cheese_press),
|
||||
@@ -203,11 +216,10 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
Beverage.pina_colada: self.money.can_spend_at(Region.island_resort, 600),
|
||||
Beverage.triple_shot_espresso: self.has("Hot Java Ring"),
|
||||
Consumable.butterfly_powder: self.money.can_spend_at(Region.sewer, 20000),
|
||||
Consumable.far_away_stone: self.region.can_reach(Region.mines_floor_100) & self.has(Artifact.ancient_doll),
|
||||
Consumable.fireworks_red: self.region.can_reach(Region.casino),
|
||||
Consumable.fireworks_purple: self.region.can_reach(Region.casino),
|
||||
Consumable.fireworks_green: self.region.can_reach(Region.casino),
|
||||
Consumable.golden_animal_cracker: self.skill.has_mastery(Skill.farming),
|
||||
Consumable.golden_animal_cracker: self.skill.has_mastery(Skill.farming) & (self.fishing.can_fish_chests | self.region.can_reach(Region.skull_cavern_25)),
|
||||
Consumable.mystery_box: self.received(CommunityUpgrade.mr_qi_plane_ride),
|
||||
Consumable.gold_mystery_box: self.received(CommunityUpgrade.mr_qi_plane_ride) & self.skill.has_mastery(Skill.foraging),
|
||||
Currency.calico_egg: self.region.can_reach(LogicRegion.desert_festival),
|
||||
@@ -229,30 +241,32 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
Fish.snail: self.fishing.can_crab_pot_at(Region.town),
|
||||
Fishing.curiosity_lure: self.monster.can_kill(self.monster.all_monsters_by_name[Monster.mummy]),
|
||||
Fishing.lead_bobber: self.skill.has_level(Skill.fishing, 6) & self.money.can_spend_at(Region.fish_shop, 200),
|
||||
Forageable.hay: self.building.has_building(Building.silo) & self.tool.has_tool(Tool.scythe), #
|
||||
Forageable.journal_scrap: self.region.can_reach_all((Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10)) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()),#
|
||||
Forageable.secret_note: self.quest.has_magnifying_glass() & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()), #
|
||||
Fishing.golden_bobber: self.region.can_reach(LogicRegion.desert_festival) & self.fishing.can_fish_chests,
|
||||
Forageable.hay: self.building.has_building(Building.silo) & self.tool.has_scythe(), #
|
||||
Forageable.journal_scrap: self.region.can_reach_all(Region.island_west, Region.island_north, Region.island_south, Region.volcano_floor_10) & (self.ability.can_chop_trees() | self.mine.can_mine_in_the_mines_floor_1_40()),#
|
||||
Forageable.secret_note: self.region.can_reach(LogicRegion.secret_notes), #
|
||||
Fossil.bone_fragment: (self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe)) | self.monster.can_kill(Monster.skeleton),
|
||||
Fossil.fossilized_leg: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.pickaxe),
|
||||
Fossil.fossilized_ribs: self.region.can_reach(Region.island_south) & self.tool.has_tool(Tool.hoe) & self.received("Open Professor Snail Cave"),
|
||||
Fossil.fossilized_skull: self.action.can_open_geode(Geode.golden_coconut),
|
||||
Fossil.fossilized_spine: self.fishing.can_fish_at(Region.dig_site),
|
||||
Fossil.fossilized_tail: self.action.can_pan_at(Region.dig_site, ToolMaterial.copper),
|
||||
Fossil.fossilized_tail: self.action.can_pan_at(Region.dig_site, ToolMaterial.iridium),
|
||||
Fossil.mummified_bat: self.region.can_reach(Region.volcano_floor_10),
|
||||
Fossil.mummified_frog: self.region.can_reach(Region.island_east) & self.tool.has_tool(Tool.scythe),
|
||||
Fossil.mummified_frog: self.region.can_reach(Region.island_east) & self.tool.has_scythe(),
|
||||
Fossil.snake_skull: self.region.can_reach(Region.dig_site) & self.tool.has_tool(Tool.hoe),
|
||||
Fossil.snake_vertebrae: self.region.can_reach(Region.island_west) & self.tool.has_tool(Tool.hoe),
|
||||
Furniture.exotic_double_bed: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 50),
|
||||
Geode.artifact_trove: self.has(Geode.omni) & self.region.can_reach(Region.desert),
|
||||
Geode.frozen: self.mine.can_mine_in_the_mines_floor_41_80(),
|
||||
Geode.geode: self.mine.can_mine_in_the_mines_floor_1_40(),
|
||||
Geode.golden_coconut: self.region.can_reach(Region.island_north),
|
||||
Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120() | (self.has(Fish.lava_eel) & self.building.has_building(Building.fish_pond)),
|
||||
Geode.omni: self.mine.can_mine_in_the_mines_floor_41_80() | self.region.can_reach(Region.desert) | self.tool.has_tool(Tool.pan, ToolMaterial.iron) | self.received(Wallet.rusty_key) | (self.has(Fish.octopus) & self.building.has_building(Building.fish_pond)) | self.region.can_reach(Region.volcano_floor_10),
|
||||
Geode.magma: self.mine.can_mine_in_the_mines_floor_81_120(), # Could add self.fish_pond.can_get_fish_pond_reward(Fish.lava_eel, 9, Geode.magma) but it makes a logic loop
|
||||
Geode.omni: self.count(2, *(self.mine.can_mine_in_the_mines_floor_81_120(), self.region.can_reach_all((Region.desert, Region.oasis, Region.sewer)), self.tool.has_pan(ToolMaterial.iron), (self.region.can_reach_all((Region.island_west, Region.island_north,)) & self.has(Consumable.treasure_totem)))), # Could add self.fish_pond.can_get_fish_pond_reward(Fish.octopus, 9, Geode.omni) but it makes a logic loop
|
||||
Gift.bouquet: self.relationship.has_hearts_with_any_bachelor(8) & self.money.can_spend_at(Region.pierre_store, 100),
|
||||
Gift.golden_pumpkin: self.season.has(Season.fall) | self.action.can_open_geode(Geode.artifact_trove),
|
||||
Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts_with_any_bachelor(10) & self.building.has_building(Building.kitchen) & self.has(Consumable.rain_totem),
|
||||
Gift.golden_pumpkin: self.festival.has_golden_pumpkin(),
|
||||
Gift.mermaid_pendant: self.region.can_reach(Region.tide_pools) & self.relationship.has_hearts_with_any_bachelor(10) & self.building.has_building(Building.kitchen) & (self.has(Consumable.rain_totem) | self.season.has_any_not_winter()),
|
||||
Gift.movie_ticket: self.money.can_spend_at(Region.movie_ticket_stand, 1000),
|
||||
Gift.pearl: (self.has(Fish.blobfish) & self.building.has_building(Building.fish_pond)) | self.action.can_open_geode(Geode.artifact_trove),
|
||||
Gift.pearl: self.fish_pond.can_get_fish_pond_reward(Fish.blobfish, 9, Gift.pearl) | self.action.can_open_geode(Geode.artifact_trove),
|
||||
Gift.tea_set: self.season.has(Season.winter) & self.time.has_lived_max_months,
|
||||
Gift.void_ghost_pendant: self.money.can_trade_at(Region.desert, Loot.void_essence, 200) & self.relationship.has_hearts(NPC.krobus, 10),
|
||||
Gift.wilted_bouquet: self.has(Machine.furnace) & self.has(Gift.bouquet) & self.has(Material.coal),
|
||||
@@ -271,15 +285,17 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
Machine.crab_pot: self.skill.has_level(Skill.fishing, 3) & self.money.can_spend_at(Region.fish_shop, 1500),
|
||||
Machine.enricher: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20),
|
||||
Machine.pressure_nozzle: self.money.can_trade_at(Region.qi_walnut_room, Currency.qi_gem, 20),
|
||||
Machine.sewing_machine: (self.region.can_reach(Region.haley_house) & self.has(ArtisanGood.cloth)) | (self.received(Machine.sewing_machine) & self.region.can_reach(Region.secret_woods)),
|
||||
Machine.statue_endless_fortune: self.has_statue_of_endless_fortune(),
|
||||
Material.cinder_shard: self.region.can_reach(Region.volcano_floor_5),
|
||||
Material.clay: self.region.can_reach_any((Region.farm, Region.beach, Region.quarry)) & self.tool.has_tool(Tool.hoe),
|
||||
Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.tool.has_tool(Tool.pan),
|
||||
Material.fiber: True_(),
|
||||
Material.clay: self.region.can_reach_any(Region.farm, Region.beach, Region.quarry) & self.tool.has_tool(Tool.hoe),
|
||||
Material.coal: self.mine.can_mine_in_the_mines_floor_41_80() | self.tool.has_pan(),
|
||||
Material.fiber: self.ability.can_scythe_vines(),
|
||||
Material.hardwood: self.tool.has_tool(Tool.axe, ToolMaterial.copper) & (self.region.can_reach(Region.secret_woods) | self.region.can_reach(Region.island_west)),
|
||||
Material.moss: self.season.has_any_not_winter() & (self.tool.has_tool(Tool.scythe) | self.combat.has_any_weapon) & self.region.can_reach(Region.forest),
|
||||
Material.moss: self.season.has_any_not_winter() & (self.tool.has_scythe() | self.combat.has_any_weapon) & self.region.can_reach(Region.forest),
|
||||
Material.sap: self.ability.can_chop_trees(),
|
||||
Material.stone: self.tool.has_tool(Tool.pickaxe),
|
||||
Material.wood: self.tool.has_tool(Tool.axe),
|
||||
Material.stone: self.ability.can_mine_stone(),
|
||||
Material.wood: self.ability.can_chop_trees(),
|
||||
Meal.ice_cream: (self.season.has(Season.summer) & self.money.can_spend_at(Region.town, 250)) | self.money.can_spend_at(Region.oasis, 240),
|
||||
Meal.strange_bun: self.relationship.has_hearts(NPC.shane, 7) & self.has(Ingredient.wheat_flour) & self.has(Fish.periwinkle) & self.has(ArtisanGood.void_mayonnaise),
|
||||
MetalBar.copper: self.can_smelt(Ore.copper),
|
||||
@@ -288,13 +304,19 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
MetalBar.iron: self.can_smelt(Ore.iron),
|
||||
MetalBar.quartz: self.can_smelt(Mineral.quartz) | self.can_smelt("Fire Quartz") | (self.has(Machine.recycling_machine) & (self.has(Trash.broken_cd) | self.has(Trash.broken_glasses))),
|
||||
MetalBar.radioactive: self.can_smelt(Ore.radioactive),
|
||||
Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_tool(Tool.pan, ToolMaterial.copper),
|
||||
Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_tool(Tool.pan, ToolMaterial.gold),
|
||||
Ore.iridium: self.count(2, *(self.mine.can_mine_in_the_skull_cavern(), self.can_fish_pond(Fish.super_cucumber), self.tool.has_tool(Tool.pan, ToolMaterial.iridium))),
|
||||
Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_tool(Tool.pan, ToolMaterial.iron),
|
||||
Ore.radioactive: self.ability.can_mine_perfectly() & self.region.can_reach(Region.qi_walnut_room),
|
||||
Mineral.any_gem: self.museum.has_any_gem(),
|
||||
Ore.copper: self.mine.can_mine_in_the_mines_floor_1_40() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_pan(),
|
||||
Ore.gold: self.mine.can_mine_in_the_mines_floor_81_120() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_pan(ToolMaterial.gold),
|
||||
Ore.iridium: self.ability.can_mine_perfectly_in_the_skull_cavern() | (self.mine.can_mine_in_the_skull_cavern() & self.tool.has_pan(ToolMaterial.gold)), # Could add self.fish_pond.can_get_fish_pond_reward(Fish.super_cucumber, 9, Ore.iridium) but it makes a logic loop
|
||||
Ore.iron: self.mine.can_mine_in_the_mines_floor_41_80() | self.mine.can_mine_in_the_skull_cavern() | self.tool.has_pan(ToolMaterial.iron),
|
||||
Ore.radioactive: self.special_order.can_get_radioactive_ore(),
|
||||
RetainingSoil.basic: self.money.can_spend_at(Region.pierre_store, 100),
|
||||
RetainingSoil.quality: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150),
|
||||
SpecialItem.lucky_purple_shorts: self.special_items.has_purple_shorts(),
|
||||
SpecialItem.trimmed_purple_shorts: self.has(SpecialItem.lucky_purple_shorts) & self.has(Machine.sewing_machine),
|
||||
SpecialItem.far_away_stone: self.special_items.has_far_away_stone(),
|
||||
SpecialItem.solid_gold_lewis: self.special_items.has_solid_gold_lewis(),
|
||||
SpecialItem.advanced_tv_remote: self.special_items.has_advanced_tv_remote(),
|
||||
SpeedGro.basic: self.money.can_spend_at(Region.pierre_store, 100),
|
||||
SpeedGro.deluxe: self.time.has_year_two & self.money.can_spend_at(Region.pierre_store, 150),
|
||||
Trash.broken_cd: self.fishing.can_crab_pot_anywhere,
|
||||
@@ -312,11 +334,11 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
Fish.clam: self.tool.can_forage(Generic.any, Region.beach),
|
||||
Fish.cockle: self.tool.can_forage(Generic.any, Region.beach),
|
||||
WaterItem.green_algae: self.fishing.can_fish_in_freshwater(),
|
||||
WaterItem.cave_jelly: self.fishing.can_fish_at(Region.mines_floor_100) & self.tool.has_fishing_rod(2),
|
||||
WaterItem.river_jelly: self.fishing.can_fish_at(Region.town) & self.tool.has_fishing_rod(2),
|
||||
WaterItem.sea_jelly: self.fishing.can_fish_at(Region.beach) & self.tool.has_fishing_rod(2),
|
||||
WaterItem.cave_jelly: self.fishing.can_fish_at(Region.mines_floor_100) & self.tool.has_fishing_rod(FishingRod.bamboo),
|
||||
WaterItem.river_jelly: self.fishing.can_fish_at(Region.town) & self.tool.has_fishing_rod(FishingRod.bamboo),
|
||||
WaterItem.sea_jelly: self.fishing.can_fish_at(Region.beach) & self.tool.has_fishing_rod(FishingRod.bamboo),
|
||||
WaterItem.seaweed: self.fishing.can_fish_at(Region.tide_pools),
|
||||
WaterItem.white_algae: self.fishing.can_fish_at(Region.mines_floor_20),
|
||||
WaterItem.white_algae: self.fishing.can_fish_at(Region.mines_floor_20) & self.tool.has_fishing_rod(FishingRod.bamboo),
|
||||
WildSeeds.grass_starter: self.money.can_spend_at(Region.pierre_store, 100),
|
||||
})
|
||||
# @formatter:on
|
||||
@@ -351,6 +373,10 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
obtention_rule = self.registry.item_rules[recipe] if recipe in self.registry.item_rules else False_()
|
||||
self.registry.item_rules[recipe] = obtention_rule | crafting_rule
|
||||
|
||||
if self.options.bundle_randomization == BundleRandomization.option_meme:
|
||||
self.meme.initialize_rules()
|
||||
self.registry.item_rules.update(self.registry.meme_item_rules)
|
||||
|
||||
self.quest.initialize_rules()
|
||||
self.quest.update_rules(self.mod.quest.get_modded_quest_rules())
|
||||
|
||||
@@ -359,31 +385,59 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
self.special_order.initialize_rules()
|
||||
self.special_order.update_rules(self.mod.special_order.get_modded_special_orders_rules())
|
||||
|
||||
self.shirt.initialize_rules()
|
||||
self.registry.item_rules.update(self.registry.shirt_rules)
|
||||
|
||||
for catalogue in items_by_catalogue:
|
||||
for item in items_by_catalogue[catalogue]:
|
||||
self.registry.item_rules[item] = self.has(catalogue)
|
||||
|
||||
for boots in tier_by_boots:
|
||||
self.registry.item_rules[boots] = self.combat.has_specific_boots(boots)
|
||||
|
||||
def setup_events(self, register_event: Callable[[str, str, StardewRule], None]) -> None:
|
||||
for logic_event in all_logic_events:
|
||||
rule = self.registry.item_rules[logic_event.item]
|
||||
register_event(logic_event.name, logic_event.region, rule)
|
||||
self.registry.item_rules[logic_event.item] = self.received(logic_event.name)
|
||||
for item_event in all_item_events:
|
||||
rule = self.registry.item_rules[item_event.item]
|
||||
|
||||
if isinstance(rule, Or) and bool(reaches := [r for r in rule.current_rules if isinstance(r, Reach) and r.resolution_hint == "Region"]):
|
||||
logger.debug("Sharding rule for %s in multiple logic events, placed in %s.", item_event.item, [r.spot for r in reaches])
|
||||
|
||||
for i, reach in enumerate(reaches):
|
||||
location_name = f"{item_event.name} sharded_{i}"
|
||||
new_rule = self.region.can_reach(item_event.region)
|
||||
register_event(item_event.name, reach.spot, new_rule, location_name=location_name)
|
||||
|
||||
remaining_rules = [r for r in rule.current_rules if not isinstance(r, Reach) or r.resolution_hint != "Region"]
|
||||
if remaining_rules:
|
||||
register_event(item_event.name, item_event.region, Or(*remaining_rules))
|
||||
|
||||
else:
|
||||
register_event(item_event.name, item_event.region, rule)
|
||||
|
||||
self.registry.item_rules[item_event.item] = self.received(item_event.name)
|
||||
|
||||
def can_smelt(self, item: str) -> StardewRule:
|
||||
return self.has(Machine.furnace) & self.has(item)
|
||||
|
||||
def has_island_trader(self) -> StardewRule:
|
||||
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
return False_()
|
||||
if self.content.is_enabled(ginger_island_content_pack):
|
||||
return self.region.can_reach(Region.island_trader)
|
||||
return self.logic.false_
|
||||
|
||||
def has_abandoned_jojamart(self) -> StardewRule:
|
||||
return self.received(CommunityUpgrade.movie_theater, 1)
|
||||
return (self.received(CommunityUpgrade.movie_theater, 1) & self.season.has_any_not_winter()) | self.has_movie_theater()
|
||||
|
||||
def has_movie_theater(self) -> StardewRule:
|
||||
return self.received(CommunityUpgrade.movie_theater, 2)
|
||||
|
||||
def can_use_obelisk(self, obelisk: str) -> StardewRule:
|
||||
return self.region.can_reach(Region.farm) & self.received(obelisk)
|
||||
return self.region.can_reach(Region.farm) & self.building.has_wizard_building(obelisk)
|
||||
|
||||
def can_fish_pond(self, fish: str, *items: str) -> StardewRule:
|
||||
rule = self.building.has_building(Building.fish_pond) & self.has(fish)
|
||||
if items:
|
||||
rule = rule & self.has_all(*items)
|
||||
return rule
|
||||
def can_purchase_statue_of_endless_fortune(self) -> StardewRule:
|
||||
return self.money.can_spend_at(Region.casino, 1_000_000)
|
||||
|
||||
def has_statue_of_endless_fortune(self) -> StardewRule:
|
||||
can_purchase_rule = self.can_purchase_statue_of_endless_fortune()
|
||||
if self.options.include_endgame_locations == IncludeEndgameLocations.option_true:
|
||||
return can_purchase_rule & self.received(Machine.statue_endless_fortune)
|
||||
return can_purchase_rule
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from ..strings.ap_names import event_names
|
||||
from ..strings.material_names import Material
|
||||
from ..strings.metal_names import MetalBar, Ore
|
||||
from ..strings.region_names import Region
|
||||
|
||||
all_events = event_names.all_events.copy()
|
||||
all_logic_events = list()
|
||||
all_item_events: list[LogicItemEvent] = list()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -25,9 +28,9 @@ class LogicItemEvent(LogicEvent):
|
||||
|
||||
def register_item_event(item: str, region: str = Region.farm):
|
||||
event = LogicItemEvent(item, region)
|
||||
all_logic_events.append(event)
|
||||
all_item_events.append(event)
|
||||
all_events.add(event.name)
|
||||
|
||||
|
||||
for i in (MetalBar.copper, MetalBar.iron, MetalBar.gold, MetalBar.iridium, Ore.copper, Ore.iron, Ore.gold, Ore.iridium):
|
||||
for i in (Material.coal, MetalBar.copper, MetalBar.iron, MetalBar.gold, MetalBar.iridium, Ore.copper, Ore.iron, Ore.gold, Ore.iridium):
|
||||
register_item_event(i)
|
||||
|
||||
57
worlds/stardew_valley/logic/meme_items_logic.py
Normal file
57
worlds/stardew_valley/logic/meme_items_logic.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..data.game_item import ItemTag
|
||||
from ..strings.ap_names.ap_weapon_names import APWeapon
|
||||
from ..strings.meme_item_names import MemeItem
|
||||
from ..strings.ring_names import all_ring_names
|
||||
from ..strings.special_item_names import NotReallyAnItem
|
||||
|
||||
|
||||
class MemeItemsLogicMixin(BaseLogicMixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.meme = MemeItemsLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class MemeItemsLogic(BaseLogic):
|
||||
|
||||
def initialize_rules(self):
|
||||
self.registry.meme_item_rules.update({
|
||||
MemeItem.trap: self.logic.true_,
|
||||
MemeItem.pot_of_gold: self.can_cheat(),
|
||||
MemeItem.seed_spot: self.can_cheat(),
|
||||
MemeItem.green_rain_weeds_0: self.can_cheat(),
|
||||
MemeItem.lumber: self.can_cheat(),
|
||||
MemeItem.weeds: self.can_cheat(),
|
||||
MemeItem.twig: self.can_cheat(),
|
||||
MemeItem.artifact_spot: self.can_cheat(),
|
||||
MemeItem.warp_totem_qis_arena: self.can_cheat(),
|
||||
MemeItem.supply_crate: self.can_cheat(),
|
||||
MemeItem.slime_crate: self.can_cheat(),
|
||||
MemeItem.decorative_pot: self.can_cheat(),
|
||||
MemeItem.camping_stove: self.can_cheat(),
|
||||
MemeItem.worn_pants: self.has_any_pants(),
|
||||
MemeItem.worn_left_ring: self.has_any_ring(),
|
||||
MemeItem.worn_right_ring: self.has_any_ring(),
|
||||
MemeItem.worn_shirt: self.has_any_shirt(),
|
||||
MemeItem.worn_boots: self.has_any_boots(),
|
||||
MemeItem.worn_hat: self.has_any_hat(),
|
||||
NotReallyAnItem.death: self.logic.true_,
|
||||
})
|
||||
|
||||
def can_cheat(self):
|
||||
return self.logic.true_
|
||||
|
||||
def has_any_pants(self):
|
||||
return self.logic.true_
|
||||
|
||||
def has_any_shirt(self):
|
||||
return self.logic.true_
|
||||
|
||||
def has_any_hat(self):
|
||||
return self.logic.has_any(*[item.name for item in self.content.find_tagged_items(ItemTag.HAT)])
|
||||
|
||||
def has_any_ring(self):
|
||||
return self.logic.received_any(*all_ring_names)
|
||||
|
||||
def has_any_boots(self):
|
||||
return self.logic.received(APWeapon.footwear)
|
||||
@@ -2,6 +2,7 @@ from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from .. import options
|
||||
from ..stardew_rule import StardewRule, True_
|
||||
from ..strings.ap_names.ap_option_names import CustomLogicOptionName
|
||||
from ..strings.performance_names import Performance
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.skill_names import Skill
|
||||
@@ -26,8 +27,7 @@ class MineLogic(BaseLogic):
|
||||
return self.logic.region.can_reach(Region.mines_floor_85)
|
||||
|
||||
def can_mine_in_the_skull_cavern(self) -> StardewRule:
|
||||
return (self.logic.mine.can_progress_in_the_mines_from_floor(120) &
|
||||
self.logic.region.can_reach(Region.skull_cavern))
|
||||
return self.logic.region.can_reach(Region.skull_cavern_mining)
|
||||
|
||||
@cache_self1
|
||||
def get_weapon_rule_for_floor_tier(self, tier: int):
|
||||
@@ -43,23 +43,40 @@ class MineLogic(BaseLogic):
|
||||
|
||||
@cache_self1
|
||||
def can_progress_in_the_mines_from_floor(self, floor: int) -> StardewRule:
|
||||
tier = floor // 40
|
||||
assert floor >= 0
|
||||
# 0-39, 40-79, 80-119
|
||||
mine_tier = floor // 40
|
||||
combat_tier = mine_tier
|
||||
rules = []
|
||||
|
||||
weapon_rule = self.logic.mine.get_weapon_rule_for_floor_tier(tier)
|
||||
if CustomLogicOptionName.extreme_combat in self.options.custom_logic:
|
||||
combat_tier -= 2
|
||||
elif CustomLogicOptionName.hard_combat in self.options.custom_logic:
|
||||
combat_tier -= 1
|
||||
elif CustomLogicOptionName.easy_combat in self.options.custom_logic:
|
||||
combat_tier += 1
|
||||
combat_tier = max(0, combat_tier)
|
||||
|
||||
if CustomLogicOptionName.extreme_mining in self.options.custom_logic:
|
||||
mine_tier -= 2
|
||||
elif CustomLogicOptionName.hard_mining in self.options.custom_logic:
|
||||
mine_tier -= 1
|
||||
elif self.options.tool_progression.is_progressive and CustomLogicOptionName.easy_mining in self.options.custom_logic:
|
||||
mine_tier += 1
|
||||
mine_tier = max(0, mine_tier)
|
||||
|
||||
weapon_rule = self.logic.mine.get_weapon_rule_for_floor_tier(combat_tier)
|
||||
rules.append(weapon_rule)
|
||||
|
||||
tool_rule = self.logic.tool.can_mine_using(ToolMaterial.tiers[tier])
|
||||
tool_rule = self.logic.tool.can_mine_using(ToolMaterial.tiers[min(5, mine_tier + 1)])
|
||||
rules.append(tool_rule)
|
||||
|
||||
# No alternative for vanilla because we assume that you will grind the levels in the mines.
|
||||
if self.content.features.skill_progression.is_progressive:
|
||||
skill_level = min(10, max(0, tier * 2))
|
||||
rules.append(self.logic.skill.has_level(Skill.combat, skill_level))
|
||||
rules.append(self.logic.skill.has_level(Skill.mining, skill_level))
|
||||
|
||||
if tier >= 4:
|
||||
rules.append(self.logic.cooking.can_cook())
|
||||
combat_level = min(10, max(0, mine_tier * 2))
|
||||
mining_level = min(10, max(0, mine_tier * 2))
|
||||
rules.append(self.logic.skill.has_level(Skill.combat, combat_level))
|
||||
rules.append(self.logic.skill.has_level(Skill.mining, mining_level))
|
||||
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
@@ -73,19 +90,47 @@ class MineLogic(BaseLogic):
|
||||
|
||||
@cache_self1
|
||||
def can_progress_in_the_skull_cavern_from_floor(self, floor: int) -> StardewRule:
|
||||
tier = floor // 50
|
||||
assert floor >= 0
|
||||
# 0-49, 50-99, 100-149, 150-199, 200-249
|
||||
mining_tier = floor // 50
|
||||
combat_tier = mining_tier
|
||||
rules = []
|
||||
|
||||
if CustomLogicOptionName.extreme_combat in self.options.custom_logic:
|
||||
weapon_rule = self.logic.combat.has_decent_weapon
|
||||
combat_tier -= 2
|
||||
elif CustomLogicOptionName.hard_combat in self.options.custom_logic:
|
||||
weapon_rule = self.logic.combat.has_good_weapon
|
||||
combat_tier -= 1
|
||||
elif CustomLogicOptionName.easy_combat in self.options.custom_logic:
|
||||
weapon_rule = self.logic.combat.has_galaxy_weapon
|
||||
combat_tier += 1
|
||||
else:
|
||||
weapon_rule = self.logic.combat.has_great_weapon
|
||||
combat_tier = max(0, combat_tier)
|
||||
|
||||
if CustomLogicOptionName.extreme_mining in self.options.custom_logic:
|
||||
mining_tier -= 2
|
||||
elif CustomLogicOptionName.hard_mining in self.options.custom_logic:
|
||||
mining_tier -= 1
|
||||
elif self.options.tool_progression.is_progressive and CustomLogicOptionName.easy_mining in self.options.custom_logic:
|
||||
mining_tier += 1
|
||||
tool_tier = mining_tier + 2
|
||||
tool_tier = min(5, max(1, tool_tier))
|
||||
mining_tier = max(0, mining_tier)
|
||||
|
||||
rules.append(weapon_rule)
|
||||
|
||||
tool_rule = self.logic.tool.can_mine_using(ToolMaterial.tiers[min(4, max(0, tier + 2))])
|
||||
tool_rule = self.logic.tool.can_mine_using(ToolMaterial.tiers[tool_tier])
|
||||
rules.append(tool_rule)
|
||||
|
||||
# No alternative for vanilla because we assume that you will grind the levels in the mines.
|
||||
if self.content.features.skill_progression.is_progressive:
|
||||
skill_level = min(10, max(0, tier * 2 + 6))
|
||||
rules.extend((self.logic.skill.has_level(Skill.combat, skill_level),
|
||||
self.logic.skill.has_level(Skill.mining, skill_level)))
|
||||
combat_level = min(10, max(0, combat_tier * 2 + 6))
|
||||
mining_level = min(10, max(0, mining_tier * 2 + 6))
|
||||
rules.append(self.logic.skill.has_level(Skill.combat, combat_level))
|
||||
rules.append(self.logic.skill.has_level(Skill.mining, mining_level))
|
||||
|
||||
rules.append(self.logic.cooking.can_cook())
|
||||
|
||||
return self.logic.and_(*rules)
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
from Options import DeathLink
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..data.shop import ShopSource
|
||||
from ..options import SpecialOrderLocations
|
||||
from ..content.vanilla.qi_board import qi_board_content_pack
|
||||
from ..data.shop import ShopSource, HatMouseSource
|
||||
from ..stardew_rule import StardewRule, True_, HasProgressionPercent, False_, true_
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.animal_names import Animal
|
||||
from ..strings.ap_names.ap_option_names import CustomLogicOptionName
|
||||
from ..strings.ap_names.event_names import Event
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.crop_names import Vegetable
|
||||
from ..strings.currency_names import Currency, MemeCurrency
|
||||
from ..strings.food_names import Beverage
|
||||
from ..strings.region_names import Region, LogicRegion
|
||||
from ..strings.season_names import Season
|
||||
|
||||
qi_gem_rewards = ("100 Qi Gems", "50 Qi Gems", "40 Qi Gems", "35 Qi Gems", "25 Qi Gems",
|
||||
"20 Qi Gems", "15 Qi Gems", "10 Qi Gems")
|
||||
@@ -20,52 +29,77 @@ class MoneyLogic(BaseLogic):
|
||||
|
||||
@cache_self1
|
||||
def can_have_earned_total(self, amount: int) -> StardewRule:
|
||||
|
||||
if CustomLogicOptionName.nightmare_money in self.options.custom_logic:
|
||||
amount /= 20
|
||||
elif CustomLogicOptionName.extreme_money in self.options.custom_logic:
|
||||
amount /= 8
|
||||
elif CustomLogicOptionName.hard_money in self.options.custom_logic:
|
||||
amount /= 2
|
||||
elif CustomLogicOptionName.easy_money in self.options.custom_logic:
|
||||
amount *= 4
|
||||
|
||||
if amount <= 1000:
|
||||
return self.logic.true_
|
||||
|
||||
pierre_rule = self.logic.region.can_reach_all((Region.pierre_store, Region.forest))
|
||||
willy_rule = self.logic.region.can_reach_all((Region.fish_shop, LogicRegion.fishing))
|
||||
clint_rule = self.logic.region.can_reach_all((Region.blacksmith, Region.mines_floor_5))
|
||||
robin_rule = self.logic.region.can_reach_all((Region.carpenter, Region.secret_woods))
|
||||
shipping_rule = self.logic.shipping.can_use_shipping_bin
|
||||
pierre_rule = self.logic.region.can_reach_all(Region.pierre_store, Region.forest)
|
||||
willy_rule = self.logic.region.can_reach_all(Region.fish_shop, LogicRegion.fishing)
|
||||
clint_rule = self.logic.region.can_reach_all(Region.blacksmith, Region.mines_floor_5)
|
||||
robin_rule = self.logic.region.can_reach_all(Region.carpenter, Region.secret_woods)
|
||||
farming_rule = self.logic.farming.can_plant_and_grow_item(Season.not_winter)
|
||||
|
||||
if amount <= 2500:
|
||||
selling_any_rule = pierre_rule | willy_rule | clint_rule | robin_rule | shipping_rule
|
||||
if amount <= 2000:
|
||||
selling_any_rule = shipping_rule | pierre_rule | willy_rule | clint_rule | robin_rule
|
||||
return selling_any_rule
|
||||
|
||||
if amount <= 3000:
|
||||
selling_any_rule = shipping_rule | pierre_rule | willy_rule
|
||||
return selling_any_rule
|
||||
|
||||
if amount <= 5000:
|
||||
selling_all_rule = (pierre_rule & willy_rule & clint_rule & robin_rule) | shipping_rule
|
||||
selling_all_rule = shipping_rule | (pierre_rule & farming_rule) | (pierre_rule & willy_rule & clint_rule & robin_rule)
|
||||
return selling_all_rule
|
||||
|
||||
if amount <= 10000:
|
||||
return shipping_rule
|
||||
return shipping_rule & farming_rule
|
||||
|
||||
seed_rules = self.logic.region.can_reach(Region.pierre_store)
|
||||
if amount <= 40000:
|
||||
return shipping_rule & seed_rules
|
||||
return shipping_rule & seed_rules & farming_rule
|
||||
|
||||
percent_progression_items_needed = min(90, amount // 20000)
|
||||
return shipping_rule & seed_rules & HasProgressionPercent(self.player, percent_progression_items_needed)
|
||||
return shipping_rule & seed_rules & farming_rule & HasProgressionPercent(self.player, percent_progression_items_needed)
|
||||
|
||||
@cache_self1
|
||||
def can_spend(self, amount: int) -> StardewRule:
|
||||
if self.options.starting_money == -1:
|
||||
return True_()
|
||||
return self.logic.money.can_have_earned_total(amount * 5)
|
||||
spend_earned_multiplier = 5 # We assume that if you earned 5x an amount, you can reasonably spend that amount on things
|
||||
return self.logic.money.can_have_earned_total(amount * spend_earned_multiplier)
|
||||
|
||||
# Should be cached
|
||||
def can_spend_at(self, region: str, amount: int) -> StardewRule:
|
||||
return self.logic.region.can_reach(region) & self.logic.money.can_spend(amount)
|
||||
|
||||
def can_shop_from_hat_mouse(self, source: HatMouseSource) -> StardewRule:
|
||||
money_rule = self.logic.money.can_spend(source.price) if source.price is not None else true_
|
||||
region_rule = self.logic.region.can_reach(LogicRegion.hat_mouse)
|
||||
requirements_rule = self.logic.requirement.meet_all_requirements(source.unlock_requirements) if source.unlock_requirements is not None else true_
|
||||
return money_rule & region_rule & requirements_rule
|
||||
|
||||
@cache_self1
|
||||
def can_shop_from(self, source: ShopSource) -> StardewRule:
|
||||
season_rule = self.logic.season.has_any(source.seasons)
|
||||
money_rule = self.logic.money.can_spend(source.money_price) if source.money_price is not None else true_
|
||||
if source.currency == Currency.money:
|
||||
money_rule = self.logic.money.can_spend(source.price) if source.price is not None else true_
|
||||
else:
|
||||
money_rule = self.logic.money.can_trade_at(source.shop_region, source.currency, source.price) if source.price is not None else true_
|
||||
|
||||
item_rules = []
|
||||
if source.items_price is not None:
|
||||
for price, item in source.items_price:
|
||||
item_rules.append(self.logic.has(item) & self.logic.grind.can_grind_item(price, item))
|
||||
item_rules.append(self.logic.grind.can_grind_item(price, item))
|
||||
|
||||
region_rule = self.logic.region.can_reach(source.shop_region)
|
||||
|
||||
@@ -74,24 +108,71 @@ class MoneyLogic(BaseLogic):
|
||||
# Should be cached
|
||||
def can_trade(self, currency: str, amount: int) -> StardewRule:
|
||||
if amount == 0:
|
||||
return True_()
|
||||
if currency == Currency.money:
|
||||
return self.logic.true_
|
||||
|
||||
if currency == Currency.money or currency == MemeCurrency.bank_money:
|
||||
return self.can_spend(amount)
|
||||
if currency == Currency.star_token:
|
||||
return self.logic.region.can_reach(LogicRegion.fair)
|
||||
if currency == Currency.qi_coin:
|
||||
return self.logic.region.can_reach(Region.casino) & self.logic.time.has_lived_months(amount // 1000)
|
||||
if currency == Currency.qi_gem:
|
||||
if self.options.special_order_locations & SpecialOrderLocations.value_qi:
|
||||
number_rewards = min(len(qi_gem_rewards), max(1, (amount // 10)))
|
||||
return self.logic.received_n(*qi_gem_rewards, count=number_rewards)
|
||||
number_rewards = 2
|
||||
return self.logic.received_n(*qi_gem_rewards, count=number_rewards) & self.logic.region.can_reach(Region.qi_walnut_room) & \
|
||||
self.logic.region.can_reach(Region.saloon) & self.can_have_earned_total(5000)
|
||||
if self.content.is_enabled(qi_board_content_pack):
|
||||
return self.logic.received(Event.received_qi_gems, amount * 3)
|
||||
return self.logic.region.can_reach_all(Region.qi_walnut_room, Region.saloon) & self.can_have_earned_total(5000)
|
||||
if currency == Currency.golden_walnut:
|
||||
return self.can_spend_walnut(amount)
|
||||
|
||||
return self.logic.has(currency) & self.logic.grind.can_grind_item(amount)
|
||||
if currency == MemeCurrency.code or currency == MemeCurrency.energy or currency == MemeCurrency.blood:
|
||||
return self.logic.true_
|
||||
if currency == MemeCurrency.clic and amount < 100:
|
||||
return self.logic.true_
|
||||
if currency == MemeCurrency.clic or currency == MemeCurrency.time:
|
||||
return self.logic.time.has_lived_months(1)
|
||||
|
||||
if currency == MemeCurrency.steps and amount < 6000:
|
||||
return self.logic.true_
|
||||
if currency == MemeCurrency.steps:
|
||||
return self.logic.time.has_lived_months(amount // 10000)
|
||||
|
||||
if currency == MemeCurrency.cookies:
|
||||
return self.logic.time.has_lived_months(amount // 10000)
|
||||
if currency == MemeCurrency.child:
|
||||
return self.logic.relationship.has_children(1)
|
||||
if currency == MemeCurrency.dead_crops:
|
||||
return self.logic.season.has_all() & self.logic.skill.can_get_farming_xp & self.logic.money.can_spend(amount * 100)
|
||||
if currency == MemeCurrency.dead_pumpkins:
|
||||
return self.logic.season.has(Season.fall) & self.logic.season.has_any([Season.spring, Season.summer, Season.winter]) & \
|
||||
self.logic.has(Vegetable.pumpkin) & self.logic.money.can_spend(amount * 100)
|
||||
if currency == MemeCurrency.missed_fish:
|
||||
return self.logic.fishing.can_catch_many_fish(max(1, amount // 4))
|
||||
if currency == MemeCurrency.honeywell:
|
||||
return self.logic.has(ArtisanGood.honey) & self.logic.building.has_building(Building.well)
|
||||
if currency == MemeCurrency.goat:
|
||||
return self.logic.animal.has_animal(Animal.goat)
|
||||
|
||||
if currency == MemeCurrency.sleep_days:
|
||||
if not self.options.multiple_day_sleep_enabled.value:
|
||||
return self.logic.false_
|
||||
if amount > 200:
|
||||
return self.logic.region.can_reach(Region.farm_house) & self.logic.season.has(Season.winter)
|
||||
return self.logic.region.can_reach(Region.farm_house)
|
||||
|
||||
if currency == MemeCurrency.time_elapsed:
|
||||
if amount <= 1000:
|
||||
return self.logic.true_
|
||||
if amount <= 1400:
|
||||
return self.logic.has(Beverage.coffee)
|
||||
if amount <= 1800:
|
||||
return self.logic.building.has_building(Building.stable)
|
||||
return self.logic.has(Beverage.coffee) & self.logic.building.has_building(Building.stable)
|
||||
|
||||
if currency == MemeCurrency.deathlinks:
|
||||
if self.options.death_link == DeathLink.option_true:
|
||||
return self.logic.time.has_lived_months(amount)
|
||||
return self.logic.false_
|
||||
|
||||
return self.logic.grind.can_grind_item(amount, currency)
|
||||
|
||||
# Should be cached
|
||||
def can_trade_at(self, region: str, currency: str, amount: int) -> StardewRule:
|
||||
|
||||
@@ -3,12 +3,9 @@ from typing import Iterable, Union, Hashable
|
||||
|
||||
from Utils import cache_self1
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from .combat_logic import CombatLogicMixin
|
||||
from .has_logic import HasLogicMixin
|
||||
from .region_logic import RegionLogicMixin
|
||||
from .time_logic import TimeLogicMixin, MAX_MONTHS
|
||||
from .. import options
|
||||
from .time_logic import MAX_MONTHS
|
||||
from ..data import monster_data
|
||||
from ..data.fish_data import ginger_island_river
|
||||
from ..stardew_rule import StardewRule
|
||||
from ..strings.generic_names import Generic
|
||||
from ..strings.region_names import Region
|
||||
@@ -24,11 +21,11 @@ class MonsterLogic(BaseLogic):
|
||||
|
||||
@cached_property
|
||||
def all_monsters_by_name(self):
|
||||
return monster_data.all_monsters_by_name_given_mods(self.options.mods.value)
|
||||
return monster_data.all_monsters_by_name_given_content_packs(self.content.registered_packs)
|
||||
|
||||
@cached_property
|
||||
def all_monsters_by_category(self):
|
||||
return monster_data.all_monsters_by_category_given_mods(self.options.mods.value)
|
||||
return monster_data.all_monsters_by_category_given_content_packs(self.content.registered_packs)
|
||||
|
||||
def can_kill(self, monster: Union[str, monster_data.StardewMonster], amount_tier: int = 0) -> StardewRule:
|
||||
if amount_tier <= 0:
|
||||
@@ -40,30 +37,30 @@ class MonsterLogic(BaseLogic):
|
||||
return self.logic.monster.can_kill_any(self.all_monsters_by_name.values()) & time_rule
|
||||
|
||||
monster = self.all_monsters_by_name[monster]
|
||||
region_rule = self.logic.region.can_reach_any(monster.locations)
|
||||
region_rule = self.logic.region.can_reach_any(*monster.locations)
|
||||
combat_rule = self.logic.combat.can_fight_at_level(monster.difficulty)
|
||||
|
||||
return region_rule & combat_rule & time_rule
|
||||
|
||||
@cache_self1
|
||||
def can_kill_many(self, monster: monster_data.StardewMonster) -> StardewRule:
|
||||
def can_kill_many(self, monster: Union[str, monster_data.StardewMonster]) -> StardewRule:
|
||||
return self.logic.monster.can_kill(monster, MAX_MONTHS / 3)
|
||||
|
||||
@cache_self1
|
||||
def can_kill_max(self, monster: monster_data.StardewMonster) -> StardewRule:
|
||||
def can_kill_max(self, monster: Union[str, monster_data.StardewMonster]) -> StardewRule:
|
||||
return self.logic.monster.can_kill(monster, MAX_MONTHS)
|
||||
|
||||
# Should be cached
|
||||
def can_kill_any(self, monsters: (Iterable[monster_data.StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule:
|
||||
def can_kill_any(self, monsters: (Iterable[Union[str, monster_data.StardewMonster]], Hashable), amount_tier: int = 0) -> StardewRule:
|
||||
return self.logic.or_(*(self.logic.monster.can_kill(monster, amount_tier) for monster in monsters))
|
||||
|
||||
# Should be cached
|
||||
def can_kill_all(self, monsters: (Iterable[monster_data.StardewMonster], Hashable), amount_tier: int = 0) -> StardewRule:
|
||||
def can_kill_all(self, monsters: (Iterable[Union[str, monster_data.StardewMonster]], Hashable), amount_tier: int = 0) -> StardewRule:
|
||||
return self.logic.and_(*(self.logic.monster.can_kill(monster, amount_tier) for monster in monsters))
|
||||
|
||||
def can_complete_all_monster_slaying_goals(self) -> StardewRule:
|
||||
rules = [self.logic.time.has_lived_max_months]
|
||||
exclude_island = self.options.exclude_ginger_island == options.ExcludeGingerIsland.option_true
|
||||
exclude_island = not self.content.is_enabled(ginger_island_river)
|
||||
island_regions = [Region.volcano_floor_5, Region.volcano_floor_10, Region.island_west, Region.dangerous_skull_cavern]
|
||||
for category in self.all_monsters_by_category:
|
||||
if exclude_island and all(all(location in island_regions for location in monster.locations)
|
||||
|
||||
58
worlds/stardew_valley/logic/movie_logic.py
Normal file
58
worlds/stardew_valley/logic/movie_logic.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from .base_logic import BaseLogicMixin, BaseLogic
|
||||
from ..data.movies import movies_by_name, npc_snacks, Snack, Movie, snacks_by_name
|
||||
from ..stardew_rule import StardewRule, Or
|
||||
from ..strings.villager_names import NPC
|
||||
|
||||
|
||||
class MovieLogicMixin(BaseLogicMixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.movie = MovieLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class MovieLogic(BaseLogic):
|
||||
|
||||
def can_watch_movie(self, movie: str | Movie) -> StardewRule:
|
||||
if isinstance(movie, str):
|
||||
movie = movies_by_name[movie]
|
||||
return self.logic.season.has(movie.season)
|
||||
|
||||
def can_watch_movie_with_loving_npc(self, movie: str | Movie) -> StardewRule:
|
||||
if isinstance(movie, str):
|
||||
movie = movies_by_name[movie]
|
||||
return self.can_watch_movie(movie) & self.logic.relationship.can_meet_any(*movie.loving_npcs)
|
||||
|
||||
def can_invite_to_movie(self, npcs: str | list[str]) -> StardewRule:
|
||||
if isinstance(npcs, str):
|
||||
npc = npcs
|
||||
if npc == NPC.leo:
|
||||
return self.logic.relationship.has_hearts(NPC.leo, 6)
|
||||
return self.logic.relationship.can_meet(npc)
|
||||
return self.logic.or_(*[self.can_invite_to_movie(npc) for npc in npcs])
|
||||
|
||||
def can_watch_movie_with_loving_npc_and_snack(self, movie: str | Movie) -> StardewRule:
|
||||
if isinstance(movie, str):
|
||||
movie = movies_by_name[movie]
|
||||
potential_partner_rules = []
|
||||
for npc in movie.loving_npcs:
|
||||
meet_rule = self.can_invite_to_movie(npc)
|
||||
snack_rule = self.can_buy_loved_snack(npc)
|
||||
potential_partner_rules.append(meet_rule & snack_rule)
|
||||
return self.can_watch_movie(movie) & Or(*potential_partner_rules)
|
||||
|
||||
def can_buy_loved_snack(self, npc: str) -> StardewRule:
|
||||
snacks = npc_snacks[npc]
|
||||
if not snacks:
|
||||
return self.logic.false_
|
||||
snacks_rule = Or(*[self.can_buy_snack(snack) for snack in snacks])
|
||||
return snacks_rule
|
||||
|
||||
def can_buy_snack(self, snack: str | Snack) -> StardewRule:
|
||||
if isinstance(snack, str):
|
||||
snack = snacks_by_name[snack]
|
||||
return self.logic.received(snack.category)
|
||||
|
||||
def can_buy_snack_for_someone_who_loves_it(self, snack: str | Snack) -> StardewRule:
|
||||
if isinstance(snack, str):
|
||||
snack = snacks_by_name[snack]
|
||||
return self.logic.received(snack.category) & self.can_invite_to_movie(snack.loving_npcs)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user