diff --git a/WebHostLib/templates/tracker__Starcraft2.html b/WebHostLib/templates/tracker__Starcraft2.html index b4252df2504d..089e7d6c2239 100644 --- a/WebHostLib/templates/tracker__Starcraft2.html +++ b/WebHostLib/templates/tracker__Starcraft2.html @@ -106,7 +106,7 @@

{{ player_name }}'s Starcraft 2 Tracker

{{ sc2_icon('Neosteel Bunker (Bunker)') }} {{ sc2_icon('Shrike Turret (Bunker)') }} {{ sc2_icon('Fortified Bunker (Bunker)') }} - + {{ sc2_icon('Missile Turret') }} {{ sc2_icon('Titanium Housing (Missile Turret)') }} {{ sc2_icon('Hellstorm Batteries (Missile Turret)') }} @@ -121,12 +121,13 @@

{{ player_name }}'s Starcraft 2 Tracker

{{ sc2_icon('Planetary Fortress') }} {{ sc2_progressive_icon_with_custom_name('Progressive Augmented Thrusters (Planetary Fortress)', augmented_thrusters_planetary_fortress_url, augmented_thrusters_planetary_fortress_name) }} {{ sc2_icon('Advanced Targeting (Planetary Fortress)') }} + + {{ sc2_icon('Micro-Filtering') }} + {{ sc2_icon('Automated Refinery') }} {{ sc2_icon('Advanced Construction (SCV)') }} {{ sc2_icon('Dual-Fusion Welders (SCV)') }} - - {{ sc2_icon('Micro-Filtering') }} - {{ sc2_icon('Automated Refinery') }} + {{ sc2_icon('Hostile Environment Adaptation (SCV)') }} {{ sc2_icon('Sensor Tower') }} @@ -180,7 +181,7 @@

{{ player_name }}'s Starcraft 2 Tracker

{{ sc2_icon('Nano Projector (Medic)') }} {{ sc2_icon('Vulture') }} - {{ sc2_progressive_icon_with_custom_name('Progressive Replenishable Magazine (Vulture)', replenishable_magazine_vulture_url, replenishable_magazine_vulture_name) }} + {{ sc2_progressive_icon_with_custom_name('Progressive Replenishable Magazine (Vulture)', replenishable_magazine_vulture_url, replenishable_magazine_vulture_name) }} {{ sc2_icon('Ion Thrusters (Vulture)') }} {{ sc2_icon('Auto Launchers (Vulture)') }} {{ sc2_icon('Auto-Repair (Vulture)') }} diff --git a/WebHostLib/tracker.py b/WebHostLib/tracker.py index c2fdab0ed074..95bca57493c2 100644 --- a/WebHostLib/tracker.py +++ b/WebHostLib/tracker.py @@ -1606,6 +1606,7 @@ def render_Starcraft2_tracker(tracker_data: TrackerData, team: int, player: int) "Hellstorm Batteries (Missile Turret)": github_icon_base_url + "blizzard/btn-ability-stetmann-corruptormissilebarrage.png", "Advanced Construction (SCV)": github_icon_base_url + "blizzard/btn-ability-mengsk-trooper-advancedconstruction.png", "Dual-Fusion Welders (SCV)": github_icon_base_url + "blizzard/btn-upgrade-swann-scvdoublerepair.png", + "Hostile Environment Adaptation (SCV)": github_icon_base_url + "blizzard/btn-upgrade-swann-hellarmor.png", "Fire-Suppression System Level 1": organics_icon_base_url + "Fire-SuppressionSystem.png", "Fire-Suppression System Level 2": github_icon_base_url + "blizzard/btn-upgrade-swann-firesuppressionsystem.png", @@ -2333,12 +2334,12 @@ def render_Starcraft2_tracker(tracker_data: TrackerData, team: int, player: int) "Progressive Zerg Armor Upgrade": 106 + SC2HOTS_ITEM_ID_OFFSET, "Progressive Zerg Ground Upgrade": 107 + SC2HOTS_ITEM_ID_OFFSET, "Progressive Zerg Flyer Upgrade": 108 + SC2HOTS_ITEM_ID_OFFSET, - "Progressive Zerg Weapon/Armor Upgrade": 109 + SC2WOL_ITEM_ID_OFFSET, - "Progressive Protoss Weapon Upgrade": 105 + SC2HOTS_ITEM_ID_OFFSET, - "Progressive Protoss Armor Upgrade": 106 + SC2HOTS_ITEM_ID_OFFSET, - "Progressive Protoss Ground Upgrade": 107 + SC2HOTS_ITEM_ID_OFFSET, - "Progressive Protoss Air Upgrade": 108 + SC2HOTS_ITEM_ID_OFFSET, - "Progressive Protoss Weapon/Armor Upgrade": 109 + SC2WOL_ITEM_ID_OFFSET, + "Progressive Zerg Weapon/Armor Upgrade": 109 + SC2HOTS_ITEM_ID_OFFSET, + "Progressive Protoss Weapon Upgrade": 105 + SC2LOTV_ITEM_ID_OFFSET, + "Progressive Protoss Armor Upgrade": 106 + SC2LOTV_ITEM_ID_OFFSET, + "Progressive Protoss Ground Upgrade": 107 + SC2LOTV_ITEM_ID_OFFSET, + "Progressive Protoss Air Upgrade": 108 + SC2LOTV_ITEM_ID_OFFSET, + "Progressive Protoss Weapon/Armor Upgrade": 109 + SC2LOTV_ITEM_ID_OFFSET, } grouped_item_replacements = { "Progressive Terran Weapon Upgrade": ["Progressive Terran Infantry Weapon", diff --git a/worlds/cv64/__init__.py b/worlds/cv64/__init__.py index ca4697bce8d5..1f528feac22f 100644 --- a/worlds/cv64/__init__.py +++ b/worlds/cv64/__init__.py @@ -48,9 +48,9 @@ class CV64Web(WebWorld): class CV64World(World): """ - Castlevania for the Nintendo 64 is the first 3D game in the franchise. As either whip-wielding Belmont descendant - Reinhardt Schneider or powerful sorceress Carrie Fernandez, brave many terrifying traps and foes as you make your - way to Dracula's chamber and stop his rule of terror! + Castlevania for the Nintendo 64 is the first 3D game in the Castlevania franchise. As either whip-wielding Belmont + descendant Reinhardt Schneider or powerful sorceress Carrie Fernandez, brave many terrifying traps and foes as you + make your way to Dracula's chamber and stop his rule of terror! """ game = "Castlevania 64" item_name_groups = { diff --git a/worlds/cv64/docs/en_Castlevania 64.md b/worlds/cv64/docs/en_Castlevania 64.md index 5fe85555c40a..692bbfe86a71 100644 --- a/worlds/cv64/docs/en_Castlevania 64.md +++ b/worlds/cv64/docs/en_Castlevania 64.md @@ -1,8 +1,8 @@ # Castlevania 64 -## Where is the settings page? +## Where is the options page? -The [player settings page for this game](../player-settings) contains all the options you need to configure and export a +The [player options page for this game](../player-options) contains all the options you need to configure and export a config file. ## What does randomization do to this game? @@ -116,7 +116,7 @@ Enabling Carrie Logic will also expect the following: - Orb-sniping dogs through the front gates in Villa -Library Skip is **NOT** logically expected on any setting. The basement hallway crack will always logically expect two Nitros +Library Skip is **NOT** logically expected by any options. The basement arena crack will always logically expect two Nitros and two Mandragoras even with Hard Logic on due to the possibility of wasting a pair on the upper wall, after managing to skip past it. And plus, the RNG manip may not even be possible after picking up all the items in the Nitro room. diff --git a/worlds/cv64/docs/setup_en.md b/worlds/cv64/docs/setup_en.md index 6065b142c82c..707618a1eba5 100644 --- a/worlds/cv64/docs/setup_en.md +++ b/worlds/cv64/docs/setup_en.md @@ -28,8 +28,8 @@ the White Jewels. ## Generating and Patching a Game -1. Create your settings file (YAML). You can make one on the -[Castlevania 64 settings page](../../../games/Castlevania 64/player-settings). +1. Create your options file (YAML). You can make one on the +[Castlevania 64 options page](../../../games/Castlevania%2064/player-options). 2. Follow the general Archipelago instructions for [generating a game](../../Archipelago/setup/en#generating-a-game). This will generate an output file for you. Your patch file will have the `.apcv64` file extension. 3. Open `ArchipelagoLauncher.exe` diff --git a/worlds/cv64/options.py b/worlds/cv64/options.py index 4545cd0b5c28..e1be03897dcf 100644 --- a/worlds/cv64/options.py +++ b/worlds/cv64/options.py @@ -337,13 +337,13 @@ class BigToss(Toggle): """Makes every non-immobilizing damage source launch you as if you got hit by Behemoth's charge. Press A while tossed to cancel the launch momentum and avoid being thrown off ledges. Hold Z to have all incoming damage be treated as it normally would. - Any tricks that might be possible with it are NOT considered in logic on any setting.""" + Any tricks that might be possible with it are NOT considered in logic by any options.""" display_name = "Big Toss" class PantherDash(Choice): """Hold C-right at any time to sprint way faster. Any tricks that might be - possible with it are NOT considered in logic on any setting and any boss + possible with it are NOT considered in logic by any options and any boss fights with boss health meters, if started, are expected to be finished before leaving their arenas if Dracula's Condition is bosses. Jumpless will prevent jumping while moving at the increased speed to ensure logic cannot be broken with it.""" diff --git a/worlds/sc2/PoolFilter.py b/worlds/sc2/PoolFilter.py index 5f8151ed399f..068c62314923 100644 --- a/worlds/sc2/PoolFilter.py +++ b/worlds/sc2/PoolFilter.py @@ -560,7 +560,7 @@ def filter_items(world: World, mission_req_table: Dict[SC2Campaign, Dict[str, Mi def get_used_races(mission_req_table: Dict[SC2Campaign, Dict[str, MissionInfo]], world: World) -> Set[SC2Race]: grant_story_tech = get_option_value(world, "grant_story_tech") take_over_ai_allies = get_option_value(world, "take_over_ai_allies") - kerrigan_presence = get_option_value(world, "kerrigan_presence") \ + kerrigan_presence = get_option_value(world, "kerrigan_presence") in kerrigan_unit_available \ and SC2Campaign.HOTS in get_enabled_campaigns(world) missions = missions_in_mission_table(mission_req_table) @@ -572,7 +572,7 @@ def get_used_races(mission_req_table: Dict[SC2Campaign, Dict[str, MissionInfo]], if SC2Mission.ENEMY_WITHIN in missions: # Zerg units need to be unlocked races.add(SC2Race.ZERG) - if kerrigan_presence in kerrigan_unit_available \ + if kerrigan_presence \ and not missions.isdisjoint({SC2Mission.BACK_IN_THE_SADDLE, SC2Mission.SUPREME, SC2Mission.CONVICTION, SC2Mission.THE_INFINITE_CYCLE}): # You need some Kerrigan abilities (they're granted if Kerriganless or story tech granted) races.add(SC2Race.ZERG) diff --git a/worlds/sm64ex/Options.py b/worlds/sm64ex/Options.py index d9a877df2b37..60ec4bbe13c2 100644 --- a/worlds/sm64ex/Options.py +++ b/worlds/sm64ex/Options.py @@ -1,5 +1,6 @@ import typing -from Options import Option, DefaultOnToggle, Range, Toggle, DeathLink, Choice +from dataclasses import dataclass +from Options import DefaultOnToggle, Range, Toggle, DeathLink, Choice, PerGameCommonOptions, OptionSet from .Items import action_item_table class EnableCoinStars(DefaultOnToggle): @@ -114,35 +115,37 @@ class StrictMoveRequirements(DefaultOnToggle): if Move Randomization is enabled""" display_name = "Strict Move Requirements" -def getMoveRandomizerOption(action: str): - class MoveRandomizerOption(Toggle): - """Mario is unable to perform this action until a corresponding item is picked up. - This option is incompatible with builds using a 'nomoverando' branch.""" - display_name = f"Randomize {action}" - return MoveRandomizerOption - - -sm64_options: typing.Dict[str, type(Option)] = { - "AreaRandomizer": AreaRandomizer, - "BuddyChecks": BuddyChecks, - "ExclamationBoxes": ExclamationBoxes, - "ProgressiveKeys": ProgressiveKeys, - "EnableCoinStars": EnableCoinStars, - "StrictCapRequirements": StrictCapRequirements, - "StrictCannonRequirements": StrictCannonRequirements, - "StrictMoveRequirements": StrictMoveRequirements, - "AmountOfStars": AmountOfStars, - "FirstBowserStarDoorCost": FirstBowserStarDoorCost, - "BasementStarDoorCost": BasementStarDoorCost, - "SecondFloorStarDoorCost": SecondFloorStarDoorCost, - "MIPS1Cost": MIPS1Cost, - "MIPS2Cost": MIPS2Cost, - "StarsToFinish": StarsToFinish, - "death_link": DeathLink, - "CompletionType": CompletionType, -} - -for action in action_item_table: - # HACK: Disable randomization of double jump - if action == 'Double Jump': continue - sm64_options[f"MoveRandomizer{action.replace(' ','')}"] = getMoveRandomizerOption(action) +class EnableMoveRandomizer(Toggle): + """Mario is unable to perform some actions until a corresponding item is picked up. + This option is incompatible with builds using a 'nomoverando' branch. + Specific actions to randomize can be specified in the YAML.""" + display_name = "Enable Move Randomizer" + +class MoveRandomizerActions(OptionSet): + """Which actions to randomize when Move Randomizer is enabled""" + display_name = "Randomized Moves" + # HACK: Disable randomization for double jump + valid_keys = [action for action in action_item_table if action != 'Double Jump'] + default = valid_keys + +@dataclass +class SM64Options(PerGameCommonOptions): + area_rando: AreaRandomizer + buddy_checks: BuddyChecks + exclamation_boxes: ExclamationBoxes + progressive_keys: ProgressiveKeys + enable_coin_stars: EnableCoinStars + enable_move_rando: EnableMoveRandomizer + move_rando_actions: MoveRandomizerActions + strict_cap_requirements: StrictCapRequirements + strict_cannon_requirements: StrictCannonRequirements + strict_move_requirements: StrictMoveRequirements + amount_of_stars: AmountOfStars + first_bowser_star_door_cost: FirstBowserStarDoorCost + basement_star_door_cost: BasementStarDoorCost + second_floor_star_door_cost: SecondFloorStarDoorCost + mips1_cost: MIPS1Cost + mips2_cost: MIPS2Cost + stars_to_finish: StarsToFinish + death_link: DeathLink + completion_type: CompletionType diff --git a/worlds/sm64ex/Regions.py b/worlds/sm64ex/Regions.py index a493281ec3f6..333e2df3a97f 100644 --- a/worlds/sm64ex/Regions.py +++ b/worlds/sm64ex/Regions.py @@ -2,6 +2,7 @@ from enum import Enum from BaseClasses import MultiWorld, Region, Entrance, Location +from .Options import SM64Options from .Locations import SM64Location, location_table, locBoB_table, locWhomp_table, locJRB_table, locCCM_table, \ locBBH_table, \ locHMC_table, locLLL_table, locSSL_table, locDDD_table, locSL_table, \ @@ -78,7 +79,7 @@ class SM64Region(Region): sm64_entrances_to_level = {**sm64_paintings_to_level, **sm64_secrets_to_level } sm64_level_to_entrances = {**sm64_level_to_paintings, **sm64_level_to_secrets } -def create_regions(world: MultiWorld, player: int): +def create_regions(world: MultiWorld, options: SM64Options, player: int): regSS = Region("Menu", player, world, "Castle Area") create_default_locs(regSS, locSS_table) world.regions.append(regSS) @@ -88,7 +89,7 @@ def create_regions(world: MultiWorld, player: int): "BoB: Mario Wings to the Sky", "BoB: Behind Chain Chomp's Gate", "BoB: Bob-omb Buddy") bob_island = create_subregion(regBoB, "BoB: Island", "BoB: Shoot to the Island in the Sky", "BoB: Find the 8 Red Coins") regBoB.subregions = [bob_island] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regBoB, "BoB: 100 Coins") regWhomp = create_region("Whomp's Fortress", player, world) @@ -96,7 +97,7 @@ def create_regions(world: MultiWorld, player: int): "WF: Fall onto the Caged Island", "WF: Blast Away the Wall") wf_tower = create_subregion(regWhomp, "WF: Tower", "WF: To the Top of the Fortress", "WF: Bob-omb Buddy") regWhomp.subregions = [wf_tower] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regWhomp, "WF: 100 Coins") regJRB = create_region("Jolly Roger Bay", player, world) @@ -104,12 +105,12 @@ def create_regions(world: MultiWorld, player: int): "JRB: Blast to the Stone Pillar", "JRB: Through the Jet Stream", "JRB: Bob-omb Buddy") jrb_upper = create_subregion(regJRB, 'JRB: Upper', "JRB: Red Coins on the Ship Afloat") regJRB.subregions = [jrb_upper] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(jrb_upper, "JRB: 100 Coins") regCCM = create_region("Cool, Cool Mountain", player, world) create_default_locs(regCCM, locCCM_table) - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regCCM, "CCM: 100 Coins") regBBH = create_region("Big Boo's Haunt", player, world) @@ -118,7 +119,7 @@ def create_regions(world: MultiWorld, player: int): bbh_third_floor = create_subregion(regBBH, "BBH: Third Floor", "BBH: Eye to Eye in the Secret Room") bbh_roof = create_subregion(bbh_third_floor, "BBH: Roof", "BBH: Big Boo's Balcony", "BBH: 1Up Block Top of Mansion") regBBH.subregions = [bbh_third_floor, bbh_roof] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regBBH, "BBH: 100 Coins") regPSS = create_region("The Princess's Secret Slide", player, world) @@ -141,7 +142,7 @@ def create_regions(world: MultiWorld, player: int): hmc_red_coin_area = create_subregion(regHMC, "HMC: Red Coin Area", "HMC: Elevate for 8 Red Coins") hmc_pit_islands = create_subregion(regHMC, "HMC: Pit Islands", "HMC: A-Maze-Ing Emergency Exit", "HMC: 1Up Block above Pit") regHMC.subregions = [hmc_red_coin_area, hmc_pit_islands] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(hmc_red_coin_area, "HMC: 100 Coins") regLLL = create_region("Lethal Lava Land", player, world) @@ -149,7 +150,7 @@ def create_regions(world: MultiWorld, player: int): "LLL: 8-Coin Puzzle with 15 Pieces", "LLL: Red-Hot Log Rolling") lll_upper_volcano = create_subregion(regLLL, "LLL: Upper Volcano", "LLL: Hot-Foot-It into the Volcano", "LLL: Elevator Tour in the Volcano") regLLL.subregions = [lll_upper_volcano] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regLLL, "LLL: 100 Coins") regSSL = create_region("Shifting Sand Land", player, world) @@ -159,7 +160,7 @@ def create_regions(world: MultiWorld, player: int): ssl_upper_pyramid = create_subregion(regSSL, "SSL: Upper Pyramid", "SSL: Inside the Ancient Pyramid", "SSL: Stand Tall on the Four Pillars", "SSL: Pyramid Puzzle") regSSL.subregions = [ssl_upper_pyramid] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regSSL, "SSL: 100 Coins") regDDD = create_region("Dire, Dire Docks", player, world) @@ -167,7 +168,7 @@ def create_regions(world: MultiWorld, player: int): "DDD: The Manta Ray's Reward", "DDD: Collect the Caps...") ddd_moving_poles = create_subregion(regDDD, "DDD: Moving Poles", "DDD: Pole-Jumping for Red Coins") regDDD.subregions = [ddd_moving_poles] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(ddd_moving_poles, "DDD: 100 Coins") regCotMC = create_region("Cavern of the Metal Cap", player, world) @@ -184,7 +185,7 @@ def create_regions(world: MultiWorld, player: int): regSL = create_region("Snowman's Land", player, world) create_default_locs(regSL, locSL_table) - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(regSL, "SL: 100 Coins") regWDW = create_region("Wet-Dry World", player, world) @@ -193,7 +194,7 @@ def create_regions(world: MultiWorld, player: int): "WDW: Secrets in the Shallows & Sky", "WDW: Bob-omb Buddy") wdw_downtown = create_subregion(regWDW, "WDW: Downtown", "WDW: Go to Town for Red Coins", "WDW: Quick Race Through Downtown!", "WDW: 1Up Block in Downtown") regWDW.subregions = [wdw_top, wdw_downtown] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(wdw_top, "WDW: 100 Coins") regTTM = create_region("Tall, Tall Mountain", player, world) @@ -202,7 +203,7 @@ def create_regions(world: MultiWorld, player: int): ttm_top = create_subregion(ttm_middle, "TTM: Top", "TTM: Scale the Mountain", "TTM: Mystery of the Monkey Cage", "TTM: Mysterious Mountainside", "TTM: Breathtaking View from Bridge") regTTM.subregions = [ttm_middle, ttm_top] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(ttm_top, "TTM: 100 Coins") create_region("Tiny-Huge Island (Huge)", player, world) @@ -214,7 +215,7 @@ def create_regions(world: MultiWorld, player: int): "THI: 1Up Block THI Large near Start", "THI: 1Up Block Windy Area") thi_large_top = create_subregion(thi_pipes, "THI: Large Top", "THI: Make Wiggler Squirm") regTHI.subregions = [thi_pipes, thi_large_top] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(thi_large_top, "THI: 100 Coins") regFloor3 = create_region("Third Floor", player, world) @@ -225,7 +226,7 @@ def create_regions(world: MultiWorld, player: int): ttc_upper = create_subregion(ttc_lower, "TTC: Upper", "TTC: Timed Jumps on Moving Bars", "TTC: The Pit and the Pendulums") ttc_top = create_subregion(ttc_upper, "TTC: Top", "TTC: Stomp on the Thwomp", "TTC: 1Up Block at the Top") regTTC.subregions = [ttc_lower, ttc_upper, ttc_top] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(ttc_top, "TTC: 100 Coins") regRR = create_region("Rainbow Ride", player, world) @@ -235,7 +236,7 @@ def create_regions(world: MultiWorld, player: int): rr_cruiser = create_subregion(regRR, "RR: Cruiser", "RR: Cruiser Crossing the Rainbow", "RR: Somewhere Over the Rainbow") rr_house = create_subregion(regRR, "RR: House", "RR: The Big House in the Sky", "RR: 1Up Block On House in the Sky") regRR.subregions = [rr_maze, rr_cruiser, rr_house] - if (world.EnableCoinStars[player].value): + if options.enable_coin_stars: create_locs(rr_maze, "RR: 100 Coins") regWMotR = create_region("Wing Mario over the Rainbow", player, world) diff --git a/worlds/sm64ex/Rules.py b/worlds/sm64ex/Rules.py index cc2b52f0f12f..72016b4f4014 100644 --- a/worlds/sm64ex/Rules.py +++ b/worlds/sm64ex/Rules.py @@ -3,6 +3,7 @@ from BaseClasses import MultiWorld from ..generic.Rules import add_rule, set_rule from .Locations import location_table +from .Options import SM64Options from .Regions import connect_regions, SM64Levels, sm64_level_to_paintings, sm64_paintings_to_level,\ sm64_level_to_secrets, sm64_secrets_to_level, sm64_entrances_to_level, sm64_level_to_entrances from .Items import action_item_table @@ -24,7 +25,7 @@ def fix_reg(entrance_map: Dict[SM64Levels, str], entrance: SM64Levels, invalid_r swapdict[entrance], swapdict[rand_entrance] = rand_region, old_dest swapdict.pop(entrance) -def set_rules(world, player: int, area_connections: dict, star_costs: dict, move_rando_bitvec: int): +def set_rules(world, options: SM64Options, player: int, area_connections: dict, star_costs: dict, move_rando_bitvec: int): randomized_level_to_paintings = sm64_level_to_paintings.copy() randomized_level_to_secrets = sm64_level_to_secrets.copy() valid_move_randomizer_start_courses = [ @@ -32,19 +33,19 @@ def set_rules(world, player: int, area_connections: dict, star_costs: dict, move "Big Boo's Haunt", "Lethal Lava Land", "Shifting Sand Land", "Dire, Dire Docks", "Snowman's Land" ] # Excluding WF, HMC, WDW, TTM, THI, TTC, and RR - if world.AreaRandomizer[player].value >= 1: # Some randomization is happening, randomize Courses + if options.area_rando >= 1: # Some randomization is happening, randomize Courses randomized_level_to_paintings = shuffle_dict_keys(world,sm64_level_to_paintings) # If not shuffling later, ensure a valid start course on move randomizer - if world.AreaRandomizer[player].value < 3 and move_rando_bitvec > 0: + if options.area_rando < 3 and move_rando_bitvec > 0: swapdict = randomized_level_to_paintings.copy() invalid_start_courses = {course for course in randomized_level_to_paintings.values() if course not in valid_move_randomizer_start_courses} fix_reg(randomized_level_to_paintings, SM64Levels.BOB_OMB_BATTLEFIELD, invalid_start_courses, swapdict, world) fix_reg(randomized_level_to_paintings, SM64Levels.WHOMPS_FORTRESS, invalid_start_courses, swapdict, world) - if world.AreaRandomizer[player].value == 2: # Randomize Secrets as well + if options.area_rando == 2: # Randomize Secrets as well randomized_level_to_secrets = shuffle_dict_keys(world,sm64_level_to_secrets) randomized_entrances = {**randomized_level_to_paintings, **randomized_level_to_secrets} - if world.AreaRandomizer[player].value == 3: # Randomize Courses and Secrets in one pool + if options.area_rando == 3: # Randomize Courses and Secrets in one pool randomized_entrances = shuffle_dict_keys(world, randomized_entrances) # Guarantee first entrance is a course swapdict = randomized_entrances.copy() @@ -67,7 +68,7 @@ def set_rules(world, player: int, area_connections: dict, star_costs: dict, move area_connections.update({int(entrance_lvl): int(sm64_entrances_to_level[destination]) for (entrance_lvl,destination) in randomized_entrances.items()}) randomized_entrances_s = {sm64_level_to_entrances[entrance_lvl]: destination for (entrance_lvl,destination) in randomized_entrances.items()} - rf = RuleFactory(world, player, move_rando_bitvec) + rf = RuleFactory(world, options, player, move_rando_bitvec) connect_regions(world, player, "Menu", randomized_entrances_s["Bob-omb Battlefield"]) connect_regions(world, player, "Menu", randomized_entrances_s["Whomp's Fortress"], lambda state: state.has("Power Star", player, 1)) @@ -199,7 +200,7 @@ def set_rules(world, player: int, area_connections: dict, star_costs: dict, move # Bowser in the Sky rf.assign_rule("BitS: Top", "CL+TJ | CL+SF+LG | MOVELESS & TJ+WK+LG") # 100 Coin Stars - if world.EnableCoinStars[player]: + if options.enable_coin_stars: rf.assign_rule("BoB: 100 Coins", "CANN & WC | CANNLESS & WC & TJ") rf.assign_rule("WF: 100 Coins", "GP | MOVELESS") rf.assign_rule("JRB: 100 Coins", "GP & {JRB: Upper}") @@ -225,9 +226,9 @@ def set_rules(world, player: int, area_connections: dict, star_costs: dict, move world.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player) - if world.CompletionType[player] == "last_bowser_stage": + if options.completion_type == "last_bowser_stage": world.completion_condition[player] = lambda state: state.can_reach("BitS: Top", 'Region', player) - elif world.CompletionType[player] == "all_bowser_stages": + elif options.completion_type == "all_bowser_stages": world.completion_condition[player] = lambda state: state.can_reach("Bowser in the Dark World", 'Region', player) and \ state.can_reach("BitFS: Upper", 'Region', player) and \ state.can_reach("BitS: Top", 'Region', player) @@ -262,14 +263,14 @@ class RuleFactory: class SM64LogicException(Exception): pass - def __init__(self, world, player, move_rando_bitvec): + def __init__(self, world, options: SM64Options, player: int, move_rando_bitvec: int): self.world = world self.player = player self.move_rando_bitvec = move_rando_bitvec - self.area_randomizer = world.AreaRandomizer[player].value > 0 - self.capless = not world.StrictCapRequirements[player] - self.cannonless = not world.StrictCannonRequirements[player] - self.moveless = not world.StrictMoveRequirements[player] or not move_rando_bitvec > 0 + self.area_randomizer = options.area_rando > 0 + self.capless = not options.strict_cap_requirements + self.cannonless = not options.strict_cannon_requirements + self.moveless = not options.strict_move_requirements or not move_rando_bitvec > 0 def assign_rule(self, target_name: str, rule_expr: str): target = self.world.get_location(target_name, self.player) if target_name in location_table else self.world.get_entrance(target_name, self.player) diff --git a/worlds/sm64ex/__init__.py b/worlds/sm64ex/__init__.py index e6a6e42c76a0..0e944aa4ab4b 100644 --- a/worlds/sm64ex/__init__.py +++ b/worlds/sm64ex/__init__.py @@ -3,7 +3,7 @@ import json from .Items import item_table, action_item_table, cannon_item_table, SM64Item from .Locations import location_table, SM64Location -from .Options import sm64_options +from .Options import SM64Options from .Rules import set_rules from .Regions import create_regions, sm64_level_to_entrances, SM64Levels from BaseClasses import Item, Tutorial, ItemClassification, Region @@ -40,7 +40,7 @@ class SM64World(World): area_connections: typing.Dict[int, int] - option_definitions = sm64_options + options_dataclass = SM64Options number_of_stars: int move_rando_bitvec: int @@ -49,38 +49,36 @@ class SM64World(World): def generate_early(self): max_stars = 120 - if (not self.multiworld.EnableCoinStars[self.player].value): + if (not self.options.enable_coin_stars): max_stars -= 15 self.move_rando_bitvec = 0 - for action, itemid in action_item_table.items(): - # HACK: Disable randomization of double jump - if action == 'Double Jump': continue - if getattr(self.multiworld, f"MoveRandomizer{action.replace(' ','')}")[self.player].value: + if self.options.enable_move_rando: + for action in self.options.move_rando_actions.value: max_stars -= 1 - self.move_rando_bitvec |= (1 << (itemid - action_item_table['Double Jump'])) - if (self.multiworld.ExclamationBoxes[self.player].value > 0): + self.move_rando_bitvec |= (1 << (action_item_table[action] - action_item_table['Double Jump'])) + if (self.options.exclamation_boxes > 0): max_stars += 29 - self.number_of_stars = min(self.multiworld.AmountOfStars[self.player].value, max_stars) + self.number_of_stars = min(self.options.amount_of_stars, max_stars) self.filler_count = max_stars - self.number_of_stars self.star_costs = { - 'FirstBowserDoorCost': round(self.multiworld.FirstBowserStarDoorCost[self.player].value * self.number_of_stars / 100), - 'BasementDoorCost': round(self.multiworld.BasementStarDoorCost[self.player].value * self.number_of_stars / 100), - 'SecondFloorDoorCost': round(self.multiworld.SecondFloorStarDoorCost[self.player].value * self.number_of_stars / 100), - 'MIPS1Cost': round(self.multiworld.MIPS1Cost[self.player].value * self.number_of_stars / 100), - 'MIPS2Cost': round(self.multiworld.MIPS2Cost[self.player].value * self.number_of_stars / 100), - 'StarsToFinish': round(self.multiworld.StarsToFinish[self.player].value * self.number_of_stars / 100) + 'FirstBowserDoorCost': round(self.options.first_bowser_star_door_cost * self.number_of_stars / 100), + 'BasementDoorCost': round(self.options.basement_star_door_cost * self.number_of_stars / 100), + 'SecondFloorDoorCost': round(self.options.second_floor_star_door_cost * self.number_of_stars / 100), + 'MIPS1Cost': round(self.options.mips1_cost * self.number_of_stars / 100), + 'MIPS2Cost': round(self.options.mips2_cost * self.number_of_stars / 100), + 'StarsToFinish': round(self.options.stars_to_finish * self.number_of_stars / 100) } # Nudge MIPS 1 to match vanilla on default percentage - if self.number_of_stars == 120 and self.multiworld.MIPS1Cost[self.player].value == 12: + if self.number_of_stars == 120 and self.options.mips1_cost == 12: self.star_costs['MIPS1Cost'] = 15 - self.topology_present = self.multiworld.AreaRandomizer[self.player].value + self.topology_present = self.options.area_rando def create_regions(self): - create_regions(self.multiworld, self.player) + create_regions(self.multiworld, self.options, self.player) def set_rules(self): self.area_connections = {} - set_rules(self.multiworld, self.player, self.area_connections, self.star_costs, self.move_rando_bitvec) + set_rules(self.multiworld, self.options, self.player, self.area_connections, self.star_costs, self.move_rando_bitvec) if self.topology_present: # Write area_connections to spoiler log for entrance, destination in self.area_connections.items(): @@ -107,7 +105,7 @@ def create_items(self): # Power Stars self.multiworld.itempool += [self.create_item("Power Star") for i in range(0,self.number_of_stars)] # Keys - if (not self.multiworld.ProgressiveKeys[self.player].value): + if (not self.options.progressive_keys): key1 = self.create_item("Basement Key") key2 = self.create_item("Second Floor Key") self.multiworld.itempool += [key1, key2] @@ -116,7 +114,7 @@ def create_items(self): # Caps self.multiworld.itempool += [self.create_item(cap_name) for cap_name in ["Wing Cap", "Metal Cap", "Vanish Cap"]] # Cannons - if (self.multiworld.BuddyChecks[self.player].value): + if (self.options.buddy_checks): self.multiworld.itempool += [self.create_item(name) for name, id in cannon_item_table.items()] # Moves self.multiworld.itempool += [self.create_item(action) @@ -124,7 +122,7 @@ def create_items(self): if self.move_rando_bitvec & (1 << itemid - action_item_table['Double Jump'])] def generate_basic(self): - if not (self.multiworld.BuddyChecks[self.player].value): + if not (self.options.buddy_checks): self.multiworld.get_location("BoB: Bob-omb Buddy", self.player).place_locked_item(self.create_item("Cannon Unlock BoB")) self.multiworld.get_location("WF: Bob-omb Buddy", self.player).place_locked_item(self.create_item("Cannon Unlock WF")) self.multiworld.get_location("JRB: Bob-omb Buddy", self.player).place_locked_item(self.create_item("Cannon Unlock JRB")) @@ -136,7 +134,7 @@ def generate_basic(self): self.multiworld.get_location("THI: Bob-omb Buddy", self.player).place_locked_item(self.create_item("Cannon Unlock THI")) self.multiworld.get_location("RR: Bob-omb Buddy", self.player).place_locked_item(self.create_item("Cannon Unlock RR")) - if (self.multiworld.ExclamationBoxes[self.player].value == 0): + if (self.options.exclamation_boxes == 0): self.multiworld.get_location("CCM: 1Up Block Near Snowman", self.player).place_locked_item(self.create_item("1Up Mushroom")) self.multiworld.get_location("CCM: 1Up Block Ice Pillar", self.player).place_locked_item(self.create_item("1Up Mushroom")) self.multiworld.get_location("CCM: 1Up Block Secret Slide", self.player).place_locked_item(self.create_item("1Up Mushroom")) @@ -174,8 +172,8 @@ def fill_slot_data(self): return { "AreaRando": self.area_connections, "MoveRandoVec": self.move_rando_bitvec, - "DeathLink": self.multiworld.death_link[self.player].value, - "CompletionType": self.multiworld.CompletionType[self.player].value, + "DeathLink": self.options.death_link.value, + "CompletionType": self.options.completion_type.value, **self.star_costs } diff --git a/worlds/stardew_valley/docs/en_Stardew Valley.md b/worlds/stardew_valley/docs/en_Stardew Valley.md index 789c12020c18..c29ae859e095 100644 --- a/worlds/stardew_valley/docs/en_Stardew Valley.md +++ b/worlds/stardew_valley/docs/en_Stardew Valley.md @@ -81,22 +81,17 @@ For the locations which do not include a normal reward, Resource Packs and traps A player can enable some options that will add some items to the pool that are relevant to progression - Seasons Randomizer: - * All 4 seasons will be items, and one of them will be selected randomly and be added to the player's start inventory. - * At the end of each month, the player can choose the next season, instead of following the vanilla season order. On -Seasons Randomizer, they can only choose from the seasons they have received. + - All 4 seasons will be items, and one of them will be selected randomly and be added to the player's start inventory. + - At the end of each month, the player can choose the next season, instead of following the vanilla season order. On Seasons Randomizer, they can only choose from the seasons they have received. - Cropsanity: - * Every single seed in the game starts off locked and cannot be purchased from any merchant. Their unlocks are received - as multiworld items. Growing each seed and harvesting the resulting crop sends a location check - * The way merchants sell seeds is considerably changed. Pierre sells fewer seeds at a high price, while Joja sells - unlimited seeds but in huge discount packs, not individually. + - Every single seed in the game starts off locked and cannot be purchased from any merchant. Their unlocks are received as multiworld items. Growing each seed and harvesting the resulting crop sends a location check + - The way merchants sell seeds is considerably changed. Pierre sells fewer seeds at a high price, while Joja sells unlimited seeds but in huge discount packs, not individually. - Museumsanity: - * The items that are normally obtained from museum donation milestones are added to the item pool. Some items, like the - magic rock candy, are duplicated for convenience. - * The Traveling Merchant now sells artifacts and minerals, with a bias towards undonated ones, to mitigate randomness. - She will sell these items as the player receives "Traveling Merchant Metal Detector" items. + - The items that are normally obtained from museum donation milestones are added to the item pool. Some items, like the magic rock candy, are duplicated for convenience. + - The Traveling Merchant now sells artifacts and minerals, with a bias towards undonated ones, to mitigate randomness. She will sell these items as the player receives "Traveling Merchant Metal Detector" items. - TV Channels - Babies - * Only if Friendsanity is enabled + - Only if Friendsanity is enabled There are a few extra vanilla items, which are added to the pool for convenience, but do not have a matching location. These include - [Wizard Buildings](https://stardewvalleywiki.com/Wizard%27s_Tower#Buildings) @@ -135,32 +130,32 @@ for these mods, the specifics will vary from mod to mod List of supported mods: - General - * [Stardew Valley Expanded](https://www.nexusmods.com/stardewvalley/mods/3753) - * [DeepWoods](https://www.nexusmods.com/stardewvalley/mods/2571) - * [Skull Cavern Elevator](https://www.nexusmods.com/stardewvalley/mods/963) - * [Bigger Backpack](https://www.nexusmods.com/stardewvalley/mods/1845) - * [Tractor Mod](https://www.nexusmods.com/stardewvalley/mods/1401) - * [Distant Lands - Witch Swamp Overhaul](https://www.nexusmods.com/stardewvalley/mods/18109) + - [Stardew Valley Expanded](https://www.nexusmods.com/stardewvalley/mods/3753) + - [DeepWoods](https://www.nexusmods.com/stardewvalley/mods/2571) + - [Skull Cavern Elevator](https://www.nexusmods.com/stardewvalley/mods/963) + - [Bigger Backpack](https://www.nexusmods.com/stardewvalley/mods/1845) + - [Tractor Mod](https://www.nexusmods.com/stardewvalley/mods/1401) + - [Distant Lands - Witch Swamp Overhaul](https://www.nexusmods.com/stardewvalley/mods/18109) - Skills - * [Magic](https://www.nexusmods.com/stardewvalley/mods/2007) - * [Luck Skill](https://www.nexusmods.com/stardewvalley/mods/521) - * [Socializing Skill](https://www.nexusmods.com/stardewvalley/mods/14142) - * [Archaeology](https://www.nexusmods.com/stardewvalley/mods/15793) - * [Cooking Skill](https://www.nexusmods.com/stardewvalley/mods/522) - * [Binning Skill](https://www.nexusmods.com/stardewvalley/mods/14073) + - [Magic](https://www.nexusmods.com/stardewvalley/mods/2007) + - [Luck Skill](https://www.nexusmods.com/stardewvalley/mods/521) + - [Socializing Skill](https://www.nexusmods.com/stardewvalley/mods/14142) + - [Archaeology](https://www.nexusmods.com/stardewvalley/mods/15793) + - [Cooking Skill](https://www.nexusmods.com/stardewvalley/mods/522) + - [Binning Skill](https://www.nexusmods.com/stardewvalley/mods/14073) - NPCs - * [Ayeisha - The Postal Worker (Custom NPC)](https://www.nexusmods.com/stardewvalley/mods/6427) - * [Mister Ginger (cat npc)](https://www.nexusmods.com/stardewvalley/mods/5295) - * [Juna - Roommate NPC](https://www.nexusmods.com/stardewvalley/mods/8606) - * [Professor Jasper Thomas](https://www.nexusmods.com/stardewvalley/mods/5599) - * [Alec Revisited](https://www.nexusmods.com/stardewvalley/mods/10697) - * [Custom NPC - Yoba](https://www.nexusmods.com/stardewvalley/mods/14871) - * [Custom NPC Eugene](https://www.nexusmods.com/stardewvalley/mods/9222) - * ['Prophet' Wellwick](https://www.nexusmods.com/stardewvalley/mods/6462) - * [Shiko - New Custom NPC](https://www.nexusmods.com/stardewvalley/mods/3732) - * [Delores - Custom NPC](https://www.nexusmods.com/stardewvalley/mods/5510) - * [Custom NPC - Riley](https://www.nexusmods.com/stardewvalley/mods/5811) - * [Alecto the Witch](https://www.nexusmods.com/stardewvalley/mods/10671) + - [Ayeisha - The Postal Worker (Custom NPC)](https://www.nexusmods.com/stardewvalley/mods/6427) + - [Mister Ginger (cat npc)](https://www.nexusmods.com/stardewvalley/mods/5295) + - [Juna - Roommate NPC](https://www.nexusmods.com/stardewvalley/mods/8606) + - [Professor Jasper Thomas](https://www.nexusmods.com/stardewvalley/mods/5599) + - [Alec Revisited](https://www.nexusmods.com/stardewvalley/mods/10697) + - [Custom NPC - Yoba](https://www.nexusmods.com/stardewvalley/mods/14871) + - [Custom NPC Eugene](https://www.nexusmods.com/stardewvalley/mods/9222) + - ['Prophet' Wellwick](https://www.nexusmods.com/stardewvalley/mods/6462) + - [Shiko - New Custom NPC](https://www.nexusmods.com/stardewvalley/mods/3732) + - [Delores - Custom NPC](https://www.nexusmods.com/stardewvalley/mods/5510) + - [Custom NPC - Riley](https://www.nexusmods.com/stardewvalley/mods/5811) + - [Alecto the Witch](https://www.nexusmods.com/stardewvalley/mods/10671) Some of these mods might need a patch mod to tie the randomizer with the mod. These can be found [here](https://github.com/Witchybun/SDV-Randomizer-Content-Patcher/releases) diff --git a/worlds/stardew_valley/docs/setup_en.md b/worlds/stardew_valley/docs/setup_en.md index 3b51622d8d0a..74caf9b7daba 100644 --- a/worlds/stardew_valley/docs/setup_en.md +++ b/worlds/stardew_valley/docs/setup_en.md @@ -3,7 +3,11 @@ ## Required Software - Stardew Valley on PC (Recommended: [Steam version](https://store.steampowered.com/app/413150/Stardew_Valley/)) -- SMAPI ([Mod loader for Stardew Valley](https://smapi.io/)) + - You need version 1.5.6. It is available in a public beta branch on Steam ![image](https://i.imgur.com/uKAUmF0.png). + - If your Stardew is not on Steam, you are responsible for finding a way to downgrade it. + - This measure is temporary. We are working hard to bring the mod to Stardew 1.6 as soon as possible. +- SMAPI 3.x.x ([Mod loader for Stardew Valley](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files)) + - Same as Stardew Valley itself, SMAPI needs a slightly older version to be compatible with Stardew Valley 1.5.6 ![image](https://i.imgur.com/kzgObHy.png) - [StardewArchipelago Mod Release 5.x.x](https://github.com/agilbert1412/StardewArchipelago/releases) - It is important to use a mod release of version 5.x.x to play seeds that have been generated here. Later releases can only be used with later releases of the world generator, that are not hosted on archipelago.gg yet. @@ -34,11 +38,10 @@ You can customize your options by visiting the [Stardew Valley Player Options Pa ### Installing the mod -- Install [SMAPI](https://smapi.io/) by following the instructions on their website +- Install [SMAPI version 3.x.x](https://www.nexusmods.com/stardewvalley/mods/2400?tab=files) by following the instructions on the mod page - Download and extract the [StardewArchipelago](https://github.com/agilbert1412/StardewArchipelago/releases) mod into your Stardew Valley "Mods" folder -- *OPTIONAL*: If you want to launch your game through Steam, add the following to your Stardew Valley launch options: - - "[PATH TO STARDEW VALLEY]\Stardew Valley\StardewModdingAPI.exe" %command% +- *OPTIONAL*: If you want to launch your game through Steam, add the following to your Stardew Valley launch options: `"[PATH TO STARDEW VALLEY]\Stardew Valley\StardewModdingAPI.exe" %command%` - Otherwise just launch "StardewModdingAPI.exe" in your installation folder directly - Stardew Valley should launch itself alongside a console which allows you to read mod information and interact with some of them. diff --git a/worlds/stardew_valley/options.py b/worlds/stardew_valley/options.py index 634de45285f7..055407d97d4a 100644 --- a/worlds/stardew_valley/options.py +++ b/worlds/stardew_valley/options.py @@ -197,7 +197,7 @@ class Cropsanity(Choice): """Formerly named "Seed Shuffle" Pierre now sells a random amount of seasonal seeds and Joja sells them without season requirements, but only in huge packs. Disabled: All the seeds are unlocked from the start, there are no location checks for growing and harvesting crops - Shuffled: Seeds are unlocked as archipelago items, for each seed there is a location check for growing and harvesting that crop + Enabled: Seeds are unlocked as archipelago items, for each seed there is a location check for growing and harvesting that crop """ internal_name = "cropsanity" display_name = "Cropsanity" diff --git a/worlds/stardew_valley/presets.py b/worlds/stardew_valley/presets.py index 020b3f49277f..e75eb5c5fcde 100644 --- a/worlds/stardew_valley/presets.py +++ b/worlds/stardew_valley/presets.py @@ -64,7 +64,7 @@ SeasonRandomization.internal_name: SeasonRandomization.option_randomized_not_winter, Cropsanity.internal_name: Cropsanity.option_enabled, BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive_very_cheap, ElevatorProgression.internal_name: ElevatorProgression.option_progressive, SkillProgression.internal_name: SkillProgression.option_progressive, BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, @@ -102,13 +102,13 @@ FarmType.internal_name: "random", StartingMoney.internal_name: "rich", ProfitMargin.internal_name: 150, - BundleRandomization.internal_name: BundleRandomization.option_thematic, + BundleRandomization.internal_name: BundleRandomization.option_remixed, BundlePrice.internal_name: BundlePrice.option_normal, EntranceRandomization.internal_name: EntranceRandomization.option_non_progression, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, Cropsanity.internal_name: Cropsanity.option_enabled, BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive_cheap, ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, SkillProgression.internal_name: SkillProgression.option_progressive, BuildingProgression.internal_name: BuildingProgression.option_progressive_cheap, @@ -146,7 +146,7 @@ FarmType.internal_name: "random", StartingMoney.internal_name: "extra", ProfitMargin.internal_name: "normal", - BundleRandomization.internal_name: BundleRandomization.option_thematic, + BundleRandomization.internal_name: BundleRandomization.option_remixed, BundlePrice.internal_name: BundlePrice.option_expensive, EntranceRandomization.internal_name: EntranceRandomization.option_buildings, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, @@ -191,7 +191,7 @@ StartingMoney.internal_name: "vanilla", ProfitMargin.internal_name: "half", BundleRandomization.internal_name: BundleRandomization.option_shuffled, - BundlePrice.internal_name: BundlePrice.option_expensive, + BundlePrice.internal_name: BundlePrice.option_very_expensive, EntranceRandomization.internal_name: EntranceRandomization.option_buildings, SeasonRandomization.internal_name: SeasonRandomization.option_randomized, Cropsanity.internal_name: Cropsanity.option_enabled, @@ -234,13 +234,13 @@ FarmType.internal_name: "random", StartingMoney.internal_name: "filthy rich", ProfitMargin.internal_name: "quadruple", - BundleRandomization.internal_name: BundleRandomization.option_thematic, - BundlePrice.internal_name: BundlePrice.option_very_cheap, + BundleRandomization.internal_name: BundleRandomization.option_remixed, + BundlePrice.internal_name: BundlePrice.option_minimum, EntranceRandomization.internal_name: EntranceRandomization.option_disabled, SeasonRandomization.internal_name: SeasonRandomization.option_randomized_not_winter, Cropsanity.internal_name: Cropsanity.option_disabled, BackpackProgression.internal_name: BackpackProgression.option_early_progressive, - ToolProgression.internal_name: ToolProgression.option_progressive, + ToolProgression.internal_name: ToolProgression.option_progressive_very_cheap, ElevatorProgression.internal_name: ElevatorProgression.option_progressive_from_previous_floor, SkillProgression.internal_name: SkillProgression.option_progressive, BuildingProgression.internal_name: BuildingProgression.option_progressive_very_cheap, diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index fdfd064561fe..96a3c39ad283 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -602,8 +602,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Library Exterior Ladder Region"].connect( connecting_region=regions["Library Exterior Tree Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) - and state.has_any({grapple, laurels}, player) - and has_ladder("Ladders in Library", state, player, options)) + and (state.has(grapple, player) or (state.has(laurels, player) + and has_ladder("Ladders in Library", state, player, options)))) regions["Library Hall Bookshelf"].connect( connecting_region=regions["Library Hall"],