mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
Stardew Valley: Replace current naive entrance rando with GER (#4624)
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import typing
|
import typing
|
||||||
from random import Random
|
from random import Random
|
||||||
from typing import Dict, Any, Iterable, Optional, List, TextIO
|
from typing import Dict, Any, Optional, List, TextIO
|
||||||
|
|
||||||
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState
|
import entrance_rando
|
||||||
|
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState
|
||||||
from Options import PerGameCommonOptions
|
from Options import PerGameCommonOptions
|
||||||
from worlds.AutoWorld import World, WebWorld
|
from worlds.AutoWorld import World, WebWorld
|
||||||
from .bundles.bundle_room import BundleRoom
|
from .bundles.bundle_room import BundleRoom
|
||||||
@@ -21,7 +22,7 @@ from .options.forced_options import force_change_options_if_incompatible
|
|||||||
from .options.option_groups import sv_option_groups
|
from .options.option_groups import sv_option_groups
|
||||||
from .options.presets import sv_options_presets
|
from .options.presets import sv_options_presets
|
||||||
from .options.worlds_group import apply_most_restrictive_options
|
from .options.worlds_group import apply_most_restrictive_options
|
||||||
from .regions import create_regions
|
from .regions import create_regions, prepare_mod_data
|
||||||
from .rules import set_rules
|
from .rules import set_rules
|
||||||
from .stardew_rule import True_, StardewRule, HasProgressionPercent
|
from .stardew_rule import True_, StardewRule, HasProgressionPercent
|
||||||
from .strings.ap_names.event_names import Event
|
from .strings.ap_names.event_names import Event
|
||||||
@@ -124,18 +125,13 @@ class StardewValleyWorld(World):
|
|||||||
self.content = create_content(self.options)
|
self.content = create_content(self.options)
|
||||||
|
|
||||||
def create_regions(self):
|
def create_regions(self):
|
||||||
def create_region(name: str, exits: Iterable[str]) -> Region:
|
def create_region(name: str) -> Region:
|
||||||
region = Region(name, self.player, self.multiworld)
|
return Region(name, self.player, self.multiworld)
|
||||||
region.exits = [Entrance(self.player, exit_name, region) for exit_name in exits]
|
|
||||||
return region
|
|
||||||
|
|
||||||
world_regions, world_entrances, self.randomized_entrances = create_regions(create_region, self.random, self.options, self.content)
|
world_regions = create_regions(create_region, self.options, self.content)
|
||||||
|
|
||||||
self.logic = StardewLogic(self.player, self.options, self.content, world_regions.keys())
|
self.logic = StardewLogic(self.player, self.options, self.content, world_regions.keys())
|
||||||
self.modified_bundles = get_all_bundles(self.random,
|
self.modified_bundles = get_all_bundles(self.random, self.logic, self.content, self.options)
|
||||||
self.logic,
|
|
||||||
self.content,
|
|
||||||
self.options)
|
|
||||||
|
|
||||||
def add_location(name: str, code: Optional[int], region: str):
|
def add_location(name: str, code: Optional[int], region: str):
|
||||||
region: Region = world_regions[region]
|
region: Region = world_regions[region]
|
||||||
@@ -308,6 +304,11 @@ class StardewValleyWorld(World):
|
|||||||
def set_rules(self):
|
def set_rules(self):
|
||||||
set_rules(self)
|
set_rules(self)
|
||||||
|
|
||||||
|
def connect_entrances(self) -> None:
|
||||||
|
no_target_groups = {0: [0]}
|
||||||
|
placement = entrance_rando.randomize_entrances(self, coupled=True, target_group_lookup=no_target_groups)
|
||||||
|
self.randomized_entrances = prepare_mod_data(placement)
|
||||||
|
|
||||||
def generate_basic(self):
|
def generate_basic(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@@ -24,6 +24,9 @@ from ...strings.skill_names import Skill
|
|||||||
from ...strings.tool_names import Tool, ToolMaterial
|
from ...strings.tool_names import Tool, ToolMaterial
|
||||||
from ...strings.villager_names import ModNPC
|
from ...strings.villager_names import ModNPC
|
||||||
|
|
||||||
|
# Used to adapt content not yet moved to content packs to easily detect when SVE and Ginger Island are both enabled.
|
||||||
|
SVE_GINGER_ISLAND_PACK = ModNames.sve + "+" + ginger_island_content_pack.name
|
||||||
|
|
||||||
|
|
||||||
class SVEContentPack(ContentPack):
|
class SVEContentPack(ContentPack):
|
||||||
|
|
||||||
@@ -67,6 +70,10 @@ class SVEContentPack(ContentPack):
|
|||||||
content.game_items.pop(SVESeed.slime)
|
content.game_items.pop(SVESeed.slime)
|
||||||
content.game_items.pop(SVEFruit.slime_berry)
|
content.game_items.pop(SVEFruit.slime_berry)
|
||||||
|
|
||||||
|
def finalize_hook(self, content: StardewContent):
|
||||||
|
if ginger_island_content_pack.name in content.registered_packs:
|
||||||
|
content.registered_packs.add(SVE_GINGER_ISLAND_PACK)
|
||||||
|
|
||||||
|
|
||||||
register_mod_content_pack(SVEContentPack(
|
register_mod_content_pack(SVEContentPack(
|
||||||
ModNames.sve,
|
ModNames.sve,
|
||||||
@@ -80,8 +87,9 @@ register_mod_content_pack(SVEContentPack(
|
|||||||
ModEdible.lightning_elixir: (ShopSource(money_price=12000, shop_region=SVERegion.galmoran_outpost),),
|
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.barbarian_elixir: (ShopSource(money_price=22000, shop_region=SVERegion.galmoran_outpost),),
|
||||||
ModEdible.gravity_elixir: (ShopSource(money_price=4000, shop_region=SVERegion.galmoran_outpost),),
|
ModEdible.gravity_elixir: (ShopSource(money_price=4000, shop_region=SVERegion.galmoran_outpost),),
|
||||||
SVEMeal.grampleton_orange_chicken: (
|
SVEMeal.grampleton_orange_chicken: (ShopSource(money_price=650,
|
||||||
ShopSource(money_price=650, shop_region=Region.saloon, other_requirements=(RelationshipRequirement(ModNPC.sophia, 6),)),),
|
shop_region=Region.saloon,
|
||||||
|
other_requirements=(RelationshipRequirement(ModNPC.sophia, 6),)),),
|
||||||
ModEdible.hero_elixir: (ShopSource(money_price=8000, shop_region=SVERegion.isaac_shop),),
|
ModEdible.hero_elixir: (ShopSource(money_price=8000, shop_region=SVERegion.isaac_shop),),
|
||||||
ModEdible.aegis_elixir: (ShopSource(money_price=28000, shop_region=SVERegion.galmoran_outpost),),
|
ModEdible.aegis_elixir: (ShopSource(money_price=28000, shop_region=SVERegion.galmoran_outpost),),
|
||||||
SVEBeverage.sports_drink: (ShopSource(money_price=750, shop_region=Region.hospital),),
|
SVEBeverage.sports_drink: (ShopSource(money_price=750, shop_region=Region.hospital),),
|
||||||
@@ -118,8 +126,8 @@ register_mod_content_pack(SVEContentPack(
|
|||||||
|
|
||||||
ModLoot.green_mushroom: (ForagingSource(regions=(SVERegion.highlands_pond,), seasons=Season.not_winter),),
|
ModLoot.green_mushroom: (ForagingSource(regions=(SVERegion.highlands_pond,), seasons=Season.not_winter),),
|
||||||
ModLoot.ornate_treasure_chest: (ForagingSource(regions=(SVERegion.highlands_outside,),
|
ModLoot.ornate_treasure_chest: (ForagingSource(regions=(SVERegion.highlands_outside,),
|
||||||
other_requirements=(
|
other_requirements=(CombatRequirement(Performance.galaxy),
|
||||||
CombatRequirement(Performance.galaxy), ToolRequirement(Tool.axe, ToolMaterial.iron))),),
|
ToolRequirement(Tool.axe, ToolMaterial.iron))),),
|
||||||
ModLoot.swirl_stone: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.galaxy),)),),
|
ModLoot.swirl_stone: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.galaxy),)),),
|
||||||
ModLoot.void_soul: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.good),)),),
|
ModLoot.void_soul: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.good),)),),
|
||||||
SVEForage.winter_star_rose: (ForagingSource(regions=(SVERegion.summit,), seasons=(Season.winter,)),),
|
SVEForage.winter_star_rose: (ForagingSource(regions=(SVERegion.summit,), seasons=(Season.winter,)),),
|
||||||
@@ -139,8 +147,9 @@ register_mod_content_pack(SVEContentPack(
|
|||||||
SVEForage.thistle: (ForagingSource(regions=(SVERegion.summit,)),),
|
SVEForage.thistle: (ForagingSource(regions=(SVERegion.summit,)),),
|
||||||
ModLoot.void_pebble: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.great),)),),
|
ModLoot.void_pebble: (ForagingSource(regions=(SVERegion.crimson_badlands,), other_requirements=(CombatRequirement(Performance.great),)),),
|
||||||
ModLoot.void_shard: (ForagingSource(regions=(SVERegion.crimson_badlands,),
|
ModLoot.void_shard: (ForagingSource(regions=(SVERegion.crimson_badlands,),
|
||||||
other_requirements=(
|
other_requirements=(CombatRequirement(Performance.galaxy),
|
||||||
CombatRequirement(Performance.galaxy), SkillRequirement(Skill.combat, 10), YearRequirement(3),)),),
|
SkillRequirement(Skill.combat, 10),
|
||||||
|
YearRequirement(3),)),),
|
||||||
SVEWaterItem.dulse_seaweed: (ForagingSource(regions=(Region.beach,), other_requirements=(FishingRequirement(Region.beach),)),),
|
SVEWaterItem.dulse_seaweed: (ForagingSource(regions=(Region.beach,), other_requirements=(FishingRequirement(Region.beach),)),),
|
||||||
|
|
||||||
# Fable Reef
|
# Fable Reef
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
from ..mod_regions import SVERegion
|
|
||||||
from ...logic.base_logic import BaseLogicMixin, BaseLogic
|
from ...logic.base_logic import BaseLogicMixin, BaseLogic
|
||||||
from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes, SVEQuestItem
|
from ...strings.ap_names.mods.mod_items import SVELocation, SVERunes, SVEQuestItem
|
||||||
from ...strings.quest_names import Quest, ModQuest
|
from ...strings.quest_names import Quest, ModQuest
|
||||||
from ...strings.region_names import Region
|
from ...strings.region_names import Region, SVERegion
|
||||||
from ...strings.tool_names import Tool, ToolMaterial
|
from ...strings.tool_names import Tool, ToolMaterial
|
||||||
from ...strings.wallet_item_names import Wallet
|
from ...strings.wallet_item_names import Wallet
|
||||||
|
|
||||||
|
@@ -1,15 +1,14 @@
|
|||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from .mod_data import ModNames
|
from .mod_data import ModNames
|
||||||
from ..region_classes import RegionData, ConnectionData, ModificationFlag, RandomizationFlag, ModRegionData
|
from ..content.mods.sve import SVE_GINGER_ISLAND_PACK
|
||||||
|
from ..regions.model import RegionData, ConnectionData, MergeFlag, RandomizationFlag, ModRegionsData
|
||||||
from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, BoardingHouseEntrance, \
|
from ..strings.entrance_names import Entrance, DeepWoodsEntrance, EugeneEntrance, LaceyEntrance, BoardingHouseEntrance, \
|
||||||
JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance
|
JasperEntrance, AlecEntrance, YobaEntrance, JunaEntrance, MagicEntrance, AyeishaEntrance, RileyEntrance, SVEEntrance, AlectoEntrance
|
||||||
from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, BoardingHouseRegion, \
|
from ..strings.region_names import Region, DeepWoodsRegion, EugeneRegion, JasperRegion, BoardingHouseRegion, \
|
||||||
AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion, LaceyRegion
|
AlecRegion, YobaRegion, JunaRegion, MagicRegion, AyeishaRegion, RileyRegion, SVERegion, AlectoRegion, LaceyRegion
|
||||||
|
|
||||||
deep_woods_regions = [
|
deep_woods_regions = [
|
||||||
RegionData(Region.farm, [DeepWoodsEntrance.use_woods_obelisk]),
|
RegionData(Region.farm, (DeepWoodsEntrance.use_woods_obelisk,)),
|
||||||
RegionData(DeepWoodsRegion.woods_obelisk_menu, [DeepWoodsEntrance.deep_woods_depth_1,
|
RegionData(DeepWoodsRegion.woods_obelisk_menu, (DeepWoodsEntrance.deep_woods_depth_1,
|
||||||
DeepWoodsEntrance.deep_woods_depth_10,
|
DeepWoodsEntrance.deep_woods_depth_10,
|
||||||
DeepWoodsEntrance.deep_woods_depth_20,
|
DeepWoodsEntrance.deep_woods_depth_20,
|
||||||
DeepWoodsEntrance.deep_woods_depth_30,
|
DeepWoodsEntrance.deep_woods_depth_30,
|
||||||
@@ -19,9 +18,9 @@ deep_woods_regions = [
|
|||||||
DeepWoodsEntrance.deep_woods_depth_70,
|
DeepWoodsEntrance.deep_woods_depth_70,
|
||||||
DeepWoodsEntrance.deep_woods_depth_80,
|
DeepWoodsEntrance.deep_woods_depth_80,
|
||||||
DeepWoodsEntrance.deep_woods_depth_90,
|
DeepWoodsEntrance.deep_woods_depth_90,
|
||||||
DeepWoodsEntrance.deep_woods_depth_100]),
|
DeepWoodsEntrance.deep_woods_depth_100)),
|
||||||
RegionData(Region.secret_woods, [DeepWoodsEntrance.secret_woods_to_deep_woods]),
|
RegionData(Region.secret_woods, (DeepWoodsEntrance.secret_woods_to_deep_woods,)),
|
||||||
RegionData(DeepWoodsRegion.main_lichtung, [DeepWoodsEntrance.deep_woods_house]),
|
RegionData(DeepWoodsRegion.main_lichtung, (DeepWoodsEntrance.deep_woods_house,)),
|
||||||
RegionData(DeepWoodsRegion.abandoned_home),
|
RegionData(DeepWoodsRegion.abandoned_home),
|
||||||
RegionData(DeepWoodsRegion.floor_10),
|
RegionData(DeepWoodsRegion.floor_10),
|
||||||
RegionData(DeepWoodsRegion.floor_20),
|
RegionData(DeepWoodsRegion.floor_20),
|
||||||
@@ -32,14 +31,13 @@ deep_woods_regions = [
|
|||||||
RegionData(DeepWoodsRegion.floor_70),
|
RegionData(DeepWoodsRegion.floor_70),
|
||||||
RegionData(DeepWoodsRegion.floor_80),
|
RegionData(DeepWoodsRegion.floor_80),
|
||||||
RegionData(DeepWoodsRegion.floor_90),
|
RegionData(DeepWoodsRegion.floor_90),
|
||||||
RegionData(DeepWoodsRegion.floor_100)
|
RegionData(DeepWoodsRegion.floor_100),
|
||||||
]
|
]
|
||||||
|
|
||||||
deep_woods_entrances = [
|
deep_woods_entrances = [
|
||||||
ConnectionData(DeepWoodsEntrance.use_woods_obelisk, DeepWoodsRegion.woods_obelisk_menu),
|
ConnectionData(DeepWoodsEntrance.use_woods_obelisk, DeepWoodsRegion.woods_obelisk_menu),
|
||||||
ConnectionData(DeepWoodsEntrance.secret_woods_to_deep_woods, DeepWoodsRegion.main_lichtung),
|
ConnectionData(DeepWoodsEntrance.secret_woods_to_deep_woods, DeepWoodsRegion.main_lichtung),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_house, DeepWoodsRegion.abandoned_home,
|
ConnectionData(DeepWoodsEntrance.deep_woods_house, DeepWoodsRegion.abandoned_home, flag=RandomizationFlag.BUILDINGS),
|
||||||
flag=RandomizationFlag.NON_PROGRESSION),
|
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_1, DeepWoodsRegion.main_lichtung),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_1, DeepWoodsRegion.main_lichtung),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_10, DeepWoodsRegion.floor_10),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_10, DeepWoodsRegion.floor_10),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_20, DeepWoodsRegion.floor_20),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_20, DeepWoodsRegion.floor_20),
|
||||||
@@ -50,165 +48,166 @@ deep_woods_entrances = [
|
|||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_70, DeepWoodsRegion.floor_70),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_70, DeepWoodsRegion.floor_70),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_80, DeepWoodsRegion.floor_80),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_80, DeepWoodsRegion.floor_80),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_90, DeepWoodsRegion.floor_90),
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_90, DeepWoodsRegion.floor_90),
|
||||||
ConnectionData(DeepWoodsEntrance.deep_woods_depth_100, DeepWoodsRegion.floor_100)
|
ConnectionData(DeepWoodsEntrance.deep_woods_depth_100, DeepWoodsRegion.floor_100),
|
||||||
]
|
]
|
||||||
|
|
||||||
eugene_regions = [
|
eugene_regions = [
|
||||||
RegionData(Region.forest, [EugeneEntrance.forest_to_garden]),
|
RegionData(Region.forest, (EugeneEntrance.forest_to_garden,)),
|
||||||
RegionData(EugeneRegion.eugene_garden, [EugeneEntrance.garden_to_bedroom]),
|
RegionData(EugeneRegion.eugene_garden, (EugeneEntrance.garden_to_bedroom,)),
|
||||||
RegionData(EugeneRegion.eugene_bedroom)
|
RegionData(EugeneRegion.eugene_bedroom),
|
||||||
]
|
]
|
||||||
|
|
||||||
eugene_entrances = [
|
eugene_entrances = [
|
||||||
ConnectionData(EugeneEntrance.forest_to_garden, EugeneRegion.eugene_garden,
|
ConnectionData(EugeneEntrance.forest_to_garden, EugeneRegion.eugene_garden,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
ConnectionData(EugeneEntrance.garden_to_bedroom, EugeneRegion.eugene_bedroom, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(EugeneEntrance.garden_to_bedroom, EugeneRegion.eugene_bedroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
magic_regions = [
|
magic_regions = [
|
||||||
RegionData(Region.pierre_store, [MagicEntrance.store_to_altar]),
|
RegionData(Region.pierre_store, (MagicEntrance.store_to_altar,)),
|
||||||
RegionData(MagicRegion.altar)
|
RegionData(MagicRegion.altar),
|
||||||
]
|
]
|
||||||
|
|
||||||
magic_entrances = [
|
magic_entrances = [
|
||||||
ConnectionData(MagicEntrance.store_to_altar, MagicRegion.altar, flag=RandomizationFlag.NOT_RANDOMIZED)
|
ConnectionData(MagicEntrance.store_to_altar, MagicRegion.altar, flag=RandomizationFlag.NOT_RANDOMIZED),
|
||||||
]
|
]
|
||||||
|
|
||||||
jasper_regions = [
|
jasper_regions = [
|
||||||
RegionData(Region.museum, [JasperEntrance.museum_to_bedroom]),
|
RegionData(Region.museum, (JasperEntrance.museum_to_bedroom,)),
|
||||||
RegionData(JasperRegion.jasper_bedroom)
|
RegionData(JasperRegion.jasper_bedroom),
|
||||||
]
|
]
|
||||||
|
|
||||||
jasper_entrances = [
|
jasper_entrances = [
|
||||||
ConnectionData(JasperEntrance.museum_to_bedroom, JasperRegion.jasper_bedroom, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(JasperEntrance.museum_to_bedroom, JasperRegion.jasper_bedroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
alec_regions = [
|
alec_regions = [
|
||||||
RegionData(Region.forest, [AlecEntrance.forest_to_petshop]),
|
RegionData(Region.forest, (AlecEntrance.forest_to_petshop,)),
|
||||||
RegionData(AlecRegion.pet_store, [AlecEntrance.petshop_to_bedroom]),
|
RegionData(AlecRegion.pet_store, (AlecEntrance.petshop_to_bedroom,)),
|
||||||
RegionData(AlecRegion.alec_bedroom)
|
RegionData(AlecRegion.alec_bedroom),
|
||||||
]
|
]
|
||||||
|
|
||||||
alec_entrances = [
|
alec_entrances = [
|
||||||
ConnectionData(AlecEntrance.forest_to_petshop, AlecRegion.pet_store,
|
ConnectionData(AlecEntrance.forest_to_petshop, AlecRegion.pet_store,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
ConnectionData(AlecEntrance.petshop_to_bedroom, AlecRegion.alec_bedroom, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(AlecEntrance.petshop_to_bedroom, AlecRegion.alec_bedroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
yoba_regions = [
|
yoba_regions = [
|
||||||
RegionData(Region.secret_woods, [YobaEntrance.secret_woods_to_clearing]),
|
RegionData(Region.secret_woods, (YobaEntrance.secret_woods_to_clearing,)),
|
||||||
RegionData(YobaRegion.yoba_clearing)
|
RegionData(YobaRegion.yoba_clearing),
|
||||||
]
|
]
|
||||||
|
|
||||||
yoba_entrances = [
|
yoba_entrances = [
|
||||||
ConnectionData(YobaEntrance.secret_woods_to_clearing, YobaRegion.yoba_clearing, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(YobaEntrance.secret_woods_to_clearing, YobaRegion.yoba_clearing, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
juna_regions = [
|
juna_regions = [
|
||||||
RegionData(Region.forest, [JunaEntrance.forest_to_juna_cave]),
|
RegionData(Region.forest, (JunaEntrance.forest_to_juna_cave,)),
|
||||||
RegionData(JunaRegion.juna_cave)
|
RegionData(JunaRegion.juna_cave),
|
||||||
]
|
]
|
||||||
|
|
||||||
juna_entrances = [
|
juna_entrances = [
|
||||||
ConnectionData(JunaEntrance.forest_to_juna_cave, JunaRegion.juna_cave,
|
ConnectionData(JunaEntrance.forest_to_juna_cave, JunaRegion.juna_cave,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA)
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
]
|
]
|
||||||
|
|
||||||
ayeisha_regions = [
|
ayeisha_regions = [
|
||||||
RegionData(Region.bus_stop, [AyeishaEntrance.bus_stop_to_mail_van]),
|
RegionData(Region.bus_stop, (AyeishaEntrance.bus_stop_to_mail_van,)),
|
||||||
RegionData(AyeishaRegion.mail_van)
|
RegionData(AyeishaRegion.mail_van),
|
||||||
]
|
]
|
||||||
|
|
||||||
ayeisha_entrances = [
|
ayeisha_entrances = [
|
||||||
ConnectionData(AyeishaEntrance.bus_stop_to_mail_van, AyeishaRegion.mail_van,
|
ConnectionData(AyeishaEntrance.bus_stop_to_mail_van, AyeishaRegion.mail_van,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA)
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
]
|
]
|
||||||
|
|
||||||
riley_regions = [
|
riley_regions = [
|
||||||
RegionData(Region.town, [RileyEntrance.town_to_riley]),
|
RegionData(Region.town, (RileyEntrance.town_to_riley,)),
|
||||||
RegionData(RileyRegion.riley_house)
|
RegionData(RileyRegion.riley_house),
|
||||||
]
|
]
|
||||||
|
|
||||||
riley_entrances = [
|
riley_entrances = [
|
||||||
ConnectionData(RileyEntrance.town_to_riley, RileyRegion.riley_house,
|
ConnectionData(RileyEntrance.town_to_riley, RileyRegion.riley_house,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA)
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
]
|
]
|
||||||
|
|
||||||
stardew_valley_expanded_regions = [
|
sve_main_land_regions = [
|
||||||
RegionData(Region.backwoods, [SVEEntrance.backwoods_to_grove]),
|
RegionData(Region.backwoods, (SVEEntrance.backwoods_to_grove,)),
|
||||||
RegionData(SVERegion.enchanted_grove, [SVEEntrance.grove_to_outpost_warp, SVEEntrance.grove_to_wizard_warp,
|
RegionData(SVERegion.enchanted_grove, (SVEEntrance.grove_to_outpost_warp, SVEEntrance.grove_to_wizard_warp,
|
||||||
SVEEntrance.grove_to_farm_warp, SVEEntrance.grove_to_guild_warp, SVEEntrance.grove_to_junimo_warp,
|
SVEEntrance.grove_to_farm_warp, SVEEntrance.grove_to_guild_warp, SVEEntrance.grove_to_junimo_warp,
|
||||||
SVEEntrance.grove_to_spring_warp, SVEEntrance.grove_to_aurora_warp]),
|
SVEEntrance.grove_to_spring_warp, SVEEntrance.grove_to_aurora_warp)),
|
||||||
RegionData(SVERegion.grove_farm_warp, [SVEEntrance.farm_warp_to_farm]),
|
RegionData(SVERegion.grove_farm_warp, (SVEEntrance.farm_warp_to_farm,)),
|
||||||
RegionData(SVERegion.grove_aurora_warp, [SVEEntrance.aurora_warp_to_aurora]),
|
RegionData(SVERegion.grove_aurora_warp, (SVEEntrance.aurora_warp_to_aurora,)),
|
||||||
RegionData(SVERegion.grove_guild_warp, [SVEEntrance.guild_warp_to_guild]),
|
RegionData(SVERegion.grove_guild_warp, (SVEEntrance.guild_warp_to_guild,)),
|
||||||
RegionData(SVERegion.grove_junimo_warp, [SVEEntrance.junimo_warp_to_junimo]),
|
RegionData(SVERegion.grove_junimo_warp, (SVEEntrance.junimo_warp_to_junimo,)),
|
||||||
RegionData(SVERegion.grove_spring_warp, [SVEEntrance.spring_warp_to_spring]),
|
RegionData(SVERegion.grove_spring_warp, (SVEEntrance.spring_warp_to_spring,)),
|
||||||
RegionData(SVERegion.grove_outpost_warp, [SVEEntrance.outpost_warp_to_outpost]),
|
RegionData(SVERegion.grove_outpost_warp, (SVEEntrance.outpost_warp_to_outpost,)),
|
||||||
RegionData(SVERegion.grove_wizard_warp, [SVEEntrance.wizard_warp_to_wizard]),
|
RegionData(SVERegion.grove_wizard_warp, (SVEEntrance.wizard_warp_to_wizard,)),
|
||||||
RegionData(SVERegion.galmoran_outpost, [SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop,
|
RegionData(SVERegion.galmoran_outpost, (SVEEntrance.outpost_to_badlands_entrance, SVEEntrance.use_alesia_shop, SVEEntrance.use_isaac_shop)),
|
||||||
SVEEntrance.use_isaac_shop]),
|
RegionData(SVERegion.badlands_entrance, (SVEEntrance.badlands_entrance_to_badlands,)),
|
||||||
RegionData(SVERegion.badlands_entrance, [SVEEntrance.badlands_entrance_to_badlands]),
|
RegionData(SVERegion.crimson_badlands, (SVEEntrance.badlands_to_cave,)),
|
||||||
RegionData(SVERegion.crimson_badlands, [SVEEntrance.badlands_to_cave]),
|
|
||||||
RegionData(SVERegion.badlands_cave),
|
RegionData(SVERegion.badlands_cave),
|
||||||
RegionData(Region.bus_stop, [SVEEntrance.bus_stop_to_shed]),
|
RegionData(Region.bus_stop, (SVEEntrance.bus_stop_to_shed,)),
|
||||||
RegionData(SVERegion.grandpas_shed, [SVEEntrance.grandpa_shed_to_interior, SVEEntrance.grandpa_shed_to_town]),
|
RegionData(SVERegion.grandpas_shed, (SVEEntrance.grandpa_shed_to_interior, SVEEntrance.grandpa_shed_to_town)),
|
||||||
RegionData(SVERegion.grandpas_shed_interior, [SVEEntrance.grandpa_interior_to_upstairs]),
|
RegionData(SVERegion.grandpas_shed_interior, (SVEEntrance.grandpa_interior_to_upstairs,)),
|
||||||
RegionData(SVERegion.grandpas_shed_upstairs),
|
RegionData(SVERegion.grandpas_shed_upstairs),
|
||||||
RegionData(Region.forest,
|
RegionData(Region.forest,
|
||||||
[SVEEntrance.forest_to_fairhaven, SVEEntrance.forest_to_west, SVEEntrance.forest_to_lost_woods,
|
(SVEEntrance.forest_to_fairhaven, SVEEntrance.forest_to_west, SVEEntrance.forest_to_lost_woods,
|
||||||
SVEEntrance.forest_to_bmv, SVEEntrance.forest_to_marnie_shed]),
|
SVEEntrance.forest_to_bmv, SVEEntrance.forest_to_marnie_shed)),
|
||||||
RegionData(SVERegion.marnies_shed),
|
RegionData(SVERegion.marnies_shed),
|
||||||
RegionData(SVERegion.fairhaven_farm),
|
RegionData(SVERegion.fairhaven_farm),
|
||||||
RegionData(Region.town, [SVEEntrance.town_to_bmv, SVEEntrance.town_to_jenkins,
|
RegionData(Region.town, (SVEEntrance.town_to_bmv, SVEEntrance.town_to_jenkins, SVEEntrance.town_to_bridge, SVEEntrance.town_to_plot)),
|
||||||
SVEEntrance.town_to_bridge, SVEEntrance.town_to_plot]),
|
RegionData(SVERegion.blue_moon_vineyard, (SVEEntrance.bmv_to_sophia, SVEEntrance.bmv_to_beach)),
|
||||||
RegionData(SVERegion.blue_moon_vineyard, [SVEEntrance.bmv_to_sophia, SVEEntrance.bmv_to_beach]),
|
|
||||||
RegionData(SVERegion.sophias_house),
|
RegionData(SVERegion.sophias_house),
|
||||||
RegionData(SVERegion.jenkins_residence, [SVEEntrance.jenkins_to_cellar]),
|
RegionData(SVERegion.jenkins_residence, (SVEEntrance.jenkins_to_cellar,)),
|
||||||
RegionData(SVERegion.jenkins_cellar),
|
RegionData(SVERegion.jenkins_cellar),
|
||||||
RegionData(SVERegion.unclaimed_plot, [SVEEntrance.plot_to_bridge]),
|
RegionData(SVERegion.unclaimed_plot, (SVEEntrance.plot_to_bridge,)),
|
||||||
RegionData(SVERegion.shearwater),
|
RegionData(SVERegion.shearwater),
|
||||||
RegionData(Region.museum, [SVEEntrance.museum_to_gunther_bedroom]),
|
RegionData(Region.museum, (SVEEntrance.museum_to_gunther_bedroom,)),
|
||||||
RegionData(SVERegion.gunther_bedroom),
|
RegionData(SVERegion.gunther_bedroom),
|
||||||
RegionData(Region.fish_shop, [SVEEntrance.fish_shop_to_willy_bedroom]),
|
RegionData(Region.fish_shop, (SVEEntrance.fish_shop_to_willy_bedroom,)),
|
||||||
RegionData(SVERegion.willy_bedroom),
|
RegionData(SVERegion.willy_bedroom),
|
||||||
RegionData(Region.mountain, [SVEEntrance.mountain_to_guild_summit]),
|
RegionData(Region.mountain, (SVEEntrance.mountain_to_guild_summit,)),
|
||||||
RegionData(SVERegion.guild_summit, [SVEEntrance.guild_to_interior, SVEEntrance.guild_to_mines,
|
# These entrances are removed from the mountain region when SVE is enabled
|
||||||
SVEEntrance.summit_to_highlands]),
|
RegionData(Region.mountain, (Entrance.mountain_to_adventurer_guild, Entrance.mountain_to_the_mines), flag=MergeFlag.REMOVE_EXITS),
|
||||||
RegionData(Region.railroad, [SVEEntrance.to_susan_house, SVEEntrance.enter_summit, SVEEntrance.railroad_to_grampleton_station]),
|
RegionData(SVERegion.guild_summit, (SVEEntrance.guild_to_interior, SVEEntrance.guild_to_mines)),
|
||||||
RegionData(SVERegion.grampleton_station, [SVEEntrance.grampleton_station_to_grampleton_suburbs]),
|
RegionData(Region.railroad, (SVEEntrance.to_susan_house, SVEEntrance.enter_summit, SVEEntrance.railroad_to_grampleton_station)),
|
||||||
RegionData(SVERegion.grampleton_suburbs, [SVEEntrance.grampleton_suburbs_to_scarlett_house]),
|
RegionData(SVERegion.grampleton_station, (SVEEntrance.grampleton_station_to_grampleton_suburbs,)),
|
||||||
|
RegionData(SVERegion.grampleton_suburbs, (SVEEntrance.grampleton_suburbs_to_scarlett_house,)),
|
||||||
RegionData(SVERegion.scarlett_house),
|
RegionData(SVERegion.scarlett_house),
|
||||||
RegionData(Region.wizard_basement, [SVEEntrance.wizard_to_fable_reef]),
|
RegionData(SVERegion.forest_west, (SVEEntrance.forest_west_to_spring, SVEEntrance.west_to_aurora, SVEEntrance.use_bear_shop,)),
|
||||||
RegionData(SVERegion.fable_reef, [SVEEntrance.fable_reef_to_guild], is_ginger_island=True),
|
RegionData(SVERegion.aurora_vineyard, (SVEEntrance.to_aurora_basement,)),
|
||||||
RegionData(SVERegion.first_slash_guild, [SVEEntrance.first_slash_guild_to_hallway], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.first_slash_hallway, [SVEEntrance.first_slash_hallway_to_room], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.first_slash_spare_room, is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.highlands_outside, [SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave, SVEEntrance.highlands_to_pond], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.highlands_pond, is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.highlands_cavern, [SVEEntrance.to_dwarf_prison], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.dwarf_prison, is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.lances_house, [SVEEntrance.lance_to_ladder], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.lances_ladder, [SVEEntrance.lance_ladder_to_highlands], is_ginger_island=True),
|
|
||||||
RegionData(SVERegion.forest_west, [SVEEntrance.forest_west_to_spring, SVEEntrance.west_to_aurora,
|
|
||||||
SVEEntrance.use_bear_shop]),
|
|
||||||
RegionData(SVERegion.aurora_vineyard, [SVEEntrance.to_aurora_basement]),
|
|
||||||
RegionData(SVERegion.aurora_vineyard_basement),
|
RegionData(SVERegion.aurora_vineyard_basement),
|
||||||
RegionData(Region.secret_woods, [SVEEntrance.secret_woods_to_west]),
|
RegionData(Region.secret_woods, (SVEEntrance.secret_woods_to_west,)),
|
||||||
RegionData(SVERegion.bear_shop),
|
RegionData(SVERegion.bear_shop),
|
||||||
RegionData(SVERegion.sprite_spring, [SVEEntrance.sprite_spring_to_cave]),
|
RegionData(SVERegion.sprite_spring, (SVEEntrance.sprite_spring_to_cave,)),
|
||||||
RegionData(SVERegion.sprite_spring_cave),
|
RegionData(SVERegion.sprite_spring_cave),
|
||||||
RegionData(SVERegion.lost_woods, [SVEEntrance.lost_woods_to_junimo_woods]),
|
RegionData(SVERegion.lost_woods, (SVEEntrance.lost_woods_to_junimo_woods,)),
|
||||||
RegionData(SVERegion.junimo_woods, [SVEEntrance.use_purple_junimo]),
|
RegionData(SVERegion.junimo_woods, (SVEEntrance.use_purple_junimo,)),
|
||||||
RegionData(SVERegion.purple_junimo_shop),
|
RegionData(SVERegion.purple_junimo_shop),
|
||||||
RegionData(SVERegion.alesia_shop),
|
RegionData(SVERegion.alesia_shop),
|
||||||
RegionData(SVERegion.isaac_shop),
|
RegionData(SVERegion.isaac_shop),
|
||||||
RegionData(SVERegion.summit),
|
RegionData(SVERegion.summit),
|
||||||
RegionData(SVERegion.susans_house),
|
RegionData(SVERegion.susans_house),
|
||||||
RegionData(Region.mountain, [Entrance.mountain_to_adventurer_guild, Entrance.mountain_to_the_mines], ModificationFlag.MODIFIED)
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
mandatory_sve_connections = [
|
sve_ginger_island_regions = [
|
||||||
|
RegionData(Region.wizard_basement, (SVEEntrance.wizard_to_fable_reef,)),
|
||||||
|
|
||||||
|
RegionData(SVERegion.fable_reef, (SVEEntrance.fable_reef_to_guild,)),
|
||||||
|
RegionData(SVERegion.first_slash_guild, (SVEEntrance.first_slash_guild_to_hallway,)),
|
||||||
|
RegionData(SVERegion.first_slash_hallway, (SVEEntrance.first_slash_hallway_to_room,)),
|
||||||
|
RegionData(SVERegion.first_slash_spare_room),
|
||||||
|
RegionData(SVERegion.guild_summit, (SVEEntrance.summit_to_highlands,)),
|
||||||
|
RegionData(SVERegion.highlands_outside, (SVEEntrance.highlands_to_lance, SVEEntrance.highlands_to_cave, SVEEntrance.highlands_to_pond), ),
|
||||||
|
RegionData(SVERegion.highlands_pond),
|
||||||
|
RegionData(SVERegion.highlands_cavern, (SVEEntrance.to_dwarf_prison,)),
|
||||||
|
RegionData(SVERegion.dwarf_prison),
|
||||||
|
RegionData(SVERegion.lances_house, (SVEEntrance.lance_to_ladder,)),
|
||||||
|
RegionData(SVERegion.lances_ladder, (SVEEntrance.lance_ladder_to_highlands,)),
|
||||||
|
]
|
||||||
|
|
||||||
|
sve_main_land_connections = [
|
||||||
ConnectionData(SVEEntrance.town_to_jenkins, SVERegion.jenkins_residence, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
ConnectionData(SVEEntrance.town_to_jenkins, SVERegion.jenkins_residence, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
ConnectionData(SVEEntrance.jenkins_to_cellar, SVERegion.jenkins_cellar, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.jenkins_to_cellar, SVERegion.jenkins_cellar, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.forest_to_bmv, SVERegion.blue_moon_vineyard),
|
ConnectionData(SVEEntrance.forest_to_bmv, SVERegion.blue_moon_vineyard),
|
||||||
@@ -223,7 +222,7 @@ mandatory_sve_connections = [
|
|||||||
ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.grandpa_interior_to_upstairs, SVERegion.grandpas_shed_upstairs, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town),
|
ConnectionData(SVEEntrance.grandpa_shed_to_town, Region.town),
|
||||||
ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
ConnectionData(SVEEntrance.bmv_to_sophia, SVERegion.sophias_house, flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.GINGER_ISLAND),
|
ConnectionData(SVEEntrance.summit_to_highlands, SVERegion.highlands_outside),
|
||||||
ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.guild_to_interior, Region.adventurer_guild, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
ConnectionData(SVEEntrance.backwoods_to_grove, SVERegion.enchanted_grove, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp),
|
ConnectionData(SVEEntrance.grove_to_outpost_warp, SVERegion.grove_outpost_warp),
|
||||||
@@ -242,8 +241,6 @@ mandatory_sve_connections = [
|
|||||||
ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop),
|
ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop),
|
||||||
ConnectionData(SVEEntrance.grove_to_spring_warp, SVERegion.grove_spring_warp),
|
ConnectionData(SVEEntrance.grove_to_spring_warp, SVERegion.grove_spring_warp),
|
||||||
ConnectionData(SVEEntrance.spring_warp_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.spring_warp_to_spring, SVERegion.sprite_spring, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.outpost_to_badlands_entrance, SVERegion.badlands_entrance, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.badlands_entrance_to_badlands, SVERegion.crimson_badlands, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.badlands_to_cave, SVERegion.badlands_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
@@ -259,71 +256,75 @@ mandatory_sve_connections = [
|
|||||||
ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.to_susan_house, SVERegion.susans_house, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.enter_summit, SVERegion.summit, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION),
|
ConnectionData(SVEEntrance.forest_to_fairhaven, SVERegion.fairhaven_farm, flag=RandomizationFlag.NON_PROGRESSION),
|
||||||
ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop),
|
ConnectionData(SVEEntrance.use_bear_shop, SVERegion.bear_shop),
|
||||||
ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop),
|
ConnectionData(SVEEntrance.use_purple_junimo, SVERegion.purple_junimo_shop),
|
||||||
ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop),
|
ConnectionData(SVEEntrance.use_alesia_shop, SVERegion.alesia_shop),
|
||||||
ConnectionData(SVEEntrance.use_isaac_shop, SVERegion.isaac_shop),
|
ConnectionData(SVEEntrance.use_isaac_shop, SVERegion.isaac_shop),
|
||||||
ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station),
|
ConnectionData(SVEEntrance.railroad_to_grampleton_station, SVERegion.grampleton_station),
|
||||||
ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs),
|
ConnectionData(SVEEntrance.grampleton_station_to_grampleton_suburbs, SVERegion.grampleton_suburbs),
|
||||||
ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.grampleton_suburbs_to_scarlett_house, SVERegion.scarlett_house, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.sprite_spring_to_cave, SVERegion.sprite_spring_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.fish_shop_to_willy_bedroom, SVERegion.willy_bedroom, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.fish_shop_to_willy_bedroom, SVERegion.willy_bedroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.museum_to_gunther_bedroom, SVERegion.gunther_bedroom, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(SVEEntrance.museum_to_gunther_bedroom, SVERegion.gunther_bedroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(SVEEntrance.highlands_to_pond, SVERegion.highlands_pond),
|
ConnectionData(SVEEntrance.highlands_to_pond, SVERegion.highlands_pond),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
sve_ginger_island_connections = [
|
||||||
|
ConnectionData(SVEEntrance.wizard_to_fable_reef, SVERegion.fable_reef, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.fable_reef_to_guild, SVERegion.first_slash_guild, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.highlands_to_lance, SVERegion.lances_house, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.lance_to_ladder, SVERegion.lances_ladder),
|
||||||
|
ConnectionData(SVEEntrance.lance_ladder_to_highlands, SVERegion.highlands_outside, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.highlands_to_cave, SVERegion.highlands_cavern, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.to_dwarf_prison, SVERegion.dwarf_prison, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.first_slash_guild_to_hallway, SVERegion.first_slash_hallway, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(SVEEntrance.first_slash_hallway_to_room, SVERegion.first_slash_spare_room, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
]
|
||||||
|
|
||||||
alecto_regions = [
|
alecto_regions = [
|
||||||
RegionData(Region.witch_hut, [AlectoEntrance.witch_hut_to_witch_attic]),
|
RegionData(Region.witch_hut, (AlectoEntrance.witch_hut_to_witch_attic,)),
|
||||||
RegionData(AlectoRegion.witch_attic)
|
RegionData(AlectoRegion.witch_attic),
|
||||||
]
|
]
|
||||||
|
|
||||||
alecto_entrances = [
|
alecto_entrances = [
|
||||||
ConnectionData(AlectoEntrance.witch_hut_to_witch_attic, AlectoRegion.witch_attic, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(AlectoEntrance.witch_hut_to_witch_attic, AlectoRegion.witch_attic, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
lacey_regions = [
|
lacey_regions = [
|
||||||
RegionData(Region.forest, [LaceyEntrance.forest_to_hat_house]),
|
RegionData(Region.forest, (LaceyEntrance.forest_to_hat_house,)),
|
||||||
RegionData(LaceyRegion.hat_house)
|
RegionData(LaceyRegion.hat_house),
|
||||||
]
|
]
|
||||||
|
|
||||||
lacey_entrances = [
|
lacey_entrances = [
|
||||||
ConnectionData(LaceyEntrance.forest_to_hat_house, LaceyRegion.hat_house, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(LaceyEntrance.forest_to_hat_house, LaceyRegion.hat_house, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
boarding_house_regions = [
|
boarding_house_regions = [
|
||||||
RegionData(Region.bus_stop, [BoardingHouseEntrance.bus_stop_to_boarding_house_plateau]),
|
RegionData(Region.bus_stop, (BoardingHouseEntrance.bus_stop_to_boarding_house_plateau,)),
|
||||||
RegionData(BoardingHouseRegion.boarding_house_plateau, [BoardingHouseEntrance.boarding_house_plateau_to_boarding_house_first,
|
RegionData(BoardingHouseRegion.boarding_house_plateau, (BoardingHouseEntrance.boarding_house_plateau_to_boarding_house_first,
|
||||||
BoardingHouseEntrance.boarding_house_plateau_to_buffalo_ranch,
|
BoardingHouseEntrance.boarding_house_plateau_to_buffalo_ranch,
|
||||||
BoardingHouseEntrance.boarding_house_plateau_to_abandoned_mines_entrance]),
|
BoardingHouseEntrance.boarding_house_plateau_to_abandoned_mines_entrance)),
|
||||||
RegionData(BoardingHouseRegion.boarding_house_first, [BoardingHouseEntrance.boarding_house_first_to_boarding_house_second]),
|
RegionData(BoardingHouseRegion.boarding_house_first, (BoardingHouseEntrance.boarding_house_first_to_boarding_house_second,)),
|
||||||
RegionData(BoardingHouseRegion.boarding_house_second),
|
RegionData(BoardingHouseRegion.boarding_house_second),
|
||||||
RegionData(BoardingHouseRegion.buffalo_ranch),
|
RegionData(BoardingHouseRegion.buffalo_ranch),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_entrance, [BoardingHouseEntrance.abandoned_mines_entrance_to_abandoned_mines_1a,
|
RegionData(BoardingHouseRegion.abandoned_mines_entrance, (BoardingHouseEntrance.abandoned_mines_entrance_to_abandoned_mines_1a,
|
||||||
BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley]),
|
BoardingHouseEntrance.abandoned_mines_entrance_to_the_lost_valley)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_1a, [BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b]),
|
RegionData(BoardingHouseRegion.abandoned_mines_1a, (BoardingHouseEntrance.abandoned_mines_1a_to_abandoned_mines_1b,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_1b, [BoardingHouseEntrance.abandoned_mines_1b_to_abandoned_mines_2a]),
|
RegionData(BoardingHouseRegion.abandoned_mines_1b, (BoardingHouseEntrance.abandoned_mines_1b_to_abandoned_mines_2a,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_2a, [BoardingHouseEntrance.abandoned_mines_2a_to_abandoned_mines_2b]),
|
RegionData(BoardingHouseRegion.abandoned_mines_2a, (BoardingHouseEntrance.abandoned_mines_2a_to_abandoned_mines_2b,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_2b, [BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3]),
|
RegionData(BoardingHouseRegion.abandoned_mines_2b, (BoardingHouseEntrance.abandoned_mines_2b_to_abandoned_mines_3,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_3, [BoardingHouseEntrance.abandoned_mines_3_to_abandoned_mines_4]),
|
RegionData(BoardingHouseRegion.abandoned_mines_3, (BoardingHouseEntrance.abandoned_mines_3_to_abandoned_mines_4,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_4, [BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5]),
|
RegionData(BoardingHouseRegion.abandoned_mines_4, (BoardingHouseEntrance.abandoned_mines_4_to_abandoned_mines_5,)),
|
||||||
RegionData(BoardingHouseRegion.abandoned_mines_5, [BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley]),
|
RegionData(BoardingHouseRegion.abandoned_mines_5, (BoardingHouseEntrance.abandoned_mines_5_to_the_lost_valley,)),
|
||||||
RegionData(BoardingHouseRegion.the_lost_valley, [BoardingHouseEntrance.the_lost_valley_to_gregory_tent,
|
RegionData(BoardingHouseRegion.the_lost_valley, (BoardingHouseEntrance.the_lost_valley_to_gregory_tent,
|
||||||
BoardingHouseEntrance.lost_valley_to_lost_valley_minecart,
|
BoardingHouseEntrance.lost_valley_to_lost_valley_minecart,
|
||||||
BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins]),
|
BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins)),
|
||||||
RegionData(BoardingHouseRegion.gregory_tent),
|
RegionData(BoardingHouseRegion.gregory_tent),
|
||||||
RegionData(BoardingHouseRegion.lost_valley_ruins, [BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1,
|
RegionData(BoardingHouseRegion.lost_valley_ruins, (BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1,
|
||||||
BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2]),
|
BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2)),
|
||||||
RegionData(BoardingHouseRegion.lost_valley_minecart),
|
RegionData(BoardingHouseRegion.lost_valley_minecart),
|
||||||
RegionData(BoardingHouseRegion.lost_valley_house_1),
|
RegionData(BoardingHouseRegion.lost_valley_house_1),
|
||||||
RegionData(BoardingHouseRegion.lost_valley_house_2)
|
RegionData(BoardingHouseRegion.lost_valley_house_2),
|
||||||
]
|
]
|
||||||
|
|
||||||
boarding_house_entrances = [
|
boarding_house_entrances = [
|
||||||
@@ -351,30 +352,29 @@ boarding_house_entrances = [
|
|||||||
ConnectionData(BoardingHouseEntrance.lost_valley_to_lost_valley_minecart, BoardingHouseRegion.lost_valley_minecart),
|
ConnectionData(BoardingHouseEntrance.lost_valley_to_lost_valley_minecart, BoardingHouseRegion.lost_valley_minecart),
|
||||||
ConnectionData(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, BoardingHouseRegion.lost_valley_ruins, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(BoardingHouseEntrance.the_lost_valley_to_lost_valley_ruins, BoardingHouseRegion.lost_valley_ruins, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, BoardingHouseRegion.lost_valley_house_1, flag=RandomizationFlag.BUILDINGS),
|
ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_1, BoardingHouseRegion.lost_valley_house_1, flag=RandomizationFlag.BUILDINGS),
|
||||||
ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2, BoardingHouseRegion.lost_valley_house_2, flag=RandomizationFlag.BUILDINGS)
|
ConnectionData(BoardingHouseEntrance.lost_valley_ruins_to_lost_valley_house_2, BoardingHouseRegion.lost_valley_house_2, flag=RandomizationFlag.BUILDINGS),
|
||||||
]
|
]
|
||||||
|
|
||||||
vanilla_connections_to_remove_by_mod: Dict[str, List[ConnectionData]] = {
|
vanilla_connections_to_remove_by_content_pack: dict[str, tuple[str, ...]] = {
|
||||||
ModNames.sve: [
|
ModNames.sve: (
|
||||||
ConnectionData(Entrance.mountain_to_the_mines, Region.mines,
|
Entrance.mountain_to_the_mines,
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
Entrance.mountain_to_adventurer_guild,
|
||||||
ConnectionData(Entrance.mountain_to_adventurer_guild, Region.adventurer_guild,
|
)
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModDataList = {
|
region_data_by_content_pack = {
|
||||||
ModNames.deepwoods: ModRegionData(ModNames.deepwoods, deep_woods_regions, deep_woods_entrances),
|
ModNames.deepwoods: ModRegionsData(ModNames.deepwoods, deep_woods_regions, deep_woods_entrances),
|
||||||
ModNames.eugene: ModRegionData(ModNames.eugene, eugene_regions, eugene_entrances),
|
ModNames.eugene: ModRegionsData(ModNames.eugene, eugene_regions, eugene_entrances),
|
||||||
ModNames.jasper: ModRegionData(ModNames.jasper, jasper_regions, jasper_entrances),
|
ModNames.jasper: ModRegionsData(ModNames.jasper, jasper_regions, jasper_entrances),
|
||||||
ModNames.alec: ModRegionData(ModNames.alec, alec_regions, alec_entrances),
|
ModNames.alec: ModRegionsData(ModNames.alec, alec_regions, alec_entrances),
|
||||||
ModNames.yoba: ModRegionData(ModNames.yoba, yoba_regions, yoba_entrances),
|
ModNames.yoba: ModRegionsData(ModNames.yoba, yoba_regions, yoba_entrances),
|
||||||
ModNames.juna: ModRegionData(ModNames.juna, juna_regions, juna_entrances),
|
ModNames.juna: ModRegionsData(ModNames.juna, juna_regions, juna_entrances),
|
||||||
ModNames.magic: ModRegionData(ModNames.magic, magic_regions, magic_entrances),
|
ModNames.magic: ModRegionsData(ModNames.magic, magic_regions, magic_entrances),
|
||||||
ModNames.ayeisha: ModRegionData(ModNames.ayeisha, ayeisha_regions, ayeisha_entrances),
|
ModNames.ayeisha: ModRegionsData(ModNames.ayeisha, ayeisha_regions, ayeisha_entrances),
|
||||||
ModNames.riley: ModRegionData(ModNames.riley, riley_regions, riley_entrances),
|
ModNames.riley: ModRegionsData(ModNames.riley, riley_regions, riley_entrances),
|
||||||
ModNames.sve: ModRegionData(ModNames.sve, stardew_valley_expanded_regions, mandatory_sve_connections),
|
ModNames.sve: ModRegionsData(ModNames.sve, sve_main_land_regions, sve_main_land_connections),
|
||||||
ModNames.alecto: ModRegionData(ModNames.alecto, alecto_regions, alecto_entrances),
|
SVE_GINGER_ISLAND_PACK: ModRegionsData(SVE_GINGER_ISLAND_PACK, sve_ginger_island_regions, sve_ginger_island_connections),
|
||||||
ModNames.lacey: ModRegionData(ModNames.lacey, lacey_regions, lacey_entrances),
|
ModNames.alecto: ModRegionsData(ModNames.alecto, alecto_regions, alecto_entrances),
|
||||||
ModNames.boarding_house: ModRegionData(ModNames.boarding_house, boarding_house_regions, boarding_house_entrances),
|
ModNames.lacey: ModRegionsData(ModNames.lacey, lacey_regions, lacey_entrances),
|
||||||
|
ModNames.boarding_house: ModRegionsData(ModNames.boarding_house, boarding_house_regions, boarding_house_entrances),
|
||||||
}
|
}
|
@@ -1,67 +0,0 @@
|
|||||||
from copy import deepcopy
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from enum import IntFlag
|
|
||||||
from typing import Optional, List, Set
|
|
||||||
|
|
||||||
connector_keyword = " to "
|
|
||||||
|
|
||||||
|
|
||||||
class ModificationFlag(IntFlag):
|
|
||||||
NOT_MODIFIED = 0
|
|
||||||
MODIFIED = 1
|
|
||||||
|
|
||||||
|
|
||||||
class RandomizationFlag(IntFlag):
|
|
||||||
NOT_RANDOMIZED = 0b0
|
|
||||||
PELICAN_TOWN = 0b00011111
|
|
||||||
NON_PROGRESSION = 0b00011110
|
|
||||||
BUILDINGS = 0b00011100
|
|
||||||
EVERYTHING = 0b00011000
|
|
||||||
GINGER_ISLAND = 0b00100000
|
|
||||||
LEAD_TO_OPEN_AREA = 0b01000000
|
|
||||||
MASTERIES = 0b10000000
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class RegionData:
|
|
||||||
name: str
|
|
||||||
exits: List[str] = field(default_factory=list)
|
|
||||||
flag: ModificationFlag = ModificationFlag.NOT_MODIFIED
|
|
||||||
is_ginger_island: bool = False
|
|
||||||
|
|
||||||
def get_merged_with(self, exits: List[str]):
|
|
||||||
merged_exits = []
|
|
||||||
merged_exits.extend(self.exits)
|
|
||||||
if exits is not None:
|
|
||||||
merged_exits.extend(exits)
|
|
||||||
merged_exits = sorted(set(merged_exits))
|
|
||||||
return RegionData(self.name, merged_exits, is_ginger_island=self.is_ginger_island)
|
|
||||||
|
|
||||||
def get_without_exits(self, exits_to_remove: Set[str]):
|
|
||||||
exits = [exit_ for exit_ in self.exits if exit_ not in exits_to_remove]
|
|
||||||
return RegionData(self.name, exits, is_ginger_island=self.is_ginger_island)
|
|
||||||
|
|
||||||
def get_clone(self):
|
|
||||||
return deepcopy(self)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class ConnectionData:
|
|
||||||
name: str
|
|
||||||
destination: str
|
|
||||||
origin: Optional[str] = None
|
|
||||||
reverse: Optional[str] = None
|
|
||||||
flag: RandomizationFlag = RandomizationFlag.NOT_RANDOMIZED
|
|
||||||
|
|
||||||
def __post_init__(self):
|
|
||||||
if connector_keyword in self.name:
|
|
||||||
origin, destination = self.name.split(connector_keyword)
|
|
||||||
if self.reverse is None:
|
|
||||||
super().__setattr__("reverse", f"{destination}{connector_keyword}{origin}")
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class ModRegionData:
|
|
||||||
mod_name: str
|
|
||||||
regions: List[RegionData]
|
|
||||||
connections: List[ConnectionData]
|
|
@@ -1,775 +0,0 @@
|
|||||||
from random import Random
|
|
||||||
from typing import Iterable, Dict, Protocol, List, Tuple, Set
|
|
||||||
|
|
||||||
from BaseClasses import Region, Entrance
|
|
||||||
from .content import content_packs, StardewContent
|
|
||||||
from .mods.mod_regions import ModDataList, vanilla_connections_to_remove_by_mod
|
|
||||||
from .options import EntranceRandomization, ExcludeGingerIsland, StardewValleyOptions
|
|
||||||
from .region_classes import RegionData, ConnectionData, RandomizationFlag, ModificationFlag
|
|
||||||
from .strings.entrance_names import Entrance, LogicEntrance
|
|
||||||
from .strings.region_names import Region as RegionName, LogicRegion
|
|
||||||
|
|
||||||
|
|
||||||
class RegionFactory(Protocol):
|
|
||||||
def __call__(self, name: str, regions: Iterable[str]) -> Region:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
vanilla_regions = [
|
|
||||||
RegionData(RegionName.menu, [Entrance.to_stardew_valley]),
|
|
||||||
RegionData(RegionName.stardew_valley, [Entrance.to_farmhouse]),
|
|
||||||
RegionData(RegionName.farm_house,
|
|
||||||
[Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, LogicEntrance.farmhouse_cooking, LogicEntrance.watch_queen_of_sauce]),
|
|
||||||
RegionData(RegionName.cellar),
|
|
||||||
RegionData(RegionName.farm,
|
|
||||||
[Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse,
|
|
||||||
Entrance.enter_coop, Entrance.enter_barn, Entrance.enter_shed, Entrance.enter_slime_hutch, LogicEntrance.grow_spring_crops,
|
|
||||||
LogicEntrance.grow_summer_crops, LogicEntrance.grow_fall_crops, LogicEntrance.grow_winter_crops, LogicEntrance.shipping,
|
|
||||||
LogicEntrance.fishing, ]),
|
|
||||||
RegionData(RegionName.backwoods, [Entrance.backwoods_to_mountain]),
|
|
||||||
RegionData(RegionName.bus_stop,
|
|
||||||
[Entrance.bus_stop_to_town, Entrance.take_bus_to_desert, Entrance.bus_stop_to_tunnel_entrance]),
|
|
||||||
RegionData(RegionName.forest,
|
|
||||||
[Entrance.forest_to_town, Entrance.enter_secret_woods, Entrance.forest_to_wizard_tower, Entrance.forest_to_marnie_ranch,
|
|
||||||
Entrance.forest_to_leah_cottage, Entrance.forest_to_sewer, Entrance.forest_to_mastery_cave, LogicEntrance.buy_from_traveling_merchant,
|
|
||||||
LogicEntrance.complete_raccoon_requests, LogicEntrance.fish_in_waterfall, LogicEntrance.attend_flower_dance, LogicEntrance.attend_trout_derby,
|
|
||||||
LogicEntrance.attend_festival_of_ice]),
|
|
||||||
RegionData(LogicRegion.forest_waterfall),
|
|
||||||
RegionData(RegionName.farm_cave),
|
|
||||||
RegionData(RegionName.greenhouse,
|
|
||||||
[LogicEntrance.grow_spring_crops_in_greenhouse, LogicEntrance.grow_summer_crops_in_greenhouse, LogicEntrance.grow_fall_crops_in_greenhouse,
|
|
||||||
LogicEntrance.grow_winter_crops_in_greenhouse, LogicEntrance.grow_indoor_crops_in_greenhouse]),
|
|
||||||
RegionData(RegionName.mountain,
|
|
||||||
[Entrance.mountain_to_railroad, Entrance.mountain_to_tent, Entrance.mountain_to_carpenter_shop,
|
|
||||||
Entrance.mountain_to_the_mines, Entrance.enter_quarry, Entrance.mountain_to_adventurer_guild,
|
|
||||||
Entrance.mountain_to_town, Entrance.mountain_to_maru_room,
|
|
||||||
Entrance.mountain_to_leo_treehouse]),
|
|
||||||
RegionData(RegionName.leo_treehouse, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.maru_room),
|
|
||||||
RegionData(RegionName.tunnel_entrance, [Entrance.tunnel_entrance_to_bus_tunnel]),
|
|
||||||
RegionData(RegionName.bus_tunnel),
|
|
||||||
RegionData(RegionName.town,
|
|
||||||
[Entrance.town_to_community_center, Entrance.town_to_beach, Entrance.town_to_hospital, Entrance.town_to_pierre_general_store,
|
|
||||||
Entrance.town_to_saloon, Entrance.town_to_alex_house, Entrance.town_to_trailer, Entrance.town_to_mayor_manor, Entrance.town_to_sam_house,
|
|
||||||
Entrance.town_to_haley_house, Entrance.town_to_sewer, Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, Entrance.town_to_jojamart,
|
|
||||||
Entrance.purchase_movie_ticket, LogicEntrance.buy_experience_books, LogicEntrance.attend_egg_festival, LogicEntrance.attend_fair,
|
|
||||||
LogicEntrance.attend_spirit_eve, LogicEntrance.attend_winter_star]),
|
|
||||||
RegionData(RegionName.beach,
|
|
||||||
[Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, LogicEntrance.attend_luau,
|
|
||||||
LogicEntrance.attend_moonlight_jellies, LogicEntrance.attend_night_market, LogicEntrance.attend_squidfest]),
|
|
||||||
RegionData(RegionName.railroad, [Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave]),
|
|
||||||
RegionData(RegionName.ranch),
|
|
||||||
RegionData(RegionName.leah_house),
|
|
||||||
RegionData(RegionName.mastery_cave),
|
|
||||||
RegionData(RegionName.sewer, [Entrance.enter_mutant_bug_lair]),
|
|
||||||
RegionData(RegionName.mutant_bug_lair),
|
|
||||||
RegionData(RegionName.wizard_tower, [Entrance.enter_wizard_basement, Entrance.use_desert_obelisk, Entrance.use_island_obelisk]),
|
|
||||||
RegionData(RegionName.wizard_basement),
|
|
||||||
RegionData(RegionName.tent),
|
|
||||||
RegionData(RegionName.carpenter, [Entrance.enter_sebastian_room]),
|
|
||||||
RegionData(RegionName.sebastian_room),
|
|
||||||
RegionData(RegionName.adventurer_guild, [Entrance.adventurer_guild_to_bedroom]),
|
|
||||||
RegionData(RegionName.adventurer_guild_bedroom),
|
|
||||||
RegionData(RegionName.community_center,
|
|
||||||
[Entrance.access_crafts_room, Entrance.access_pantry, Entrance.access_fish_tank,
|
|
||||||
Entrance.access_boiler_room, Entrance.access_bulletin_board, Entrance.access_vault]),
|
|
||||||
RegionData(RegionName.crafts_room),
|
|
||||||
RegionData(RegionName.pantry),
|
|
||||||
RegionData(RegionName.fish_tank),
|
|
||||||
RegionData(RegionName.boiler_room),
|
|
||||||
RegionData(RegionName.bulletin_board),
|
|
||||||
RegionData(RegionName.vault),
|
|
||||||
RegionData(RegionName.hospital, [Entrance.enter_harvey_room]),
|
|
||||||
RegionData(RegionName.harvey_room),
|
|
||||||
RegionData(RegionName.pierre_store, [Entrance.enter_sunroom]),
|
|
||||||
RegionData(RegionName.sunroom),
|
|
||||||
RegionData(RegionName.saloon, [Entrance.play_journey_of_the_prairie_king, Entrance.play_junimo_kart]),
|
|
||||||
RegionData(RegionName.jotpk_world_1, [Entrance.reach_jotpk_world_2]),
|
|
||||||
RegionData(RegionName.jotpk_world_2, [Entrance.reach_jotpk_world_3]),
|
|
||||||
RegionData(RegionName.jotpk_world_3),
|
|
||||||
RegionData(RegionName.junimo_kart_1, [Entrance.reach_junimo_kart_2]),
|
|
||||||
RegionData(RegionName.junimo_kart_2, [Entrance.reach_junimo_kart_3]),
|
|
||||||
RegionData(RegionName.junimo_kart_3, [Entrance.reach_junimo_kart_4]),
|
|
||||||
RegionData(RegionName.junimo_kart_4),
|
|
||||||
RegionData(RegionName.alex_house),
|
|
||||||
RegionData(RegionName.trailer),
|
|
||||||
RegionData(RegionName.mayor_house),
|
|
||||||
RegionData(RegionName.sam_house),
|
|
||||||
RegionData(RegionName.haley_house),
|
|
||||||
RegionData(RegionName.blacksmith, [LogicEntrance.blacksmith_copper]),
|
|
||||||
RegionData(RegionName.museum),
|
|
||||||
RegionData(RegionName.jojamart, [Entrance.enter_abandoned_jojamart]),
|
|
||||||
RegionData(RegionName.abandoned_jojamart, [Entrance.enter_movie_theater]),
|
|
||||||
RegionData(RegionName.movie_ticket_stand),
|
|
||||||
RegionData(RegionName.movie_theater),
|
|
||||||
RegionData(RegionName.fish_shop, [Entrance.fish_shop_to_boat_tunnel]),
|
|
||||||
RegionData(RegionName.boat_tunnel, [Entrance.boat_to_ginger_island], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.elliott_house),
|
|
||||||
RegionData(RegionName.tide_pools),
|
|
||||||
RegionData(RegionName.bathhouse_entrance, [Entrance.enter_locker_room]),
|
|
||||||
RegionData(RegionName.locker_room, [Entrance.enter_public_bath]),
|
|
||||||
RegionData(RegionName.public_bath),
|
|
||||||
RegionData(RegionName.witch_warp_cave, [Entrance.enter_witch_swamp]),
|
|
||||||
RegionData(RegionName.witch_swamp, [Entrance.enter_witch_hut]),
|
|
||||||
RegionData(RegionName.witch_hut, [Entrance.witch_warp_to_wizard_basement]),
|
|
||||||
RegionData(RegionName.quarry, [Entrance.enter_quarry_mine_entrance]),
|
|
||||||
RegionData(RegionName.quarry_mine_entrance, [Entrance.enter_quarry_mine]),
|
|
||||||
RegionData(RegionName.quarry_mine),
|
|
||||||
RegionData(RegionName.secret_woods),
|
|
||||||
RegionData(RegionName.desert, [Entrance.enter_skull_cavern_entrance, Entrance.enter_oasis, LogicEntrance.attend_desert_festival]),
|
|
||||||
RegionData(RegionName.oasis, [Entrance.enter_casino]),
|
|
||||||
RegionData(RegionName.casino),
|
|
||||||
RegionData(RegionName.skull_cavern_entrance, [Entrance.enter_skull_cavern]),
|
|
||||||
RegionData(RegionName.skull_cavern, [Entrance.mine_to_skull_cavern_floor_25]),
|
|
||||||
RegionData(RegionName.skull_cavern_25, [Entrance.mine_to_skull_cavern_floor_50]),
|
|
||||||
RegionData(RegionName.skull_cavern_50, [Entrance.mine_to_skull_cavern_floor_75]),
|
|
||||||
RegionData(RegionName.skull_cavern_75, [Entrance.mine_to_skull_cavern_floor_100]),
|
|
||||||
RegionData(RegionName.skull_cavern_100, [Entrance.mine_to_skull_cavern_floor_125]),
|
|
||||||
RegionData(RegionName.skull_cavern_125, [Entrance.mine_to_skull_cavern_floor_150]),
|
|
||||||
RegionData(RegionName.skull_cavern_150, [Entrance.mine_to_skull_cavern_floor_175]),
|
|
||||||
RegionData(RegionName.skull_cavern_175, [Entrance.mine_to_skull_cavern_floor_200]),
|
|
||||||
RegionData(RegionName.skull_cavern_200, [Entrance.enter_dangerous_skull_cavern]),
|
|
||||||
RegionData(RegionName.dangerous_skull_cavern, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_south,
|
|
||||||
[Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast,
|
|
||||||
Entrance.use_island_resort, Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_docks_to_dig_site,
|
|
||||||
Entrance.parrot_express_docks_to_jungle],
|
|
||||||
is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_resort, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_west,
|
|
||||||
[Entrance.island_west_to_islandfarmhouse, Entrance.island_west_to_gourmand_cave, Entrance.island_west_to_crystals_cave,
|
|
||||||
Entrance.island_west_to_shipwreck, Entrance.island_west_to_qi_walnut_room, Entrance.use_farm_obelisk, Entrance.parrot_express_jungle_to_docks,
|
|
||||||
Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_jungle_to_volcano, LogicEntrance.grow_spring_crops_on_island,
|
|
||||||
LogicEntrance.grow_summer_crops_on_island, LogicEntrance.grow_fall_crops_on_island, LogicEntrance.grow_winter_crops_on_island,
|
|
||||||
LogicEntrance.grow_indoor_crops_on_island],
|
|
||||||
is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_east, [Entrance.island_east_to_leo_hut, Entrance.island_east_to_island_shrine], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_shrine, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_south_east, [Entrance.island_southeast_to_pirate_cove], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_north,
|
|
||||||
[Entrance.talk_to_island_trader, Entrance.island_north_to_field_office, Entrance.island_north_to_dig_site, Entrance.island_north_to_volcano,
|
|
||||||
Entrance.parrot_express_volcano_to_dig_site, Entrance.parrot_express_volcano_to_jungle, Entrance.parrot_express_volcano_to_docks],
|
|
||||||
is_ginger_island=True),
|
|
||||||
RegionData(RegionName.volcano, [Entrance.climb_to_volcano_5, Entrance.volcano_to_secret_beach], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.volcano_secret_beach, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.volcano_floor_5, [Entrance.talk_to_volcano_dwarf, Entrance.climb_to_volcano_10], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.volcano_dwarf_shop, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.volcano_floor_10, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_trader, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.island_farmhouse, [LogicEntrance.island_cooking], is_ginger_island=True),
|
|
||||||
RegionData(RegionName.gourmand_frog_cave, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.colored_crystals_cave, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.shipwreck, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.qi_walnut_room, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.leo_hut, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.pirate_cove, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.field_office, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.dig_site,
|
|
||||||
[Entrance.dig_site_to_professor_snail_cave, Entrance.parrot_express_dig_site_to_volcano,
|
|
||||||
Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_dig_site_to_jungle],
|
|
||||||
is_ginger_island=True),
|
|
||||||
RegionData(RegionName.professor_snail_cave, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.coop),
|
|
||||||
RegionData(RegionName.barn),
|
|
||||||
RegionData(RegionName.shed),
|
|
||||||
RegionData(RegionName.slime_hutch),
|
|
||||||
|
|
||||||
RegionData(RegionName.mines, [LogicEntrance.talk_to_mines_dwarf,
|
|
||||||
Entrance.dig_to_mines_floor_5]),
|
|
||||||
RegionData(RegionName.mines_floor_5, [Entrance.dig_to_mines_floor_10]),
|
|
||||||
RegionData(RegionName.mines_floor_10, [Entrance.dig_to_mines_floor_15]),
|
|
||||||
RegionData(RegionName.mines_floor_15, [Entrance.dig_to_mines_floor_20]),
|
|
||||||
RegionData(RegionName.mines_floor_20, [Entrance.dig_to_mines_floor_25]),
|
|
||||||
RegionData(RegionName.mines_floor_25, [Entrance.dig_to_mines_floor_30]),
|
|
||||||
RegionData(RegionName.mines_floor_30, [Entrance.dig_to_mines_floor_35]),
|
|
||||||
RegionData(RegionName.mines_floor_35, [Entrance.dig_to_mines_floor_40]),
|
|
||||||
RegionData(RegionName.mines_floor_40, [Entrance.dig_to_mines_floor_45]),
|
|
||||||
RegionData(RegionName.mines_floor_45, [Entrance.dig_to_mines_floor_50]),
|
|
||||||
RegionData(RegionName.mines_floor_50, [Entrance.dig_to_mines_floor_55]),
|
|
||||||
RegionData(RegionName.mines_floor_55, [Entrance.dig_to_mines_floor_60]),
|
|
||||||
RegionData(RegionName.mines_floor_60, [Entrance.dig_to_mines_floor_65]),
|
|
||||||
RegionData(RegionName.mines_floor_65, [Entrance.dig_to_mines_floor_70]),
|
|
||||||
RegionData(RegionName.mines_floor_70, [Entrance.dig_to_mines_floor_75]),
|
|
||||||
RegionData(RegionName.mines_floor_75, [Entrance.dig_to_mines_floor_80]),
|
|
||||||
RegionData(RegionName.mines_floor_80, [Entrance.dig_to_mines_floor_85]),
|
|
||||||
RegionData(RegionName.mines_floor_85, [Entrance.dig_to_mines_floor_90]),
|
|
||||||
RegionData(RegionName.mines_floor_90, [Entrance.dig_to_mines_floor_95]),
|
|
||||||
RegionData(RegionName.mines_floor_95, [Entrance.dig_to_mines_floor_100]),
|
|
||||||
RegionData(RegionName.mines_floor_100, [Entrance.dig_to_mines_floor_105]),
|
|
||||||
RegionData(RegionName.mines_floor_105, [Entrance.dig_to_mines_floor_110]),
|
|
||||||
RegionData(RegionName.mines_floor_110, [Entrance.dig_to_mines_floor_115]),
|
|
||||||
RegionData(RegionName.mines_floor_115, [Entrance.dig_to_mines_floor_120]),
|
|
||||||
RegionData(RegionName.mines_floor_120, [Entrance.dig_to_dangerous_mines_20, Entrance.dig_to_dangerous_mines_60, Entrance.dig_to_dangerous_mines_100]),
|
|
||||||
RegionData(RegionName.dangerous_mines_20, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.dangerous_mines_60, is_ginger_island=True),
|
|
||||||
RegionData(RegionName.dangerous_mines_100, is_ginger_island=True),
|
|
||||||
|
|
||||||
RegionData(LogicRegion.mines_dwarf_shop),
|
|
||||||
RegionData(LogicRegion.blacksmith_copper, [LogicEntrance.blacksmith_iron]),
|
|
||||||
RegionData(LogicRegion.blacksmith_iron, [LogicEntrance.blacksmith_gold]),
|
|
||||||
RegionData(LogicRegion.blacksmith_gold, [LogicEntrance.blacksmith_iridium]),
|
|
||||||
RegionData(LogicRegion.blacksmith_iridium),
|
|
||||||
RegionData(LogicRegion.kitchen),
|
|
||||||
RegionData(LogicRegion.queen_of_sauce),
|
|
||||||
RegionData(LogicRegion.fishing),
|
|
||||||
|
|
||||||
RegionData(LogicRegion.spring_farming),
|
|
||||||
RegionData(LogicRegion.summer_farming, [LogicEntrance.grow_summer_fall_crops_in_summer]),
|
|
||||||
RegionData(LogicRegion.fall_farming, [LogicEntrance.grow_summer_fall_crops_in_fall]),
|
|
||||||
RegionData(LogicRegion.winter_farming),
|
|
||||||
RegionData(LogicRegion.summer_or_fall_farming),
|
|
||||||
RegionData(LogicRegion.indoor_farming),
|
|
||||||
|
|
||||||
RegionData(LogicRegion.shipping),
|
|
||||||
RegionData(LogicRegion.traveling_cart, [LogicEntrance.buy_from_traveling_merchant_sunday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_monday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_tuesday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_wednesday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_thursday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_friday,
|
|
||||||
LogicEntrance.buy_from_traveling_merchant_saturday]),
|
|
||||||
RegionData(LogicRegion.traveling_cart_sunday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_monday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_tuesday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_wednesday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_thursday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_friday),
|
|
||||||
RegionData(LogicRegion.traveling_cart_saturday),
|
|
||||||
RegionData(LogicRegion.raccoon_daddy, [LogicEntrance.buy_from_raccoon]),
|
|
||||||
RegionData(LogicRegion.raccoon_shop),
|
|
||||||
|
|
||||||
RegionData(LogicRegion.egg_festival),
|
|
||||||
RegionData(LogicRegion.desert_festival),
|
|
||||||
RegionData(LogicRegion.flower_dance),
|
|
||||||
RegionData(LogicRegion.luau),
|
|
||||||
RegionData(LogicRegion.trout_derby),
|
|
||||||
RegionData(LogicRegion.moonlight_jellies),
|
|
||||||
RegionData(LogicRegion.fair),
|
|
||||||
RegionData(LogicRegion.spirit_eve),
|
|
||||||
RegionData(LogicRegion.festival_of_ice),
|
|
||||||
RegionData(LogicRegion.night_market),
|
|
||||||
RegionData(LogicRegion.winter_star),
|
|
||||||
RegionData(LogicRegion.squidfest),
|
|
||||||
RegionData(LogicRegion.bookseller_1, [LogicEntrance.buy_year1_books]),
|
|
||||||
RegionData(LogicRegion.bookseller_2, [LogicEntrance.buy_year3_books]),
|
|
||||||
RegionData(LogicRegion.bookseller_3),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Exists and where they lead
|
|
||||||
vanilla_connections = [
|
|
||||||
ConnectionData(Entrance.to_stardew_valley, RegionName.stardew_valley),
|
|
||||||
ConnectionData(Entrance.to_farmhouse, RegionName.farm_house),
|
|
||||||
ConnectionData(Entrance.farmhouse_to_farm, RegionName.farm),
|
|
||||||
ConnectionData(Entrance.downstairs_to_cellar, RegionName.cellar),
|
|
||||||
ConnectionData(Entrance.farm_to_backwoods, RegionName.backwoods),
|
|
||||||
ConnectionData(Entrance.farm_to_bus_stop, RegionName.bus_stop),
|
|
||||||
ConnectionData(Entrance.farm_to_forest, RegionName.forest),
|
|
||||||
ConnectionData(Entrance.farm_to_farmcave, RegionName.farm_cave, flag=RandomizationFlag.NON_PROGRESSION),
|
|
||||||
ConnectionData(Entrance.enter_greenhouse, RegionName.greenhouse),
|
|
||||||
ConnectionData(Entrance.enter_coop, RegionName.coop),
|
|
||||||
ConnectionData(Entrance.enter_barn, RegionName.barn),
|
|
||||||
ConnectionData(Entrance.enter_shed, RegionName.shed),
|
|
||||||
ConnectionData(Entrance.enter_slime_hutch, RegionName.slime_hutch),
|
|
||||||
ConnectionData(Entrance.use_desert_obelisk, RegionName.desert),
|
|
||||||
ConnectionData(Entrance.use_island_obelisk, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.use_farm_obelisk, RegionName.farm),
|
|
||||||
ConnectionData(Entrance.backwoods_to_mountain, RegionName.mountain),
|
|
||||||
ConnectionData(Entrance.bus_stop_to_town, RegionName.town),
|
|
||||||
ConnectionData(Entrance.bus_stop_to_tunnel_entrance, RegionName.tunnel_entrance),
|
|
||||||
ConnectionData(Entrance.tunnel_entrance_to_bus_tunnel, RegionName.bus_tunnel, flag=RandomizationFlag.NON_PROGRESSION),
|
|
||||||
ConnectionData(Entrance.take_bus_to_desert, RegionName.desert),
|
|
||||||
ConnectionData(Entrance.forest_to_town, RegionName.town),
|
|
||||||
ConnectionData(Entrance.forest_to_wizard_tower, RegionName.wizard_tower,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.forest_to_marnie_ranch, RegionName.ranch,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.forest_to_leah_cottage, RegionName.leah_house,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_secret_woods, RegionName.secret_woods),
|
|
||||||
ConnectionData(Entrance.forest_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.forest_to_mastery_cave, RegionName.mastery_cave, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.MASTERIES),
|
|
||||||
ConnectionData(Entrance.town_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_mutant_bug_lair, RegionName.mutant_bug_lair, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.mountain_to_railroad, RegionName.railroad),
|
|
||||||
ConnectionData(Entrance.mountain_to_tent, RegionName.tent,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.mountain_to_leo_treehouse, RegionName.leo_treehouse,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.mountain_to_carpenter_shop, RegionName.carpenter,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.mountain_to_maru_room, RegionName.maru_room,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_sebastian_room, RegionName.sebastian_room, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.mountain_to_adventurer_guild, RegionName.adventurer_guild,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.adventurer_guild_to_bedroom, RegionName.adventurer_guild_bedroom),
|
|
||||||
ConnectionData(Entrance.enter_quarry, RegionName.quarry),
|
|
||||||
ConnectionData(Entrance.enter_quarry_mine_entrance, RegionName.quarry_mine_entrance,
|
|
||||||
flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_quarry_mine, RegionName.quarry_mine),
|
|
||||||
ConnectionData(Entrance.mountain_to_town, RegionName.town),
|
|
||||||
ConnectionData(Entrance.town_to_community_center, RegionName.community_center,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.access_crafts_room, RegionName.crafts_room),
|
|
||||||
ConnectionData(Entrance.access_pantry, RegionName.pantry),
|
|
||||||
ConnectionData(Entrance.access_fish_tank, RegionName.fish_tank),
|
|
||||||
ConnectionData(Entrance.access_boiler_room, RegionName.boiler_room),
|
|
||||||
ConnectionData(Entrance.access_bulletin_board, RegionName.bulletin_board),
|
|
||||||
ConnectionData(Entrance.access_vault, RegionName.vault),
|
|
||||||
ConnectionData(Entrance.town_to_hospital, RegionName.hospital,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_harvey_room, RegionName.harvey_room, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.town_to_pierre_general_store, RegionName.pierre_store,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_sunroom, RegionName.sunroom, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.town_to_clint_blacksmith, RegionName.blacksmith,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_saloon, RegionName.saloon,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.play_journey_of_the_prairie_king, RegionName.jotpk_world_1),
|
|
||||||
ConnectionData(Entrance.reach_jotpk_world_2, RegionName.jotpk_world_2),
|
|
||||||
ConnectionData(Entrance.reach_jotpk_world_3, RegionName.jotpk_world_3),
|
|
||||||
ConnectionData(Entrance.play_junimo_kart, RegionName.junimo_kart_1),
|
|
||||||
ConnectionData(Entrance.reach_junimo_kart_2, RegionName.junimo_kart_2),
|
|
||||||
ConnectionData(Entrance.reach_junimo_kart_3, RegionName.junimo_kart_3),
|
|
||||||
ConnectionData(Entrance.reach_junimo_kart_4, RegionName.junimo_kart_4),
|
|
||||||
ConnectionData(Entrance.town_to_sam_house, RegionName.sam_house,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_haley_house, RegionName.haley_house,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_mayor_manor, RegionName.mayor_house,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_alex_house, RegionName.alex_house,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_trailer, RegionName.trailer,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_museum, RegionName.museum,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.town_to_jojamart, RegionName.jojamart,
|
|
||||||
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.purchase_movie_ticket, RegionName.movie_ticket_stand),
|
|
||||||
ConnectionData(Entrance.enter_abandoned_jojamart, RegionName.abandoned_jojamart),
|
|
||||||
ConnectionData(Entrance.enter_movie_theater, RegionName.movie_theater),
|
|
||||||
ConnectionData(Entrance.town_to_beach, RegionName.beach),
|
|
||||||
ConnectionData(Entrance.enter_elliott_house, RegionName.elliott_house,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.beach_to_willy_fish_shop, RegionName.fish_shop,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.fish_shop_to_boat_tunnel, RegionName.boat_tunnel,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.boat_to_ginger_island, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.enter_tide_pools, RegionName.tide_pools),
|
|
||||||
ConnectionData(Entrance.mountain_to_the_mines, RegionName.mines,
|
|
||||||
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_5, RegionName.mines_floor_5),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_10, RegionName.mines_floor_10),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_15, RegionName.mines_floor_15),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_20, RegionName.mines_floor_20),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_25, RegionName.mines_floor_25),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_30, RegionName.mines_floor_30),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_35, RegionName.mines_floor_35),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_40, RegionName.mines_floor_40),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_45, RegionName.mines_floor_45),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_50, RegionName.mines_floor_50),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_55, RegionName.mines_floor_55),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_60, RegionName.mines_floor_60),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_65, RegionName.mines_floor_65),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_70, RegionName.mines_floor_70),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_75, RegionName.mines_floor_75),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_80, RegionName.mines_floor_80),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_85, RegionName.mines_floor_85),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_90, RegionName.mines_floor_90),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_95, RegionName.mines_floor_95),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_100, RegionName.mines_floor_100),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_105, RegionName.mines_floor_105),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_110, RegionName.mines_floor_110),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_115, RegionName.mines_floor_115),
|
|
||||||
ConnectionData(Entrance.dig_to_mines_floor_120, RegionName.mines_floor_120),
|
|
||||||
ConnectionData(Entrance.dig_to_dangerous_mines_20, RegionName.dangerous_mines_20, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.dig_to_dangerous_mines_60, RegionName.dangerous_mines_60, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.dig_to_dangerous_mines_100, RegionName.dangerous_mines_100, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.enter_skull_cavern_entrance, RegionName.skull_cavern_entrance,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_oasis, RegionName.oasis,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_casino, RegionName.casino, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_skull_cavern, RegionName.skull_cavern),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_25, RegionName.skull_cavern_25),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_50, RegionName.skull_cavern_50),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_75, RegionName.skull_cavern_75),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_100, RegionName.skull_cavern_100),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_125, RegionName.skull_cavern_125),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_150, RegionName.skull_cavern_150),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_175, RegionName.skull_cavern_175),
|
|
||||||
ConnectionData(Entrance.mine_to_skull_cavern_floor_200, RegionName.skull_cavern_200),
|
|
||||||
ConnectionData(Entrance.enter_dangerous_skull_cavern, RegionName.dangerous_skull_cavern, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.enter_witch_warp_cave, RegionName.witch_warp_cave, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_witch_swamp, RegionName.witch_swamp, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_witch_hut, RegionName.witch_hut, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.witch_warp_to_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_bathhouse_entrance, RegionName.bathhouse_entrance,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
|
||||||
ConnectionData(Entrance.enter_locker_room, RegionName.locker_room, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.enter_public_bath, RegionName.public_bath, flag=RandomizationFlag.BUILDINGS),
|
|
||||||
ConnectionData(Entrance.island_south_to_west, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_south_to_north, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_south_to_east, RegionName.island_east, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_south_to_southeast, RegionName.island_south_east,
|
|
||||||
flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.use_island_resort, RegionName.island_resort, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_west_to_islandfarmhouse, RegionName.island_farmhouse,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_west_to_gourmand_cave, RegionName.gourmand_frog_cave,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_west_to_crystals_cave, RegionName.colored_crystals_cave,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_west_to_shipwreck, RegionName.shipwreck,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_west_to_qi_walnut_room, RegionName.qi_walnut_room, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_east_to_leo_hut, RegionName.leo_hut,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_east_to_island_shrine, RegionName.island_shrine,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_southeast_to_pirate_cove, RegionName.pirate_cove,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_north_to_field_office, RegionName.field_office,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_north_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.dig_site_to_professor_snail_cave, RegionName.professor_snail_cave,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.island_north_to_volcano, RegionName.volcano,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.volcano_to_secret_beach, RegionName.volcano_secret_beach,
|
|
||||||
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.talk_to_island_trader, RegionName.island_trader, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.climb_to_volcano_5, RegionName.volcano_floor_5, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.talk_to_volcano_dwarf, RegionName.volcano_dwarf_shop, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.climb_to_volcano_10, RegionName.volcano_floor_10, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_jungle_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_dig_site_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_volcano_to_docks, RegionName.island_south, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_volcano_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_docks_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_dig_site_to_jungle, RegionName.island_west, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_docks_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_volcano_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_jungle_to_dig_site, RegionName.dig_site, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_dig_site_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_docks_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(Entrance.parrot_express_jungle_to_volcano, RegionName.island_north, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
|
|
||||||
ConnectionData(LogicEntrance.talk_to_mines_dwarf, LogicRegion.mines_dwarf_shop),
|
|
||||||
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant, LogicRegion.traveling_cart),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_sunday, LogicRegion.traveling_cart_sunday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_monday, LogicRegion.traveling_cart_monday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_tuesday, LogicRegion.traveling_cart_tuesday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_wednesday, LogicRegion.traveling_cart_wednesday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_thursday, LogicRegion.traveling_cart_thursday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_friday, LogicRegion.traveling_cart_friday),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_traveling_merchant_saturday, LogicRegion.traveling_cart_saturday),
|
|
||||||
ConnectionData(LogicEntrance.complete_raccoon_requests, LogicRegion.raccoon_daddy),
|
|
||||||
ConnectionData(LogicEntrance.fish_in_waterfall, LogicRegion.forest_waterfall),
|
|
||||||
ConnectionData(LogicEntrance.buy_from_raccoon, LogicRegion.raccoon_shop),
|
|
||||||
ConnectionData(LogicEntrance.farmhouse_cooking, LogicRegion.kitchen),
|
|
||||||
ConnectionData(LogicEntrance.watch_queen_of_sauce, LogicRegion.queen_of_sauce),
|
|
||||||
|
|
||||||
ConnectionData(LogicEntrance.grow_spring_crops, LogicRegion.spring_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_summer_crops, LogicRegion.summer_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_fall_crops, LogicRegion.fall_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_winter_crops, LogicRegion.winter_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_spring_crops_in_greenhouse, LogicRegion.spring_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_summer_crops_in_greenhouse, LogicRegion.summer_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_fall_crops_in_greenhouse, LogicRegion.fall_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_winter_crops_in_greenhouse, LogicRegion.winter_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_indoor_crops_in_greenhouse, LogicRegion.indoor_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_spring_crops_on_island, LogicRegion.spring_farming, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(LogicEntrance.grow_summer_crops_on_island, LogicRegion.summer_farming, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(LogicEntrance.grow_fall_crops_on_island, LogicRegion.fall_farming, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(LogicEntrance.grow_winter_crops_on_island, LogicRegion.winter_farming, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(LogicEntrance.grow_indoor_crops_on_island, LogicRegion.indoor_farming, flag=RandomizationFlag.GINGER_ISLAND),
|
|
||||||
ConnectionData(LogicEntrance.grow_summer_fall_crops_in_summer, LogicRegion.summer_or_fall_farming),
|
|
||||||
ConnectionData(LogicEntrance.grow_summer_fall_crops_in_fall, LogicRegion.summer_or_fall_farming),
|
|
||||||
|
|
||||||
ConnectionData(LogicEntrance.shipping, LogicRegion.shipping),
|
|
||||||
ConnectionData(LogicEntrance.blacksmith_copper, LogicRegion.blacksmith_copper),
|
|
||||||
ConnectionData(LogicEntrance.blacksmith_iron, LogicRegion.blacksmith_iron),
|
|
||||||
ConnectionData(LogicEntrance.blacksmith_gold, LogicRegion.blacksmith_gold),
|
|
||||||
ConnectionData(LogicEntrance.blacksmith_iridium, LogicRegion.blacksmith_iridium),
|
|
||||||
ConnectionData(LogicEntrance.fishing, LogicRegion.fishing),
|
|
||||||
ConnectionData(LogicEntrance.island_cooking, LogicRegion.kitchen),
|
|
||||||
ConnectionData(LogicEntrance.attend_egg_festival, LogicRegion.egg_festival),
|
|
||||||
ConnectionData(LogicEntrance.attend_desert_festival, LogicRegion.desert_festival),
|
|
||||||
ConnectionData(LogicEntrance.attend_flower_dance, LogicRegion.flower_dance),
|
|
||||||
ConnectionData(LogicEntrance.attend_luau, LogicRegion.luau),
|
|
||||||
ConnectionData(LogicEntrance.attend_trout_derby, LogicRegion.trout_derby),
|
|
||||||
ConnectionData(LogicEntrance.attend_moonlight_jellies, LogicRegion.moonlight_jellies),
|
|
||||||
ConnectionData(LogicEntrance.attend_fair, LogicRegion.fair),
|
|
||||||
ConnectionData(LogicEntrance.attend_spirit_eve, LogicRegion.spirit_eve),
|
|
||||||
ConnectionData(LogicEntrance.attend_festival_of_ice, LogicRegion.festival_of_ice),
|
|
||||||
ConnectionData(LogicEntrance.attend_night_market, LogicRegion.night_market),
|
|
||||||
ConnectionData(LogicEntrance.attend_winter_star, LogicRegion.winter_star),
|
|
||||||
ConnectionData(LogicEntrance.attend_squidfest, LogicRegion.squidfest),
|
|
||||||
ConnectionData(LogicEntrance.buy_experience_books, LogicRegion.bookseller_1),
|
|
||||||
ConnectionData(LogicEntrance.buy_year1_books, LogicRegion.bookseller_2),
|
|
||||||
ConnectionData(LogicEntrance.buy_year3_books, LogicRegion.bookseller_3),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def create_final_regions(world_options) -> List[RegionData]:
|
|
||||||
final_regions = []
|
|
||||||
final_regions.extend(vanilla_regions)
|
|
||||||
if world_options.mods is None:
|
|
||||||
return final_regions
|
|
||||||
for mod in sorted(world_options.mods.value):
|
|
||||||
if mod not in ModDataList:
|
|
||||||
continue
|
|
||||||
for mod_region in ModDataList[mod].regions:
|
|
||||||
existing_region = next(
|
|
||||||
(region for region in final_regions if region.name == mod_region.name), None)
|
|
||||||
if existing_region:
|
|
||||||
final_regions.remove(existing_region)
|
|
||||||
if ModificationFlag.MODIFIED in mod_region.flag:
|
|
||||||
mod_region = modify_vanilla_regions(existing_region, mod_region)
|
|
||||||
final_regions.append(existing_region.get_merged_with(mod_region.exits))
|
|
||||||
continue
|
|
||||||
final_regions.append(mod_region.get_clone())
|
|
||||||
|
|
||||||
return final_regions
|
|
||||||
|
|
||||||
|
|
||||||
def create_final_connections_and_regions(world_options) -> Tuple[Dict[str, ConnectionData], Dict[str, RegionData]]:
|
|
||||||
regions_data: Dict[str, RegionData] = {region.name: region for region in create_final_regions(world_options)}
|
|
||||||
connections = {connection.name: connection for connection in vanilla_connections}
|
|
||||||
connections = modify_connections_for_mods(connections, sorted(world_options.mods.value))
|
|
||||||
include_island = world_options.exclude_ginger_island == ExcludeGingerIsland.option_false
|
|
||||||
return remove_ginger_island_regions_and_connections(regions_data, connections, include_island)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_ginger_island_regions_and_connections(regions_by_name: Dict[str, RegionData], connections: Dict[str, ConnectionData], include_island: bool):
|
|
||||||
if include_island:
|
|
||||||
return connections, regions_by_name
|
|
||||||
|
|
||||||
removed_connections = set()
|
|
||||||
|
|
||||||
for connection_name in tuple(connections):
|
|
||||||
connection = connections[connection_name]
|
|
||||||
if connection.flag & RandomizationFlag.GINGER_ISLAND:
|
|
||||||
connections.pop(connection_name)
|
|
||||||
removed_connections.add(connection_name)
|
|
||||||
|
|
||||||
for region_name in tuple(regions_by_name):
|
|
||||||
region = regions_by_name[region_name]
|
|
||||||
if region.is_ginger_island:
|
|
||||||
regions_by_name.pop(region_name)
|
|
||||||
else:
|
|
||||||
regions_by_name[region_name] = region.get_without_exits(removed_connections)
|
|
||||||
|
|
||||||
return connections, regions_by_name
|
|
||||||
|
|
||||||
|
|
||||||
def modify_connections_for_mods(connections: Dict[str, ConnectionData], mods: Iterable) -> Dict[str, ConnectionData]:
|
|
||||||
for mod in mods:
|
|
||||||
if mod not in ModDataList:
|
|
||||||
continue
|
|
||||||
if mod in vanilla_connections_to_remove_by_mod:
|
|
||||||
for connection_data in vanilla_connections_to_remove_by_mod[mod]:
|
|
||||||
connections.pop(connection_data.name)
|
|
||||||
connections.update({connection.name: connection for connection in ModDataList[mod].connections})
|
|
||||||
return connections
|
|
||||||
|
|
||||||
|
|
||||||
def modify_vanilla_regions(existing_region: RegionData, modified_region: RegionData) -> RegionData:
|
|
||||||
updated_region = existing_region
|
|
||||||
region_exits = updated_region.exits
|
|
||||||
modified_exits = modified_region.exits
|
|
||||||
for exits in modified_exits:
|
|
||||||
region_exits.remove(exits)
|
|
||||||
|
|
||||||
return updated_region
|
|
||||||
|
|
||||||
|
|
||||||
def create_regions(region_factory: RegionFactory, random: Random, world_options: StardewValleyOptions, content: StardewContent) \
|
|
||||||
-> Tuple[Dict[str, Region], Dict[str, Entrance], Dict[str, str]]:
|
|
||||||
entrances_data, regions_data = create_final_connections_and_regions(world_options)
|
|
||||||
regions_by_name: Dict[str: Region] = {region_name: region_factory(region_name, regions_data[region_name].exits) for region_name in regions_data}
|
|
||||||
entrances_by_name: Dict[str: Entrance] = {
|
|
||||||
entrance.name: entrance
|
|
||||||
for region in regions_by_name.values()
|
|
||||||
for entrance in region.exits
|
|
||||||
if entrance.name in entrances_data
|
|
||||||
}
|
|
||||||
|
|
||||||
connections, randomized_data = randomize_connections(random, world_options, content, regions_data, entrances_data)
|
|
||||||
|
|
||||||
for connection in connections:
|
|
||||||
if connection.name in entrances_by_name:
|
|
||||||
entrances_by_name[connection.name].connect(regions_by_name[connection.destination])
|
|
||||||
return regions_by_name, entrances_by_name, randomized_data
|
|
||||||
|
|
||||||
|
|
||||||
def randomize_connections(random: Random, world_options: StardewValleyOptions, content: StardewContent, regions_by_name: Dict[str, RegionData],
|
|
||||||
connections_by_name: Dict[str, ConnectionData]) -> Tuple[List[ConnectionData], Dict[str, str]]:
|
|
||||||
connections_to_randomize: List[ConnectionData] = []
|
|
||||||
if world_options.entrance_randomization == EntranceRandomization.option_pelican_town:
|
|
||||||
connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if
|
|
||||||
RandomizationFlag.PELICAN_TOWN in connections_by_name[connection].flag]
|
|
||||||
elif world_options.entrance_randomization == EntranceRandomization.option_non_progression:
|
|
||||||
connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if
|
|
||||||
RandomizationFlag.NON_PROGRESSION in connections_by_name[connection].flag]
|
|
||||||
elif world_options.entrance_randomization == EntranceRandomization.option_buildings or world_options.entrance_randomization == EntranceRandomization.option_buildings_without_house:
|
|
||||||
connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if
|
|
||||||
RandomizationFlag.BUILDINGS in connections_by_name[connection].flag]
|
|
||||||
elif world_options.entrance_randomization == EntranceRandomization.option_chaos:
|
|
||||||
connections_to_randomize = [connections_by_name[connection] for connection in connections_by_name if
|
|
||||||
RandomizationFlag.BUILDINGS in connections_by_name[connection].flag]
|
|
||||||
connections_to_randomize = remove_excluded_entrances(connections_to_randomize, content)
|
|
||||||
|
|
||||||
# On Chaos, we just add the connections to randomize, unshuffled, and the client does it every day
|
|
||||||
randomized_data_for_mod = {}
|
|
||||||
for connection in connections_to_randomize:
|
|
||||||
randomized_data_for_mod[connection.name] = connection.name
|
|
||||||
randomized_data_for_mod[connection.reverse] = connection.reverse
|
|
||||||
return list(connections_by_name.values()), randomized_data_for_mod
|
|
||||||
|
|
||||||
connections_to_randomize = remove_excluded_entrances(connections_to_randomize, content)
|
|
||||||
random.shuffle(connections_to_randomize)
|
|
||||||
destination_pool = list(connections_to_randomize)
|
|
||||||
random.shuffle(destination_pool)
|
|
||||||
|
|
||||||
randomized_connections = randomize_chosen_connections(connections_to_randomize, destination_pool)
|
|
||||||
add_non_randomized_connections(list(connections_by_name.values()), connections_to_randomize, randomized_connections)
|
|
||||||
|
|
||||||
swap_connections_until_valid(regions_by_name, connections_by_name, randomized_connections, connections_to_randomize, random)
|
|
||||||
randomized_connections_for_generation = create_connections_for_generation(randomized_connections)
|
|
||||||
randomized_data_for_mod = create_data_for_mod(randomized_connections, connections_to_randomize)
|
|
||||||
|
|
||||||
return randomized_connections_for_generation, randomized_data_for_mod
|
|
||||||
|
|
||||||
|
|
||||||
def remove_excluded_entrances(connections_to_randomize: List[ConnectionData], content: StardewContent) -> List[ConnectionData]:
|
|
||||||
# FIXME remove when regions are handled in content packs
|
|
||||||
if content_packs.ginger_island_content_pack.name not in content.registered_packs:
|
|
||||||
connections_to_randomize = [connection for connection in connections_to_randomize if RandomizationFlag.GINGER_ISLAND not in connection.flag]
|
|
||||||
if not content.features.skill_progression.are_masteries_shuffled:
|
|
||||||
connections_to_randomize = [connection for connection in connections_to_randomize if RandomizationFlag.MASTERIES not in connection.flag]
|
|
||||||
|
|
||||||
return connections_to_randomize
|
|
||||||
|
|
||||||
|
|
||||||
def randomize_chosen_connections(connections_to_randomize: List[ConnectionData],
|
|
||||||
destination_pool: List[ConnectionData]) -> Dict[ConnectionData, ConnectionData]:
|
|
||||||
randomized_connections = {}
|
|
||||||
for connection in connections_to_randomize:
|
|
||||||
destination = destination_pool.pop()
|
|
||||||
randomized_connections[connection] = destination
|
|
||||||
return randomized_connections
|
|
||||||
|
|
||||||
|
|
||||||
def create_connections_for_generation(randomized_connections: Dict[ConnectionData, ConnectionData]) -> List[ConnectionData]:
|
|
||||||
connections = []
|
|
||||||
for connection in randomized_connections:
|
|
||||||
destination = randomized_connections[connection]
|
|
||||||
connections.append(ConnectionData(connection.name, destination.destination, destination.reverse))
|
|
||||||
return connections
|
|
||||||
|
|
||||||
|
|
||||||
def create_data_for_mod(randomized_connections: Dict[ConnectionData, ConnectionData],
|
|
||||||
connections_to_randomize: List[ConnectionData]) -> Dict[str, str]:
|
|
||||||
randomized_data_for_mod = {}
|
|
||||||
for connection in randomized_connections:
|
|
||||||
if connection not in connections_to_randomize:
|
|
||||||
continue
|
|
||||||
destination = randomized_connections[connection]
|
|
||||||
add_to_mod_data(connection, destination, randomized_data_for_mod)
|
|
||||||
return randomized_data_for_mod
|
|
||||||
|
|
||||||
|
|
||||||
def add_to_mod_data(connection: ConnectionData, destination: ConnectionData, randomized_data_for_mod: Dict[str, str]):
|
|
||||||
randomized_data_for_mod[connection.name] = destination.name
|
|
||||||
randomized_data_for_mod[destination.reverse] = connection.reverse
|
|
||||||
|
|
||||||
|
|
||||||
def add_non_randomized_connections(all_connections: List[ConnectionData], connections_to_randomize: List[ConnectionData],
|
|
||||||
randomized_connections: Dict[ConnectionData, ConnectionData]):
|
|
||||||
for connection in all_connections:
|
|
||||||
if connection in connections_to_randomize:
|
|
||||||
continue
|
|
||||||
randomized_connections[connection] = connection
|
|
||||||
|
|
||||||
|
|
||||||
def swap_connections_until_valid(regions_by_name, connections_by_name: Dict[str, ConnectionData], randomized_connections: Dict[ConnectionData, ConnectionData],
|
|
||||||
connections_to_randomize: List[ConnectionData], random: Random):
|
|
||||||
while True:
|
|
||||||
reachable_regions, unreachable_regions = find_reachable_regions(regions_by_name, connections_by_name, randomized_connections)
|
|
||||||
if not unreachable_regions:
|
|
||||||
return randomized_connections
|
|
||||||
swap_one_random_connection(regions_by_name, connections_by_name, randomized_connections, reachable_regions,
|
|
||||||
unreachable_regions, connections_to_randomize, random)
|
|
||||||
|
|
||||||
|
|
||||||
def region_should_be_reachable(region_name: str, connections_in_slot: Iterable[ConnectionData]) -> bool:
|
|
||||||
if region_name == RegionName.menu:
|
|
||||||
return True
|
|
||||||
for connection in connections_in_slot:
|
|
||||||
if region_name == connection.destination:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def find_reachable_regions(regions_by_name, connections_by_name,
|
|
||||||
randomized_connections: Dict[ConnectionData, ConnectionData]):
|
|
||||||
reachable_regions = {RegionName.menu}
|
|
||||||
unreachable_regions = {region for region in regions_by_name.keys()}
|
|
||||||
# unreachable_regions = {region for region in regions_by_name.keys() if region_should_be_reachable(region, connections_by_name.values())}
|
|
||||||
unreachable_regions.remove(RegionName.menu)
|
|
||||||
exits_to_explore = list(regions_by_name[RegionName.menu].exits)
|
|
||||||
while exits_to_explore:
|
|
||||||
exit_name = exits_to_explore.pop()
|
|
||||||
# if exit_name not in connections_by_name:
|
|
||||||
# continue
|
|
||||||
exit_connection = connections_by_name[exit_name]
|
|
||||||
replaced_connection = randomized_connections[exit_connection]
|
|
||||||
target_region_name = replaced_connection.destination
|
|
||||||
if target_region_name in reachable_regions:
|
|
||||||
continue
|
|
||||||
|
|
||||||
target_region = regions_by_name[target_region_name]
|
|
||||||
reachable_regions.add(target_region_name)
|
|
||||||
unreachable_regions.remove(target_region_name)
|
|
||||||
exits_to_explore.extend(target_region.exits)
|
|
||||||
return reachable_regions, unreachable_regions
|
|
||||||
|
|
||||||
|
|
||||||
def swap_one_random_connection(regions_by_name, connections_by_name, randomized_connections: Dict[ConnectionData, ConnectionData],
|
|
||||||
reachable_regions: Set[str], unreachable_regions: Set[str],
|
|
||||||
connections_to_randomize: List[ConnectionData], random: Random):
|
|
||||||
randomized_connections_already_shuffled = {connection: randomized_connections[connection]
|
|
||||||
for connection in randomized_connections
|
|
||||||
if connection != randomized_connections[connection]}
|
|
||||||
unreachable_regions_names_leading_somewhere = [region for region in sorted(unreachable_regions) if len(regions_by_name[region].exits) > 0]
|
|
||||||
unreachable_regions_leading_somewhere = [regions_by_name[region_name] for region_name in unreachable_regions_names_leading_somewhere]
|
|
||||||
unreachable_regions_exits_names = [exit_name for region in unreachable_regions_leading_somewhere for exit_name in region.exits]
|
|
||||||
unreachable_connections = [connections_by_name[exit_name] for exit_name in unreachable_regions_exits_names]
|
|
||||||
unreachable_connections_that_can_be_randomized = [connection for connection in unreachable_connections if connection in connections_to_randomize]
|
|
||||||
|
|
||||||
chosen_unreachable_entrance = random.choice(unreachable_connections_that_can_be_randomized)
|
|
||||||
|
|
||||||
chosen_reachable_entrance = None
|
|
||||||
while chosen_reachable_entrance is None or chosen_reachable_entrance not in randomized_connections_already_shuffled:
|
|
||||||
chosen_reachable_region_name = random.choice(sorted(reachable_regions))
|
|
||||||
chosen_reachable_region = regions_by_name[chosen_reachable_region_name]
|
|
||||||
if not any(chosen_reachable_region.exits):
|
|
||||||
continue
|
|
||||||
chosen_reachable_entrance_name = random.choice(chosen_reachable_region.exits)
|
|
||||||
chosen_reachable_entrance = connections_by_name[chosen_reachable_entrance_name]
|
|
||||||
|
|
||||||
swap_two_connections(chosen_reachable_entrance, chosen_unreachable_entrance, randomized_connections)
|
|
||||||
|
|
||||||
|
|
||||||
def swap_two_connections(entrance_1, entrance_2, randomized_connections):
|
|
||||||
reachable_destination = randomized_connections[entrance_1]
|
|
||||||
unreachable_destination = randomized_connections[entrance_2]
|
|
||||||
randomized_connections[entrance_1] = unreachable_destination
|
|
||||||
randomized_connections[entrance_2] = reachable_destination
|
|
2
worlds/stardew_valley/regions/__init__.py
Normal file
2
worlds/stardew_valley/regions/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from .entrance_rando import prepare_mod_data
|
||||||
|
from .regions import create_regions, RegionFactory
|
73
worlds/stardew_valley/regions/entrance_rando.py
Normal file
73
worlds/stardew_valley/regions/entrance_rando.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
from BaseClasses import Region
|
||||||
|
from entrance_rando import ERPlacementState
|
||||||
|
from .model import ConnectionData, RandomizationFlag, reverse_connection_name, RegionData
|
||||||
|
from ..content import StardewContent
|
||||||
|
from ..options import EntranceRandomization
|
||||||
|
|
||||||
|
|
||||||
|
def create_player_randomization_flag(entrance_randomization_choice: EntranceRandomization, content: StardewContent):
|
||||||
|
"""Return the flag that a connection is expected to have to be randomized. Only the bit corresponding to the player randomization choice will be enabled.
|
||||||
|
|
||||||
|
Other bits for content exclusion might also be enabled, tho the preferred solution to exclude content should be to not create those regions at alls, when possible.
|
||||||
|
"""
|
||||||
|
flag = RandomizationFlag.NOT_RANDOMIZED
|
||||||
|
|
||||||
|
if entrance_randomization_choice.value == EntranceRandomization.option_disabled:
|
||||||
|
return flag
|
||||||
|
|
||||||
|
if entrance_randomization_choice == EntranceRandomization.option_pelican_town:
|
||||||
|
flag |= RandomizationFlag.BIT_PELICAN_TOWN
|
||||||
|
elif entrance_randomization_choice == EntranceRandomization.option_non_progression:
|
||||||
|
flag |= RandomizationFlag.BIT_NON_PROGRESSION
|
||||||
|
elif entrance_randomization_choice in (
|
||||||
|
EntranceRandomization.option_buildings,
|
||||||
|
EntranceRandomization.option_buildings_without_house,
|
||||||
|
EntranceRandomization.option_chaos
|
||||||
|
):
|
||||||
|
flag |= RandomizationFlag.BIT_BUILDINGS
|
||||||
|
|
||||||
|
if not content.features.skill_progression.are_masteries_shuffled:
|
||||||
|
flag |= RandomizationFlag.EXCLUDE_MASTERIES
|
||||||
|
|
||||||
|
return flag
|
||||||
|
|
||||||
|
|
||||||
|
def connect_regions(region_data_by_name: dict[str, RegionData], connection_data_by_name: dict[str, ConnectionData], regions_by_name: dict[str, Region],
|
||||||
|
player_randomization_flag: RandomizationFlag) -> None:
|
||||||
|
for region_name, region_data in region_data_by_name.items():
|
||||||
|
origin_region = regions_by_name[region_name]
|
||||||
|
|
||||||
|
for exit_name in region_data.exits:
|
||||||
|
connection_data = connection_data_by_name[exit_name]
|
||||||
|
destination_region = regions_by_name[connection_data.destination]
|
||||||
|
|
||||||
|
if connection_data.is_eligible_for_randomization(player_randomization_flag):
|
||||||
|
create_entrance_rando_target(origin_region, destination_region, connection_data)
|
||||||
|
else:
|
||||||
|
origin_region.connect(destination_region, connection_data.name)
|
||||||
|
|
||||||
|
|
||||||
|
def create_entrance_rando_target(origin: Region, destination: Region, connection_data: ConnectionData) -> None:
|
||||||
|
"""We need our own function to create the GER targets, because the Stardew Mod have very specific expectations for the name of the entrances.
|
||||||
|
We need to know exactly which entrances to swap in both directions."""
|
||||||
|
origin.create_exit(connection_data.name)
|
||||||
|
destination.create_er_target(connection_data.reverse)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_mod_data(placements: ERPlacementState) -> dict[str, str]:
|
||||||
|
"""Take the placements from GER and prepare the data for the mod.
|
||||||
|
The mod require a dictionary detailing which connections need to be swapped. It acts as if the connections are decoupled, so both directions are required.
|
||||||
|
|
||||||
|
For instance, GER will provide placements like (Town to Community Center, Hospital to Town), meaning that the door of the Community Center will instead lead
|
||||||
|
to the Hospital, and that the exit of the Hospital will lead to the Town by the Community Center door. The StardewAP mod need to know both swaps, being the
|
||||||
|
original destination of the "Town to Community Center" connection is to be replaced by the original destination of "Town to Hospital", and the original
|
||||||
|
destination of "Hospital to Town" is to be replaced by the original destination of "Community Center to Town".
|
||||||
|
"""
|
||||||
|
|
||||||
|
swapped_connections = {}
|
||||||
|
|
||||||
|
for entrance, exit_ in placements.pairings:
|
||||||
|
swapped_connections[entrance] = reverse_connection_name(exit_)
|
||||||
|
swapped_connections[exit_] = reverse_connection_name(entrance)
|
||||||
|
|
||||||
|
return swapped_connections
|
94
worlds/stardew_valley/regions/model.py
Normal file
94
worlds/stardew_valley/regions/model.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Container
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from enum import IntFlag
|
||||||
|
|
||||||
|
connector_keyword = " to "
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_connection_name(name: str) -> str | None:
|
||||||
|
try:
|
||||||
|
origin, destination = name.split(connector_keyword)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
return f"{destination}{connector_keyword}{origin}"
|
||||||
|
|
||||||
|
|
||||||
|
class MergeFlag(IntFlag):
|
||||||
|
ADD_EXITS = 0
|
||||||
|
REMOVE_EXITS = 1
|
||||||
|
|
||||||
|
|
||||||
|
class RandomizationFlag(IntFlag):
|
||||||
|
NOT_RANDOMIZED = 0
|
||||||
|
|
||||||
|
# Randomization options
|
||||||
|
# The first 4 bits are used to mark if an entrance is eligible for randomization according to the entrance randomization options.
|
||||||
|
BIT_PELICAN_TOWN = 1 # 0b0001
|
||||||
|
BIT_NON_PROGRESSION = 1 << 1 # 0b0010
|
||||||
|
BIT_BUILDINGS = 1 << 2 # 0b0100
|
||||||
|
BIT_EVERYTHING = 1 << 3 # 0b1000
|
||||||
|
|
||||||
|
# Content flag for entrances exclusions
|
||||||
|
# The next 2 bits are used to mark if an entrance is to be excluded from randomization according to the content options.
|
||||||
|
# Those bits must be removed from an entrance flags when then entrance must be excluded.
|
||||||
|
__UNUSED = 1 << 4 # 0b010000
|
||||||
|
EXCLUDE_MASTERIES = 1 << 5 # 0b100000
|
||||||
|
|
||||||
|
# Entrance groups
|
||||||
|
# The last bit is used to add additional qualifiers on entrances to group them
|
||||||
|
# Those bits should be added when an entrance need additional qualifiers.
|
||||||
|
LEAD_TO_OPEN_AREA = 1 << 6
|
||||||
|
|
||||||
|
# Tags to apply on connections
|
||||||
|
EVERYTHING = EXCLUDE_MASTERIES | BIT_EVERYTHING
|
||||||
|
BUILDINGS = EVERYTHING | BIT_BUILDINGS
|
||||||
|
NON_PROGRESSION = BUILDINGS | BIT_NON_PROGRESSION
|
||||||
|
PELICAN_TOWN = NON_PROGRESSION | BIT_PELICAN_TOWN
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class RegionData:
|
||||||
|
name: str
|
||||||
|
exits: tuple[str, ...] = field(default_factory=tuple)
|
||||||
|
flag: MergeFlag = MergeFlag.ADD_EXITS
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
assert not isinstance(self.exits, str), "Exits must be a tuple of strings, you probably forgot a trailing comma."
|
||||||
|
|
||||||
|
def merge_with(self, other: RegionData) -> RegionData:
|
||||||
|
assert self.name == other.name, "Regions must have the same name to be merged"
|
||||||
|
|
||||||
|
if other.flag == MergeFlag.REMOVE_EXITS:
|
||||||
|
return self.get_without_exits(other.exits)
|
||||||
|
|
||||||
|
merged_exits = self.exits + other.exits
|
||||||
|
assert len(merged_exits) == len(set(merged_exits)), "Two regions getting merged have duplicated exists..."
|
||||||
|
|
||||||
|
return RegionData(self.name, merged_exits)
|
||||||
|
|
||||||
|
def get_without_exits(self, exits_to_remove: Container[str]) -> RegionData:
|
||||||
|
exits = tuple(exit_ for exit_ in self.exits if exit_ not in exits_to_remove)
|
||||||
|
return RegionData(self.name, exits)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ConnectionData:
|
||||||
|
name: str
|
||||||
|
destination: str
|
||||||
|
flag: RandomizationFlag = RandomizationFlag.NOT_RANDOMIZED
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reverse(self) -> str | None:
|
||||||
|
return reverse_connection_name(self.name)
|
||||||
|
|
||||||
|
def is_eligible_for_randomization(self, chosen_randomization_flag: RandomizationFlag) -> bool:
|
||||||
|
return chosen_randomization_flag and chosen_randomization_flag in self.flag
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ModRegionsData:
|
||||||
|
mod_name: str
|
||||||
|
regions: list[RegionData]
|
||||||
|
connections: list[ConnectionData]
|
46
worlds/stardew_valley/regions/mods.py
Normal file
46
worlds/stardew_valley/regions/mods.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from collections.abc import Iterable
|
||||||
|
|
||||||
|
from .model import ConnectionData, RegionData, ModRegionsData
|
||||||
|
from ..mods.region_data import region_data_by_content_pack, vanilla_connections_to_remove_by_content_pack
|
||||||
|
|
||||||
|
|
||||||
|
def modify_regions_for_mods(current_regions_by_name: dict[str, RegionData], active_content_packs: Iterable[str]) -> None:
|
||||||
|
for content_pack in active_content_packs:
|
||||||
|
try:
|
||||||
|
region_data = region_data_by_content_pack[content_pack]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
merge_mod_regions(current_regions_by_name, region_data)
|
||||||
|
|
||||||
|
|
||||||
|
def merge_mod_regions(current_regions_by_name: dict[str, RegionData], mod_region_data: ModRegionsData) -> None:
|
||||||
|
for new_region in mod_region_data.regions:
|
||||||
|
region_name = new_region.name
|
||||||
|
try:
|
||||||
|
current_region = current_regions_by_name[region_name]
|
||||||
|
except KeyError:
|
||||||
|
current_regions_by_name[region_name] = new_region
|
||||||
|
continue
|
||||||
|
|
||||||
|
current_regions_by_name[region_name] = current_region.merge_with(new_region)
|
||||||
|
|
||||||
|
|
||||||
|
def modify_connections_for_mods(connections: dict[str, ConnectionData], active_mods: Iterable[str]) -> None:
|
||||||
|
for active_mod in active_mods:
|
||||||
|
try:
|
||||||
|
region_data = region_data_by_content_pack[active_mod]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
vanilla_connections_to_remove = vanilla_connections_to_remove_by_content_pack[active_mod]
|
||||||
|
for connection_name in vanilla_connections_to_remove:
|
||||||
|
connections.pop(connection_name)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
connections.update({
|
||||||
|
connection.name: connection
|
||||||
|
for connection in region_data.connections
|
||||||
|
})
|
61
worlds/stardew_valley/regions/regions.py
Normal file
61
worlds/stardew_valley/regions/regions.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
from typing import Protocol
|
||||||
|
|
||||||
|
from BaseClasses import Region
|
||||||
|
from . import vanilla_data, mods
|
||||||
|
from .entrance_rando import create_player_randomization_flag, connect_regions
|
||||||
|
from .model import ConnectionData, RegionData
|
||||||
|
from ..content import StardewContent
|
||||||
|
from ..content.vanilla.ginger_island import ginger_island_content_pack
|
||||||
|
from ..options import StardewValleyOptions
|
||||||
|
|
||||||
|
|
||||||
|
class RegionFactory(Protocol):
|
||||||
|
def __call__(self, name: str) -> Region:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def create_regions(region_factory: RegionFactory, world_options: StardewValleyOptions, content: StardewContent) -> dict[str, Region]:
|
||||||
|
connection_data_by_name, region_data_by_name = create_connections_and_regions(content.registered_packs)
|
||||||
|
|
||||||
|
regions_by_name: dict[str: Region] = {
|
||||||
|
region_name: region_factory(region_name)
|
||||||
|
for region_name in region_data_by_name
|
||||||
|
}
|
||||||
|
|
||||||
|
randomization_flag = create_player_randomization_flag(world_options.entrance_randomization, content)
|
||||||
|
connect_regions(region_data_by_name, connection_data_by_name, regions_by_name, randomization_flag)
|
||||||
|
|
||||||
|
return regions_by_name
|
||||||
|
|
||||||
|
|
||||||
|
def create_connections_and_regions(active_content_packs: set[str]) -> tuple[dict[str, ConnectionData], dict[str, RegionData]]:
|
||||||
|
regions_by_name = create_all_regions(active_content_packs)
|
||||||
|
connections_by_name = create_all_connections(active_content_packs)
|
||||||
|
|
||||||
|
return connections_by_name, regions_by_name
|
||||||
|
|
||||||
|
|
||||||
|
def create_all_regions(active_content_packs: set[str]) -> dict[str, RegionData]:
|
||||||
|
current_regions_by_name = create_vanilla_regions(active_content_packs)
|
||||||
|
mods.modify_regions_for_mods(current_regions_by_name, sorted(active_content_packs))
|
||||||
|
return current_regions_by_name
|
||||||
|
|
||||||
|
|
||||||
|
def create_vanilla_regions(active_content_packs: set[str]) -> dict[str, RegionData]:
|
||||||
|
if ginger_island_content_pack.name in active_content_packs:
|
||||||
|
return {**vanilla_data.regions_with_ginger_island_by_name}
|
||||||
|
else:
|
||||||
|
return {**vanilla_data.regions_without_ginger_island_by_name}
|
||||||
|
|
||||||
|
|
||||||
|
def create_all_connections(active_content_packs: set[str]) -> dict[str, ConnectionData]:
|
||||||
|
connections = create_vanilla_connections(active_content_packs)
|
||||||
|
mods.modify_connections_for_mods(connections, sorted(active_content_packs))
|
||||||
|
return connections
|
||||||
|
|
||||||
|
|
||||||
|
def create_vanilla_connections(active_content_packs: set[str]) -> dict[str, ConnectionData]:
|
||||||
|
if ginger_island_content_pack.name in active_content_packs:
|
||||||
|
return {**vanilla_data.connections_with_ginger_island_by_name}
|
||||||
|
else:
|
||||||
|
return {**vanilla_data.connections_without_ginger_island_by_name}
|
522
worlds/stardew_valley/regions/vanilla_data.py
Normal file
522
worlds/stardew_valley/regions/vanilla_data.py
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
from collections.abc import Mapping
|
||||||
|
from types import MappingProxyType
|
||||||
|
|
||||||
|
from .model import ConnectionData, RandomizationFlag, RegionData
|
||||||
|
from ..strings.entrance_names import LogicEntrance, Entrance
|
||||||
|
from ..strings.region_names import LogicRegion, Region as RegionName
|
||||||
|
|
||||||
|
vanilla_regions: tuple[RegionData, ...] = (
|
||||||
|
RegionData(RegionName.menu, (Entrance.to_stardew_valley,)),
|
||||||
|
RegionData(RegionName.stardew_valley, (Entrance.to_farmhouse,)),
|
||||||
|
RegionData(RegionName.farm_house,
|
||||||
|
(Entrance.farmhouse_to_farm, Entrance.downstairs_to_cellar, LogicEntrance.farmhouse_cooking, LogicEntrance.watch_queen_of_sauce)),
|
||||||
|
RegionData(RegionName.cellar),
|
||||||
|
RegionData(RegionName.farm,
|
||||||
|
(Entrance.farm_to_backwoods, Entrance.farm_to_bus_stop, Entrance.farm_to_forest, Entrance.farm_to_farmcave, Entrance.enter_greenhouse,
|
||||||
|
Entrance.enter_coop, Entrance.enter_barn, Entrance.enter_shed, Entrance.enter_slime_hutch, LogicEntrance.grow_spring_crops,
|
||||||
|
LogicEntrance.grow_summer_crops, LogicEntrance.grow_fall_crops, LogicEntrance.grow_winter_crops, LogicEntrance.shipping,
|
||||||
|
LogicEntrance.fishing,)),
|
||||||
|
RegionData(RegionName.backwoods, (Entrance.backwoods_to_mountain,)),
|
||||||
|
RegionData(RegionName.bus_stop,
|
||||||
|
(Entrance.bus_stop_to_town, Entrance.take_bus_to_desert, Entrance.bus_stop_to_tunnel_entrance)),
|
||||||
|
RegionData(RegionName.forest,
|
||||||
|
(Entrance.forest_to_town, Entrance.enter_secret_woods, Entrance.forest_to_wizard_tower, Entrance.forest_to_marnie_ranch,
|
||||||
|
Entrance.forest_to_leah_cottage, Entrance.forest_to_sewer, Entrance.forest_to_mastery_cave, LogicEntrance.buy_from_traveling_merchant,
|
||||||
|
LogicEntrance.complete_raccoon_requests, LogicEntrance.fish_in_waterfall, LogicEntrance.attend_flower_dance, LogicEntrance.attend_trout_derby,
|
||||||
|
LogicEntrance.attend_festival_of_ice)),
|
||||||
|
RegionData(LogicRegion.forest_waterfall),
|
||||||
|
RegionData(RegionName.farm_cave),
|
||||||
|
RegionData(RegionName.greenhouse,
|
||||||
|
(LogicEntrance.grow_spring_crops_in_greenhouse, LogicEntrance.grow_summer_crops_in_greenhouse, LogicEntrance.grow_fall_crops_in_greenhouse,
|
||||||
|
LogicEntrance.grow_winter_crops_in_greenhouse, LogicEntrance.grow_indoor_crops_in_greenhouse)),
|
||||||
|
RegionData(RegionName.mountain,
|
||||||
|
(Entrance.mountain_to_railroad, Entrance.mountain_to_tent, Entrance.mountain_to_carpenter_shop,
|
||||||
|
Entrance.mountain_to_the_mines, Entrance.enter_quarry, Entrance.mountain_to_adventurer_guild,
|
||||||
|
Entrance.mountain_to_town, Entrance.mountain_to_maru_room)),
|
||||||
|
RegionData(RegionName.maru_room),
|
||||||
|
RegionData(RegionName.tunnel_entrance, (Entrance.tunnel_entrance_to_bus_tunnel,)),
|
||||||
|
RegionData(RegionName.bus_tunnel),
|
||||||
|
RegionData(RegionName.town,
|
||||||
|
(Entrance.town_to_community_center, Entrance.town_to_beach, Entrance.town_to_hospital, Entrance.town_to_pierre_general_store,
|
||||||
|
Entrance.town_to_saloon, Entrance.town_to_alex_house, Entrance.town_to_trailer, Entrance.town_to_mayor_manor, Entrance.town_to_sam_house,
|
||||||
|
Entrance.town_to_haley_house, Entrance.town_to_sewer, Entrance.town_to_clint_blacksmith, Entrance.town_to_museum, Entrance.town_to_jojamart,
|
||||||
|
Entrance.purchase_movie_ticket, LogicEntrance.buy_experience_books, LogicEntrance.attend_egg_festival, LogicEntrance.attend_fair,
|
||||||
|
LogicEntrance.attend_spirit_eve, LogicEntrance.attend_winter_star)),
|
||||||
|
RegionData(RegionName.beach,
|
||||||
|
(Entrance.beach_to_willy_fish_shop, Entrance.enter_elliott_house, Entrance.enter_tide_pools, LogicEntrance.attend_luau,
|
||||||
|
LogicEntrance.attend_moonlight_jellies, LogicEntrance.attend_night_market, LogicEntrance.attend_squidfest)),
|
||||||
|
RegionData(RegionName.railroad, (Entrance.enter_bathhouse_entrance, Entrance.enter_witch_warp_cave)),
|
||||||
|
RegionData(RegionName.ranch),
|
||||||
|
RegionData(RegionName.leah_house),
|
||||||
|
RegionData(RegionName.mastery_cave),
|
||||||
|
RegionData(RegionName.sewer, (Entrance.enter_mutant_bug_lair,)),
|
||||||
|
RegionData(RegionName.mutant_bug_lair),
|
||||||
|
RegionData(RegionName.wizard_tower, (Entrance.enter_wizard_basement, Entrance.use_desert_obelisk)),
|
||||||
|
RegionData(RegionName.wizard_basement),
|
||||||
|
RegionData(RegionName.tent),
|
||||||
|
RegionData(RegionName.carpenter, (Entrance.enter_sebastian_room,)),
|
||||||
|
RegionData(RegionName.sebastian_room),
|
||||||
|
RegionData(RegionName.adventurer_guild, (Entrance.adventurer_guild_to_bedroom,)),
|
||||||
|
RegionData(RegionName.adventurer_guild_bedroom),
|
||||||
|
RegionData(RegionName.community_center,
|
||||||
|
(Entrance.access_crafts_room, Entrance.access_pantry, Entrance.access_fish_tank,
|
||||||
|
Entrance.access_boiler_room, Entrance.access_bulletin_board, Entrance.access_vault)),
|
||||||
|
RegionData(RegionName.crafts_room),
|
||||||
|
RegionData(RegionName.pantry),
|
||||||
|
RegionData(RegionName.fish_tank),
|
||||||
|
RegionData(RegionName.boiler_room),
|
||||||
|
RegionData(RegionName.bulletin_board),
|
||||||
|
RegionData(RegionName.vault),
|
||||||
|
RegionData(RegionName.hospital, (Entrance.enter_harvey_room,)),
|
||||||
|
RegionData(RegionName.harvey_room),
|
||||||
|
RegionData(RegionName.pierre_store, (Entrance.enter_sunroom,)),
|
||||||
|
RegionData(RegionName.sunroom),
|
||||||
|
RegionData(RegionName.saloon, (Entrance.play_journey_of_the_prairie_king, Entrance.play_junimo_kart)),
|
||||||
|
RegionData(RegionName.jotpk_world_1, (Entrance.reach_jotpk_world_2,)),
|
||||||
|
RegionData(RegionName.jotpk_world_2, (Entrance.reach_jotpk_world_3,)),
|
||||||
|
RegionData(RegionName.jotpk_world_3),
|
||||||
|
RegionData(RegionName.junimo_kart_1, (Entrance.reach_junimo_kart_2,)),
|
||||||
|
RegionData(RegionName.junimo_kart_2, (Entrance.reach_junimo_kart_3,)),
|
||||||
|
RegionData(RegionName.junimo_kart_3, (Entrance.reach_junimo_kart_4,)),
|
||||||
|
RegionData(RegionName.junimo_kart_4),
|
||||||
|
RegionData(RegionName.alex_house),
|
||||||
|
RegionData(RegionName.trailer),
|
||||||
|
RegionData(RegionName.mayor_house),
|
||||||
|
RegionData(RegionName.sam_house),
|
||||||
|
RegionData(RegionName.haley_house),
|
||||||
|
RegionData(RegionName.blacksmith, (LogicEntrance.blacksmith_copper,)),
|
||||||
|
RegionData(RegionName.museum),
|
||||||
|
RegionData(RegionName.jojamart, (Entrance.enter_abandoned_jojamart,)),
|
||||||
|
RegionData(RegionName.abandoned_jojamart, (Entrance.enter_movie_theater,)),
|
||||||
|
RegionData(RegionName.movie_ticket_stand),
|
||||||
|
RegionData(RegionName.movie_theater),
|
||||||
|
RegionData(RegionName.fish_shop),
|
||||||
|
RegionData(RegionName.elliott_house),
|
||||||
|
RegionData(RegionName.tide_pools),
|
||||||
|
RegionData(RegionName.bathhouse_entrance, (Entrance.enter_locker_room,)),
|
||||||
|
RegionData(RegionName.locker_room, (Entrance.enter_public_bath,)),
|
||||||
|
RegionData(RegionName.public_bath),
|
||||||
|
RegionData(RegionName.witch_warp_cave, (Entrance.enter_witch_swamp,)),
|
||||||
|
RegionData(RegionName.witch_swamp, (Entrance.enter_witch_hut,)),
|
||||||
|
RegionData(RegionName.witch_hut, (Entrance.witch_warp_to_wizard_basement,)),
|
||||||
|
RegionData(RegionName.quarry, (Entrance.enter_quarry_mine_entrance,)),
|
||||||
|
RegionData(RegionName.quarry_mine_entrance, (Entrance.enter_quarry_mine,)),
|
||||||
|
RegionData(RegionName.quarry_mine),
|
||||||
|
RegionData(RegionName.secret_woods),
|
||||||
|
RegionData(RegionName.desert, (Entrance.enter_skull_cavern_entrance, Entrance.enter_oasis, LogicEntrance.attend_desert_festival)),
|
||||||
|
RegionData(RegionName.oasis, (Entrance.enter_casino,)),
|
||||||
|
RegionData(RegionName.casino),
|
||||||
|
RegionData(RegionName.skull_cavern_entrance, (Entrance.enter_skull_cavern,)),
|
||||||
|
RegionData(RegionName.skull_cavern, (Entrance.mine_to_skull_cavern_floor_25,)),
|
||||||
|
RegionData(RegionName.skull_cavern_25, (Entrance.mine_to_skull_cavern_floor_50,)),
|
||||||
|
RegionData(RegionName.skull_cavern_50, (Entrance.mine_to_skull_cavern_floor_75,)),
|
||||||
|
RegionData(RegionName.skull_cavern_75, (Entrance.mine_to_skull_cavern_floor_100,)),
|
||||||
|
RegionData(RegionName.skull_cavern_100, (Entrance.mine_to_skull_cavern_floor_125,)),
|
||||||
|
RegionData(RegionName.skull_cavern_125, (Entrance.mine_to_skull_cavern_floor_150,)),
|
||||||
|
RegionData(RegionName.skull_cavern_150, (Entrance.mine_to_skull_cavern_floor_175,)),
|
||||||
|
RegionData(RegionName.skull_cavern_175, (Entrance.mine_to_skull_cavern_floor_200,)),
|
||||||
|
RegionData(RegionName.skull_cavern_200),
|
||||||
|
|
||||||
|
RegionData(RegionName.coop),
|
||||||
|
RegionData(RegionName.barn),
|
||||||
|
RegionData(RegionName.shed),
|
||||||
|
RegionData(RegionName.slime_hutch),
|
||||||
|
|
||||||
|
RegionData(RegionName.mines, (LogicEntrance.talk_to_mines_dwarf, Entrance.dig_to_mines_floor_5)),
|
||||||
|
RegionData(RegionName.mines_floor_5, (Entrance.dig_to_mines_floor_10,)),
|
||||||
|
RegionData(RegionName.mines_floor_10, (Entrance.dig_to_mines_floor_15,)),
|
||||||
|
RegionData(RegionName.mines_floor_15, (Entrance.dig_to_mines_floor_20,)),
|
||||||
|
RegionData(RegionName.mines_floor_20, (Entrance.dig_to_mines_floor_25,)),
|
||||||
|
RegionData(RegionName.mines_floor_25, (Entrance.dig_to_mines_floor_30,)),
|
||||||
|
RegionData(RegionName.mines_floor_30, (Entrance.dig_to_mines_floor_35,)),
|
||||||
|
RegionData(RegionName.mines_floor_35, (Entrance.dig_to_mines_floor_40,)),
|
||||||
|
RegionData(RegionName.mines_floor_40, (Entrance.dig_to_mines_floor_45,)),
|
||||||
|
RegionData(RegionName.mines_floor_45, (Entrance.dig_to_mines_floor_50,)),
|
||||||
|
RegionData(RegionName.mines_floor_50, (Entrance.dig_to_mines_floor_55,)),
|
||||||
|
RegionData(RegionName.mines_floor_55, (Entrance.dig_to_mines_floor_60,)),
|
||||||
|
RegionData(RegionName.mines_floor_60, (Entrance.dig_to_mines_floor_65,)),
|
||||||
|
RegionData(RegionName.mines_floor_65, (Entrance.dig_to_mines_floor_70,)),
|
||||||
|
RegionData(RegionName.mines_floor_70, (Entrance.dig_to_mines_floor_75,)),
|
||||||
|
RegionData(RegionName.mines_floor_75, (Entrance.dig_to_mines_floor_80,)),
|
||||||
|
RegionData(RegionName.mines_floor_80, (Entrance.dig_to_mines_floor_85,)),
|
||||||
|
RegionData(RegionName.mines_floor_85, (Entrance.dig_to_mines_floor_90,)),
|
||||||
|
RegionData(RegionName.mines_floor_90, (Entrance.dig_to_mines_floor_95,)),
|
||||||
|
RegionData(RegionName.mines_floor_95, (Entrance.dig_to_mines_floor_100,)),
|
||||||
|
RegionData(RegionName.mines_floor_100, (Entrance.dig_to_mines_floor_105,)),
|
||||||
|
RegionData(RegionName.mines_floor_105, (Entrance.dig_to_mines_floor_110,)),
|
||||||
|
RegionData(RegionName.mines_floor_110, (Entrance.dig_to_mines_floor_115,)),
|
||||||
|
RegionData(RegionName.mines_floor_115, (Entrance.dig_to_mines_floor_120,)),
|
||||||
|
RegionData(RegionName.mines_floor_120),
|
||||||
|
|
||||||
|
RegionData(LogicRegion.mines_dwarf_shop),
|
||||||
|
RegionData(LogicRegion.blacksmith_copper, (LogicEntrance.blacksmith_iron,)),
|
||||||
|
RegionData(LogicRegion.blacksmith_iron, (LogicEntrance.blacksmith_gold,)),
|
||||||
|
RegionData(LogicRegion.blacksmith_gold, (LogicEntrance.blacksmith_iridium,)),
|
||||||
|
RegionData(LogicRegion.blacksmith_iridium),
|
||||||
|
RegionData(LogicRegion.kitchen),
|
||||||
|
RegionData(LogicRegion.queen_of_sauce),
|
||||||
|
RegionData(LogicRegion.fishing),
|
||||||
|
|
||||||
|
RegionData(LogicRegion.spring_farming),
|
||||||
|
RegionData(LogicRegion.summer_farming, (LogicEntrance.grow_summer_fall_crops_in_summer,)),
|
||||||
|
RegionData(LogicRegion.fall_farming, (LogicEntrance.grow_summer_fall_crops_in_fall,)),
|
||||||
|
RegionData(LogicRegion.winter_farming),
|
||||||
|
RegionData(LogicRegion.summer_or_fall_farming),
|
||||||
|
RegionData(LogicRegion.indoor_farming),
|
||||||
|
|
||||||
|
RegionData(LogicRegion.shipping),
|
||||||
|
RegionData(LogicRegion.traveling_cart, (LogicEntrance.buy_from_traveling_merchant_sunday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_monday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_tuesday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_wednesday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_thursday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_friday,
|
||||||
|
LogicEntrance.buy_from_traveling_merchant_saturday)),
|
||||||
|
RegionData(LogicRegion.traveling_cart_sunday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_monday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_tuesday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_wednesday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_thursday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_friday),
|
||||||
|
RegionData(LogicRegion.traveling_cart_saturday),
|
||||||
|
RegionData(LogicRegion.raccoon_daddy, (LogicEntrance.buy_from_raccoon,)),
|
||||||
|
RegionData(LogicRegion.raccoon_shop),
|
||||||
|
|
||||||
|
RegionData(LogicRegion.egg_festival),
|
||||||
|
RegionData(LogicRegion.desert_festival),
|
||||||
|
RegionData(LogicRegion.flower_dance),
|
||||||
|
RegionData(LogicRegion.luau),
|
||||||
|
RegionData(LogicRegion.trout_derby),
|
||||||
|
RegionData(LogicRegion.moonlight_jellies),
|
||||||
|
RegionData(LogicRegion.fair),
|
||||||
|
RegionData(LogicRegion.spirit_eve),
|
||||||
|
RegionData(LogicRegion.festival_of_ice),
|
||||||
|
RegionData(LogicRegion.night_market),
|
||||||
|
RegionData(LogicRegion.winter_star),
|
||||||
|
RegionData(LogicRegion.squidfest),
|
||||||
|
RegionData(LogicRegion.bookseller_1, (LogicEntrance.buy_year1_books,)),
|
||||||
|
RegionData(LogicRegion.bookseller_2, (LogicEntrance.buy_year3_books,)),
|
||||||
|
RegionData(LogicRegion.bookseller_3),
|
||||||
|
)
|
||||||
|
ginger_island_regions = (
|
||||||
|
# This overrides the regions from vanilla... When regions are moved to content packs, overriding existing entrances should no longer be necessary.
|
||||||
|
RegionData(RegionName.mountain,
|
||||||
|
(Entrance.mountain_to_railroad, Entrance.mountain_to_tent, Entrance.mountain_to_carpenter_shop,
|
||||||
|
Entrance.mountain_to_the_mines, Entrance.enter_quarry, Entrance.mountain_to_adventurer_guild,
|
||||||
|
Entrance.mountain_to_town, Entrance.mountain_to_maru_room, Entrance.mountain_to_leo_treehouse)),
|
||||||
|
RegionData(RegionName.wizard_tower, (Entrance.enter_wizard_basement, Entrance.use_desert_obelisk, Entrance.use_island_obelisk,)),
|
||||||
|
RegionData(RegionName.fish_shop, (Entrance.fish_shop_to_boat_tunnel,)),
|
||||||
|
RegionData(RegionName.mines_floor_120, (Entrance.dig_to_dangerous_mines_20, Entrance.dig_to_dangerous_mines_60, Entrance.dig_to_dangerous_mines_100)),
|
||||||
|
RegionData(RegionName.skull_cavern_200, (Entrance.enter_dangerous_skull_cavern,)),
|
||||||
|
|
||||||
|
RegionData(RegionName.leo_treehouse),
|
||||||
|
RegionData(RegionName.boat_tunnel, (Entrance.boat_to_ginger_island,)),
|
||||||
|
RegionData(RegionName.dangerous_skull_cavern),
|
||||||
|
RegionData(RegionName.island_south,
|
||||||
|
(Entrance.island_south_to_west, Entrance.island_south_to_north, Entrance.island_south_to_east, Entrance.island_south_to_southeast,
|
||||||
|
Entrance.use_island_resort, Entrance.parrot_express_docks_to_volcano, Entrance.parrot_express_docks_to_dig_site,
|
||||||
|
Entrance.parrot_express_docks_to_jungle), ),
|
||||||
|
RegionData(RegionName.island_resort),
|
||||||
|
RegionData(RegionName.island_west,
|
||||||
|
(Entrance.island_west_to_islandfarmhouse, Entrance.island_west_to_gourmand_cave, Entrance.island_west_to_crystals_cave,
|
||||||
|
Entrance.island_west_to_shipwreck, Entrance.island_west_to_qi_walnut_room, Entrance.use_farm_obelisk, Entrance.parrot_express_jungle_to_docks,
|
||||||
|
Entrance.parrot_express_jungle_to_dig_site, Entrance.parrot_express_jungle_to_volcano, LogicEntrance.grow_spring_crops_on_island,
|
||||||
|
LogicEntrance.grow_summer_crops_on_island, LogicEntrance.grow_fall_crops_on_island, LogicEntrance.grow_winter_crops_on_island,
|
||||||
|
LogicEntrance.grow_indoor_crops_on_island), ),
|
||||||
|
RegionData(RegionName.island_east, (Entrance.island_east_to_leo_hut, Entrance.island_east_to_island_shrine)),
|
||||||
|
RegionData(RegionName.island_shrine),
|
||||||
|
RegionData(RegionName.island_south_east, (Entrance.island_southeast_to_pirate_cove,)),
|
||||||
|
RegionData(RegionName.island_north,
|
||||||
|
(Entrance.talk_to_island_trader, Entrance.island_north_to_field_office, Entrance.island_north_to_dig_site, Entrance.island_north_to_volcano,
|
||||||
|
Entrance.parrot_express_volcano_to_dig_site, Entrance.parrot_express_volcano_to_jungle, Entrance.parrot_express_volcano_to_docks), ),
|
||||||
|
RegionData(RegionName.volcano, (Entrance.climb_to_volcano_5, Entrance.volcano_to_secret_beach)),
|
||||||
|
RegionData(RegionName.volcano_secret_beach),
|
||||||
|
RegionData(RegionName.volcano_floor_5, (Entrance.talk_to_volcano_dwarf, Entrance.climb_to_volcano_10)),
|
||||||
|
RegionData(RegionName.volcano_dwarf_shop),
|
||||||
|
RegionData(RegionName.volcano_floor_10),
|
||||||
|
RegionData(RegionName.island_trader),
|
||||||
|
RegionData(RegionName.island_farmhouse, (LogicEntrance.island_cooking,)),
|
||||||
|
RegionData(RegionName.gourmand_frog_cave),
|
||||||
|
RegionData(RegionName.colored_crystals_cave),
|
||||||
|
RegionData(RegionName.shipwreck),
|
||||||
|
RegionData(RegionName.qi_walnut_room),
|
||||||
|
RegionData(RegionName.leo_hut),
|
||||||
|
RegionData(RegionName.pirate_cove),
|
||||||
|
RegionData(RegionName.field_office),
|
||||||
|
RegionData(RegionName.dig_site,
|
||||||
|
(Entrance.dig_site_to_professor_snail_cave, Entrance.parrot_express_dig_site_to_volcano,
|
||||||
|
Entrance.parrot_express_dig_site_to_docks, Entrance.parrot_express_dig_site_to_jungle), ),
|
||||||
|
|
||||||
|
RegionData(RegionName.professor_snail_cave),
|
||||||
|
RegionData(RegionName.dangerous_mines_20),
|
||||||
|
RegionData(RegionName.dangerous_mines_60),
|
||||||
|
RegionData(RegionName.dangerous_mines_100),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Exists and where they lead
|
||||||
|
vanilla_connections: tuple[ConnectionData, ...] = (
|
||||||
|
ConnectionData(Entrance.to_stardew_valley, RegionName.stardew_valley),
|
||||||
|
ConnectionData(Entrance.to_farmhouse, RegionName.farm_house),
|
||||||
|
ConnectionData(Entrance.farmhouse_to_farm, RegionName.farm),
|
||||||
|
ConnectionData(Entrance.downstairs_to_cellar, RegionName.cellar),
|
||||||
|
ConnectionData(Entrance.farm_to_backwoods, RegionName.backwoods),
|
||||||
|
ConnectionData(Entrance.farm_to_bus_stop, RegionName.bus_stop),
|
||||||
|
ConnectionData(Entrance.farm_to_forest, RegionName.forest),
|
||||||
|
ConnectionData(Entrance.farm_to_farmcave, RegionName.farm_cave, flag=RandomizationFlag.NON_PROGRESSION),
|
||||||
|
ConnectionData(Entrance.enter_greenhouse, RegionName.greenhouse),
|
||||||
|
ConnectionData(Entrance.enter_coop, RegionName.coop),
|
||||||
|
ConnectionData(Entrance.enter_barn, RegionName.barn),
|
||||||
|
ConnectionData(Entrance.enter_shed, RegionName.shed),
|
||||||
|
ConnectionData(Entrance.enter_slime_hutch, RegionName.slime_hutch),
|
||||||
|
ConnectionData(Entrance.use_desert_obelisk, RegionName.desert),
|
||||||
|
ConnectionData(Entrance.backwoods_to_mountain, RegionName.mountain),
|
||||||
|
ConnectionData(Entrance.bus_stop_to_town, RegionName.town),
|
||||||
|
ConnectionData(Entrance.bus_stop_to_tunnel_entrance, RegionName.tunnel_entrance),
|
||||||
|
ConnectionData(Entrance.tunnel_entrance_to_bus_tunnel, RegionName.bus_tunnel, flag=RandomizationFlag.NON_PROGRESSION),
|
||||||
|
ConnectionData(Entrance.take_bus_to_desert, RegionName.desert),
|
||||||
|
ConnectionData(Entrance.forest_to_town, RegionName.town),
|
||||||
|
ConnectionData(Entrance.forest_to_wizard_tower, RegionName.wizard_tower,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.forest_to_marnie_ranch, RegionName.ranch,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.forest_to_leah_cottage, RegionName.leah_house,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_secret_woods, RegionName.secret_woods),
|
||||||
|
ConnectionData(Entrance.forest_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
# We remove the bit for masteries, because the mastery cave is to be excluded from the randomization if masteries are not shuffled.
|
||||||
|
ConnectionData(Entrance.forest_to_mastery_cave, RegionName.mastery_cave, flag=RandomizationFlag.BUILDINGS ^ RandomizationFlag.EXCLUDE_MASTERIES),
|
||||||
|
ConnectionData(Entrance.town_to_sewer, RegionName.sewer, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_mutant_bug_lair, RegionName.mutant_bug_lair, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.mountain_to_railroad, RegionName.railroad),
|
||||||
|
ConnectionData(Entrance.mountain_to_tent, RegionName.tent,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.mountain_to_carpenter_shop, RegionName.carpenter,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.mountain_to_maru_room, RegionName.maru_room,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_sebastian_room, RegionName.sebastian_room, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.mountain_to_adventurer_guild, RegionName.adventurer_guild,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.adventurer_guild_to_bedroom, RegionName.adventurer_guild_bedroom),
|
||||||
|
ConnectionData(Entrance.enter_quarry, RegionName.quarry),
|
||||||
|
ConnectionData(Entrance.enter_quarry_mine_entrance, RegionName.quarry_mine_entrance,
|
||||||
|
flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_quarry_mine, RegionName.quarry_mine),
|
||||||
|
ConnectionData(Entrance.mountain_to_town, RegionName.town),
|
||||||
|
ConnectionData(Entrance.town_to_community_center, RegionName.community_center,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.access_crafts_room, RegionName.crafts_room),
|
||||||
|
ConnectionData(Entrance.access_pantry, RegionName.pantry),
|
||||||
|
ConnectionData(Entrance.access_fish_tank, RegionName.fish_tank),
|
||||||
|
ConnectionData(Entrance.access_boiler_room, RegionName.boiler_room),
|
||||||
|
ConnectionData(Entrance.access_bulletin_board, RegionName.bulletin_board),
|
||||||
|
ConnectionData(Entrance.access_vault, RegionName.vault),
|
||||||
|
ConnectionData(Entrance.town_to_hospital, RegionName.hospital,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_harvey_room, RegionName.harvey_room, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.town_to_pierre_general_store, RegionName.pierre_store,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_sunroom, RegionName.sunroom, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.town_to_clint_blacksmith, RegionName.blacksmith,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_saloon, RegionName.saloon,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.play_journey_of_the_prairie_king, RegionName.jotpk_world_1),
|
||||||
|
ConnectionData(Entrance.reach_jotpk_world_2, RegionName.jotpk_world_2),
|
||||||
|
ConnectionData(Entrance.reach_jotpk_world_3, RegionName.jotpk_world_3),
|
||||||
|
ConnectionData(Entrance.play_junimo_kart, RegionName.junimo_kart_1),
|
||||||
|
ConnectionData(Entrance.reach_junimo_kart_2, RegionName.junimo_kart_2),
|
||||||
|
ConnectionData(Entrance.reach_junimo_kart_3, RegionName.junimo_kart_3),
|
||||||
|
ConnectionData(Entrance.reach_junimo_kart_4, RegionName.junimo_kart_4),
|
||||||
|
ConnectionData(Entrance.town_to_sam_house, RegionName.sam_house,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_haley_house, RegionName.haley_house,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_mayor_manor, RegionName.mayor_house,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_alex_house, RegionName.alex_house,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_trailer, RegionName.trailer,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_museum, RegionName.museum,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.town_to_jojamart, RegionName.jojamart,
|
||||||
|
flag=RandomizationFlag.PELICAN_TOWN | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.purchase_movie_ticket, RegionName.movie_ticket_stand),
|
||||||
|
ConnectionData(Entrance.enter_abandoned_jojamart, RegionName.abandoned_jojamart),
|
||||||
|
ConnectionData(Entrance.enter_movie_theater, RegionName.movie_theater),
|
||||||
|
ConnectionData(Entrance.town_to_beach, RegionName.beach),
|
||||||
|
ConnectionData(Entrance.enter_elliott_house, RegionName.elliott_house,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.beach_to_willy_fish_shop, RegionName.fish_shop,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_tide_pools, RegionName.tide_pools),
|
||||||
|
ConnectionData(Entrance.mountain_to_the_mines, RegionName.mines,
|
||||||
|
flag=RandomizationFlag.NON_PROGRESSION | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_5, RegionName.mines_floor_5),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_10, RegionName.mines_floor_10),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_15, RegionName.mines_floor_15),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_20, RegionName.mines_floor_20),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_25, RegionName.mines_floor_25),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_30, RegionName.mines_floor_30),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_35, RegionName.mines_floor_35),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_40, RegionName.mines_floor_40),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_45, RegionName.mines_floor_45),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_50, RegionName.mines_floor_50),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_55, RegionName.mines_floor_55),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_60, RegionName.mines_floor_60),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_65, RegionName.mines_floor_65),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_70, RegionName.mines_floor_70),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_75, RegionName.mines_floor_75),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_80, RegionName.mines_floor_80),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_85, RegionName.mines_floor_85),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_90, RegionName.mines_floor_90),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_95, RegionName.mines_floor_95),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_100, RegionName.mines_floor_100),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_105, RegionName.mines_floor_105),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_110, RegionName.mines_floor_110),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_115, RegionName.mines_floor_115),
|
||||||
|
ConnectionData(Entrance.dig_to_mines_floor_120, RegionName.mines_floor_120),
|
||||||
|
ConnectionData(Entrance.enter_skull_cavern_entrance, RegionName.skull_cavern_entrance,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_oasis, RegionName.oasis,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_casino, RegionName.casino, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_skull_cavern, RegionName.skull_cavern),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_25, RegionName.skull_cavern_25),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_50, RegionName.skull_cavern_50),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_75, RegionName.skull_cavern_75),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_100, RegionName.skull_cavern_100),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_125, RegionName.skull_cavern_125),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_150, RegionName.skull_cavern_150),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_175, RegionName.skull_cavern_175),
|
||||||
|
ConnectionData(Entrance.mine_to_skull_cavern_floor_200, RegionName.skull_cavern_200),
|
||||||
|
ConnectionData(Entrance.enter_witch_warp_cave, RegionName.witch_warp_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_witch_swamp, RegionName.witch_swamp, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_witch_hut, RegionName.witch_hut, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.witch_warp_to_wizard_basement, RegionName.wizard_basement, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_bathhouse_entrance, RegionName.bathhouse_entrance,
|
||||||
|
flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.enter_locker_room, RegionName.locker_room, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.enter_public_bath, RegionName.public_bath, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(LogicEntrance.talk_to_mines_dwarf, LogicRegion.mines_dwarf_shop),
|
||||||
|
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant, LogicRegion.traveling_cart),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_sunday, LogicRegion.traveling_cart_sunday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_monday, LogicRegion.traveling_cart_monday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_tuesday, LogicRegion.traveling_cart_tuesday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_wednesday, LogicRegion.traveling_cart_wednesday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_thursday, LogicRegion.traveling_cart_thursday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_friday, LogicRegion.traveling_cart_friday),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_traveling_merchant_saturday, LogicRegion.traveling_cart_saturday),
|
||||||
|
ConnectionData(LogicEntrance.complete_raccoon_requests, LogicRegion.raccoon_daddy),
|
||||||
|
ConnectionData(LogicEntrance.fish_in_waterfall, LogicRegion.forest_waterfall),
|
||||||
|
ConnectionData(LogicEntrance.buy_from_raccoon, LogicRegion.raccoon_shop),
|
||||||
|
ConnectionData(LogicEntrance.farmhouse_cooking, LogicRegion.kitchen),
|
||||||
|
ConnectionData(LogicEntrance.watch_queen_of_sauce, LogicRegion.queen_of_sauce),
|
||||||
|
|
||||||
|
ConnectionData(LogicEntrance.grow_spring_crops, LogicRegion.spring_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_summer_crops, LogicRegion.summer_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_fall_crops, LogicRegion.fall_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_winter_crops, LogicRegion.winter_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_spring_crops_in_greenhouse, LogicRegion.spring_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_summer_crops_in_greenhouse, LogicRegion.summer_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_fall_crops_in_greenhouse, LogicRegion.fall_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_winter_crops_in_greenhouse, LogicRegion.winter_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_indoor_crops_in_greenhouse, LogicRegion.indoor_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_summer_fall_crops_in_summer, LogicRegion.summer_or_fall_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_summer_fall_crops_in_fall, LogicRegion.summer_or_fall_farming),
|
||||||
|
|
||||||
|
ConnectionData(LogicEntrance.shipping, LogicRegion.shipping),
|
||||||
|
ConnectionData(LogicEntrance.blacksmith_copper, LogicRegion.blacksmith_copper),
|
||||||
|
ConnectionData(LogicEntrance.blacksmith_iron, LogicRegion.blacksmith_iron),
|
||||||
|
ConnectionData(LogicEntrance.blacksmith_gold, LogicRegion.blacksmith_gold),
|
||||||
|
ConnectionData(LogicEntrance.blacksmith_iridium, LogicRegion.blacksmith_iridium),
|
||||||
|
ConnectionData(LogicEntrance.fishing, LogicRegion.fishing),
|
||||||
|
ConnectionData(LogicEntrance.attend_egg_festival, LogicRegion.egg_festival),
|
||||||
|
ConnectionData(LogicEntrance.attend_desert_festival, LogicRegion.desert_festival),
|
||||||
|
ConnectionData(LogicEntrance.attend_flower_dance, LogicRegion.flower_dance),
|
||||||
|
ConnectionData(LogicEntrance.attend_luau, LogicRegion.luau),
|
||||||
|
ConnectionData(LogicEntrance.attend_trout_derby, LogicRegion.trout_derby),
|
||||||
|
ConnectionData(LogicEntrance.attend_moonlight_jellies, LogicRegion.moonlight_jellies),
|
||||||
|
ConnectionData(LogicEntrance.attend_fair, LogicRegion.fair),
|
||||||
|
ConnectionData(LogicEntrance.attend_spirit_eve, LogicRegion.spirit_eve),
|
||||||
|
ConnectionData(LogicEntrance.attend_festival_of_ice, LogicRegion.festival_of_ice),
|
||||||
|
ConnectionData(LogicEntrance.attend_night_market, LogicRegion.night_market),
|
||||||
|
ConnectionData(LogicEntrance.attend_winter_star, LogicRegion.winter_star),
|
||||||
|
ConnectionData(LogicEntrance.attend_squidfest, LogicRegion.squidfest),
|
||||||
|
ConnectionData(LogicEntrance.buy_experience_books, LogicRegion.bookseller_1),
|
||||||
|
ConnectionData(LogicEntrance.buy_year1_books, LogicRegion.bookseller_2),
|
||||||
|
ConnectionData(LogicEntrance.buy_year3_books, LogicRegion.bookseller_3),
|
||||||
|
)
|
||||||
|
|
||||||
|
ginger_island_connections = (
|
||||||
|
ConnectionData(Entrance.use_island_obelisk, RegionName.island_south),
|
||||||
|
ConnectionData(Entrance.use_farm_obelisk, RegionName.farm),
|
||||||
|
ConnectionData(Entrance.mountain_to_leo_treehouse, RegionName.leo_treehouse, flag=RandomizationFlag.BUILDINGS | RandomizationFlag.LEAD_TO_OPEN_AREA),
|
||||||
|
ConnectionData(Entrance.fish_shop_to_boat_tunnel, RegionName.boat_tunnel, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.boat_to_ginger_island, RegionName.island_south),
|
||||||
|
ConnectionData(Entrance.enter_dangerous_skull_cavern, RegionName.dangerous_skull_cavern),
|
||||||
|
ConnectionData(Entrance.dig_to_dangerous_mines_20, RegionName.dangerous_mines_20),
|
||||||
|
ConnectionData(Entrance.dig_to_dangerous_mines_60, RegionName.dangerous_mines_60),
|
||||||
|
ConnectionData(Entrance.dig_to_dangerous_mines_100, RegionName.dangerous_mines_100),
|
||||||
|
ConnectionData(Entrance.island_south_to_west, RegionName.island_west),
|
||||||
|
ConnectionData(Entrance.island_south_to_north, RegionName.island_north),
|
||||||
|
ConnectionData(Entrance.island_south_to_east, RegionName.island_east),
|
||||||
|
ConnectionData(Entrance.island_south_to_southeast, RegionName.island_south_east),
|
||||||
|
ConnectionData(Entrance.use_island_resort, RegionName.island_resort),
|
||||||
|
ConnectionData(Entrance.island_west_to_islandfarmhouse, RegionName.island_farmhouse, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_west_to_gourmand_cave, RegionName.gourmand_frog_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_west_to_crystals_cave, RegionName.colored_crystals_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_west_to_shipwreck, RegionName.shipwreck, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_west_to_qi_walnut_room, RegionName.qi_walnut_room, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_east_to_leo_hut, RegionName.leo_hut, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_east_to_island_shrine, RegionName.island_shrine, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_southeast_to_pirate_cove, RegionName.pirate_cove, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_north_to_field_office, RegionName.field_office, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_north_to_dig_site, RegionName.dig_site),
|
||||||
|
ConnectionData(Entrance.dig_site_to_professor_snail_cave, RegionName.professor_snail_cave, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.island_north_to_volcano, RegionName.volcano, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.volcano_to_secret_beach, RegionName.volcano_secret_beach, flag=RandomizationFlag.BUILDINGS),
|
||||||
|
ConnectionData(Entrance.talk_to_island_trader, RegionName.island_trader),
|
||||||
|
ConnectionData(Entrance.climb_to_volcano_5, RegionName.volcano_floor_5),
|
||||||
|
ConnectionData(Entrance.talk_to_volcano_dwarf, RegionName.volcano_dwarf_shop),
|
||||||
|
ConnectionData(Entrance.climb_to_volcano_10, RegionName.volcano_floor_10),
|
||||||
|
ConnectionData(Entrance.parrot_express_jungle_to_docks, RegionName.island_south),
|
||||||
|
ConnectionData(Entrance.parrot_express_dig_site_to_docks, RegionName.island_south),
|
||||||
|
ConnectionData(Entrance.parrot_express_volcano_to_docks, RegionName.island_south),
|
||||||
|
ConnectionData(Entrance.parrot_express_volcano_to_jungle, RegionName.island_west),
|
||||||
|
ConnectionData(Entrance.parrot_express_docks_to_jungle, RegionName.island_west),
|
||||||
|
ConnectionData(Entrance.parrot_express_dig_site_to_jungle, RegionName.island_west),
|
||||||
|
ConnectionData(Entrance.parrot_express_docks_to_dig_site, RegionName.dig_site),
|
||||||
|
ConnectionData(Entrance.parrot_express_volcano_to_dig_site, RegionName.dig_site),
|
||||||
|
ConnectionData(Entrance.parrot_express_jungle_to_dig_site, RegionName.dig_site),
|
||||||
|
ConnectionData(Entrance.parrot_express_dig_site_to_volcano, RegionName.island_north),
|
||||||
|
ConnectionData(Entrance.parrot_express_docks_to_volcano, RegionName.island_north),
|
||||||
|
ConnectionData(Entrance.parrot_express_jungle_to_volcano, RegionName.island_north),
|
||||||
|
ConnectionData(LogicEntrance.grow_spring_crops_on_island, LogicRegion.spring_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_summer_crops_on_island, LogicRegion.summer_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_fall_crops_on_island, LogicRegion.fall_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_winter_crops_on_island, LogicRegion.winter_farming),
|
||||||
|
ConnectionData(LogicEntrance.grow_indoor_crops_on_island, LogicRegion.indoor_farming),
|
||||||
|
ConnectionData(LogicEntrance.island_cooking, LogicRegion.kitchen),
|
||||||
|
)
|
||||||
|
|
||||||
|
connections_without_ginger_island_by_name: Mapping[str, ConnectionData] = MappingProxyType({
|
||||||
|
connection.name: connection
|
||||||
|
for connection in vanilla_connections
|
||||||
|
})
|
||||||
|
regions_without_ginger_island_by_name: Mapping[str, RegionData] = MappingProxyType({
|
||||||
|
region.name: region
|
||||||
|
for region in vanilla_regions
|
||||||
|
})
|
||||||
|
|
||||||
|
connections_with_ginger_island_by_name: Mapping[str, ConnectionData] = MappingProxyType({
|
||||||
|
connection.name: connection
|
||||||
|
for connection in vanilla_connections + ginger_island_connections
|
||||||
|
})
|
||||||
|
regions_with_ginger_island_by_name: Mapping[str, RegionData] = MappingProxyType({
|
||||||
|
region.name: region
|
||||||
|
for region in vanilla_regions + ginger_island_regions
|
||||||
|
})
|
@@ -1,173 +0,0 @@
|
|||||||
import random
|
|
||||||
import unittest
|
|
||||||
from typing import Set
|
|
||||||
|
|
||||||
from BaseClasses import get_seed
|
|
||||||
from .bases import SVTestCase
|
|
||||||
from .options.utils import fill_dataclass_with_default
|
|
||||||
from .. import create_content
|
|
||||||
from ..options import EntranceRandomization, ExcludeGingerIsland, SkillProgression
|
|
||||||
from ..regions import vanilla_regions, vanilla_connections, randomize_connections, RandomizationFlag, create_final_connections_and_regions
|
|
||||||
from ..strings.entrance_names import Entrance as EntranceName
|
|
||||||
from ..strings.region_names import Region as RegionName
|
|
||||||
|
|
||||||
connections_by_name = {connection.name for connection in vanilla_connections}
|
|
||||||
regions_by_name = {region.name for region in vanilla_regions}
|
|
||||||
|
|
||||||
|
|
||||||
class TestRegions(unittest.TestCase):
|
|
||||||
def test_region_exits_lead_somewhere(self):
|
|
||||||
for region in vanilla_regions:
|
|
||||||
with self.subTest(region=region):
|
|
||||||
for exit in region.exits:
|
|
||||||
self.assertIn(exit, connections_by_name,
|
|
||||||
f"{region.name} is leading to {exit} but it does not exist.")
|
|
||||||
|
|
||||||
def test_connection_lead_somewhere(self):
|
|
||||||
for connection in vanilla_connections:
|
|
||||||
with self.subTest(connection=connection):
|
|
||||||
self.assertIn(connection.destination, regions_by_name,
|
|
||||||
f"{connection.name} is leading to {connection.destination} but it does not exist.")
|
|
||||||
|
|
||||||
|
|
||||||
def explore_connections_tree_up_to_blockers(blocked_entrances: Set[str], connections_by_name, regions_by_name):
|
|
||||||
explored_entrances = set()
|
|
||||||
explored_regions = set()
|
|
||||||
entrances_to_explore = set()
|
|
||||||
current_node_name = "Menu"
|
|
||||||
current_node = regions_by_name[current_node_name]
|
|
||||||
entrances_to_explore.update(current_node.exits)
|
|
||||||
while entrances_to_explore:
|
|
||||||
current_entrance_name = entrances_to_explore.pop()
|
|
||||||
current_entrance = connections_by_name[current_entrance_name]
|
|
||||||
current_node_name = current_entrance.destination
|
|
||||||
|
|
||||||
explored_entrances.add(current_entrance_name)
|
|
||||||
explored_regions.add(current_node_name)
|
|
||||||
|
|
||||||
if current_entrance_name in blocked_entrances:
|
|
||||||
continue
|
|
||||||
|
|
||||||
current_node = regions_by_name[current_node_name]
|
|
||||||
entrances_to_explore.update({entrance for entrance in current_node.exits if entrance not in explored_entrances})
|
|
||||||
return explored_regions
|
|
||||||
|
|
||||||
|
|
||||||
class TestEntranceRando(SVTestCase):
|
|
||||||
|
|
||||||
def test_entrance_randomization(self):
|
|
||||||
for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),
|
|
||||||
(EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION),
|
|
||||||
(EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS),
|
|
||||||
(EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]:
|
|
||||||
sv_options = fill_dataclass_with_default({
|
|
||||||
EntranceRandomization.internal_name: option,
|
|
||||||
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false,
|
|
||||||
SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries,
|
|
||||||
})
|
|
||||||
content = create_content(sv_options)
|
|
||||||
seed = get_seed()
|
|
||||||
rand = random.Random(seed)
|
|
||||||
with self.subTest(flag=flag, msg=f"Seed: {seed}"):
|
|
||||||
entrances, regions = create_final_connections_and_regions(sv_options)
|
|
||||||
_, randomized_connections = randomize_connections(rand, sv_options, content, regions, entrances)
|
|
||||||
|
|
||||||
for connection in vanilla_connections:
|
|
||||||
if flag in connection.flag:
|
|
||||||
connection_in_randomized = connection.name in randomized_connections
|
|
||||||
reverse_in_randomized = connection.reverse in randomized_connections
|
|
||||||
self.assertTrue(connection_in_randomized, f"Connection {connection.name} should be randomized but it is not in the output.")
|
|
||||||
self.assertTrue(reverse_in_randomized, f"Connection {connection.reverse} should be randomized but it is not in the output.")
|
|
||||||
|
|
||||||
self.assertEqual(len(set(randomized_connections.values())), len(randomized_connections.values()),
|
|
||||||
f"Connections are duplicated in randomization.")
|
|
||||||
|
|
||||||
def test_entrance_randomization_without_island(self):
|
|
||||||
for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),
|
|
||||||
(EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION),
|
|
||||||
(EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS),
|
|
||||||
(EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]:
|
|
||||||
|
|
||||||
sv_options = fill_dataclass_with_default({
|
|
||||||
EntranceRandomization.internal_name: option,
|
|
||||||
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true,
|
|
||||||
SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries,
|
|
||||||
})
|
|
||||||
content = create_content(sv_options)
|
|
||||||
seed = get_seed()
|
|
||||||
rand = random.Random(seed)
|
|
||||||
with self.subTest(option=option, flag=flag, seed=seed):
|
|
||||||
entrances, regions = create_final_connections_and_regions(sv_options)
|
|
||||||
_, randomized_connections = randomize_connections(rand, sv_options, content, regions, entrances)
|
|
||||||
|
|
||||||
for connection in vanilla_connections:
|
|
||||||
if flag in connection.flag:
|
|
||||||
if RandomizationFlag.GINGER_ISLAND in connection.flag:
|
|
||||||
self.assertNotIn(connection.name, randomized_connections,
|
|
||||||
f"Connection {connection.name} should not be randomized but it is in the output.")
|
|
||||||
self.assertNotIn(connection.reverse, randomized_connections,
|
|
||||||
f"Connection {connection.reverse} should not be randomized but it is in the output.")
|
|
||||||
else:
|
|
||||||
self.assertIn(connection.name, randomized_connections,
|
|
||||||
f"Connection {connection.name} should be randomized but it is not in the output.")
|
|
||||||
self.assertIn(connection.reverse, randomized_connections,
|
|
||||||
f"Connection {connection.reverse} should be randomized but it is not in the output.")
|
|
||||||
|
|
||||||
self.assertEqual(len(set(randomized_connections.values())), len(randomized_connections.values()),
|
|
||||||
f"Connections are duplicated in randomization.")
|
|
||||||
|
|
||||||
def test_cannot_put_island_access_on_island(self):
|
|
||||||
sv_options = fill_dataclass_with_default({
|
|
||||||
EntranceRandomization.internal_name: EntranceRandomization.option_buildings,
|
|
||||||
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_false,
|
|
||||||
SkillProgression.internal_name: SkillProgression.option_progressive_with_masteries,
|
|
||||||
})
|
|
||||||
content = create_content(sv_options)
|
|
||||||
|
|
||||||
for i in range(0, 100 if self.skip_long_tests else 10000):
|
|
||||||
seed = get_seed()
|
|
||||||
rand = random.Random(seed)
|
|
||||||
with self.subTest(msg=f"Seed: {seed}"):
|
|
||||||
entrances, regions = create_final_connections_and_regions(sv_options)
|
|
||||||
randomized_connections, randomized_data = randomize_connections(rand, sv_options, content, regions, entrances)
|
|
||||||
connections_by_name = {connection.name: connection for connection in randomized_connections}
|
|
||||||
|
|
||||||
blocked_entrances = {EntranceName.use_island_obelisk, EntranceName.boat_to_ginger_island}
|
|
||||||
required_regions = {RegionName.wizard_tower, RegionName.boat_tunnel}
|
|
||||||
self.assert_can_reach_any_region_before_blockers(required_regions, blocked_entrances, connections_by_name, regions)
|
|
||||||
|
|
||||||
def assert_can_reach_any_region_before_blockers(self, required_regions, blocked_entrances, connections_by_name, regions_by_name):
|
|
||||||
explored_regions = explore_connections_tree_up_to_blockers(blocked_entrances, connections_by_name, regions_by_name)
|
|
||||||
self.assertTrue(any(region in explored_regions for region in required_regions))
|
|
||||||
|
|
||||||
|
|
||||||
class TestEntranceClassifications(SVTestCase):
|
|
||||||
|
|
||||||
def test_non_progression_are_all_accessible_with_empty_inventory(self):
|
|
||||||
for option, flag in [(EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),
|
|
||||||
(EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION)]:
|
|
||||||
world_options = {
|
|
||||||
EntranceRandomization.internal_name: option
|
|
||||||
}
|
|
||||||
with self.solo_world_sub_test(world_options=world_options, flag=flag) as (multiworld, sv_world):
|
|
||||||
ap_entrances = {entrance.name: entrance for entrance in multiworld.get_entrances()}
|
|
||||||
for randomized_entrance in sv_world.randomized_entrances:
|
|
||||||
if randomized_entrance in ap_entrances:
|
|
||||||
ap_entrance_origin = ap_entrances[randomized_entrance]
|
|
||||||
self.assertTrue(ap_entrance_origin.access_rule(multiworld.state))
|
|
||||||
if sv_world.randomized_entrances[randomized_entrance] in ap_entrances:
|
|
||||||
ap_entrance_destination = multiworld.get_entrance(sv_world.randomized_entrances[randomized_entrance], 1)
|
|
||||||
self.assertTrue(ap_entrance_destination.access_rule(multiworld.state))
|
|
||||||
|
|
||||||
def test_no_ginger_island_entrances_when_excluded(self):
|
|
||||||
world_options = {
|
|
||||||
EntranceRandomization.internal_name: EntranceRandomization.option_disabled,
|
|
||||||
ExcludeGingerIsland.internal_name: ExcludeGingerIsland.option_true
|
|
||||||
}
|
|
||||||
with self.solo_world_sub_test(world_options=world_options) as (multiworld, _):
|
|
||||||
ap_entrances = {entrance.name: entrance for entrance in multiworld.get_entrances()}
|
|
||||||
entrance_data_by_name = {entrance.name: entrance for entrance in vanilla_connections}
|
|
||||||
for entrance_name in ap_entrances:
|
|
||||||
entrance_data = entrance_data_by_name[entrance_name]
|
|
||||||
with self.subTest(f"{entrance_name}: {entrance_data.flag}"):
|
|
||||||
self.assertFalse(entrance_data.flag & RandomizationFlag.GINGER_ISLAND)
|
|
@@ -1,7 +1,7 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
from BaseClasses import CollectionState, Location, Region
|
from BaseClasses import CollectionState, Location, Region, Entrance
|
||||||
from ...stardew_rule import StardewRule, false_, MISSING_ITEM, Reach
|
from ...stardew_rule import StardewRule, false_, MISSING_ITEM, Reach
|
||||||
from ...stardew_rule.rule_explain import explain
|
from ...stardew_rule.rule_explain import explain
|
||||||
|
|
||||||
@@ -79,3 +79,13 @@ class RuleAssertMixin(TestCase):
|
|||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
raise AssertionError(f"Error while checking region {region_name}: {e}"
|
raise AssertionError(f"Error while checking region {region_name}: {e}"
|
||||||
f"\nExplanation: {expl}")
|
f"\nExplanation: {expl}")
|
||||||
|
|
||||||
|
def assert_can_reach_entrance(self, entrance: Entrance | str, state: CollectionState) -> None:
|
||||||
|
entrance_name = entrance.name if isinstance(entrance, Entrance) else entrance
|
||||||
|
expl = explain(Reach(entrance_name, "Entrance", 1), state)
|
||||||
|
try:
|
||||||
|
can_reach = state.can_reach_entrance(entrance_name, 1)
|
||||||
|
self.assertTrue(can_reach, expl)
|
||||||
|
except KeyError as e:
|
||||||
|
raise AssertionError(f"Error while checking entrance {entrance_name}: {e}"
|
||||||
|
f"\nExplanation: {expl}")
|
||||||
|
@@ -7,7 +7,7 @@ import unittest
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Optional, Dict, Union, Any, List, Iterable
|
from typing import Optional, Dict, Union, Any, List, Iterable
|
||||||
|
|
||||||
from BaseClasses import get_seed, MultiWorld, Location, Item, CollectionState
|
from BaseClasses import get_seed, MultiWorld, Location, Item, CollectionState, Entrance
|
||||||
from test.bases import WorldTestBase
|
from test.bases import WorldTestBase
|
||||||
from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld
|
from test.general import gen_steps, setup_solo_multiworld as setup_base_solo_multiworld
|
||||||
from worlds.AutoWorld import call_all
|
from worlds.AutoWorld import call_all
|
||||||
@@ -179,6 +179,11 @@ class SVTestBase(RuleAssertMixin, WorldTestBase, SVTestCase):
|
|||||||
state = self.multiworld.state
|
state = self.multiworld.state
|
||||||
super().assert_cannot_reach_location(location, state)
|
super().assert_cannot_reach_location(location, state)
|
||||||
|
|
||||||
|
def assert_can_reach_entrance(self, entrance: Entrance | str, state: CollectionState | None = None) -> None:
|
||||||
|
if state is None:
|
||||||
|
state = self.multiworld.state
|
||||||
|
super().assert_can_reach_entrance(entrance, state)
|
||||||
|
|
||||||
|
|
||||||
pre_generated_worlds = {}
|
pre_generated_worlds = {}
|
||||||
|
|
||||||
|
@@ -1,17 +1,13 @@
|
|||||||
import random
|
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
|
|
||||||
from BaseClasses import get_seed
|
|
||||||
from test.param import classvar_matrix
|
from test.param import classvar_matrix
|
||||||
from ..TestGeneration import get_all_permanent_progression_items
|
from ..TestGeneration import get_all_permanent_progression_items
|
||||||
from ..assertion import ModAssertMixin, WorldAssertMixin
|
from ..assertion import ModAssertMixin, WorldAssertMixin
|
||||||
from ..bases import SVTestCase, SVTestBase, solo_multiworld
|
from ..bases import SVTestCase, SVTestBase, solo_multiworld
|
||||||
from ..options.presets import allsanity_mods_6_x_x
|
from ..options.presets import allsanity_mods_6_x_x
|
||||||
from ..options.utils import fill_dataclass_with_default
|
from ... import options, Group
|
||||||
from ... import options, Group, create_content
|
|
||||||
from ...mods.mod_data import ModNames
|
from ...mods.mod_data import ModNames
|
||||||
from ...options.options import all_mods
|
from ...options.options import all_mods
|
||||||
from ...regions import RandomizationFlag, randomize_connections, create_final_connections_and_regions
|
|
||||||
|
|
||||||
|
|
||||||
class TestCanGenerateAllsanityWithMods(WorldAssertMixin, ModAssertMixin, SVTestCase):
|
class TestCanGenerateAllsanityWithMods(WorldAssertMixin, ModAssertMixin, SVTestCase):
|
||||||
@@ -117,39 +113,6 @@ class TestNoGingerIslandModItemGeneration(SVTestBase):
|
|||||||
self.assertIn(progression_item.name, all_created_items)
|
self.assertIn(progression_item.name, all_created_items)
|
||||||
|
|
||||||
|
|
||||||
class TestModEntranceRando(SVTestCase):
|
|
||||||
|
|
||||||
def test_mod_entrance_randomization(self):
|
|
||||||
for option, flag in [(options.EntranceRandomization.option_pelican_town, RandomizationFlag.PELICAN_TOWN),
|
|
||||||
(options.EntranceRandomization.option_non_progression, RandomizationFlag.NON_PROGRESSION),
|
|
||||||
(options.EntranceRandomization.option_buildings_without_house, RandomizationFlag.BUILDINGS),
|
|
||||||
(options.EntranceRandomization.option_buildings, RandomizationFlag.BUILDINGS)]:
|
|
||||||
sv_options = fill_dataclass_with_default({
|
|
||||||
options.EntranceRandomization.internal_name: option,
|
|
||||||
options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false,
|
|
||||||
options.SkillProgression.internal_name: options.SkillProgression.option_progressive_with_masteries,
|
|
||||||
options.Mods.internal_name: frozenset(options.Mods.valid_keys)
|
|
||||||
})
|
|
||||||
content = create_content(sv_options)
|
|
||||||
seed = get_seed()
|
|
||||||
rand = random.Random(seed)
|
|
||||||
with self.subTest(option=option, flag=flag, seed=seed):
|
|
||||||
final_connections, final_regions = create_final_connections_and_regions(sv_options)
|
|
||||||
|
|
||||||
_, randomized_connections = randomize_connections(rand, sv_options, content, final_regions, final_connections)
|
|
||||||
|
|
||||||
for connection_name in final_connections:
|
|
||||||
connection = final_connections[connection_name]
|
|
||||||
if flag in connection.flag:
|
|
||||||
connection_in_randomized = connection_name in randomized_connections
|
|
||||||
reverse_in_randomized = connection.reverse in randomized_connections
|
|
||||||
self.assertTrue(connection_in_randomized, f"Connection {connection_name} should be randomized but it is not in the output")
|
|
||||||
self.assertTrue(reverse_in_randomized, f"Connection {connection.reverse} should be randomized but it is not in the output.")
|
|
||||||
|
|
||||||
self.assertEqual(len(set(randomized_connections.values())), len(randomized_connections.values()),
|
|
||||||
f"Connections are duplicated in randomization.")
|
|
||||||
|
|
||||||
|
|
||||||
class TestVanillaLogicAlternativeWhenQuestsAreNotRandomized(WorldAssertMixin, SVTestBase):
|
class TestVanillaLogicAlternativeWhenQuestsAreNotRandomized(WorldAssertMixin, SVTestBase):
|
||||||
"""We often forget to add an alternative rule that works when quests are not randomized. When this happens, some
|
"""We often forget to add an alternative rule that works when quests are not randomized. When this happens, some
|
||||||
Location are not reachable because they depend on items that are only added to the pool when quests are randomized.
|
Location are not reachable because they depend on items that are only added to the pool when quests are randomized.
|
||||||
|
@@ -0,0 +1,36 @@
|
|||||||
|
from ..bases import SVTestBase
|
||||||
|
from ... import options
|
||||||
|
from ...regions.model import RandomizationFlag
|
||||||
|
from ...regions.regions import create_all_connections
|
||||||
|
|
||||||
|
|
||||||
|
class EntranceRandomizationAssertMixin:
|
||||||
|
|
||||||
|
def assert_non_progression_are_all_accessible_with_empty_inventory(self: SVTestBase):
|
||||||
|
all_connections = create_all_connections(self.world.content.registered_packs)
|
||||||
|
non_progression_connections = [connection for connection in all_connections.values() if RandomizationFlag.BIT_NON_PROGRESSION in connection.flag]
|
||||||
|
|
||||||
|
for non_progression_connections in non_progression_connections:
|
||||||
|
with self.subTest(connection=non_progression_connections):
|
||||||
|
self.assert_can_reach_entrance(non_progression_connections.name)
|
||||||
|
|
||||||
|
|
||||||
|
# This test does not actually need to generate with entrance randomization. Entrances rules are the same regardless of the randomization.
|
||||||
|
class TestVanillaEntranceClassifications(EntranceRandomizationAssertMixin, SVTestBase):
|
||||||
|
options = {
|
||||||
|
options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false,
|
||||||
|
options.Mods: frozenset()
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_non_progression_are_all_accessible_with_empty_inventory(self):
|
||||||
|
self.assert_non_progression_are_all_accessible_with_empty_inventory()
|
||||||
|
|
||||||
|
|
||||||
|
class TestModdedEntranceClassifications(EntranceRandomizationAssertMixin, SVTestBase):
|
||||||
|
options = {
|
||||||
|
options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false,
|
||||||
|
options.Mods: frozenset(options.Mods.valid_keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_non_progression_are_all_accessible_with_empty_inventory(self):
|
||||||
|
self.assert_non_progression_are_all_accessible_with_empty_inventory()
|
167
worlds/stardew_valley/test/regions/TestEntranceRandomization.py
Normal file
167
worlds/stardew_valley/test/regions/TestEntranceRandomization.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
from collections import deque
|
||||||
|
from collections.abc import Collection
|
||||||
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
|
from BaseClasses import get_seed, MultiWorld, Entrance
|
||||||
|
from ..assertion import WorldAssertMixin
|
||||||
|
from ..bases import SVTestCase, solo_multiworld
|
||||||
|
from ... import options
|
||||||
|
from ...mods.mod_data import ModNames
|
||||||
|
from ...options import EntranceRandomization, ExcludeGingerIsland, SkillProgression
|
||||||
|
from ...options.options import all_mods
|
||||||
|
from ...regions.entrance_rando import create_entrance_rando_target, prepare_mod_data, connect_regions
|
||||||
|
from ...regions.model import RegionData, ConnectionData, RandomizationFlag
|
||||||
|
from ...strings.entrance_names import Entrance as EntranceName
|
||||||
|
from ...strings.region_names import Region as RegionName
|
||||||
|
|
||||||
|
|
||||||
|
class TestEntranceRando(SVTestCase):
|
||||||
|
|
||||||
|
def test_given_connection_matching_randomization_when_connect_regions_then_make_connection_entrance_rando_target(self):
|
||||||
|
region_data_by_name = {
|
||||||
|
"Region1": RegionData("Region1", ("randomized_connection", "not_randomized")),
|
||||||
|
"Region2": RegionData("Region2"),
|
||||||
|
"Region3": RegionData("Region3"),
|
||||||
|
}
|
||||||
|
connection_data_by_name = {
|
||||||
|
"randomized_connection": ConnectionData("randomized_connection", "Region2", flag=RandomizationFlag.PELICAN_TOWN),
|
||||||
|
"not_randomized": ConnectionData("not_randomized", "Region2", flag=RandomizationFlag.BUILDINGS),
|
||||||
|
}
|
||||||
|
regions_by_name = {
|
||||||
|
"Region1": Mock(),
|
||||||
|
"Region2": Mock(),
|
||||||
|
"Region3": Mock(),
|
||||||
|
}
|
||||||
|
player_randomization_flag = RandomizationFlag.BIT_PELICAN_TOWN
|
||||||
|
|
||||||
|
with patch("worlds.stardew_valley.regions.entrance_rando.create_entrance_rando_target") as mock_create_entrance_rando_target:
|
||||||
|
connect_regions(region_data_by_name, connection_data_by_name, regions_by_name, player_randomization_flag)
|
||||||
|
|
||||||
|
expected_origin, expected_destination = regions_by_name["Region1"], regions_by_name["Region2"]
|
||||||
|
expected_connection = connection_data_by_name["randomized_connection"]
|
||||||
|
mock_create_entrance_rando_target.assert_called_once_with(expected_origin, expected_destination, expected_connection)
|
||||||
|
|
||||||
|
def test_when_create_entrance_rando_target_then_create_exit_and_er_target(self):
|
||||||
|
origin = Mock()
|
||||||
|
destination = Mock()
|
||||||
|
connection_data = ConnectionData("origin to destination", "destination")
|
||||||
|
|
||||||
|
create_entrance_rando_target(origin, destination, connection_data)
|
||||||
|
|
||||||
|
origin.create_exit.assert_called_once_with("origin to destination")
|
||||||
|
destination.create_er_target.assert_called_once_with("destination to origin")
|
||||||
|
|
||||||
|
def test_when_prepare_mod_data_then_swapped_connections_contains_both_directions(self):
|
||||||
|
placements = Mock(pairings=[("A to B", "C to A"), ("C to D", "A to C")])
|
||||||
|
|
||||||
|
swapped_connections = prepare_mod_data(placements)
|
||||||
|
|
||||||
|
self.assertEqual({"A to B": "A to C", "C to A": "B to A", "C to D": "C to A", "A to C": "D to C"}, swapped_connections)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEntranceRandoCreatesValidWorlds(WorldAssertMixin, SVTestCase):
|
||||||
|
|
||||||
|
# The following tests validate that ER still generates winnable and logically-sane games with given mods.
|
||||||
|
# Mods that do not interact with entrances are skipped
|
||||||
|
# Not all ER settings are tested, because 'buildings' is, essentially, a superset of all others
|
||||||
|
def test_ginger_island_excluded_buildings(self):
|
||||||
|
world_options = {
|
||||||
|
options.EntranceRandomization: options.EntranceRandomization.option_buildings,
|
||||||
|
options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_true
|
||||||
|
}
|
||||||
|
with solo_multiworld(world_options) as (multi_world, _):
|
||||||
|
self.assert_basic_checks(multi_world)
|
||||||
|
|
||||||
|
def test_deepwoods_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.deepwoods, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_juna_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.juna, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_jasper_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.jasper, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_alec_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.alec, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_yoba_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.yoba, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_eugene_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.eugene, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_ayeisha_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.ayeisha, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_riley_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.riley, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_sve_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.sve, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_alecto_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.alecto, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_lacey_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.lacey, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_boarding_house_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(ModNames.boarding_house, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def test_all_mods_entrance_randomization_buildings(self):
|
||||||
|
self.perform_basic_checks_on_mod_with_er(all_mods, options.EntranceRandomization.option_buildings)
|
||||||
|
|
||||||
|
def perform_basic_checks_on_mod_with_er(self, mods: str | set[str], er_option: int) -> None:
|
||||||
|
if isinstance(mods, str):
|
||||||
|
mods = {mods}
|
||||||
|
world_options = {
|
||||||
|
options.EntranceRandomization: er_option,
|
||||||
|
options.Mods: frozenset(mods),
|
||||||
|
options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false
|
||||||
|
}
|
||||||
|
with solo_multiworld(world_options) as (multi_world, _):
|
||||||
|
self.assert_basic_checks(multi_world)
|
||||||
|
|
||||||
|
|
||||||
|
# GER should have this covered, but it's good to have a backup
|
||||||
|
class TestGingerIslandEntranceRando(SVTestCase):
|
||||||
|
def test_cannot_put_island_access_on_island(self):
|
||||||
|
test_options = {
|
||||||
|
options.EntranceRandomization: EntranceRandomization.option_buildings,
|
||||||
|
options.ExcludeGingerIsland: ExcludeGingerIsland.option_false,
|
||||||
|
options.SkillProgression: SkillProgression.option_progressive_with_masteries,
|
||||||
|
}
|
||||||
|
|
||||||
|
blocked_entrances = {EntranceName.use_island_obelisk, EntranceName.boat_to_ginger_island}
|
||||||
|
required_regions = {RegionName.wizard_tower, RegionName.boat_tunnel}
|
||||||
|
|
||||||
|
for i in range(0, 10 if self.skip_long_tests else 1000):
|
||||||
|
seed = get_seed()
|
||||||
|
with self.solo_world_sub_test(f"Seed: {seed}", world_options=test_options, world_caching=False, seed=seed) as (multiworld, world):
|
||||||
|
self.assert_can_reach_any_region_before_blockers(required_regions, blocked_entrances, multiworld)
|
||||||
|
|
||||||
|
def assert_can_reach_any_region_before_blockers(self, required_regions: Collection[str], blocked_entrances: Collection[str], multiworld: MultiWorld):
|
||||||
|
explored_regions = explore_regions_up_to_blockers(blocked_entrances, multiworld)
|
||||||
|
self.assertTrue(any(region in explored_regions for region in required_regions))
|
||||||
|
|
||||||
|
|
||||||
|
def explore_regions_up_to_blockers(blocked_entrances: Collection[str], multiworld: MultiWorld) -> set[str]:
|
||||||
|
explored_regions: set[str] = set()
|
||||||
|
regions_by_name = multiworld.regions.region_cache[1]
|
||||||
|
regions_to_explore = deque([regions_by_name["Menu"]])
|
||||||
|
|
||||||
|
while regions_to_explore:
|
||||||
|
region = regions_to_explore.pop()
|
||||||
|
|
||||||
|
if region.name in explored_regions:
|
||||||
|
continue
|
||||||
|
|
||||||
|
explored_regions.add(region.name)
|
||||||
|
|
||||||
|
for exit_ in region.exits:
|
||||||
|
exit_: Entrance
|
||||||
|
if exit_.name in blocked_entrances:
|
||||||
|
continue
|
||||||
|
regions_to_explore.append(exit_.connected_region)
|
||||||
|
|
||||||
|
return explored_regions
|
88
worlds/stardew_valley/test/regions/TestRandomizationFlag.py
Normal file
88
worlds/stardew_valley/test/regions/TestRandomizationFlag.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from ..options.utils import fill_dataclass_with_default
|
||||||
|
from ... import create_content, options
|
||||||
|
from ...regions.entrance_rando import create_player_randomization_flag
|
||||||
|
from ...regions.model import RandomizationFlag, ConnectionData
|
||||||
|
|
||||||
|
|
||||||
|
class TestConnectionData(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_given_entrances_not_randomized_when_is_eligible_for_randomization_then_not_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.NOT_RANDOMIZED
|
||||||
|
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.PELICAN_TOWN)
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertFalse(is_eligible)
|
||||||
|
|
||||||
|
def test_given_pelican_town_connection_when_is_eligible_for_pelican_town_randomization_then_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.BIT_PELICAN_TOWN
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.PELICAN_TOWN)
|
||||||
|
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertTrue(is_eligible)
|
||||||
|
|
||||||
|
def test_given_pelican_town_connection_when_is_eligible_for_buildings_randomization_then_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.BIT_BUILDINGS
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.PELICAN_TOWN)
|
||||||
|
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertTrue(is_eligible)
|
||||||
|
|
||||||
|
def test_given_non_progression_connection_when_is_eligible_for_pelican_town_randomization_then_not_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.BIT_PELICAN_TOWN
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.NON_PROGRESSION)
|
||||||
|
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertFalse(is_eligible)
|
||||||
|
|
||||||
|
def test_given_non_progression_masteries_connection_when_is_eligible_for_non_progression_randomization_then_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.BIT_NON_PROGRESSION
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.NON_PROGRESSION ^ RandomizationFlag.EXCLUDE_MASTERIES)
|
||||||
|
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertTrue(is_eligible)
|
||||||
|
|
||||||
|
def test_given_non_progression_masteries_connection_when_is_eligible_for_non_progression_without_masteries_randomization_then_not_eligible(self):
|
||||||
|
player_flag = RandomizationFlag.BIT_NON_PROGRESSION | RandomizationFlag.EXCLUDE_MASTERIES
|
||||||
|
connection = ConnectionData("Go to Somewhere", "Somewhere", RandomizationFlag.NON_PROGRESSION ^ RandomizationFlag.EXCLUDE_MASTERIES)
|
||||||
|
|
||||||
|
is_eligible = connection.is_eligible_for_randomization(player_flag)
|
||||||
|
|
||||||
|
self.assertFalse(is_eligible)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRandomizationFlag(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_given_entrance_randomization_choice_when_create_player_randomization_flag_then_only_relevant_bit_is_enabled(self):
|
||||||
|
for entrance_randomization_choice, expected_bit in (
|
||||||
|
(options.EntranceRandomization.option_disabled, RandomizationFlag.NOT_RANDOMIZED),
|
||||||
|
(options.EntranceRandomization.option_pelican_town, RandomizationFlag.BIT_PELICAN_TOWN),
|
||||||
|
(options.EntranceRandomization.option_non_progression, RandomizationFlag.BIT_NON_PROGRESSION),
|
||||||
|
(options.EntranceRandomization.option_buildings_without_house, RandomizationFlag.BIT_BUILDINGS),
|
||||||
|
(options.EntranceRandomization.option_buildings, RandomizationFlag.BIT_BUILDINGS),
|
||||||
|
(options.EntranceRandomization.option_chaos, RandomizationFlag.BIT_BUILDINGS),
|
||||||
|
):
|
||||||
|
player_options = fill_dataclass_with_default({options.EntranceRandomization: entrance_randomization_choice})
|
||||||
|
content = create_content(player_options)
|
||||||
|
|
||||||
|
flag = create_player_randomization_flag(player_options.entrance_randomization, content)
|
||||||
|
|
||||||
|
self.assertEqual(flag, expected_bit)
|
||||||
|
|
||||||
|
def test_given_masteries_not_randomized_when_create_player_randomization_flag_then_exclude_masteries_bit_enabled(self):
|
||||||
|
for entrance_randomization_choice in set(options.EntranceRandomization.options.values()) ^ {options.EntranceRandomization.option_disabled}:
|
||||||
|
player_options = fill_dataclass_with_default({
|
||||||
|
options.EntranceRandomization: entrance_randomization_choice,
|
||||||
|
options.SkillProgression: options.SkillProgression.option_progressive
|
||||||
|
})
|
||||||
|
content = create_content(player_options)
|
||||||
|
|
||||||
|
flag = create_player_randomization_flag(player_options.entrance_randomization, content)
|
||||||
|
|
||||||
|
self.assertIn(RandomizationFlag.EXCLUDE_MASTERIES, flag)
|
66
worlds/stardew_valley/test/regions/TestRegionConnections.py
Normal file
66
worlds/stardew_valley/test/regions/TestRegionConnections.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import unittest
|
||||||
|
|
||||||
|
from ..options.utils import fill_dataclass_with_default
|
||||||
|
from ... import options
|
||||||
|
from ...content import create_content
|
||||||
|
from ...mods.region_data import region_data_by_content_pack
|
||||||
|
from ...regions import vanilla_data
|
||||||
|
from ...regions.model import MergeFlag
|
||||||
|
from ...regions.regions import create_all_regions, create_all_connections
|
||||||
|
|
||||||
|
|
||||||
|
class TestVanillaRegionsConnectionsWithGingerIsland(unittest.TestCase):
|
||||||
|
def test_region_exits_lead_somewhere(self):
|
||||||
|
for region in vanilla_data.regions_with_ginger_island_by_name.values():
|
||||||
|
with self.subTest(region=region):
|
||||||
|
for exit_ in region.exits:
|
||||||
|
self.assertIn(exit_, vanilla_data.connections_with_ginger_island_by_name,
|
||||||
|
f"{region.name} is leading to {exit_} but it does not exist.")
|
||||||
|
|
||||||
|
def test_connection_lead_somewhere(self):
|
||||||
|
for connection in vanilla_data.connections_with_ginger_island_by_name.values():
|
||||||
|
with self.subTest(connection=connection):
|
||||||
|
self.assertIn(connection.destination, vanilla_data.regions_with_ginger_island_by_name,
|
||||||
|
f"{connection.name} is leading to {connection.destination} but it does not exist.")
|
||||||
|
|
||||||
|
|
||||||
|
class TestVanillaRegionsConnectionsWithoutGingerIsland(unittest.TestCase):
|
||||||
|
def test_region_exits_lead_somewhere(self):
|
||||||
|
for region in vanilla_data.regions_without_ginger_island_by_name.values():
|
||||||
|
with self.subTest(region=region):
|
||||||
|
for exit_ in region.exits:
|
||||||
|
self.assertIn(exit_, vanilla_data.connections_without_ginger_island_by_name,
|
||||||
|
f"{region.name} is leading to {exit_} but it does not exist.")
|
||||||
|
|
||||||
|
def test_connection_lead_somewhere(self):
|
||||||
|
for connection in vanilla_data.connections_without_ginger_island_by_name.values():
|
||||||
|
with self.subTest(connection=connection):
|
||||||
|
self.assertIn(connection.destination, vanilla_data.regions_without_ginger_island_by_name,
|
||||||
|
f"{connection.name} is leading to {connection.destination} but it does not exist.")
|
||||||
|
|
||||||
|
|
||||||
|
class TestModsConnections(unittest.TestCase):
|
||||||
|
options = {
|
||||||
|
options.ExcludeGingerIsland: options.ExcludeGingerIsland.option_false,
|
||||||
|
options.Mods: frozenset(options.Mods.valid_keys)
|
||||||
|
}
|
||||||
|
content = create_content(fill_dataclass_with_default(options))
|
||||||
|
all_regions_by_name = create_all_regions(content.registered_packs)
|
||||||
|
all_connections_by_name = create_all_connections(content.registered_packs)
|
||||||
|
|
||||||
|
def test_region_exits_lead_somewhere(self):
|
||||||
|
for mod_region_data in region_data_by_content_pack.values():
|
||||||
|
for region in mod_region_data.regions:
|
||||||
|
if MergeFlag.REMOVE_EXITS in region.flag:
|
||||||
|
continue
|
||||||
|
|
||||||
|
with self.subTest(mod=mod_region_data.mod_name, region=region.name):
|
||||||
|
for exit_ in region.exits:
|
||||||
|
self.assertIn(exit_, self.all_connections_by_name, f"{region.name} is leading to {exit_} but it does not exist.")
|
||||||
|
|
||||||
|
def test_connection_lead_somewhere(self):
|
||||||
|
for mod_region_data in region_data_by_content_pack.values():
|
||||||
|
for connection in mod_region_data.connections:
|
||||||
|
with self.subTest(mod=mod_region_data.mod_name, connection=connection.name):
|
||||||
|
self.assertIn(connection.destination, self.all_regions_by_name,
|
||||||
|
f"{connection.name} is leading to {connection.destination} but it does not exist.")
|
0
worlds/stardew_valley/test/regions/__init__.py
Normal file
0
worlds/stardew_valley/test/regions/__init__.py
Normal file
Reference in New Issue
Block a user