mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Stardew Valley: implement new game (#1455)
* Stardew Valley Archipelago implementation * fix breaking changes * - Added and Updated Documentation for the game * Removed fun * Remove entire idea of step, due to possible inconsistency with the main AP core * Commented out the desired steps, fix renaming after rebase * Fixed wording * tests now passes on 3.8 * run flake8 * remove dependency so apworld work again * remove dependency for real * - Fix Formatting in the Game Page - Removed disabled Option Descriptions for Entrance Randomizer - Improved Game Page's description of the Arcade Machine buffs - Trimmed down the text on the Options page for Arcade Machines, so that it is smaller * - Removed blankspace * remove player field * remove None check in options * document the scripts * fix pytest warning * use importlib.resources.files * fix * add version requirement to importlib_resources * remove __init__.py from data folder * increment data version * let the __init__.py for 3.9 * use sorted() instead of list() * replace frozenset from fish_data with tuples * remove dependency on pytest * - Add a bit of text to the guide to tell them about how to redeem some received items * - Added a comment about which mod version to use * change single quotes for double quotes * Minimum client version both ways * Changed version number to be more specific. The mod will handle deciding --------- Co-authored-by: Alex Gilbert <alexgilbert@yahoo.com>
This commit is contained in:
175
worlds/stardew_valley/locations.py
Normal file
175
worlds/stardew_valley/locations.py
Normal file
@@ -0,0 +1,175 @@
|
||||
import csv
|
||||
import enum
|
||||
from dataclasses import dataclass
|
||||
from random import Random
|
||||
from typing import Optional, Dict, Protocol, List, FrozenSet
|
||||
|
||||
from . import options, data
|
||||
from .fish_data import legendary_fish, special_fish, all_fish_items
|
||||
|
||||
LOCATION_CODE_OFFSET = 717000
|
||||
|
||||
|
||||
class LocationTags(enum.Enum):
|
||||
MANDATORY = enum.auto()
|
||||
BUNDLE = enum.auto()
|
||||
COMMUNITY_CENTER_BUNDLE = enum.auto()
|
||||
CRAFTS_ROOM_BUNDLE = enum.auto()
|
||||
PANTRY_BUNDLE = enum.auto()
|
||||
FISH_TANK_BUNDLE = enum.auto()
|
||||
BOILER_ROOM_BUNDLE = enum.auto()
|
||||
BULLETIN_BOARD_BUNDLE = enum.auto()
|
||||
VAULT_BUNDLE = enum.auto()
|
||||
COMMUNITY_CENTER_ROOM = enum.auto()
|
||||
BACKPACK = enum.auto()
|
||||
TOOL_UPGRADE = enum.auto()
|
||||
HOE_UPGRADE = enum.auto()
|
||||
PICKAXE_UPGRADE = enum.auto()
|
||||
AXE_UPGRADE = enum.auto()
|
||||
WATERING_CAN_UPGRADE = enum.auto()
|
||||
TRASH_CAN_UPGRADE = enum.auto()
|
||||
FISHING_ROD_UPGRADE = enum.auto()
|
||||
THE_MINES_TREASURE = enum.auto()
|
||||
THE_MINES_ELEVATOR = enum.auto()
|
||||
SKILL_LEVEL = enum.auto()
|
||||
FARMING_LEVEL = enum.auto()
|
||||
FISHING_LEVEL = enum.auto()
|
||||
FORAGING_LEVEL = enum.auto()
|
||||
COMBAT_LEVEL = enum.auto()
|
||||
MINING_LEVEL = enum.auto()
|
||||
BUILDING_BLUEPRINT = enum.auto()
|
||||
QUEST = enum.auto()
|
||||
ARCADE_MACHINE = enum.auto()
|
||||
ARCADE_MACHINE_VICTORY = enum.auto()
|
||||
JOTPK = enum.auto()
|
||||
JUNIMO_KART = enum.auto()
|
||||
HELP_WANTED = enum.auto()
|
||||
TRAVELING_MERCHANT = enum.auto()
|
||||
FISHSANITY = enum.auto()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LocationData:
|
||||
code_without_offset: Optional[int]
|
||||
region: str
|
||||
name: str
|
||||
tags: FrozenSet[LocationTags] = frozenset()
|
||||
|
||||
@property
|
||||
def code(self) -> Optional[int]:
|
||||
return LOCATION_CODE_OFFSET + self.code_without_offset if self.code_without_offset is not None else None
|
||||
|
||||
|
||||
class StardewLocationCollector(Protocol):
|
||||
def __call__(self, name: str, code: Optional[int], region: str) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def load_location_csv() -> List[LocationData]:
|
||||
try:
|
||||
from importlib.resources import files
|
||||
except ImportError:
|
||||
from importlib_resources import files
|
||||
|
||||
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"],
|
||||
frozenset(LocationTags[group]
|
||||
for group in location["tags"].split(",")
|
||||
if group))
|
||||
for location in reader]
|
||||
|
||||
|
||||
events_locations = [
|
||||
LocationData(None, "Stardew Valley", "Succeed Grandpa's Evaluation"),
|
||||
LocationData(None, "Community Center", "Complete Community Center"),
|
||||
LocationData(None, "The Mines - Floor 120", "Reach the Bottom of The Mines"),
|
||||
LocationData(None, "Skull Cavern", "Complete Quest Cryptic Note"),
|
||||
LocationData(None, "Stardew Valley", "Catch Every Fish"),
|
||||
LocationData(None, "Stardew Valley", "Summer"),
|
||||
LocationData(None, "Stardew Valley", "Fall"),
|
||||
LocationData(None, "Stardew Valley", "Winter"),
|
||||
LocationData(None, "Stardew Valley", "Year Two"),
|
||||
]
|
||||
|
||||
all_locations = load_location_csv() + events_locations
|
||||
location_table: Dict[str, LocationData] = {location.name: location for location in all_locations}
|
||||
locations_by_tag: Dict[LocationTags, List[LocationData]] = {}
|
||||
|
||||
|
||||
def initialize_groups():
|
||||
for location in all_locations:
|
||||
for tag in location.tags:
|
||||
location_group = locations_by_tag.get(tag, list())
|
||||
location_group.append(location)
|
||||
locations_by_tag[tag] = location_group
|
||||
|
||||
|
||||
initialize_groups()
|
||||
|
||||
|
||||
def extend_help_wanted_quests(randomized_locations: List[LocationData], desired_number_of_quests: int):
|
||||
for i in range(0, desired_number_of_quests):
|
||||
batch = i // 7
|
||||
index_this_batch = i % 7
|
||||
if index_this_batch < 4:
|
||||
randomized_locations.append(
|
||||
location_table[f"Help Wanted: Item Delivery {(batch * 4) + index_this_batch + 1}"])
|
||||
elif index_this_batch == 4:
|
||||
randomized_locations.append(location_table[f"Help Wanted: Fishing {batch + 1}"])
|
||||
elif index_this_batch == 5:
|
||||
randomized_locations.append(location_table[f"Help Wanted: Slay Monsters {batch + 1}"])
|
||||
elif index_this_batch == 6:
|
||||
randomized_locations.append(location_table[f"Help Wanted: Gathering {batch + 1}"])
|
||||
|
||||
|
||||
def extend_fishsanity_locations(randomized_locations: List[LocationData], fishsanity: int, random: Random):
|
||||
prefix = "Fishsanity: "
|
||||
if fishsanity == options.Fishsanity.option_none:
|
||||
return
|
||||
elif fishsanity == options.Fishsanity.option_legendaries:
|
||||
randomized_locations.extend(location_table[f"{prefix}{legendary.name}"] for legendary in legendary_fish)
|
||||
elif fishsanity == options.Fishsanity.option_special:
|
||||
randomized_locations.extend(location_table[f"{prefix}{special.name}"] for special in special_fish)
|
||||
elif fishsanity == options.Fishsanity.option_random_selection:
|
||||
randomized_locations.extend(location_table[f"{prefix}{fish.name}"]
|
||||
for fish in all_fish_items if random.random() < 0.4)
|
||||
elif fishsanity == options.Fishsanity.option_all:
|
||||
randomized_locations.extend(location_table[f"{prefix}{fish.name}"] for fish in all_fish_items)
|
||||
|
||||
|
||||
def create_locations(location_collector: StardewLocationCollector,
|
||||
world_options: options.StardewOptions,
|
||||
random: Random):
|
||||
randomized_locations = []
|
||||
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.MANDATORY])
|
||||
|
||||
if not world_options[options.BackpackProgression] == options.BackpackProgression.option_vanilla:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.BACKPACK])
|
||||
|
||||
if not world_options[options.ToolProgression] == options.ToolProgression.option_vanilla:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.TOOL_UPGRADE])
|
||||
|
||||
if not world_options[options.TheMinesElevatorsProgression] == options.TheMinesElevatorsProgression.option_vanilla:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.THE_MINES_ELEVATOR])
|
||||
|
||||
if not world_options[options.SkillProgression] == options.SkillProgression.option_vanilla:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.SKILL_LEVEL])
|
||||
|
||||
if not world_options[options.BuildingProgression] == options.BuildingProgression.option_vanilla:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.BUILDING_BLUEPRINT])
|
||||
|
||||
if not world_options[options.ArcadeMachineLocations] == options.ArcadeMachineLocations.option_disabled:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.ARCADE_MACHINE_VICTORY])
|
||||
|
||||
if world_options[options.ArcadeMachineLocations] == options.ArcadeMachineLocations.option_full_shuffling:
|
||||
randomized_locations.extend(locations_by_tag[LocationTags.ARCADE_MACHINE])
|
||||
|
||||
extend_help_wanted_quests(randomized_locations, world_options[options.HelpWantedLocations])
|
||||
extend_fishsanity_locations(randomized_locations, world_options[options.Fishsanity], random)
|
||||
|
||||
for location_data in randomized_locations:
|
||||
location_collector(location_data.name, location_data.code, location_data.region)
|
||||
Reference in New Issue
Block a user