From 8f6ba280a057454fbffb149c7bf7c3f9a9ebaa70 Mon Sep 17 00:00:00 2001 From: lil David <1337lilDavid@gmail.com> Date: Mon, 15 Jul 2024 12:05:28 -0500 Subject: [PATCH 01/14] Partially implement new logic rules system --- logic.py | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rules.py | 39 ++++++++++++++ 2 files changed, 192 insertions(+) diff --git a/logic.py b/logic.py index a25ec61..1914834 100644 --- a/logic.py +++ b/logic.py @@ -2,9 +2,162 @@ Functions used to describe Metroid: Zero Mission logic rules in rules.py """ +from __future__ import annotations + +import builtins +import functools +from typing import TYPE_CHECKING, Any, Callable, NamedTuple from BaseClasses import CollectionState + from .options import MZMOptions +if TYPE_CHECKING: + from . import MZMWorld + + +class Requirement(NamedTuple): + rule: Callable[[MZMWorld, CollectionState], bool] + + def create_rule(self, world: MZMWorld): + return functools.partial(self.rule, world) + + @classmethod + def item(cls, item: str, count: int = 1): + return cls(lambda world, state: state.has(item, world.player, count)) + + @classmethod + def location(cls, location: str): + return cls(lambda world, state: state.can_reach_location(location, world.player)) + + @classmethod + def entrance(cls, entrance: str): + return cls(lambda world, state: state.can_reach_entrance(entrance, world.player)) + + @classmethod + def setting_enabled(cls, setting: str): + return cls(lambda world, _: getattr(world.options, setting)) + + @classmethod + def setting_is(cls, setting: str, value: Any): + return cls(lambda world, _: getattr(world.options, setting) == value) + + @classmethod + def setting_atleast(cls, setting: str, value: int): + return cls(lambda world, _: getattr(world.options, setting) >= value) + + +def all(*args: Requirement): + return Requirement(lambda world, state: builtins.all(req.rule(world, state) for req in args)) + +def any(*args: Requirement): + return Requirement(lambda world, state: builtins.any(req.rule(world, state) for req in args)) + + +KraidBoss = Requirement.item("Kraid Defeated") +RidleyBoss = Requirement.item("Ridley Defeated") +MotherBrainBoss = Requirement.item("Mother Brain Defeated") +ChozoGhostBoss = Requirement.item("Chozo Ghost Defeated") +MechaRidleyBoss = Requirement.item("Mecha Ridley Defeated") + +UnknownItem1 = Requirement.location("Crateria Plasma Beam/Unknown Item 1") +UnknownItem2 = Requirement.location("Kraid Space Jump/Unknown Item 2") +UnknownItem3 = Requirement.location("Ridley Gravity Suit/Unknown Item 3") + +CanUseUnknownItems = any( + Requirement.setting_enabled("unknown_items_always_usable"), + ChozoGhostBoss, +) +LayoutPatches = Requirement.setting_enabled("layout_patches") + +EnergyTanks = lambda n: Requirement.item("Energy Tank", n) +MissileTanks = lambda n: Requirement.item("Missile Tank", n) +SuperMissileTanks = lambda n: Requirement.item("Super Missile Tank", n) +PowerBombTanks = lambda n: Requirement.item("Power Bomb Tank", n) +LongBeam = Requirement.item("Long Beam") +ChargeBeam = Requirement.item("Charge Beam") +IceBeam = Requirement.item("Ice Beam") +WaveBeam = Requirement.item("Wave Beam") +PlasmaBeam = all( + Requirement.item("Plasma Beam"), + CanUseUnknownItems, +) +Bomb = Requirement.item("Bomb") +VariaSuit = Requirement.item("Varia Suit") +GravitySuit = all( + Requirement.item("Gravity Suit"), + CanUseUnknownItems +) +MorphBall = Requirement.item("Morph Ball") +SpeedBooster = Requirement.item("Speed Booster") +HiJump = Requirement.item("Hi-Jump") +ScrewAttack = Requirement.item("Screw Attack") +SpaceJump = all( + Requirement.item("Space Jump"), + CanUseUnknownItems +) +PowerGrip = Requirement.item("Power Grip") + +Missiles = any( + MissileTanks(1), + SuperMissileTanks(1), +) +MissileCount = lambda n: Requirement( + lambda world, state: + 5 * state.count("Missile Tank", world.player) + 2 * state.count("Super Missile Tank", world.player) + >= n +) +SuperMissiles = SuperMissileTanks(1) +PowerBombs = PowerBombTanks(1) +PowerBombCount = lambda n: PowerBombTanks(n // 2) + +CanRegularBomb = all( + MorphBall, + Bomb, +) +CanIBJ = all( + Requirement.setting_enabled("ibj_in_logic"), + CanRegularBomb, +) +CanHiJump = any( + HiJump, + SpaceJump, + CanIBJ, +) +CanHjSjIbjOrGrip = any( # This name is even more cursed in Pascal case + CanHiJump, + PowerGrip, +) +CanWallJump = Requirement.setting_enabled("walljumps_in_logic") +CanTrickySparks = all( + lambda world, state: False, + SpeedBooster, +) + +CanBombBlock = all( + MorphBall, + any( + Bomb, + PowerBombTanks(1), + ), +) +CanBallCannon = CanRegularBomb +CanBallspark = all( + MorphBall, + SpeedBooster, + HiJump, +) + +CanLongBeam = any( + LongBeam, + MissileCount(1), + CanBombBlock, +) + +CanTraverseHeat = VariaSuit +Hellrun = lambda n: all( + Requirement.setting_enabled("heatruns_lavadives"), + EnergyTanks(n), +) # TODO: Add missing logic options # TODO: Fine tune boss logic diff --git a/rules.py b/rules.py index a091b3d..8299598 100644 --- a/rules.py +++ b/rules.py @@ -7,7 +7,9 @@ from __future__ import annotations from typing import TYPE_CHECKING from worlds.generic.Rules import add_rule + from . import logic +from .logic import * if TYPE_CHECKING: from . import MZMWorld @@ -18,15 +20,32 @@ def set_rules(world: MZMWorld, locations): player = world.player + # The rules can be moved out of this function once they've all been converted brinstar_access_rules = { "Brinstar Morph Ball Cannon": lambda state: logic.can_regular_bomb(state, player), +# "Brinstar Morph Ball Cannon": CanRegularBomb "Brinstar Long Beam": lambda state: (state.has("Morph Ball", player) and (logic.can_long_beam(state, player) or world.options.layout_patches.value)), +# "Brinstar Long Beam": all( +# MorphBall, +# any( +# CanLongBeam, +# LayoutPatches, +# ) +# ), "Brinstar Ceiling E-Tank": lambda state: (state.has("Ice Beam", player) and state.has("Ridley Defeated", player)) or logic.can_space_jump(state, player) or logic.can_ibj(state, player), +# "Brinstar Ceiling E-Tank": any( +# all( +# IceBeam, +# RidleyBoss +# ), +# SpaceJump, +# CanIBJ, +# ), "Brinstar Missile Above Super": lambda state: (logic.can_bomb_block(state, player) and (logic.can_space_jump(state, player) @@ -36,6 +55,19 @@ def set_rules(world: MZMWorld, locations): or logic.can_walljump(state, player) ) ), +# "Brinstar Missile Above Super": all( +# CanBombBlock, +# any( +# SpaceJump, +# IceBeam, +# CanIBJ, +# CanWallJump, +# all( +# HiJump, +# PowerGrip, +# ), +# ) +# ), "Brinstar Super Missile": lambda state: logic.can_ballspark(state, player), "Brinstar Top Missile": lambda state: (state.has_all({"Morph Ball", "Power Grip"}, player) @@ -341,6 +373,7 @@ def set_rules(world: MZMWorld, locations): lambda state: logic.ridley_longway_right_shaft_access(state, player), "Ridley E-Tank behind Gravity": lambda state: state.can_reach("Ridley Gravity Suit/Unknown Item 3", "Location", player), +# "Ridley E-Tank behind Gravity": UnknownItem3, "Ridley Gravity Suit/Unknown Item 3": lambda state: ( logic.ridley_central_access(state, player) and logic.has_missile_count(state, player, 40) @@ -435,7 +468,12 @@ def set_rules(world: MZMWorld, locations): state.has_any({"Bomb", "Hi-Jump"}, player) and logic.can_hj_sj_ibj_or_grip(state, player)), "Crateria Statue Water": lambda state: state.can_reach("Crateria Plasma Beam/Unknown Item 1", "Location", player), +# "Crateria Statue Water": UnknownItem1, "Crateria Plasma Beam/Unknown Item 1": lambda state: state.has_any({"Bomb", "Hi-Jump"}, player), +# "Crateria Plasma Beam/Unknown Item 1": any( +# Bomb, +# HiJump, +# ), "Crateria East Ballspark": lambda state: ( logic.can_ballspark(state, player) and (logic.can_space_jump(state, player) or logic.can_walljump(state, player)) @@ -572,5 +610,6 @@ def set_rules(world: MZMWorld, locations): location = world.multiworld.get_location(i, player) try: add_rule(location, access_rules[i]) +# add_rule(location, access_rules[i].create_rule(world)) except KeyError: continue From 09c6bdab59c5de7c14f2662d65cb166061b548e5 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:28:36 -0400 Subject: [PATCH 02/14] Options: Split IBJ into vertical/horizontal, implement Tricky Shinesparks --- __init__.py | 2 ++ options.py | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/__init__.py b/__init__.py index 0b1c31f..913eae3 100644 --- a/__init__.py +++ b/__init__.py @@ -126,9 +126,11 @@ def fill_slot_data(self) -> Dict[str, Any]: return { "unknown_items": self.options.unknown_items_always_usable.value, "layout_patches": self.options.layout_patches.value, + "logic_difficulty": self.options.logic_difficulty.value, "ibj_logic": self.options.ibj_in_logic.value, "heatruns": self.options.heatruns_lavadives.value, "walljump_logic": self.options.walljumps_in_logic.value, + "tricky_shinesparks": self.options.tricky_shinesparks.value, "death_link": self.options.death_link.value } diff --git a/options.py b/options.py index 089b6c3..3b60c86 100644 --- a/options.py +++ b/options.py @@ -13,7 +13,7 @@ class ChozodiaAccess(Choice): """ - Open: You can access Chozodia by using a Power Bomb to open the doors. + Open: You can access Chozodia at any time by using a Power Bomb to open the doors. Closed: You must defeat Mother Brain to access Chozodia. """ display_name = "Chozodia Access" @@ -39,17 +39,36 @@ class SkipChozodiaStealth(DefaultOnToggle): display_name = "Skip Chozodia Stealth" -class IBJInLogic(Toggle): +class LogicDifficulty(Choice): + """ + Determines the general difficulty of the game's logic. On advanced difficulty, more niche techniques and game + knowledge may be required to collect items or progress, and you may be required to complete areas or bosses + with fewer resources. Examples of "tricks" this may put in logic include entering invisible tunnels, jump extends, + and Acid Worm skip. + + Other specific tricks (such as difficult Shinesparks and horizontal IBJ) have individual difficulty settings that + this does not affect. + """ + display_name = "Logic Difficulty" + option_normal = 0 + option_advanced = 1 + + +class IBJInLogic(Choice): """ Allows for using IBJ (infinite bomb jumping) in logic. - Enabling this option may require you to traverse long vertical or horizontal distances using only bombs. + Enabling this option may require you to traverse long vertical and/or horizontal distances using only bombs. If disabled, this option does not disable performing IBJ, but it will never be logically required. """ display_name = "IBJ In Logic" + option_none = 0 + option_vertical_only = 1 + option_horizontal_and_vertical = 2 +# TODO: split into none/simple/advanced class HeatRunsAndLavaDives(Toggle): """ Allows for traversing heated rooms and acid/lava dives without the appropriate suit(s) in logic. @@ -71,9 +90,20 @@ class WalljumpsInLogic(DefaultOnToggle): display_name = "Wall Jumps In Logic" +class TrickyShinesparks(Toggle): + """ + If enabled, logic will include long, difficult, and/or unintuitive Shinesparks as valid methods of collecting + items or traversing areas that normally would not require an advanced Shinespark to collect. + + This has no effect on long Shinespark puzzles which are the intended way of collecting an item, such as the long + Shinespark chain in Chozodia near the Chozo Ghost room. + """ + display_name = "Tricky Shinesparks" + + class LayoutPatches(DefaultOnToggle): """ - Modify the layout of a few rooms to reduce softlocks. + Slightly modify the layout of some rooms to reduce softlocks. NOTE: You can warp to the starting room from any save station or Samus' ship by holding L+R while selecting "No" when asked to save. """ @@ -134,9 +164,11 @@ class JunkFillWeights(OptionDict): MorphBallPlacement, # TODO: Shuffle settings group? ]), OptionGroup("Logic", [ + LogicDifficulty, IBJInLogic, HeatRunsAndLavaDives, WalljumpsInLogic, + TrickyShinesparks ]), OptionGroup("Cosmetic", [ DisplayNonLocalItems, @@ -155,9 +187,11 @@ class MZMOptions(PerGameCommonOptions): unknown_items_always_usable: UnknownItemsAlwaysUsable layout_patches: LayoutPatches morph_ball: MorphBallPlacement + logic_difficulty: LogicDifficulty ibj_in_logic: IBJInLogic heatruns_lavadives: HeatRunsAndLavaDives walljumps_in_logic: WalljumpsInLogic + tricky_shinesparks: TrickyShinesparks display_nonlocal_items: DisplayNonLocalItems start_inventory_from_pool: StartInventoryPool junk_fill_weights: JunkFillWeights From 9fad6fcae31db72327e70ef3fbc40bac4a87f226 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:58:39 -0400 Subject: [PATCH 03/14] Convert logic to new system, create more regions The logic generates spoiler logs with completable playthroughs. However, this build is currently broken because it does not play nice with the client. In spite of that I decided to push so that changes from here can be tracked. There's still a bit to do. --- __init__.py | 12 +- locations.py | 226 +++++---- logic.py | 881 ++++++++++++++++++++++---------- regions.py | 187 ++++--- rules.py | 1358 +++++++++++++++++++++++++++++--------------------- 5 files changed, 1637 insertions(+), 1027 deletions(-) diff --git a/__init__.py b/__init__.py index 913eae3..7b2dd1a 100644 --- a/__init__.py +++ b/__init__.py @@ -12,7 +12,7 @@ from .items import item_data_table, major_item_data_table, MZMItem from .locations import full_location_table from .options import MZMOptions, MorphBallPlacement, mzm_option_groups -from .regions import create_regions +from .regions import create_regions_and_connections from .rom import MZMProcedurePatch, write_tokens from .rules import set_rules @@ -41,7 +41,7 @@ class MZMWeb(WebWorld): "English", "multiworld_en.md", "multiworld/en", - ["lil David, NoiseCrush"] + ["N/A"] ) tutorials = [setup] @@ -65,7 +65,7 @@ class MZMWorld(World): required_client_version = (0, 5, 0) item_name_to_id = {name: data.code for name, data in item_data_table.items()} - location_name_to_id = full_location_table + location_name_to_id = {name: data.code for name, data in full_location_table.items()} junk_fill: List[str] @@ -79,14 +79,14 @@ def generate_early(self): self.options.local_items.value.add("Nothing") def create_regions(self) -> None: - create_regions(self) + create_regions_and_connections(self) self.place_event("Kraid Defeated", "Kraid") self.place_event("Ridley Defeated", "Ridley") self.place_event("Mother Brain Defeated", "Mother Brain") self.place_event("Chozo Ghost Defeated", "Chozo Ghost") self.place_event("Mecha Ridley Defeated", "Mecha Ridley") - self.place_event("Mission Complete", "Chozodia Space Pirate's Ship") + self.place_event("Mission Accomplished!", "Chozodia Space Pirate's Ship") def create_items(self) -> None: item_pool: List[MZMItem] = [] @@ -106,7 +106,7 @@ def create_items(self) -> None: def set_rules(self) -> None: set_rules(self, full_location_table) self.multiworld.completion_condition[self.player] = lambda state: ( - state.has("Mission Complete", self.player)) + state.has("Mission Accomplished!", self.player)) def generate_output(self, output_directory: str): output_path = Path(output_directory) diff --git a/locations.py b/locations.py index fe5c5e5..f4aa1bf 100644 --- a/locations.py +++ b/locations.py @@ -1,145 +1,151 @@ """ Classes and functions related to AP locations for Metroid: Zero Mission """ -from BaseClasses import Location + from .items import AP_MZM_ID_BASE -class MZMLocation(Location): - game: str = "Metroid Zero Mission" +class LocationData: + region: str + code: int + + def __init__(self, reg, id): + self.region = reg + self.code = id # Location numbers/order and some names from Biospark's MZM Randomizer. # Events in any region must be at the end of its table for the client to work correctly +# TODO: Double check that these are all correctly assigned to their right regions brinstar_location_table = { - "Brinstar Morph Ball": AP_MZM_ID_BASE + 0, - "Brinstar Morph Ball Cannon": AP_MZM_ID_BASE + 1, - "Brinstar Long Beam": AP_MZM_ID_BASE + 2, - "Brinstar Ceiling E-Tank": AP_MZM_ID_BASE + 3, - "Brinstar Missile Above Super": AP_MZM_ID_BASE + 4, - "Brinstar Super Missile": AP_MZM_ID_BASE + 5, - "Brinstar Top Missile": AP_MZM_ID_BASE + 6, - "Brinstar Speed Booster Shortcut Missile": AP_MZM_ID_BASE + 7, - "Brinstar Varia Suit": AP_MZM_ID_BASE + 8, - "Brinstar Worm drop": AP_MZM_ID_BASE + 9, - "Brinstar Acid near Varia": AP_MZM_ID_BASE + 10, - "Brinstar First Missile": AP_MZM_ID_BASE + 11, - "Brinstar Behind Hive": AP_MZM_ID_BASE + 12, - "Brinstar Under Bridge": AP_MZM_ID_BASE + 13, - "Brinstar Post-Hive Missile": AP_MZM_ID_BASE + 14, - "Brinstar Upper Pillar Missile": AP_MZM_ID_BASE + 15, - "Brinstar Behind Bombs": AP_MZM_ID_BASE + 16, - "Brinstar Bomb": AP_MZM_ID_BASE + 17, - "Brinstar Post-Hive E-Tank": AP_MZM_ID_BASE + 18, + "Brinstar Morph Ball": LocationData("Brinstar Start", AP_MZM_ID_BASE + 0), + "Brinstar Morph Ball Cannon": LocationData("Brinstar Start", AP_MZM_ID_BASE + 1), + "Brinstar Long Beam": LocationData("Brinstar Main", AP_MZM_ID_BASE + 2), + "Brinstar Ceiling E-Tank": LocationData("Brinstar Start", AP_MZM_ID_BASE + 3), + "Brinstar Main Shaft Left Alcove": LocationData("Brinstar Main", AP_MZM_ID_BASE + 4), #TODO Renamed + "Brinstar Ballspark": LocationData("Brinstar Main", AP_MZM_ID_BASE + 5), #TODO Renamed + "Brinstar Ripper Climb": LocationData("Brinstar Main", AP_MZM_ID_BASE + 6), # TODO Renamed + "Brinstar Speed Booster Shortcut": LocationData("Brinstar Main", AP_MZM_ID_BASE + 7), #TODO Renamed + "Brinstar Varia Suit": LocationData("Brinstar Top", AP_MZM_ID_BASE + 8), + "Brinstar Worm drop": LocationData("Brinstar Main", AP_MZM_ID_BASE + 9), + "Brinstar Acid near Varia": LocationData("Brinstar Top", AP_MZM_ID_BASE + 10), + "Brinstar First Missile": LocationData("Brinstar Main", AP_MZM_ID_BASE + 11), + "Brinstar Behind Hive": LocationData("Brinstar Main", AP_MZM_ID_BASE + 12), + "Brinstar Under Bridge": LocationData("Brinstar Main", AP_MZM_ID_BASE + 13), + "Brinstar Post-Hive In Wall": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 14), #TODO renamed + "Brinstar Upper Pillar": LocationData("Brinstar Top", AP_MZM_ID_BASE + 15), #TODO renamed + "Brinstar Behind Bombs": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 16), + "Brinstar Bomb": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 17), + "Brinstar Post-Hive Pillar": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 18) #TODO renamed } kraid_location_table = { - "Kraid Giant Hoppers Missile": AP_MZM_ID_BASE + 19, - "Kraid Save Room Missile": AP_MZM_ID_BASE + 20, - "Kraid Crumble Block Missile": AP_MZM_ID_BASE + 21, - "Kraid Quad Ball Cannon Room": AP_MZM_ID_BASE + 22, - "Kraid Space Jump/Unknown Item 2": AP_MZM_ID_BASE + 23, - "Kraid Acid Ballspark": AP_MZM_ID_BASE + 24, - "Kraid Speed Booster": AP_MZM_ID_BASE + 25, - "Kraid Worm Missile": AP_MZM_ID_BASE + 26, - "Kraid Pillar Missile": AP_MZM_ID_BASE + 27, - "Kraid Acid Fall": AP_MZM_ID_BASE + 28, - "Kraid Worm E-Tank": AP_MZM_ID_BASE + 29, - "Kraid Speed Jump": AP_MZM_ID_BASE + 30, - "Kraid Upper Right Morph Ball Cannon": AP_MZM_ID_BASE + 31, - "Kraid": None + "Kraid Behind Giant Hoppers": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 19), #TODO Renamed + "Kraid Save Room Tunnel": LocationData("Kraid Main", AP_MZM_ID_BASE + 20), #TODO renamed + "Kraid Zipline Morph Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 21), #TODO renamed + "Kraid Quad Ball Cannon Room": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 22), + "Kraid Unknown Item Statue": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 23), #TODO Renamed + "Kraid Acid Ballspark": LocationData("Kraid Main", AP_MZM_ID_BASE + 24), + "Kraid Speed Booster": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 25), + "Kraid Under Acid Worm": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 26), #TODO renamed + "Kraid Right Hall Pillar": LocationData("Kraid Main", AP_MZM_ID_BASE + 27), #TODO renamed + "Kraid Acid Fall": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 28), + "Kraid Zipline Activator Room": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 29), #TODO renamed + "Kraid Speed Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 30), + "Kraid Upper Right Morph Ball Cannon": LocationData("Kraid Main", AP_MZM_ID_BASE + 31), + "Kraid": LocationData("Kraid Bottom", None) } norfair_location_table = { - "Norfair Lava Power Bomb": AP_MZM_ID_BASE + 32, - "Norfair Lava Missile": AP_MZM_ID_BASE + 33, - "Norfair Screw Attack": AP_MZM_ID_BASE + 34, - "Norfair Screw Attack Missile": AP_MZM_ID_BASE + 35, - "Norfair Power Grip Missile": AP_MZM_ID_BASE + 36, - "Norfair Under Crateria Elevator": AP_MZM_ID_BASE + 37, - "Norfair Wave Beam": AP_MZM_ID_BASE + 38, - "Norfair Bomb Trap": AP_MZM_ID_BASE + 39, - "Norfair Bottom Heated Room First": AP_MZM_ID_BASE + 40, #TODO: maybe rename - "Norfair Bottom Heated Room Second": AP_MZM_ID_BASE + 41, #TODO and this one - "Norfair Heated Room Under Brinstar Elevator": AP_MZM_ID_BASE + 42, - "Norfair Space Boost Missile": AP_MZM_ID_BASE + 43, # TODO maybe rename - "Norfair Space Boost Super Missile": AP_MZM_ID_BASE + 44, # TODO and this one - "Norfair Ice Beam": AP_MZM_ID_BASE + 45, - "Norfair Heated Room above Ice Beam": AP_MZM_ID_BASE + 46, - "Norfair Hi-Jump": AP_MZM_ID_BASE + 47, - "Norfair Big Room": AP_MZM_ID_BASE + 48, - "Norfair Behind Top Chozo Statue": AP_MZM_ID_BASE + 49, - "Norfair Larva Ceiling E-tank": AP_MZM_ID_BASE + 50, - "Norfair Right Shaft Lower": AP_MZM_ID_BASE + 51, - "Norfair Right Shaft Bottom": AP_MZM_ID_BASE + 52 + "Norfair Lava Dive Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 32), #TODO Renamed + "Norfair Lava Dive Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 33), #TODO renamed + "Norfair Screw Attack": LocationData("Norfair Screw Attack Area", AP_MZM_ID_BASE + 34), + "Norfair Next to Screw Attack": LocationData("Norfair Screw Attack Area", AP_MZM_ID_BASE + 35), #TODO renamed + "Norfair Hallway to Crateria": LocationData("Norfair Main", AP_MZM_ID_BASE + 36), #TODO renamed + "Norfair Under Crateria Elevator": LocationData("Norfair Main", AP_MZM_ID_BASE + 37), + "Norfair Wave Beam": LocationData("Lower Norfair", AP_MZM_ID_BASE + 38), + "Norfair Bomb Trap": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 39), #TODO may change region + "Norfair Heated Room Below Wave - Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 40), #TODO Renamed + "Norfair Heated Room Below Wave - Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 41), #TODO Renamed + "Norfair Heated Room Under Brinstar Elevator": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 42), #TODO may change region + "Norfair Behind Lower Super Missile Door - Right": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 43), #TODO Renamed + "Norfair Behind Lower Super Missile Door - Left": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 44), #TODO renamed + "Norfair Ice Beam": LocationData("Norfair Upper Right Shaft", AP_MZM_ID_BASE + 45), + "Norfair Heated Room above Ice Beam": LocationData("Norfair Upper Right Shaft", AP_MZM_ID_BASE + 46), + "Norfair Hi-Jump": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 47), + "Norfair Big Room": LocationData("Norfair Right Shaft", AP_MZM_ID_BASE + 48), + "Norfair Behind Top Chozo Statue": LocationData("Norfair Behind Ice Beam", AP_MZM_ID_BASE + 49), + "Norfair Larva Ceiling": LocationData("Norfair Bottom", AP_MZM_ID_BASE + 50), #TODO Renamed + "Norfair Right Shaft Near Hi-Jump": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 51), #TODO Renamed + "Norfair Right Shaft Bottom": LocationData("Norfair Bottom", AP_MZM_ID_BASE + 52) } ridley_location_table = { - "Ridley Southwest Puzzle Top": AP_MZM_ID_BASE + 53, - "Ridley Southwest Puzzle Bottom": AP_MZM_ID_BASE + 54, - "Ridley West Pillar": AP_MZM_ID_BASE + 55, - "Ridley E-Tank behind Gravity": AP_MZM_ID_BASE + 56, - "Ridley Gravity Suit/Unknown Item 3": AP_MZM_ID_BASE + 57, - "Ridley Fake Floor E-Tank": AP_MZM_ID_BASE + 58, - "Ridley Upper Ball Cannon Puzzle": AP_MZM_ID_BASE + 59, - "Ridley Lower Ball Cannon Puzzle": AP_MZM_ID_BASE + 60, - "Ridley Imago Super Missile": AP_MZM_ID_BASE + 61, - "Ridley After Sidehopper Hall Upper": AP_MZM_ID_BASE + 62, - "Ridley After Sidehopper Hall Lower": AP_MZM_ID_BASE + 63, - "Ridley Long Hall": AP_MZM_ID_BASE + 64, - "Ridley Center Pillar Missile": AP_MZM_ID_BASE + 65, - "Ridley Ball Room Missile": AP_MZM_ID_BASE + 66, - "Ridley Ball Room Super": AP_MZM_ID_BASE + 67, - "Ridley Fake Lava Missile": AP_MZM_ID_BASE + 68, - "Ridley Owl E-Tank": AP_MZM_ID_BASE + 69, - "Ridley Northeast corner Missile": AP_MZM_ID_BASE + 70, - "Ridley Bomb Puzzle": AP_MZM_ID_BASE + 71, - "Ridley Speed Jump": AP_MZM_ID_BASE + 72, - "Ridley": None + "Ridley Southwest Puzzle Top": LocationData("Ridley SW Puzzle", AP_MZM_ID_BASE + 53), + "Ridley Southwest Puzzle Bottom": LocationData("Ridley SW Puzzle", AP_MZM_ID_BASE + 54), + "Ridley West Pillar": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 55), + "Ridley Behind Unknown Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 56), #TODO Renamed + "Ridley Unknown Item Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 57), #TODO Renamed + "Ridley Fake Floor": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 58), #TODO Renamed + "Ridley Upper Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 59), #TODO may change region + "Ridley Lower Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 60), #TODO may change region + "Ridley Imago Super Missile": LocationData("Ridley Main", AP_MZM_ID_BASE + 61), + "Ridley After Sidehopper Hall Upper": LocationData("Central Ridley", AP_MZM_ID_BASE + 62), + "Ridley After Sidehopper Hall Lower": LocationData("Central Ridley", AP_MZM_ID_BASE + 63), + "Ridley Long Hall": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 64), + "Ridley Center Pillar": LocationData("Central Ridley", AP_MZM_ID_BASE + 65), #TODO Renamed + "Ridley Ball Room Lower": LocationData("Central Ridley", AP_MZM_ID_BASE + 66), #TODO Renamed + "Ridley Ball Room Upper": LocationData("Central Ridley", AP_MZM_ID_BASE + 67), #TODO Renamed + "Ridley Fake Lava Under Floor": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 68), #TODO Renamed + "Ridley Under Owls": LocationData("Central Ridley", AP_MZM_ID_BASE + 69), #TODO Renamed + "Ridley Northeast Corner": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 70), #TODO Renamed + "Ridley Bomb Puzzle": LocationData("Ridley Speed Puzzles", AP_MZM_ID_BASE + 71), + "Ridley Speed Jump": LocationData("Ridley Speed Puzzles", AP_MZM_ID_BASE + 72), + "Ridley": LocationData("Ridley Room", None) } tourian_location_table = { - "Tourian Left of Mother Brain": AP_MZM_ID_BASE + 73, - "Tourian Under Mother Brain": AP_MZM_ID_BASE + 74, - "Mother Brain": None + "Tourian Left of Mother Brain": LocationData("Tourian", AP_MZM_ID_BASE + 73), + "Tourian Under Mother Brain": LocationData("Tourian", AP_MZM_ID_BASE + 74), + "Mother Brain": LocationData("Tourian", None) } crateria_location_table = { - "Crateria Landing Site Ballspark": AP_MZM_ID_BASE + 75, - "Crateria Power Grip": AP_MZM_ID_BASE + 76, - "Crateria Moat": AP_MZM_ID_BASE + 77, - "Crateria Statue Water": AP_MZM_ID_BASE + 78, - "Crateria Plasma Beam/Unknown Item 1": AP_MZM_ID_BASE + 79, - "Crateria East Ballspark": AP_MZM_ID_BASE + 80, - "Crateria Northeast Corner": AP_MZM_ID_BASE + 81 + "Crateria Landing Site Ballspark": LocationData("Crateria", AP_MZM_ID_BASE + 75), + "Crateria Power Grip": LocationData("Upper Crateria", AP_MZM_ID_BASE + 76), + "Crateria Moat": LocationData("Crateria", AP_MZM_ID_BASE + 77), + "Crateria Statue Water": LocationData("Upper Crateria", AP_MZM_ID_BASE + 78), + "Crateria Unknown Item Statue": LocationData("Upper Crateria", AP_MZM_ID_BASE + 79), #TODO renamed + "Crateria East Ballspark": LocationData("Upper Crateria", AP_MZM_ID_BASE + 80), + "Crateria Northeast Corner": LocationData("Upper Crateria", AP_MZM_ID_BASE + 81) } chozodia_location_table = { - "Chozodia Upper Crateria Door": AP_MZM_ID_BASE + 82, - "Chozodia Bomb Maze": AP_MZM_ID_BASE + 83, - "Chozodia Zoomer Maze": AP_MZM_ID_BASE + 84, - "Chozodia Ruins Near Upper Crateria Door": AP_MZM_ID_BASE + 85, - "Chozodia Chozo Ghost Area Morph Tunnel Above Water": AP_MZM_ID_BASE + 86, - "Chozodia Chozo Ghost Area Underwater": AP_MZM_ID_BASE + 87, - "Chozodia Under Chozo Ghost Area Water": AP_MZM_ID_BASE + 88, - "Chozodia Glass Tube E-Tank": AP_MZM_ID_BASE + 89, - "Chozodia Lava Super": AP_MZM_ID_BASE + 90, - "Chozodia Original Power Bomb": AP_MZM_ID_BASE + 91, - "Chozodia Next to Original Power Bomb": AP_MZM_ID_BASE + 92, - "Chozodia Glass Tube Power Bomb": AP_MZM_ID_BASE + 93, - "Chozodia Chozo Ghost Area Long Shinespark": AP_MZM_ID_BASE + 94, - "Chozodia Shortcut Super": AP_MZM_ID_BASE + 95, - "Chozodia Workbot Super": AP_MZM_ID_BASE + 96, - "Chozodia Mothership Ceiling Near ZSS Start": AP_MZM_ID_BASE + 97, - "Chozodia Under Mecha Ridley Hallway": AP_MZM_ID_BASE + 98, - "Chozodia Southeast Corner In Hull": AP_MZM_ID_BASE + 99, - "Chozo Ghost": None, - "Mecha Ridley": None, - "Chozodia Space Pirate's Ship": None + "Chozodia Upper Crateria Door": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 82), + "Chozodia Bomb Maze": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 83), + "Chozodia Zoomer Maze": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 84), + "Chozodia Ruins East of Upper Crateria Door": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 85), #TODO renamed + "Chozodia Chozo Ghost Area Morph Tunnel Above Water": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 86), + "Chozodia Chozo Ghost Area Underwater": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 87), + "Chozodia Triple Crawling Pirates": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 88), #TODO renamed + "Chozodia West of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), #TODO renamed + "Chozodia Lava Dive": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 90), #TODO Renamed + "Chozodia Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 91), + "Chozodia Next to Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 92), + "Chozodia Southeast of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), #TODO Renamed + "Chozodia Chozo Ghost Area Long Shinespark": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 94), + "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), #TODO renamed + "Chozodia Behind Workbot": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 96), #TODO Renamed + "Chozodia Mothership Ceiling Near ZSS Start": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 97), + "Chozodia Under Mecha Ridley Hallway": LocationData("Chozodia Mecha Ridley Hallway", AP_MZM_ID_BASE + 98), + "Chozodia Southeast Corner In Hull": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 99), + "Chozo Ghost": LocationData("Chozodia Ruins Test Area", None), + "Mecha Ridley": LocationData("Chozodia Mecha Ridley Hallway", None), + "Chozodia Space Pirate's Ship": LocationData("Chozodia Mecha Ridley Hallway", None) } -full_location_table: dict[str, int] = { +full_location_table = { **brinstar_location_table, **kraid_location_table, **norfair_location_table, diff --git a/logic.py b/logic.py index 1914834..1a02d2b 100644 --- a/logic.py +++ b/logic.py @@ -1,5 +1,5 @@ """ -Functions used to describe Metroid: Zero Mission logic rules in rules.py +Functions used to describe Metroid: Zero Mission logic rules """ from __future__ import annotations @@ -9,8 +9,6 @@ from typing import TYPE_CHECKING, Any, Callable, NamedTuple from BaseClasses import CollectionState -from .options import MZMOptions - if TYPE_CHECKING: from . import MZMWorld @@ -49,6 +47,7 @@ def setting_atleast(cls, setting: str, value: int): def all(*args: Requirement): return Requirement(lambda world, state: builtins.all(req.rule(world, state) for req in args)) + def any(*args: Requirement): return Requirement(lambda world, state: builtins.any(req.rule(world, state) for req in args)) @@ -58,10 +57,12 @@ def any(*args: Requirement): MotherBrainBoss = Requirement.item("Mother Brain Defeated") ChozoGhostBoss = Requirement.item("Chozo Ghost Defeated") MechaRidleyBoss = Requirement.item("Mecha Ridley Defeated") +CanReachLocation = lambda n: Requirement.location(n) +CanReachEntrance = lambda n: Requirement.entrance(n) -UnknownItem1 = Requirement.location("Crateria Plasma Beam/Unknown Item 1") -UnknownItem2 = Requirement.location("Kraid Space Jump/Unknown Item 2") -UnknownItem3 = Requirement.location("Ridley Gravity Suit/Unknown Item 3") +UnknownItem1 = Requirement.location("Crateria Unknown Item Statue") +UnknownItem2 = Requirement.location("Kraid Unknown Item Statue") +UnknownItem3 = Requirement.location("Ridley Unknown Item Statue") CanUseUnknownItems = any( Requirement.setting_enabled("unknown_items_always_usable"), @@ -102,354 +103,732 @@ def any(*args: Requirement): SuperMissileTanks(1), ) MissileCount = lambda n: Requirement( + # TODO: account for Hard lambda world, state: - 5 * state.count("Missile Tank", world.player) + 2 * state.count("Super Missile Tank", world.player) - >= n + 5 * state.count("Missile Tank", world.player) + 2 * state.count("Super Missile Tank", world.player) >= n ) SuperMissiles = SuperMissileTanks(1) PowerBombs = PowerBombTanks(1) -PowerBombCount = lambda n: PowerBombTanks(n // 2) +PowerBombCount = lambda n: PowerBombTanks(n // 2) # TODO: account for Hard +# Various morph/bomb rules CanRegularBomb = all( MorphBall, - Bomb, -) -CanIBJ = all( - Requirement.setting_enabled("ibj_in_logic"), - CanRegularBomb, -) -CanHiJump = any( - HiJump, - SpaceJump, - CanIBJ, + Bomb ) -CanHjSjIbjOrGrip = any( # This name is even more cursed in Pascal case - CanHiJump, - PowerGrip, -) -CanWallJump = Requirement.setting_enabled("walljumps_in_logic") -CanTrickySparks = all( - lambda world, state: False, - SpeedBooster, -) - -CanBombBlock = all( +CanBombTunnelBlock = all( MorphBall, any( Bomb, PowerBombTanks(1), ), ) +CanSingleBombBlock = any( + CanBombTunnelBlock, + ScrewAttack +) CanBallCannon = CanRegularBomb CanBallspark = all( MorphBall, SpeedBooster, HiJump, ) - +CanBallJump = all( + MorphBall, + any( + Bomb, + HiJump + ) +) CanLongBeam = any( LongBeam, MissileCount(1), - CanBombBlock, + CanBombTunnelBlock, ) -CanTraverseHeat = VariaSuit +# Logic option rules +AdvancedLogic = Requirement.setting_atleast("logic_difficulty", 1) +CanIBJ = all( + Requirement.setting_atleast("ibj_in_logic", 1), + CanRegularBomb, +) +CanHorizontalIBJ = all( + CanIBJ, + Requirement.setting_atleast("ibj_in_logic", 2) +) +CanWallJump = Requirement.setting_atleast("walljumps_in_logic", 1) +#CanAdvancedWallJump = Requirement.setting_atleast("walljumps_in_logic", 2) #TODO +CanTrickySparks = all( + Requirement.setting_enabled("tricky_shinesparks"), + SpeedBooster, +) Hellrun = lambda n: all( Requirement.setting_enabled("heatruns_lavadives"), EnergyTanks(n), ) -# TODO: Add missing logic options -# TODO: Fine tune boss logic - -def _get_options(state: CollectionState, player: int) -> MZMOptions: - return state.multiworld.worlds[player].options - +# Miscellaneous rules +CanFly = any( # infinite vertical + CanIBJ, + SpaceJump +) +CanFlyWall = any( # infinite vertical with a usable wall + CanFly, + CanWallJump +) +CanVertical = any( # fka can_hj_sj_ibj_or_grip + HiJump, + PowerGrip, + CanFly +) +CanHiGrip = all( + HiJump, + PowerGrip +) +CanEnterHighMorphTunnel = any( + CanIBJ, + all( + MorphBall, + PowerGrip + ) +) +CanEnterMediumMorphTunnel = any( + CanEnterHighMorphTunnel, + all( + MorphBall, + HiJump + ) +) +# Kraid ziplines +Ziplines = CanReachEntrance("Kraid Main -> Acid Worm Area") +ChozodiaCombat = all( + any( + IceBeam, + PlasmaBeam + ), + EnergyTanks(4) +) -def has_missiles(state: CollectionState, player: int) -> bool: - return state.has_any({"Missile Tank", "Super Missile Tank"}, player) +# Regional connection requirements + +# brinstar main to past-hives, top to past-hives is different +def brinstar_past_hives(): + return all( + MorphBall, + Missiles, + any( + AdvancedLogic, + MissileCount(10), + SuperMissiles, + LongBeam, + IceBeam, + WaveBeam, + PlasmaBeam, + ScrewAttack + ) + ) -def has_missile_count(state: CollectionState, player: int, required_missiles: int) -> int: - # TODO: somehow account for Hard mode - missilecount = (state.count("Missile Tank", player) * 5) + (state.count("Super Missile Tank", player) * 2) - return missilecount >= required_missiles +def brinstar_main_to_brinstar_top(): + return any( + all( + CanSingleBombBlock, + CanBallJump + ), + all( + AdvancedLogic, + IceBeam, + CanWallJump, + PowerBombs + ) + ) -def has_super_missiles(state: CollectionState, player: int) -> bool: - return state.has("Super Missile Tank", player) +def brinstar_pasthives_to_brinstar_top(): + return all( + any( + CanFly, + all( + HiJump, + IceBeam, + CanWallJump + ) + ), + CanBallJump + ) -def has_power_bombs(state: CollectionState, player: int): - return state.has("Power Bomb Tank", player) +# this works for now. it's kind of tricky, cause all you need just to get there is PBs and bombs, +# but to actually do anything (including get to ship) you need IBJ/speed/sj. it only checks for speed +# for now since the only thing you'd potentially need this entrance for is Landing Site Ballspark +# (this assumption changes if/when entrance/elevator rando happens) +def brinstar_crateria_ballcannon(): + return all( + PowerBombs, + CanBallCannon, + CanVertical, + SpeedBooster + ) -def power_bomb_count(state: CollectionState, player: int, required_pbs: int): - pbcount = (state.count("Power Bomb Tank", player) * 2) - return pbcount >= required_pbs +# used for the items in this area as well as determining whether the ziplines can be activated +def kraid_upper_right(): + return all( + Missiles, + CanBallCannon, + any( + CanHorizontalIBJ, + PowerGrip, + all( + IceBeam, + CanBallJump + ) + ) + ) -def can_regular_bomb(state: CollectionState, player: int): - return state.has_all({"Morph Ball", "Bomb"}, player) +# access to lower kraid +def kraid_left_shaft_access(): + return all( + any( + CanHorizontalIBJ, + all( + PowerGrip, + HiJump + ) + ), + CanBallJump, + CanBombTunnelBlock, + any( + Ziplines, + SpaceJump, + all( + GravitySuit, + any( + CanTrickySparks, + CanIBJ + ) + ), + all( # Acid Worm Skip + AdvancedLogic, + PowerGrip + ) + ) + ) -# this may be different from can_regular_bomb later and also just reads easier in some rules -def can_ballcannon(state: CollectionState, player: int): - return state.has_all({"Morph Ball", "Bomb"}, player) +# TODO: double check this +def kraid_left_shaft_to_bottom(): + return any( + UnknownItem2, + CanReachEntrance("Lower Norfair -> Kraid") + ) -def can_bomb_block(state: CollectionState, player: int) -> bool: - return (state.has("Morph Ball", player) - and state.has_any({"Bomb", "Power Bomb Tank"}, player)) +def kraid_bottom_to_lower_norfair(): + return all( + ScrewAttack, + PowerBombs, + Missiles, + MorphBall + ) -# checked for ability to clear blocks that would require long beam to hit -def can_long_beam(state: CollectionState, player: int) -> bool: - return (state.has("Long Beam", player) - or has_missile_count(state, player, 3) - or can_bomb_block(state, player)) +def norfair_main_to_crateria(): + return all( + MorphBall, + any( + CanLongBeam, + CanBallspark + ) + ) -def can_hi_jump(state: CollectionState, player: int) -> bool: - return state.has("Hi-Jump", player) or can_space_jump(state, player) or can_ibj(state, player) +def norfair_right_shaft_access(): + return any( + CanVertical, + SpeedBooster + ) -# this particular combination is extremely common -def can_hj_sj_ibj_or_grip(state: CollectionState, player: int) -> bool: - return can_hi_jump(state, player) or state.has("Power Grip", player) +def norfair_upper_right_shaft(): + return any( + CanVertical, + IceBeam, + CanWallJump + ) -def can_ballspark(state: CollectionState, player: int) -> bool: - return state.has_all({"Morph Ball", "Hi-Jump", "Speed Booster"}, player) +# used for one item and the ridley shortcut +def norfair_behind_ice_beam(): + return all( + any( + CanLongBeam, + WaveBeam + ), + MorphBall, + any( + all( + PowerGrip, + any( + CanWallJump, + SpaceJump, + IceBeam + ) + ), + CanIBJ, + all( + IceBeam, + HiJump + ) + ) + ) -def can_space_jump(state: CollectionState, player: int) -> bool: - return (state.has("Space Jump", player) - and (state.has("Chozo Ghost Defeated", player) - or _get_options(state, player).unknown_items_always_usable.value) +def norfair_behind_ice_to_bottom(): + return all( + Missiles, + CanBombTunnelBlock, + any( + PowerGrip, + CanHorizontalIBJ, + all( + IceBeam, + CanBallJump + ) + ), + any( + all( + AdvancedLogic, + PowerBombs, + HiJump + ), + all( + PowerGrip, + any( + CanWallJump, + SpaceJump + ) ) + ) + ) -def can_traverse_heat(state: CollectionState, player: int) -> bool: - return state.has("Varia Suit", player) +def norfair_lower_right_shaft(): + return any( + ScrewAttack, + all( + SpeedBooster, + CanBallCannon + ) + ) -def can_gravity_suit(state: CollectionState, player: int) -> bool: - return (state.has("Gravity Suit", player) - and (state.has("Chozo Ghost Defeated", player) - or _get_options(state, player).unknown_items_always_usable.value) +def norfair_lower_right_shaft_to_lower_norfair(): + return all( + Missiles, + CanBombTunnelBlock, + any( + SpaceJump, + CanWallJump, + all( + Bomb, + any( + PowerGrip, + CanHorizontalIBJ, + all( + AdvancedLogic, + SuperMissiles, + IceBeam + ) + ) + ), + ), + any( + VariaSuit, + Hellrun(6) + ), + any( + SpaceJump, + CanHorizontalIBJ, + all( + CanSingleBombBlock, + SpeedBooster ) + ) + ) -# currently used for both heated rooms AND lava dives -def hellrun(state: CollectionState, player: int, required_etanks: int) -> bool: - return (_get_options(state, player).heatruns_lavadives.value - and (state.count("Energy Tank", player) >= required_etanks)) +def lower_norfair_to_screwattack(): + return any( + CanTrickySparks, + all( + ScrewAttack, + any( + CanWallJump, + SpaceJump + ) + ), + all( + MissileCount(5), + any( + CanFlyWall, + all( + AdvancedLogic, + IceBeam, + HiJump + ) + ) + ) + ) -def can_ibj(state: CollectionState, player: int) -> bool: - return _get_options(state, player).ibj_in_logic.value and can_regular_bomb(state, player) +def lower_norfair_to_kraid(): + return all( + ScrewAttack, + PowerBombs, + Missiles, + any( + CanIBJ, + PowerGrip, + all( + HiJump, + IceBeam + ), + all( + CanTrickySparks, + CanBallspark + ) + ) + ) -def can_walljump(state: CollectionState, player: int) -> bool: - return _get_options(state, player).walljumps_in_logic.value +# The two items in Lower Norfair behind the Super Missile door right under the Screw Attack area +def lower_norfair_to_spaceboost_room(): + return all( + SuperMissiles, + any( + SpeedBooster, + Bomb, + PowerBombCount(2), + all( + WaveBeam, + LongBeam, + any( + PowerGrip, + all( + GravitySuit, + HiJump + ) + ) + ) + ), + CanVertical + ) -def can_tricky_sparks(state: CollectionState, player: int) -> bool: - return False and state.has("Speed Booster", player) # TODO: add option +def lower_norfair_to_bottom_norfair(): + return all( + MissileCount(2), + SpeedBooster, + any( + WaveBeam, + CanTrickySparks + ), + CanEnterMediumMorphTunnel + ) -def brinstar_past_hives(state: CollectionState, player: int) -> bool: - return (state.has("Morph Ball", player) - and (has_missile_count(state, player, 10) - or state.has("Super Missile Tank", player) - or state.has_any({"Long Beam", "Ice Beam", "Wave Beam", "Plasma Beam", "Screw Attack"}, player))) +def bottom_norfair_to_ridley(): + return any( + all( + MissileCount(6), # Covers the case where you only have Supers; 1 normal missile is enough from drops + any( + IceBeam, + AdvancedLogic + ) + ), + PowerBombs + ) -# used for the items in this area as well as determining whether the ziplines can be activated -# it's technically possible to do the climb after ballcannon with just hi-jump using tight morph jumps -# TODO: add solo hi-jump logic once an option for advanced tricks is added -def kraid_upper_right(state: CollectionState, player: int) -> bool: - return (has_missiles(state, player) - and can_ballcannon(state, player) - and (can_ibj(state, player) - or can_walljump(state, player) - or can_space_jump(state, player) - or state.has("Power Grip", player)) - ) and (can_ibj(state, player) - or state.has("Power Grip", player) - or (state.has_all({"Ice Beam", "Hi-Jump"}, player))) - - -# access to lower kraid via left shaft -# TODO: add logic for acid worm skip -def kraid_left_shaft_access(state: CollectionState, player: int) -> bool: - return ((can_ibj(state, player) or state.has_any({"Power Grip", "Hi-Jump"}, player)) - and can_bomb_block(state, player) - and (can_regular_bomb(state, player) or state.has("Hi-Jump", player)) - and (kraid_upper_right(state, player) - or can_space_jump(state, player) - or (can_gravity_suit(state, player) and can_tricky_sparks(state, player)) - ) +# LN elevator to the bottom long hall +# connects to right shaft with no extra req's +# this happens to cover the reqs for left pillar, fake floor, long room, and the ability to get to right shaft +def ridley_main_to_left_shaft(): + return all( + SuperMissiles, + any( + CanVertical, + CanWallJump, + IceBeam + ), + any( + VariaSuit, + Hellrun(1), + all( + CanFly, + CanBombTunnelBlock ) + ), + MorphBall + ) -def norfair_right_shaft_access(state: CollectionState, player: int) -> bool: - return can_hj_sj_ibj_or_grip(state, player) or state.has("Speed Booster", player) +# shortcut to the right of elevator +def ridley_main_to_right_shaft(): + return all( + Missiles, + any( + CanIBJ, + all( + PowerGrip, + CanBombTunnelBlock, + any( + SpaceJump, + HiJump, + IceBeam + ) + ) + ) + ) -def norfair_upper_right_shaft(state: CollectionState, player: int) -> bool: - return (norfair_right_shaft_access(state, player) - and (can_hj_sj_ibj_or_grip(state, player) - or state.has("Ice Beam", player) - or can_walljump(state, player)) +def ridley_left_shaft_to_sw_puzzle(): + return all( + SpeedBooster, + any( + PowerGrip, + SpaceJump + ), + any( + PowerGrip, + PowerBombs, + all( + LongBeam, + WaveBeam ) + ) + ) -# used for one item and the ridley shortcut -def norfair_behind_ice_beam(state: CollectionState, player: int) -> bool: - return (norfair_upper_right_shaft(state, player) - and (can_long_beam(state, player) or state.has("Wave Beam", player)) - and ((state.has("Ice Beam", player) and state.has_any({"Hi-Jump", "Power Grip"}, - player)) # to get up the rippers - or can_ibj(state, player) - or (can_walljump(state, player) and state.has("Power Grip", player))) - ) +def ridley_speed_puzzles_access(): + return all( + SpeedBooster, + any( + CanVertical, + IceBeam + ) + ) -def norfair_lower_right_shaft(state: CollectionState, player: int) -> bool: - return (norfair_right_shaft_access(state, player) - and (state.has("Screw Attack", player) - or (state.has("Speed Booster", player) and can_ballcannon(state, player))) +# getting into the gap at the start of "ball room" and subsequently into the general area of ridley himself +def ridley_right_shaft_to_central(): + return CanEnterMediumMorphTunnel + + +# Ridley, Unknown 3, and the item behind Unknown 3 +def ridley_central_to_ridley_room(): + return all( + MissileCount(40), + EnergyTanks(3), + any( + CanFly, + all( + IceBeam, + CanHiGrip ) + ) + ) -def norfair_to_save_behind_hijump(state: CollectionState, player: int) -> bool: - return (norfair_lower_right_shaft(state, player) - and has_missiles(state, player) - and can_bomb_block(state, player) - and (can_ibj(state, player) - or (has_power_bombs(state, player) and state.has("Hi-Jump", player)) - or (state.has("Bomb", player) and state.has_any({"Hi-Jump", "Power Grip"}, player)) - ) - and (can_hj_sj_ibj_or_grip(state, player) or can_walljump(state, player) - or state.has("Ice Beam", player)) - and (can_traverse_heat(state, player) - or hellrun(state, player, 6)) - and (can_ibj(state, player) - or can_space_jump(state, player) - or (state.has("Speed Booster", player) - and (can_bomb_block(state, player) or state.has("Screw Attack", player)) - ) - ) - ) +# Getting to Unknown 1 and everything above +def crateria_main_to_crateria_upper(): + return CanBallJump + + +# Upper Crateria door to Ruins, the two items right by it, and the Triple Crawling Pirates +def crateria_upper_to_chozo_ruins(): + return all( + PowerBombs, + MorphBall, + Missiles, + any( + CanFly, + CanReachLocation("Crateria Northeast Corner") + ), + any( + MotherBrainBoss, + Requirement.setting_is("chozodia_access", 0) + ) + ) +# Ruins to Chozo Ghost, the three items in that general area, and the lava dive item +def chozo_ruins_to_ruins_test(): + return all( + MorphBall, + PowerBombs, + any( + Bomb, + PowerBombCount(2) + ), + any( + AdvancedLogic, + ChozodiaCombat + ), + any( # Required to exit the Ruins Test + all( + AdvancedLogic, + CanHiGrip, + CanWallJump + ), + CanIBJ, + Requirement.item("Space Jump") # Need SJ to escape, but it doesn't need to be active yet + ), + CanEnterMediumMorphTunnel # Required to exit the Ruins Test + ) -def norfair_shortcut(state: CollectionState, player: int) -> bool: - return (norfair_behind_ice_beam(state, player) - and has_missiles(state, player) - and (can_ibj(state, player) - or (state.has("Power Grip", player) - and (can_space_jump(state, player) or can_walljump(state, player)) - and can_bomb_block(state, player))) - ) +def chozo_ruins_to_chozodia_tube(): + return any( + all( # Getting up to the tube is doable with just walljumps but tricky enough to be advanced imo + AdvancedLogic, + CanWallJump + ), + CanFly + ) -def norfair_bottom_right_shaft(state: CollectionState, player: int) -> bool: - return ((norfair_to_save_behind_hijump(state, player) - and has_missile_count(state, player, 4) - and state.has_all({"Wave Beam", "Speed Booster"}, player) - ) - or (norfair_shortcut(state, player))) +# Relevant for region/elevator rando +def chozodia_tube_to_chozo_ruins(): + return all( + any( + CanFlyWall, + CanHiGrip + ), + CanBombTunnelBlock + ) -def ridley_left_shaft_access(state: CollectionState, player: int) -> bool: - return (has_super_missiles(state, player) - and (can_hj_sj_ibj_or_grip(state, player) or can_walljump(state, player) - or state.has("Ice Beam", player) or can_bomb_block(state, player)) - and (can_traverse_heat(state, player) or hellrun(state, player, 1) - or (can_space_jump(state, player) and can_bomb_block(state, player))) - ) +def crateria_to_under_tube(): + return all( + PowerBombs, + MorphBall, + any( # To get to the save station and warp out + SpeedBooster, + CanFlyWall, + CanHiGrip + ), + any( + MotherBrainBoss, + Requirement.setting_is("chozodia_access", 0) + ) + ) -# going the "intended" way, to the left of the elevator, down, and back to the right to get to the right shaft -def ridley_longway_right_shaft_access(state: CollectionState, player: int) -> bool: - return (ridley_left_shaft_access(state, player) - and (state.has("Power Grip", player) - and (can_hj_sj_ibj_or_grip(state, player) or can_walljump(state, player))) - ) +def under_tube_to_tube(): + return any( + SpeedBooster, + all( + CanFly, + PowerBombs, + ChozoGhostBoss # Change if basepatch makes the tube breakable before Charlie + ) + ) -# taking the shortcut, to the right of the elevator and up the hole -def ridley_shortcut_right_shaft_access(state: CollectionState, player: int) -> bool: - return (has_missiles(state, player) - and (can_ibj(state, player) - or (state.has("Power Grip", player) - and can_bomb_block(state, player) - and (state.has_any({"Ice Beam", "Hi-Jump"}, player) - or can_space_jump(state, player))) - ) - ) +def under_tube_to_crateria(): + return any( + CanIBJ, + all( + PowerGrip, + CanFlyWall + ), + all( + CanTrickySparks, + CanBallspark + ) + ) -# getting into the gap at the start of "ball room" and subsequently into the general area of ridley himself -def ridley_central_access(state: CollectionState, player: int) -> bool: - return ( - (ridley_shortcut_right_shaft_access(state, player) or ridley_longway_right_shaft_access(state, player)) - and (can_ibj(state, player) or state.has_any({"Hi-Jump", "Power Grip"}, player)) - ) - - -# ice/plasma beam makes dealing with the pirates a ton easier. etanks keeps you from needing to go too deep before you have -# a decent chance to survive. the rest is the strictest requirement to get in and back out of the chozo ghost area -def chozodia_ghost_from_upper_crateria_door(state: CollectionState, player: int) -> bool: - return ( - state.has_any({"Ice Beam", "Plasma Beam"}, player) and (state.count("Energy Tank", player) >= 4) - and has_missiles(state, player) - and (can_walljump(state, player) or can_ibj(state, player) - or can_space_jump(state, player)) - and state.count("Power Bomb Tank", player) >= 2 - ) - - -def chozodia_glass_tube_from_crateria_door(state: CollectionState, player: int) -> bool: - return ( - # from upper door - (state.has_any({"Ice Beam", "Plasma Beam"}, player) - and state.count("Energy Tank", player) >= 2 - and has_missiles(state, player) - and has_power_bombs(state, player) - and (can_space_jump(state, player) or can_ibj(state, player))) - # from lower door - or (state.has_any({"Ice Beam", "Plasma Beam"}, player) - and state.count("Energy Tank", player) >= 2 - and (can_ibj(state, player) - or can_space_jump(state, player) - or has_power_bombs(state, player) - ) - and has_missile_count(state, player, 6) - and has_power_bombs(state, player) - ) +def tube_to_under_tube(): + return all( + ChozoGhostBoss, + PowerBombs ) -# from the ruins to the save station next to the big room with all the tripwires -def chozodia_tube_to_mothership_central(state: CollectionState, player: int) -> bool: - return (chozodia_glass_tube_from_crateria_door(state, player) - and state.count("Energy Tank", player) >= 6 - and (can_ibj(state, player) - or can_space_jump(state, player) - or (state.has("Hi-Jump", player) - and (can_walljump(state, player) or state.has("Power Grip", player))) - ) +def chozodia_tube_to_mothership_central(): + return all( + any( + AdvancedLogic, + ChozodiaCombat + ), + any( + CanFly, + all( + CanWallJump, + HiJump ) + ) + ) -def chozodia_to_cockpit(state: CollectionState, player: int) -> bool: - return (chozodia_tube_to_mothership_central(state, player) - and (can_space_jump(state, player) - or can_ibj(state, player) - or (can_walljump(state, player) and state.has("Hi-Jump", player)) +def mothership_central_to_cockpit(): + return all( + any( + Bomb, + PowerBombCount(2) + ), + any( + ScrewAttack, + MissileCount(5) + ), + any( + SuperMissiles, + PowerGrip, + CanFly + ), + any( + AdvancedLogic, + EnergyTanks(6) + ) + ) + + +# From cockpit to Mecha Ridley hallway +# This one stupid room is so randomly complicated lol +def cockpit_to_mecha_ridley(): + return all( + CanBombTunnelBlock, + any( + CanIBJ, + PowerGrip, + all( + AdvancedLogic, + IceBeam, + HiJump ) - and (state.has("Bomb", player) or state.count("Power Bomb Tank", player) >= 2) + ), + CanBallJump, + any( + PowerBombCount(2), + all( + Bomb, + PowerBombs + ), + all( + AdvancedLogic, + any( + CanIBJ, + all( + PowerGrip, + any( + HiJump, + SpaceJump, + CanWallJump + ) + ) + ) ) + ) + ) diff --git a/regions.py b/regions.py index 49cbe75..25cebd1 100644 --- a/regions.py +++ b/regions.py @@ -1,94 +1,119 @@ from __future__ import annotations -from typing import TYPE_CHECKING -from BaseClasses import Region -from .locations import (brinstar_location_table, kraid_location_table, norfair_location_table, - ridley_location_table, tourian_location_table, crateria_location_table, - chozodia_location_table, MZMLocation) -from . import logic +from typing import TYPE_CHECKING, Dict, List, Optional +from BaseClasses import Region, Location, MultiWorld +from .logic import * +from .locations import full_location_table if TYPE_CHECKING: from . import MZMWorld -# TODO: Split regions up into sub-regions based on shared-access logic rules +def create_region(world: MultiWorld, player: int, region_name: str): + region = Region(region_name, player, world) -def create_regions(world: MZMWorld): - # create all regions and populate with locations - menu = Region("Menu", world.player, world.multiworld) - world.multiworld.regions.append(menu) - - brinstar = Region("Brinstar", world.player, world.multiworld) - brinstar.add_locations(brinstar_location_table, MZMLocation) - world.multiworld.regions.append(brinstar) - - kraid = Region("Kraid", world.player, world.multiworld) - kraid.add_locations(kraid_location_table, MZMLocation) - world.multiworld.regions.append(kraid) - - norfair = Region("Norfair", world.player, world.multiworld) - norfair.add_locations(norfair_location_table, MZMLocation) - world.multiworld.regions.append(norfair) - - ridley = Region("Ridley", world.player, world.multiworld) - ridley.add_locations(ridley_location_table, MZMLocation) - world.multiworld.regions.append(ridley) - - tourian = Region("Tourian", world.player, world.multiworld) - tourian.add_locations(tourian_location_table, MZMLocation) - world.multiworld.regions.append(tourian) - - crateria = Region("Crateria", world.player, world.multiworld) - crateria.add_locations(crateria_location_table, MZMLocation) - world.multiworld.regions.append(crateria) + for location_name, location_data in full_location_table.items(): + if location_data.region == region_name: + location = Location(player, location_name, location_data.code, region) + region.locations.append(location) - chozodia = Region("Chozodia", world.player, world.multiworld) - chozodia.add_locations(chozodia_location_table, MZMLocation) - world.multiworld.regions.append(chozodia) + world.regions.append(region) - mission_complete = Region("Mission Complete", world.player, world.multiworld) - world.multiworld.regions.append(mission_complete) - menu.connect(brinstar) +def connect(world: MultiWorld, player: int, entrance_name: str, source: str, target: str, + rule: Optional[Requirement] = None): - brinstar.connect(norfair, "Brinstar-Norfair elevator", - lambda state: logic.can_bomb_block(state, world.player)) + source_region = world.get_region(source, player) + target_region = world.get_region(target, player) + source_region.connect(target_region, entrance_name, rule) - brinstar.connect(kraid, "Brinstar-Kraid elevator", - lambda state: logic.can_bomb_block(state, world.player) or state.has("Screw Attack", world.player)) - # this works for now. it's kind of tricky, cause all you need just to get there is PBs and bombs, - # but to actually do anything (including get to ship) you need IBJ/speed/sj. it only checks for speed - # since the only thing you'd potentially need this entrance for is Landing Site Ballspark - brinstar.connect(crateria, "Brinstar-Crateria ball cannon", lambda state: ( - logic.has_power_bombs(state, world.player) - and logic.can_ballcannon(state, world.player) - and logic.can_hj_sj_ibj_or_grip(state, world.player) - and state.has("Speed Booster", world.player) - )) - - brinstar.connect(tourian, "Brinstar-Tourian elevator", - lambda state: state.has_all({"Kraid Defeated", "Ridley Defeated"}, world.player)) - - norfair.connect(crateria, "Norfair-Crateria elevator", - lambda state: logic.can_long_beam(state, world.player)) - - norfair.connect(ridley, "Norfair-Ridley elevator", lambda state: ( - ((logic.norfair_to_save_behind_hijump(state, world.player) - and logic.has_missile_count(state, world.player, 4) - and state.has_all({"Wave Beam", "Speed Booster"}, world.player) - ) - or logic.norfair_shortcut(state, world.player)) - and (logic.has_missile_count(state, world.player, 6) - or logic.has_power_bombs(state, world.player)) - )) - - crateria.connect(chozodia, "Crateria-Chozodia Upper Door", lambda state: ( - logic.has_power_bombs(state, world.player) - and (logic.can_ibj(state, world.player) - or logic.can_space_jump(state, world.player) - or (state.has("Speed Booster", world.player) and logic.can_walljump(state, world.player))) - and (state.has("Mother Brain Defeated", world.player) or not world.options.chozodia_access.value))) - - crateria.connect(chozodia, "Crateria-Chozodia Lower Door", lambda state: ( - logic.has_power_bombs(state, world.player) - and (state.has("Mother Brain Defeated", world.player) or not world.options.chozodia_access.value))) +def create_regions_and_connections(world: MZMWorld): + # create all regions and populate with locations + player = world.player + multiworld = world.multiworld + + create_region(multiworld, player, "Menu") + create_region(multiworld, player, "Brinstar Start") + create_region(multiworld, player, "Brinstar Main") + create_region(multiworld, player, "Brinstar Top") + create_region(multiworld, player, "Brinstar Past Hives") + create_region(multiworld, player, "Kraid Main") + create_region(multiworld, player, "Kraid Acid Worm Area") + create_region(multiworld, player, "Kraid Left Shaft") + create_region(multiworld, player, "Kraid Bottom") + create_region(multiworld, player, "Norfair Main") + create_region(multiworld, player, "Norfair Right Shaft") + create_region(multiworld, player, "Norfair Upper Right Shaft") + create_region(multiworld, player, "Norfair Behind Ice Beam") + create_region(multiworld, player, "Norfair Lower Right Shaft") + create_region(multiworld, player, "Lower Norfair") + create_region(multiworld, player, "Norfair Screw Attack Area") + create_region(multiworld, player, "Norfair Behind Super Door") + create_region(multiworld, player, "Norfair Bottom") + create_region(multiworld, player, "Ridley Main") + create_region(multiworld, player, "Ridley Left Shaft") + create_region(multiworld, player, "Ridley SW Puzzle") + create_region(multiworld, player, "Ridley Right Shaft") + create_region(multiworld, player, "Ridley Speed Puzzles") + create_region(multiworld, player, "Central Ridley") + create_region(multiworld, player, "Ridley Room") + create_region(multiworld, player, "Tourian") + create_region(multiworld, player, "Crateria") + create_region(multiworld, player, "Upper Crateria") + create_region(multiworld, player, "Chozodia Ruins") + create_region(multiworld, player, "Chozodia Ruins Test Area") + create_region(multiworld, player, "Chozodia Glass Tube") + create_region(multiworld, player, "Chozodia Under Tube") + create_region(multiworld, player, "Chozodia Mothership Central") + create_region(multiworld, player, "Chozodia Mothership Cockpit") + create_region(multiworld, player, "Chozodia Mecha Ridley Hallway") + create_region(multiworld, player, "Mission Accomplished!") + + connect(multiworld, player, "Game Start", "Menu", "Brinstar Start") + connect(multiworld, player, "Brinstar Start -> Main Shaft", "Brinstar Start", "Brinstar Main", MorphBall.create_rule(world)) + connect(multiworld, player, "Brinstar Main -> Brinstar Top", "Brinstar Main", "Brinstar Top", brinstar_main_to_brinstar_top().create_rule(world)) + connect(multiworld, player, "Brinstar Main -> Past Hives", "Brinstar Main", "Brinstar Past Hives", brinstar_past_hives().create_rule(world)) + connect(multiworld, player, "Brinstar Past Hives -> Top", "Brinstar Past Hives", "Brinstar Top", brinstar_pasthives_to_brinstar_top().create_rule(world)) + connect(multiworld, player, "Brinstar Top -> Past Hives", "Brinstar Top", "Brinstar Past Hives", CanEnterMediumMorphTunnel.create_rule(world)) + connect(multiworld, player, "Brinstar -> Kraid Elevator", "Brinstar Start", "Kraid Main", CanSingleBombBlock.create_rule(world)) + #TODO: account for layout patches in Brinstar -> Norfair elevator + connect(multiworld, player, "Brinstar -> Norfair Elevator", "Brinstar Main", "Norfair Main", CanBombTunnelBlock.create_rule(world)) + connect(multiworld, player, "Brinstar -> Tourian Elevator", "Brinstar Main", "Tourian", all(MorphBall, KraidBoss, RidleyBoss).create_rule(world)) + connect(multiworld, player, "Brinstar -> Crateria Ballcannon", "Brinstar Start", "Upper Crateria", brinstar_crateria_ballcannon().create_rule(world)) + connect(multiworld, player, "Kraid Main -> Acid Worm Area", "Kraid Main", "Kraid Acid Worm Area", kraid_upper_right().create_rule(world)) + connect(multiworld, player, "Kraid Main -> Left Shaft", "Kraid Main", "Kraid Left Shaft", kraid_left_shaft_access().create_rule(world)) + connect(multiworld, player, "Kraid Left Shaft -> Bottom", "Kraid Left Shaft", "Kraid Bottom", kraid_left_shaft_to_bottom().create_rule(world)) + connect(multiworld, player, "Kraid -> Lower Norfair Shortcut", "Kraid Bottom", "Lower Norfair", kraid_bottom_to_lower_norfair().create_rule(world)) + connect(multiworld, player, "Norfair -> Crateria Elevator", "Norfair Main", "Crateria", norfair_main_to_crateria().create_rule(world)) + connect(multiworld, player, "Norfair Elevator -> Right Shaft", "Norfair Main", "Norfair Right Shaft", norfair_right_shaft_access().create_rule(world)) + connect(multiworld, player, "Norfair Right Shaft -> Upper", "Norfair Right Shaft", "Norfair Upper Right Shaft", norfair_upper_right_shaft().create_rule(world)) + connect(multiworld, player, "Norfair Upper Right -> Behind Ice Beam", "Norfair Upper Right Shaft", "Norfair Behind Ice Beam", norfair_behind_ice_beam().create_rule(world)) + connect(multiworld, player, "Norfair Ridley Shortcut", "Norfair Behind Ice Beam", "Norfair Bottom", norfair_behind_ice_to_bottom().create_rule(world)) + connect(multiworld, player, "Norfair Right Shaft -> Lower Shaft", "Norfair Right Shaft", "Norfair Lower Right Shaft", norfair_lower_right_shaft().create_rule(world)) + connect(multiworld, player, "Norfair Right Shaft -> Lower Norfair", "Norfair Lower Right Shaft", "Lower Norfair", norfair_lower_right_shaft_to_lower_norfair().create_rule(world)) + connect(multiworld, player, "Lower Norfair -> Screw Attack", "Lower Norfair", "Norfair Screw Attack Area", lower_norfair_to_screwattack().create_rule(world)) + connect(multiworld, player, "Lower Norfair -> Behind Super Missile Door", "Lower Norfair", "Norfair Behind Super Door", lower_norfair_to_spaceboost_room().create_rule(world)) + connect(multiworld, player, "Lower Norfair -> Kraid", "Lower Norfair", "Kraid Bottom", lower_norfair_to_kraid().create_rule(world)) + connect(multiworld, player, "Lower Norfair -> Bottom", "Lower Norfair", "Norfair Bottom", lower_norfair_to_bottom_norfair().create_rule(world)) + connect(multiworld, player, "Norfair -> Ridley Elevator", "Norfair Bottom", "Ridley Main", bottom_norfair_to_ridley().create_rule(world)) + connect(multiworld, player, "Ridley Elevator -> Left Shaft", "Ridley Main", "Ridley Left Shaft", ridley_main_to_left_shaft().create_rule(world)) + connect(multiworld, player, "Ridley Elevator -> Right Shaft Shortcut", "Ridley Main", "Ridley Right Shaft", ridley_main_to_right_shaft().create_rule(world)) + connect(multiworld, player, "Ridley Left Shaft -> SW Puzzle", "Ridley Left Shaft", "Ridley SW Puzzle", ridley_left_shaft_to_sw_puzzle().create_rule(world)) + connect(multiworld, player, "Ridley Left Shaft -> Right Shaft", "Ridley Left Shaft", "Ridley Right Shaft") + connect(multiworld, player, "Ridley Right Shaft -> Speed Puzzles", "Ridley Right Shaft", "Ridley Speed Puzzles", ridley_speed_puzzles_access().create_rule(world)) + connect(multiworld, player, "Ridley Right Shaft -> Central", "Ridley Right Shaft", "Central Ridley", ridley_right_shaft_to_central().create_rule(world)) + connect(multiworld, player, "Ridley Central -> Ridley's Room", "Central Ridley", "Ridley Room", ridley_central_to_ridley_room().create_rule(world)) + connect(multiworld, player, "Tourian Escape -> Chozodia", "Tourian", "Chozodia Ruins Test Area", MotherBrainBoss.create_rule(world)) + connect(multiworld, player, "Crateria -> Upper", "Crateria", "Upper Crateria", crateria_main_to_crateria_upper().create_rule(world)) + connect(multiworld, player, "Crateria -> Chozodia Lower Door", "Crateria", "Chozodia Under Tube", crateria_to_under_tube().create_rule(world)) + connect(multiworld, player, "Crateria -> Chozodia Upper Door", "Upper Crateria", "Chozodia Ruins", crateria_upper_to_chozo_ruins().create_rule(world)) + connect(multiworld, player, "Chozo Ruins -> Chozo Ruins Test", "Chozodia Ruins", "Chozodia Ruins Test Area", chozo_ruins_to_ruins_test().create_rule(world)) + connect(multiworld, player, "Chozo Ruins Test -> Chozo Ruins", "Chozodia Ruins Test Area", "Chozodia Ruins", ChozoGhostBoss.create_rule(world)) + connect(multiworld, player, "Chozo Ruins -> Glass Tube", "Chozodia Ruins", "Chozodia Glass Tube", chozo_ruins_to_chozodia_tube().create_rule(world)) + connect(multiworld, player, "Chozodia Under Tube -> Crateria", "Chozodia Under Tube", "Crateria", under_tube_to_crateria().create_rule(world)) + connect(multiworld, player, "Chozodia Under Tube -> Glass Tube", "Chozodia Under Tube", "Chozodia Glass Tube", under_tube_to_tube().create_rule(world)) + connect(multiworld, player, "Chozodia Glass Tube -> Under Tube", "Chozodia Glass Tube", "Chozodia Under Tube", tube_to_under_tube().create_rule(world)) + connect(multiworld, player, "Chozodia Glass Tube -> Chozo Ruins", "Chozodia Glass Tube", "Chozodia Ruins", chozodia_tube_to_chozo_ruins().create_rule(world)) + connect(multiworld, player, "Chozozia Glass Tube -> Mothership Central", "Chozodia Glass Tube", "Chozodia Mothership Central", chozodia_tube_to_mothership_central().create_rule(world)) + connect(multiworld, player, "Chozodia Mothership -> Cockpit", "Chozodia Mothership Central", "Chozodia Mothership Cockpit", mothership_central_to_cockpit().create_rule(world)) + connect(multiworld, player, "Chozodia Cockpit -> Mecha Ridley", "Chozodia Mothership Cockpit", "Chozodia Mecha Ridley Hallway", cockpit_to_mecha_ridley().create_rule(world)) diff --git a/rules.py b/rules.py index 8299598..6baf1c9 100644 --- a/rules.py +++ b/rules.py @@ -6,610 +6,810 @@ from __future__ import annotations from typing import TYPE_CHECKING -from worlds.generic.Rules import add_rule -from . import logic from .logic import * +from worlds.generic.Rules import add_rule if TYPE_CHECKING: from . import MZMWorld -# Logic pass 1. Probably scuffed in edge cases but it seems to work. -# TODO: prep for potential elevator/start rando by re-writing logic to not assume vanilla regional access rules -def set_rules(world: MZMWorld, locations): - player = world.player +brinstar_start = { + "Brinstar Morph Ball": None, + "Brinstar Morph Ball Cannon": CanBallCannon, + "Brinstar Ceiling E-Tank": any( + all( + IceBeam, + RidleyBoss + ), + CanFly, + all( + MorphBall, + CanTrickySparks + ) + ), + } + +brinstar_main = { + "Brinstar Long Beam": all( + MorphBall, + any( + CanLongBeam, + LayoutPatches, + ) + ), + "Brinstar Main Shaft Left Alcove": all( + CanSingleBombBlock, + any( + CanFlyWall, + IceBeam, + CanHiGrip + ) + ), + "Brinstar Ballspark": CanBallspark, + "Brinstar Ripper Climb": any( + all( + CanEnterHighMorphTunnel, + any( + IceBeam, + CanFlyWall + ) + ), + CanIBJ, + all( + CanBallspark, + CanTrickySparks + ) + ), + "Brinstar Speed Booster Shortcut": all( + any( + CanBallspark, + AdvancedLogic + ), + CanBombTunnelBlock, + any( + CanVertical, + CanWallJump + ) + ), + "Brinstar Worm drop": all( + MorphBall, + Missiles + ), + "Brinstar First Missile": MorphBall, + "Brinstar Behind Hive": all( + MorphBall, + Missiles), + "Brinstar Under Bridge": all( + Missiles, + CanSingleBombBlock + ), + } + +brinstar_top = { + "Brinstar Varia Suit": all( + any( + CanFly, + CanHiGrip, + CanTrickySparks + ), + CanBallJump, + any( + CanIBJ, + PowerGrip, + all( + HiJump, + any( + CanWallJump, + GravitySuit + ) + ) + ), + CanBombTunnelBlock + ), + "Brinstar Acid near Varia": all( + any( + CanFly, + CanHiGrip + ), + CanBallJump, + CanLongBeam, + any( + VariaSuit, + GravitySuit, + Hellrun(2), + ) + ), + "Brinstar Upper Pillar": None + } + +brinstar_pasthives = { + "Brinstar Post-Hive In Wall": None, + "Brinstar Behind Bombs": all( + CanBombTunnelBlock, + CanBallJump + ), + "Brinstar Bomb": None, + "Brinstar Post-Hive Pillar": None + } + + +kraid_main = { + "Kraid Save Room Tunnel": CanBombTunnelBlock, + "Kraid Zipline Morph Jump": all( + Ziplines, + CanBallJump + ), + "Kraid Acid Ballspark": all( + any( + CanIBJ, + HiJump, + PowerGrip + ), + CanBombTunnelBlock, + CanBallJump, + GravitySuit, + CanBallspark + ), + "Kraid Right Hall Pillar": Missiles, + "Kraid Speed Jump": all( + Missiles, + SpeedBooster + ), + "Kraid Upper Right Morph Ball Cannon": all( + Missiles, + CanBallCannon + ) + } + +kraid_acidworm_area = { + "Kraid Under Acid Worm": all( + MissileCount(20), + CanSingleBombBlock, + any( + CanVertical, + CanWallJump + ) + ), + "Kraid Zipline Activator Room": None + } + +# past acid worm skip +kraid_left_shaft = { + "Kraid Behind Giant Hoppers": CanEnterHighMorphTunnel, + "Kraid Quad Ball Cannon Room": all( + CanBombTunnelBlock, + Ziplines, + Missiles + ), # there are some other seriously degen ways too + "Kraid Unknown Item Statue": all( + any( + Bomb, + PowerBombCount(2) + ), + any( + PowerGrip, + HiJump, + CanIBJ, + all( + IceBeam, + Bomb + ) + ), + Missiles # required for escape - covers both cases of only hijump or only grip + ) + } + +# req either unknown 2 or norfair backdoor +# 3 locations: Unknown 2 + Speed + Kraid + Acid Fall +# Connects back to Kraid main and Norfair +kraid_bottom = { + "Kraid Speed Booster": any( + KraidBoss, + SpeedBooster + ), + "Kraid Acid Fall": None, # doesn't require anything more than access to the region + "Kraid": all( + any( + UnknownItem2, + SpeedBooster + ), + any( + all( + MissileCount(20), + EnergyTanks(1), + ), + all( + AdvancedLogic, + MissileTanks(1) + ) + ), + any( + SpeedBooster, + CanHiGrip, + CanFlyWall + ) # to escape, or to get to the upper door if you take the speed booster exit into the room + ) + } + +norfair_main = { + "Norfair Hallway to Crateria": any( + PowerGrip, + CanIBJ, + all( + IceBeam, + CanEnterMediumMorphTunnel + ) + ), + "Norfair Under Crateria Elevator": all( + any( + CanLongBeam, + CanBallspark + ), + CanEnterHighMorphTunnel + ) + } + +norfair_right_shaft = { + "Norfair Big Room": any( + SpeedBooster, + CanFly, + all( + IceBeam, + any( + CanVertical, + CanWallJump + ) + ), + all( # this method requires some jump extends + AdvancedLogic, + CanHiGrip, + CanWallJump + ) + ) + } + +norfair_upper_right = { + "Norfair Ice Beam": None, + "Norfair Heated Room above Ice Beam": any( + VariaSuit, + Hellrun(1) + ) + } + +norfair_behind_ice = { + "Norfair Behind Top Chozo Statue": None, + } - # The rules can be moved out of this function once they've all been converted - brinstar_access_rules = { - "Brinstar Morph Ball Cannon": lambda state: logic.can_regular_bomb(state, player), -# "Brinstar Morph Ball Cannon": CanRegularBomb - "Brinstar Long Beam": lambda state: (state.has("Morph Ball", player) - and (logic.can_long_beam(state, player) - or world.options.layout_patches.value)), -# "Brinstar Long Beam": all( -# MorphBall, -# any( -# CanLongBeam, -# LayoutPatches, -# ) -# ), - "Brinstar Ceiling E-Tank": - lambda state: (state.has("Ice Beam", player) and state.has("Ridley Defeated", player)) or - logic.can_space_jump(state, player) - or logic.can_ibj(state, player), -# "Brinstar Ceiling E-Tank": any( -# all( -# IceBeam, -# RidleyBoss -# ), -# SpaceJump, -# CanIBJ, -# ), - "Brinstar Missile Above Super": - lambda state: (logic.can_bomb_block(state, player) - and (logic.can_space_jump(state, player) - or state.has("Ice Beam", player) - or state.has_all({"Hi-Jump", "Power Grip"}, player) - or logic.can_ibj(state, player) - or logic.can_walljump(state, player) - ) - ), -# "Brinstar Missile Above Super": all( -# CanBombBlock, -# any( -# SpaceJump, -# IceBeam, -# CanIBJ, -# CanWallJump, -# all( -# HiJump, -# PowerGrip, -# ), -# ) -# ), - "Brinstar Super Missile": lambda state: logic.can_ballspark(state, player), - "Brinstar Top Missile": - lambda state: (state.has_all({"Morph Ball", "Power Grip"}, player) - and (state.has("Ice Beam", player) - or logic.can_space_jump(state, player) - or logic.can_walljump(state, player)) - ) - or logic.can_ibj(state, player), # needs a rewrite - "Brinstar Speed Booster Shortcut Missile": - lambda state: (logic.can_bomb_block(state, player) - and logic.can_ballspark(state, player) - and (logic.can_walljump(state, player) or logic.can_hj_sj_ibj_or_grip(state, player)) - ), - "Brinstar Varia Suit": - lambda state: (logic.can_ibj(state, player) - or logic.can_space_jump(state, player) - or state.has_all({"Power Grip", "Hi-Jump"}, player)) - and (logic.can_regular_bomb(state, player) - or state.has_all({"Morph Ball", "Hi-Jump"}, player)) - and ((logic.can_ibj(state, player) - or state.has("Power Grip", player) - or (state.has("Hi-Jump", player) - and (logic.can_walljump(state, player) - or logic.can_gravity_suit(state, player)) - ) - ) - and logic.can_bomb_block(state, player) - ), - "Brinstar Worm drop": - lambda state: (state.has("Morph Ball", player) - and logic.has_missiles(state, player)), - "Brinstar Acid near Varia": - lambda state: ((logic.can_ibj(state, player) - or logic.can_space_jump(state, player) - or state.has_all({"Power Grip", "Hi-Jump"}, player)) - and (logic.can_regular_bomb(state, player) - or state.has_all({"Morph Ball", "Hi-Jump"}, player)) - and (logic.can_long_beam(state, player) - and (logic.hellrun(state, player, 2) - or state.has("Varia Suit", player) - or logic.can_gravity_suit(state, player) - ) - ) - ), - "Brinstar First Missile": lambda state: state.has("Morph Ball", player), - "Brinstar Behind Hive": - lambda state: (state.has("Morph Ball", player) - and logic.has_missile_count(state, player, 5)), - "Brinstar Under Bridge": - lambda state: (logic.has_missiles(state, player) - and logic.can_bomb_block(state, player)), - "Brinstar Post-Hive Missile": lambda state: logic.brinstar_past_hives(state, player), - "Brinstar Upper Pillar Missile": - lambda state: ((logic.can_bomb_block(state, player) and state.has_any({"Bomb", "Hi-Jump"}, player)) - or (logic.brinstar_past_hives(state, player) - and (logic.can_ibj(state, player) - or (logic.can_space_jump(state, player) - and state.has_any({"Bomb", "Hi-Jump"}, player)) - or (logic.can_walljump(state, player) - and state.has_all({"Hi-Jump", "Ice Beam"}, player))) - ) - ), - "Brinstar Behind Bombs": - lambda state: (logic.brinstar_past_hives(state, player) - and (logic.can_bomb_block(state, player) - and state.has_any({"Bomb", "Hi-Jump"}, player)) - ), - "Brinstar Bomb": - lambda state: logic.brinstar_past_hives(state, player), - "Brinstar Post-Hive E-Tank": - lambda state: logic.brinstar_past_hives(state, player) - } - - # TODO: add norfair-kraid backdoor logic - kraid_access_rules = { - "Kraid Giant Hoppers Missile": lambda state: ( - logic.kraid_left_shaft_access(state, player) - and (logic.can_ibj(state, player) - or state.has_all({"Morph Ball", "Power Grip"}, player)) - ), - "Kraid Save Room Missile": lambda state: logic.can_bomb_block(state, player), - "Kraid Crumble Block Missile": lambda state: ( - logic.kraid_upper_right(state, player) - and state.has("Morph Ball", player) - and state.has_any({"Bomb", "Hi-Jump"}, player) - ), - "Kraid Quad Ball Cannon Room": lambda state: ( # there are trickier ways to add later - logic.kraid_left_shaft_access(state, player) - and logic.kraid_upper_right(state, player) - and logic.has_missiles(state, player) - ), - "Kraid Space Jump/Unknown Item 2": lambda state: ( - logic.kraid_left_shaft_access(state, player) - and (state.has("Bomb", player) or logic.power_bomb_count(state, player, 2)) - and (state.has_any({"Power Grip", "Hi-Jump"}, player) or logic.can_ibj(state, player)) - and logic.has_missiles(state, player) # to get out - ), - "Kraid Acid Ballspark": lambda state: ( - (logic.can_ibj(state, player) or state.has_any({"Power Grip", "Hi-Jump"}, player)) - and logic.can_bomb_block(state, player) - and (logic.can_regular_bomb(state, player) or state.has("Hi-Jump", player)) - and (logic.can_gravity_suit(state, player) and logic.can_ballspark(state, player)) - ), - "Kraid Speed Booster": lambda state: state.has("Kraid Defeated", player), - "Kraid Worm Missile": lambda state: ( - logic.kraid_upper_right(state, player) - and logic.has_missile_count(state, player, 20) - and logic.can_bomb_block(state, player) - and (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player)) - ), - "Kraid Pillar Missile": lambda state: logic.has_missiles(state, player), - "Kraid Acid Fall": lambda state: ( - state.can_reach("Kraid Space Jump/Unknown Item 2", "Location", player) - and state.has("Morph Ball", player) - ), - "Kraid Worm E-Tank": lambda state: logic.kraid_upper_right(state, player), - "Kraid Speed Jump": lambda state: (logic.has_missiles(state, player) - and state.has("Speed Booster", player)), - "Kraid Upper Right Morph Ball Cannon": lambda state: logic.has_missiles(state, player) - and logic.can_ballcannon(state, player), - "Kraid": lambda state: ( - state.can_reach("Kraid Space Jump/Unknown Item 2", "Location", player) - and logic.has_missile_count(state, player, 20) - and (state.count("Energy Tank", player) >= 1) - and (state.has_all({"Hi-Jump", "Power Grip"}, player) - or state.has("Speed Booster", player) - or logic.can_space_jump(state, player) - or logic.can_ibj(state, player) - or logic.can_walljump(state, player)) +norfair_lowerrightshaft = { + "Norfair Bomb Trap": all( + any( + Bomb, + all( + SpaceJump, + PowerBombs + ) + ), + CanReachLocation("Norfair Heated Room Under Brinstar Elevator") + ), + "Norfair Heated Room Under Brinstar Elevator": all( + SuperMissiles, + any( + VariaSuit, + Hellrun(4), + all( + SpeedBooster, + Hellrun(1) + ) + ) + ), + "Norfair Hi-Jump": Missiles, + "Norfair Right Shaft Near Hi-Jump": all( + CanEnterHighMorphTunnel, + any( + HiJump, + CanWallJump + ) ) } - norfair_access_rules = { - "Norfair Lava Power Bomb": lambda state: ( - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_missile_count(state, player, 5) - and logic.can_gravity_suit(state, player) - and (logic.can_space_jump(state, player) or logic.can_ibj(state, player)) - ), - "Norfair Lava Missile": lambda state: ( - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_missile_count(state, player, 3) - and (logic.can_bomb_block(state, player) or state.has("Wave Beam", player)) - and (logic.can_gravity_suit(state, player) - or (state.has("Varia Suit", player) and logic.hellrun(state, player, 5)) - or logic.hellrun(state, player, 9)) - and (logic.can_ibj(state, player) or logic.can_space_jump(state, player) - or logic.can_walljump(state, player) or state.has_any({"Hi-Jump", "Power Grip"}, player)) - ), - "Norfair Screw Attack": lambda state: ( # there's an obnoxious enemy freeze you can do here too but ehhh - logic.norfair_to_save_behind_hijump(state, player) - and (logic.can_tricky_sparks(state, player) - or (state.has("Screw Attack", player) - and (logic.can_space_jump(state, player) - or logic.can_walljump(state, player))) - or (logic.has_missile_count(state, player, 5) - and (logic.can_walljump(state, player) - or logic.can_ibj(state, player) - or logic.can_space_jump(state, player)) - ) - ) - and (logic.can_hj_sj_ibj_or_grip(state, player) or state.has("Ice Beam", player)) - ), - "Norfair Screw Attack Missile": lambda state: ( - logic.norfair_to_save_behind_hijump(state, player) - and state.has("Screw Attack", player) - and (logic.can_tricky_sparks(state, player) - or logic.can_space_jump(state, player) - or logic.can_walljump(state, player) - or (logic.has_missile_count(state, player, 5) - and logic.can_ibj(state, player))) - and (logic.can_hj_sj_ibj_or_grip(state, player) or state.has("Ice Beam", player)) - ), - "Norfair Power Grip Missile": lambda state: ( - logic.can_ibj(state, player) - or (state.has("Power Grip", player) - or state.has_all({"Hi-Jump", "Ice Beam"}, player)) - ), - "Norfair Under Crateria Elevator": lambda state: ( - (logic.can_long_beam(state, player) - or logic.can_ballspark(state, player) - ) - and (state.has("Power Grip", player) or logic.can_ibj(state, player)) - ), - "Norfair Wave Beam": lambda state: ( - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_missile_count(state, player, 4)), - "Norfair Bomb Trap": lambda state: ( - logic.norfair_lower_right_shaft(state, player) - and logic.has_super_missiles(state, player) - and (logic.can_traverse_heat(state, player) - or logic.hellrun(state, player, 4) - or (state.has("Speed Booster", player) - and logic.hellrun(state, player, 1)) - ) - and (state.has_all({"Morph Ball", "Bomb"}, player) - or (logic.can_space_jump(state, player) - and logic.has_power_bombs(state, player)) - ) - ), - "Norfair Bottom Heated Room First": lambda state: logic.norfair_to_save_behind_hijump(state, player), - "Norfair Bottom Heated Room Second": lambda state: logic.norfair_to_save_behind_hijump(state, player), - "Norfair Heated Room Under Brinstar Elevator": lambda state: ( - logic.norfair_lower_right_shaft(state, player) - and logic.has_super_missiles(state, player) - and (logic.can_traverse_heat(state, player) - or logic.hellrun(state, player, 4) - or (state.has("Speed Booster", player) and logic.hellrun(state, player, 1)) - ) - ), - "Norfair Space Boost Missile": lambda state: ( # TODO may need to rename, and double check this later - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_super_missiles(state, player) - and (state.has("Speed Booster", player) - or (logic.can_bomb_block(state, player) - or (state.has_all({"Long Beam", "Wave Beam"}, player)) - and (state.has("Power Grip", player) - or (logic.can_gravity_suit(state, player) and state.has("Hi-Jump", player))) - ) - ) - and (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player)) - and ((logic.can_ibj(state, player) and logic.can_gravity_suit(state, player)) - or (logic.can_space_jump(state, player) and state.has("Power Grip", player)) - or (state.has("Ice Beam", player) and (state.has_any({"Power Grip", "Hi-Jump", "Bomb"}, player))) - ) - ), - "Norfair Space Boost Super Missile": lambda state: ( # TODO may need to rename, and double check this later - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_super_missiles(state, player) - and (state.has("Speed Booster", player) - or (logic.can_bomb_block(state, player) - or (state.has_all({"Long Beam", "Wave Beam"}, player)) - and (state.has("Power Grip", player) - or (logic.can_gravity_suit(state, player) and state.has("Hi-Jump", player))) - ) - ) - and (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player)) - and (logic.can_ibj(state, player) or logic.can_space_jump(state, player) - or state.has_all({"Ice Beam", "Hi-Jump"}, player) - or (logic.can_gravity_suit(state, player) and logic.can_walljump(state, player) - and state.has("Hi-Jump", player))) - ), - "Norfair Ice Beam": lambda state: (logic.norfair_upper_right_shaft(state, player)), - "Norfair Heated Room above Ice Beam": lambda state: ( - logic.norfair_upper_right_shaft(state, player) - and (logic.can_traverse_heat(state, player) or logic.hellrun(state, player, 1)) - ), - "Norfair Hi-Jump": - lambda state: logic.norfair_lower_right_shaft(state, player) and logic.has_missiles(state, player), - "Norfair Big Room": lambda state: ( - # there's also a way to do this with hi-jump, grip, a walljump, and a jump extend - state.has("Speed Booster", player) - or (logic.norfair_right_shaft_access(state, player) - and (logic.can_ibj(state, player) - or logic.can_space_jump(state, player) - or (state.has("Ice Beam", player) - and (state.has_any({"Hi-Jump", "Power Grip"}, player) - or logic.can_walljump(state, player)) - ) - ) +lower_norfair = { + "Norfair Lava Dive Left": all( + MissileCount(5), + GravitySuit, + CanFly + ), + "Norfair Lava Dive Right": all( + MissileCount(3), + any( + GravitySuit, + all( + VariaSuit, + Hellrun(5) + ), + Hellrun(9) + ), + any( + CanBombTunnelBlock, + WaveBeam + ), + any( + CanVertical, + CanWallJump, + ) + ), + "Norfair Wave Beam": MissileCount(4), + "Norfair Heated Room Below Wave - Left": None, + "Norfair Heated Room Below Wave - Right": None, + } + +norfair_screwattack = { + "Norfair Screw Attack": None, + "Norfair Next to Screw Attack": ScrewAttack, + } + +norfair_behind_superdoor = { + "Norfair Behind Lower Super Missile Door - Left": all( + any( + all( + CanIBJ, + GravitySuit + ), + all( + SpaceJump, + PowerGrip + ), + all( + IceBeam, + any( + CanEnterMediumMorphTunnel, + Bomb + ), + CanReachLocation("Norfair Behind Lower Super Missile Door - Right"), + ) + ), + any( + SpeedBooster, + CanBallJump + ) + ), + "Norfair Behind Lower Super Missile Door - Right": any( + CanFly, + all( + HiJump, + any( + IceBeam, + all( + GravitySuit, + CanWallJump ) - ), - "Norfair Behind Top Chozo Statue": lambda state: logic.norfair_behind_ice_beam(state, player), - "Norfair Larva Ceiling E-tank": lambda state: ( - logic.norfair_to_save_behind_hijump(state, player) - and logic.has_missile_count(state, player, 4) - and state.has_all({"Wave Beam", "Speed Booster"}, player) - ), - "Norfair Right Shaft Lower": lambda state: ( - logic.norfair_lower_right_shaft(state, player) - and (logic.can_ibj(state, player) - or (state.has("Power Grip", player) - and (logic.can_hi_jump(state, player) or logic.can_walljump(state, player)))) - ), - "Norfair Right Shaft Bottom": lambda state: ( - logic.norfair_bottom_right_shaft(state, player) - and (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player) - or state.has("Ice Beam", player)) + ) + ) ) } - ridley_access_rules = { - "Ridley Southwest Puzzle Top": lambda state: ( - (logic.ridley_longway_right_shaft_access(state, player) - or logic.ridley_shortcut_right_shaft_access(state, player)) - and state.has("Speed Booster", player) - and (state.has("Power Grip", player) or logic.can_space_jump(state, player)) - and (state.has("Power Grip", player) or logic.has_power_bombs(state, player) - or state.has_all({"Long Beam", "Wave Beam"}, player)) - and (logic.has_missile_count(state, player, 5) - and (logic.can_walljump(state, player) or logic.can_space_jump(state, player) - or state.has("Power Grip", player))) - ), - "Ridley Southwest Puzzle Bottom": lambda state: ( - (logic.ridley_longway_right_shaft_access(state, player) - or logic.ridley_shortcut_right_shaft_access(state, player)) - and state.has("Speed Booster", player) - and (state.has("Power Grip", player) or logic.can_space_jump(state, player)) - and (state.has("Power Grip", player) or logic.has_power_bombs(state, player) - or state.has_all({"Long Beam", "Wave Beam"}, player)) - ), - "Ridley West Pillar": - lambda state: logic.ridley_longway_right_shaft_access(state, player), - "Ridley E-Tank behind Gravity": - lambda state: state.can_reach("Ridley Gravity Suit/Unknown Item 3", "Location", player), -# "Ridley E-Tank behind Gravity": UnknownItem3, - "Ridley Gravity Suit/Unknown Item 3": lambda state: ( - logic.ridley_central_access(state, player) - and logic.has_missile_count(state, player, 40) - and (state.count("Energy Tank", player) >= 3) - and ((state.has("Ice Beam", player) and state.has_any({"Hi-Jump", "Power Grip"}, player)) - or logic.can_ibj(state, player) or logic.can_space_jump(state, player))), - "Ridley Fake Floor E-Tank": - lambda state: (logic.ridley_left_shaft_access(state, player) - and (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player)) - and logic.can_bomb_block(state, player)), - "Ridley Upper Ball Cannon Puzzle": lambda state: ( - logic.ridley_central_access(state, player) - and logic.can_ballcannon(state, player) - and ((logic.can_walljump(state, player) and state.has("Power Grip", player)) - or state.has("Hi-Jump", player) or logic.can_ibj(state, player)) - ), - "Ridley Lower Ball Cannon Puzzle": lambda state: ( - logic.ridley_central_access(state, player) - and logic.can_ballcannon(state, player) - and (state.has_any({"Hi-Jump", "Bomb"}, player) or logic.can_walljump(state, player) - or logic.can_space_jump(state, player)) - ), - "Ridley Imago Super Missile": lambda state: ( - (logic.can_hj_sj_ibj_or_grip(state, player) or logic.can_walljump(state, player)) - and (logic.has_missile_count(state, player, 20) or state.has("Charge Beam", player)) - ), - "Ridley After Sidehopper Hall Upper": lambda state: logic.ridley_central_access(state, player), - "Ridley After Sidehopper Hall Lower": lambda state: logic.ridley_central_access(state, player), - "Ridley Long Hall": lambda state: ( - logic.ridley_longway_right_shaft_access(state, player) - or logic.ridley_shortcut_right_shaft_access(state, player) - ), - "Ridley Center Pillar Missile": lambda state: logic.ridley_central_access(state, player), - "Ridley Ball Room Missile": lambda state: logic.ridley_central_access(state, player), - "Ridley Ball Room Super": lambda state: ( - logic.ridley_central_access(state, player) and logic.has_super_missiles(state, player) - and (logic.can_ibj(state, player) or logic.can_walljump(state, player) - or logic.can_space_jump(state, player) or state.has_all({"Hi-Jump", "Power Grip"}, player)) - ), - "Ridley Fake Lava Missile": lambda state: ( - logic.ridley_central_access(state, player) - and (state.has("Wave Beam", player) or logic.can_bomb_block(state, player)) - and logic.can_ibj(state, player) or state.has("Power Grip", player)), - "Ridley Owl E-Tank": lambda state: logic.ridley_central_access(state, player), - "Ridley Northeast Corner Missile": lambda state: ( - logic.has_missiles(state, player) - and (logic.can_ibj(state, player) - or (state.has("Power Grip", player) and logic.has_power_bombs(state, player) - and state.has_any({"Ice Beam", "Hi-Jump"}, player))) - and (logic.can_bomb_block(state, player) or state.has("Screw Attack", player)) - ), # can also do this without ice beam using hj, grip, and walljumps - "Ridley Bomb Puzzle": lambda state: ( - (logic.ridley_longway_right_shaft_access(state, player) - or logic.ridley_shortcut_right_shaft_access(state, player)) - and state.has_all({"Speed Booster", "Bomb", "Power Grip"}, player) - and (logic.can_walljump(state, player) or state.has("Hi-Jump", player) - or logic.can_space_jump(state, player)) - ), - "Ridley Speed Jump": lambda state: ( - (logic.ridley_longway_right_shaft_access(state, player) - or logic.ridley_shortcut_right_shaft_access(state, player)) - and state.has_all({"Wave Beam", "Speed Booster"}, player) - ), - "Ridley": lambda state: state.can_reach("Ridley Gravity Suit/Unknown Item 3", "Location", player) - } - - tourian_access_rules = { - "Tourian Left of Mother Brain": lambda state: ( - state.has_all({"Chozo Ghost Defeated", "Speed Booster"}, player) - and logic.can_space_jump(state, player)), - "Tourian Under Mother Brain": lambda state: (state.has("Mother Brain Defeated", player) - and logic.has_super_missiles(state, player)), - "Mother Brain": lambda state: ( - state.has_all({"Ice Beam", "Bomb"}, player) # only bomb will unlatch Metroids - and logic.has_missile_count(state, player, 40) - and state.count("Energy Tank", player) >= 4 - and logic.can_hj_sj_ibj_or_grip(state, player) - and (state.has("Speed Booster", player) - or logic.can_space_jump(state, player) - or logic.can_ibj(state, player) - or (state.has("Hi-Jump", player) and logic.can_walljump(state, player)) - ) +norfair_bottom = { + "Norfair Larva Ceiling": None, + "Norfair Right Shaft Bottom": all( + any( + CanVertical, + CanWallJump, + IceBeam + ), + CanBallJump ) } - crateria_access_rules = { - "Crateria Landing Site Ballspark": lambda state: ( - state.has("Chozo Ghost Defeated", player) and logic.can_ballspark(state, player) - and (logic.can_gravity_suit(state, player) - or state.can_reach_entrance("Brinstar-Crateria ball cannon", player))), - "Crateria Power Grip": lambda state: ( - state.has_any({"Bomb", "Hi-Jump"}, player) and logic.can_hj_sj_ibj_or_grip(state, player)), - "Crateria Statue Water": - lambda state: state.can_reach("Crateria Plasma Beam/Unknown Item 1", "Location", player), -# "Crateria Statue Water": UnknownItem1, - "Crateria Plasma Beam/Unknown Item 1": lambda state: state.has_any({"Bomb", "Hi-Jump"}, player), -# "Crateria Plasma Beam/Unknown Item 1": any( -# Bomb, -# HiJump, -# ), - "Crateria East Ballspark": lambda state: ( - logic.can_ballspark(state, player) - and (logic.can_space_jump(state, player) or logic.can_walljump(state, player)) - ), - "Crateria Northeast Corner": lambda state: ( - state.has("Speed Booster", player) - and (logic.can_space_jump(state, player) or logic.can_walljump(state, player) - or logic.can_tricky_sparks(state, player)) +ridley_main = { + "Ridley Imago Super Missile": all( + any( + CanVertical, + CanWallJump + ), + any( + MissileCount(20), + all( + AdvancedLogic, + MissileTanks(1) + ), + ChargeBeam + ) ) } - chozodia_access_rules = { - "Chozodia Upper Crateria Door": lambda state: ( - state.can_reach_entrance("Crateria-Chozodia Upper Door", player) - and logic.has_missiles(state, player) - and (logic.can_walljump(state, player) or logic.can_ibj(state, player) - or logic.can_space_jump(state, player)) - ), - "Chozodia Bomb Maze": lambda state: ( - (logic.can_ibj(state, player) or logic.can_ballspark(state, player) - or (state.has("Power Grip", player) - and (logic.can_walljump(state, player) or logic.can_space_jump(state, player)))) - and (state.has("Bomb", player) or state.count("Power Bomb Tank", player) >= 3) - and (state.has("Bomb", player) or state.has("Hi-Jump", player)) - and (state.has("Hi-Jump", player) or logic.can_ibj(state, player) - or (state.has("Power Grip", player) and logic.can_walljump(state, player))) - ), - "Chozodia Zoomer Maze": lambda state: ( - (logic.can_ibj(state, player) or logic.can_ballspark(state, player) - or (state.has("Power Grip", player) - and (logic.can_walljump(state, player) or logic.can_space_jump(state, player)))) - and (logic.can_ibj(state, player) - or (state.has("Hi-Jump", player) and state.has_any({"Speed Booster", "Power Grip"}, player))) - ), - "Chozodia Ruins Near Upper Crateria Door": lambda state: ( - state.can_reach_entrance("Crateria-Chozodia Upper Door", player) - and logic.has_missiles(state, player) - and (logic.can_walljump(state, player) or logic.can_ibj(state, player) - or logic.can_space_jump(state, player)) - and logic.has_power_bombs(state, player) - ), - "Chozodia Chozo Ghost Area Morph Tunnel Above Water": lambda state: ( - # The room leading to this item is inaccessible until the Chozo Ghost is defeated - state.has("Chozo Ghost Defeated", player) and state.has_any({"Hi-Jump", "Bomb"}, player) - ), - "Chozodia Chozo Ghost Area Underwater": lambda state: ( - # This item does not really exist until the Chozo Ghost is defeated - state.has("Chozo Ghost Defeated", player) - and logic.can_gravity_suit(state, player) and state.has("Speed Booster", player) - ), - "Chozodia Under Chozo Ghost Area Water": lambda state: ( - logic.chozodia_ghost_from_upper_crateria_door(state, player) - or state.has("Mother Brain Defeated", player)), - "Chozodia Glass Tube E-Tank": lambda state: ( - (logic.can_ibj(state, player) or logic.can_ballspark(state, player) - or (state.has("Power Grip", player) - and (logic.can_walljump(state, player) or logic.can_space_jump(state, player)))) - and logic.has_missile_count(state, player, 6) - and state.has("Speed Booster", player) - ), - "Chozodia Lava Super": lambda state: ( # This room is inaccessible until the Chozo Ghost is defeated - state.has("Chozo Ghost Defeated", player) - and ((logic.can_gravity_suit(state, player) - and ((state.has("Power Grip", player) and state.has_any({"Hi-Jump", "Bomb"}, player)) - or logic.can_ibj(state, player))) - or (state.has_all({"Hi-Jump", "Power Grip"}, player) - and (state.has("Varia Suit", player) - or logic.hellrun(state, player, 6)))) - and (logic.can_walljump(state, player) - or (logic.can_gravity_suit(state, player) - and (logic.can_ibj(state, player) or logic.can_space_jump(state, player)))) - ), - "Chozodia Original Power Bomb": lambda state: logic.chozodia_to_cockpit(state, player), - "Chozodia Next to Original Power Bomb": lambda state: ( - logic.chozodia_to_cockpit(state, player) - and logic.has_power_bombs(state, player) - and (logic.can_space_jump(state, player) or logic.can_ibj(state, player)) - ), - "Chozodia Glass Tube Power Bomb": lambda state: logic.chozodia_glass_tube_from_crateria_door(state, player), - "Chozodia Chozo Ghost Area Long Shinespark": lambda state: ( - # The room leading to this item is inaccessible until the Chozo Ghost is defeated - state.has_all({"Chozo Ghost Defeated", "Speed Booster"}, player) - and logic.can_gravity_suit(state, player) - ), - "Chozodia Shortcut Super": lambda state: ( - # you can also do this with screw and not need ibj/wj/sj but that's for advanced logic later - (logic.chozodia_tube_to_mothership_central(state, player) - or state.has("Chozo Ghost Defeated", player)) - and state.has_any({"Super Missile Tank", "Power Bomb Tank"}, player) - and (logic.can_ibj(state, player) or logic.can_walljump(state, player) - or logic.can_space_jump(state, player)) - ), - "Chozodia Workbot Super": lambda state: ( - (logic.chozodia_tube_to_mothership_central(state, player) - or state.has("Chozo Ghost Defeated", player)) - and logic.has_missile_count(state, player, 5) - ), - "Chozodia Mothership Ceiling Near ZSS Start": - lambda state: logic.chozodia_tube_to_mothership_central(state, player) - or state.has_all({"Chozo Ghost Defeated", "Power Bomb Tank"}, player), - "Chozodia Under Mecha Ridley Hallway": lambda state: ( - # you can also get here without PBs but we'll save that for advanced logic later - logic.chozodia_to_cockpit(state, player) - and (state.has("Power Grip", player) or logic.can_ibj(state, player)) - and state.has_all({"Power Bomb Tank", "Speed Booster"}, player) - ), - "Chozodia Southeast Corner In Hull": - lambda state: logic.chozodia_tube_to_mothership_central(state, player) - or state.has_all({"Chozo Ghost Defeated", "Power Bomb Tank"}, player), - "Chozo Ghost": lambda state: ( - state.has("Mother Brain Defeated", player) - and (logic.can_ibj(state, player) - or (logic.can_space_jump(state, player) and state.has_any({"Power Grip", "Hi-Jump"}, player))) - ), # Extra requirements needed to escape--can also do it without SJ using tight WJs and hj+grip - "Mecha Ridley": lambda state: ( - logic.chozodia_to_cockpit(state, player) - and logic.has_missile_count(state, player, 40) - and logic.has_power_bombs(state, player) # Or can skip them by flying to the tunnel - ), - "Chozodia Space Pirate's Ship": lambda state: state.has_all({"Mecha Ridley Defeated", "Plasma Beam"}, player) - } - - access_rules = { - **brinstar_access_rules, - **kraid_access_rules, - **norfair_access_rules, - **ridley_access_rules, - **tourian_access_rules, - **crateria_access_rules, - **chozodia_access_rules +ridley_left_shaft = { + "Ridley West Pillar": None, + "Ridley Fake Floor": None, + "Ridley Long Hall": None + } + +ridley_sw_puzzle = { + "Ridley Southwest Puzzle Top": all( + MissileCount(5), + any( + CanWallJump, + PowerGrip, + SpaceJump + ) + ), + "Ridley Southwest Puzzle Bottom": None } +ridley_right_shaft = { + "Ridley Northeast Corner": any( + CanFly, + all( + AdvancedLogic, + CanWallJump, + HiJump # disable hi-jump mid walljump to get this, might be possible without + ), + all( + IceBeam, + any( + CanWallJump, + CanHiGrip + ) + ) + ) + } + +# obviously, requires speed booster +ridley_right_speed_puzzles = { + "Ridley Bomb Puzzle": all( + Bomb, + PowerGrip, + any( + CanWallJump, + SpaceJump + ) + ), + "Ridley Speed Jump": WaveBeam + } + +ridley_central = { + "Ridley Upper Ball Cannon Puzzle": all( + any( + HiJump, + all( + CanWallJump, + any( + PowerGrip, + SpaceJump + ) + ) + ), + any( + CanBallCannon, + LayoutPatches # TODO: make this layout patch + ) + ), + "Ridley Lower Ball Cannon Puzzle": all( + any( + PowerBombs, + PowerGrip, + all( + WaveBeam, + any( + CanWallJump, + SpaceJump + ) + ) + ), + any( + CanBallCannon, + all( + LayoutPatches, + any( + HiJump, + SpaceJump, + CanWallJump + ) + ) + ) + ), + "Ridley After Sidehopper Hall Upper": None, + "Ridley After Sidehopper Hall Lower": None, + "Ridley Center Pillar": None, + "Ridley Ball Room Lower": None, + "Ridley Ball Room Upper": all( + SuperMissiles, + any( + CanFlyWall, + CanHiGrip + ) + ), + "Ridley Fake Lava Under Floor": all( + any( + WaveBeam, + CanBombTunnelBlock + ), + CanEnterHighMorphTunnel + ), + "Ridley Under Owls": None, + } + +#TODO determine reasonable Ridley combat logic for advanced +ridley_room = { + "Ridley Behind Unknown Statue": UnknownItem3, + "Ridley Unknown Item Statue": None, + "Ridley": UnknownItem3, + } + +tourian = { + "Tourian Left of Mother Brain": all( + ChozoGhostBoss, # TODO: Double check if Mother Brain is also required + SpeedBooster, + any( + SpaceJump, + CanTrickySparks + ) + ), + "Tourian Under Mother Brain": all( + MotherBrainBoss, + SuperMissiles, + CanEnterMediumMorphTunnel # to escape + ), + "Mother Brain": all( # TODO: determine reasonable logic for advanced + IceBeam, + CanRegularBomb, # only bomb can unlatch metroids + any( + AdvancedLogic, + all( + MissileCount(40), + EnergyTanks(4), + ) + ), + CanVertical, # to get through escape shaft + any( # to get to ship + SpeedBooster, + CanFly, + all( + HiJump, + CanWallJump + ) + ) + ) + } + +crateria_main = { + "Crateria Landing Site Ballspark": all( + ChozoGhostBoss, # TODO: Double check if Mother Brain is also required + CanBallspark, + CanBallJump, + any( + GravitySuit, + CanReachEntrance("Brinstar -> Crateria Ballcannon") + ) + ), + "Crateria Moat": None + } + +crateria_upper = { + "Crateria Power Grip": CanVertical, + "Crateria Statue Water": UnknownItem1, + "Crateria Unknown Item Statue": None, + "Crateria East Ballspark": all( + CanBallspark, + any( + CanReachEntrance("Crateria -> Chozodia Upper Door"), + CanReachLocation("Crateria Northeast Corner") + ) + ), + "Crateria Northeast Corner": all( + SpeedBooster, + any( + SpaceJump, + CanWallJump, + CanTrickySparks + ) + ) + } + +chozodia_ruins_crateria_entrance = { + "Chozodia Upper Crateria Door": + CanReachEntrance("Crateria -> Chozodia Upper Door"), # Specifically need to access this entrance, not just the region as it's one-way + "Chozodia Ruins East of Upper Crateria Door": Missiles, + "Chozodia Triple Crawling Pirates": all( # Rename to Triple Crawling Pirates + any( + Bomb, + PowerBombCount(2) + ), + any( + AdvancedLogic, + ChozodiaCombat + ) + ), + } + +chozodia_ruins_test = { + "Chozodia Chozo Ghost Area Morph Tunnel Above Water": all( + ChozoGhostBoss, # The room leading to this item is inaccessible until the Chozo Ghost is defeated + Missiles, + CanBallJump + ), + "Chozodia Chozo Ghost Area Underwater": all( + ChozoGhostBoss, # This item is fake until the Chozo Ghost is defeated + SpeedBooster, + GravitySuit + ), + "Chozodia Chozo Ghost Area Long Shinespark": all( + ChozoGhostBoss, # The room leading to this item is inaccessible until the Chozo Ghost is defeated + SpeedBooster, + GravitySuit + ), + "Chozodia Lava Dive": all( # TODO split this lavadive into regular/advanced, current values are close to bare minimum + ChozoGhostBoss, + any( + GravitySuit, + all( + Hellrun(4), + VariaSuit, + CanHiGrip + ), + all( + AdvancedLogic, + Hellrun(6), + CanHiGrip + ) + ), + CanEnterHighMorphTunnel, + CanBallJump, + any( + CanWallJump, + all( + GravitySuit, + CanFly + ) + ) + ), + "Chozo Ghost": None # Regional access requirements should cover what is needed + } + +chozodia_under_tube = { + "Chozodia Bomb Maze": all( + MorphBall, + any( + CanIBJ, + all( + CanBallspark, + CanTrickySparks + ), + all( + PowerGrip, + any( + CanWallJump, + SpaceJump + ) + ) + ), + any( + Bomb, + PowerBombCount(3) + ), + CanBallJump + ), + "Chozodia Zoomer Maze": any( + CanIBJ, + all( + PowerGrip, + CanBallJump + ), + all( + CanBallspark, + CanTrickySparks + ) + ), + "Chozodia West of Glass Tube": all( + SpeedBooster, + CanReachEntrance("Chozodia Glass Tube -> Chozo Ruins") # Required to access a save station after collecting to warp if necessary + ), + "Chozodia Southeast of Glass Tube": all( + PowerBombs, + CanFly + ) + } + +chozodia_mothership = { + "Chozodia Pirate Pitfall Trap": all( + Missiles, + SuperMissiles, + any( + ScrewAttack, + MissileCount(5) + ), + any( + all( + CanBombTunnelBlock, + CanFlyWall + ), + all( + AdvancedLogic, # doable without falling down using screw, but can get softlocked without infinite vertical + CanSingleBombBlock + ) + ) + ), + "Chozodia Behind Workbot": MissileCount(5), + "Chozodia Mothership Ceiling Near ZSS Start": all( + Missiles, + any( + PowerBombs, + ScrewAttack, + MissileCount(6) + ) + ), + "Chozodia Southeast Corner In Hull": PowerBombs + } + +chozodia_cockpit = { + "Chozodia Original Power Bomb": None, + "Chozodia Next to Original Power Bomb": CanFly, + } + +chozodia_mecha_ridley_hall = { + "Chozodia Under Mecha Ridley Hallway": SpeedBooster, + "Mecha Ridley": all( + PlasmaBeam, + any( + MissileCount(40), + all( + AdvancedLogic, + Missiles, + any( + HiJump, + CanWallJump + ) + ) + ), + CanEnterHighMorphTunnel # To escape + ), + "Chozodia Space Pirate's Ship": MechaRidleyBoss +} + +access_rules = { + **brinstar_start, + **brinstar_main, + **brinstar_top, + **brinstar_pasthives, + **kraid_main, + **kraid_acidworm_area, + **kraid_left_shaft, + **kraid_bottom, + **norfair_main, + **norfair_right_shaft, + **norfair_upper_right, + **norfair_behind_ice, + **norfair_lowerrightshaft, + **lower_norfair, + **norfair_screwattack, + **norfair_behind_superdoor, + **norfair_bottom, + **ridley_main, + **ridley_left_shaft, + **ridley_sw_puzzle, + **ridley_right_shaft, + **ridley_right_speed_puzzles, + **ridley_central, + **ridley_room, + **tourian, + **crateria_main, + **crateria_upper, + **chozodia_ruins_crateria_entrance, + **chozodia_ruins_test, + **chozodia_under_tube, + **chozodia_mothership, + **chozodia_cockpit, + **chozodia_mecha_ridley_hall + } + + +def set_rules(world: MZMWorld, locations): + player = world.player + for i in locations: location = world.multiworld.get_location(i, player) + try: - add_rule(location, access_rules[i]) -# add_rule(location, access_rules[i].create_rule(world)) + if access_rules[i]: + add_rule(location, access_rules[i].create_rule(world)) except KeyError: continue From a24364ad01485d41f9fd197565d8cb6106212cc5 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Mon, 12 Aug 2024 23:05:23 -0400 Subject: [PATCH 04/14] Ridley minimal logic Adds advanced logic requirements for Ridley, and clarifies that advanced logic assumes minimal requirements for combat --- logic.py | 9 +++++++-- options.py | 4 ++-- rules.py | 1 - 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/logic.py b/logic.py index 1a02d2b..1a55aa8 100644 --- a/logic.py +++ b/logic.py @@ -630,8 +630,13 @@ def ridley_right_shaft_to_central(): # Ridley, Unknown 3, and the item behind Unknown 3 def ridley_central_to_ridley_room(): return all( - MissileCount(40), - EnergyTanks(3), + any( + AdvancedLogic, + all( + MissileCount(40), + EnergyTanks(3), + ) + ), any( CanFly, all( diff --git a/options.py b/options.py index 3b60c86..b54f1b2 100644 --- a/options.py +++ b/options.py @@ -43,8 +43,8 @@ class LogicDifficulty(Choice): """ Determines the general difficulty of the game's logic. On advanced difficulty, more niche techniques and game knowledge may be required to collect items or progress, and you may be required to complete areas or bosses - with fewer resources. Examples of "tricks" this may put in logic include entering invisible tunnels, jump extends, - and Acid Worm skip. + with the minimum required resources. Examples of "tricks" this may put in logic include entering invisible tunnels, + jump extends, and Acid Worm skip. Other specific tricks (such as difficult Shinesparks and horizontal IBJ) have individual difficulty settings that this does not affect. diff --git a/rules.py b/rules.py index 6baf1c9..ade61c7 100644 --- a/rules.py +++ b/rules.py @@ -528,7 +528,6 @@ "Ridley Under Owls": None, } -#TODO determine reasonable Ridley combat logic for advanced ridley_room = { "Ridley Behind Unknown Statue": UnknownItem3, "Ridley Unknown Item Statue": None, From 946ec7ad4391bdd559d2c3e2d0adf4eaecf41c6a Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Tue, 13 Aug 2024 22:27:26 -0400 Subject: [PATCH 05/14] Client and local item fix This fixes the client and local item placements to work with the changed location file, so this branch now generates playable ROMs with the new logic. --- client.py | 2 +- regions.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/client.py b/client.py index f605bc9..fa6930a 100644 --- a/client.py +++ b/client.py @@ -285,7 +285,7 @@ async def game_watcher(self, client_ctx: BizHawkClientContext) -> None: ): for location in location_table.values(): if location_flags & 1: - checked_locations.append(location) + checked_locations.append(location.code) location_flags >>= 1 # Deorem flags are in a weird arrangement, but he also drops Charge Beam so whatever just look for that check diff --git a/regions.py b/regions.py index 25cebd1..34d8923 100644 --- a/regions.py +++ b/regions.py @@ -14,6 +14,7 @@ def create_region(world: MultiWorld, player: int, region_name: str): for location_name, location_data in full_location_table.items(): if location_data.region == region_name: location = Location(player, location_name, location_data.code, region) + location.game = world.game.get(player) region.locations.append(location) world.regions.append(region) From 27722834aca3df14a3d36789ae0ac4d50ea58cb1 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Tue, 13 Aug 2024 23:13:33 -0400 Subject: [PATCH 06/14] Minor changes for Kraid bottom access, Brinstar Speed Shortcut, Norfair Lava Dives --- logic.py | 8 ++------ rules.py | 11 +++++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/logic.py b/logic.py index 1a55aa8..ac27366 100644 --- a/logic.py +++ b/logic.py @@ -241,7 +241,7 @@ def brinstar_main_to_brinstar_top(): IceBeam, CanWallJump, PowerBombs - ) + ) # truly cursed strat ) @@ -317,12 +317,8 @@ def kraid_left_shaft_access(): ) -# TODO: double check this def kraid_left_shaft_to_bottom(): - return any( - UnknownItem2, - CanReachEntrance("Lower Norfair -> Kraid") - ) + return UnknownItem2 def kraid_bottom_to_lower_norfair(): diff --git a/rules.py b/rules.py index ade61c7..89ec9d8 100644 --- a/rules.py +++ b/rules.py @@ -64,7 +64,10 @@ "Brinstar Speed Booster Shortcut": all( any( CanBallspark, - AdvancedLogic + all( + AdvancedLogic, + CanBallJump + ) ), CanBombTunnelBlock, any( @@ -315,12 +318,12 @@ lower_norfair = { "Norfair Lava Dive Left": all( - MissileCount(5), + MissileCount(7), GravitySuit, CanFly ), "Norfair Lava Dive Right": all( - MissileCount(3), + MissileCount(5), any( GravitySuit, all( @@ -548,7 +551,7 @@ SuperMissiles, CanEnterMediumMorphTunnel # to escape ), - "Mother Brain": all( # TODO: determine reasonable logic for advanced + "Mother Brain": all( IceBeam, CanRegularBomb, # only bomb can unlatch metroids any( From a6a1dcd4ae8da2239f94c641134d57a4bd16dd44 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Tue, 13 Aug 2024 23:54:27 -0400 Subject: [PATCH 07/14] Create CanVerticalWall rule CanVertical was most commonly also paired in any any() block with CanWalljump so there is now one rule to consolidate them --- logic.py | 14 ++++++++------ rules.py | 30 +++++++----------------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/logic.py b/logic.py index ac27366..2a7b629 100644 --- a/logic.py +++ b/logic.py @@ -181,6 +181,10 @@ def any(*args: Requirement): PowerGrip, CanFly ) +CanVerticalWall = any( + CanVertical, + CanWallJump +) CanHiGrip = all( HiJump, PowerGrip @@ -349,9 +353,8 @@ def norfair_right_shaft_access(): def norfair_upper_right_shaft(): return any( - CanVertical, - IceBeam, - CanWallJump + CanVerticalWall, + IceBeam ) @@ -555,8 +558,7 @@ def ridley_main_to_left_shaft(): return all( SuperMissiles, any( - CanVertical, - CanWallJump, + CanVerticalWall, IceBeam ), any( @@ -637,7 +639,7 @@ def ridley_central_to_ridley_room(): CanFly, all( IceBeam, - CanHiGrip + CanVerticalWall ) ) ) diff --git a/rules.py b/rules.py index 89ec9d8..ef8b1fb 100644 --- a/rules.py +++ b/rules.py @@ -70,10 +70,7 @@ ) ), CanBombTunnelBlock, - any( - CanVertical, - CanWallJump - ) + CanVerticalWall, ), "Brinstar Worm drop": all( MorphBall, @@ -169,10 +166,7 @@ "Kraid Under Acid Worm": all( MissileCount(20), CanSingleBombBlock, - any( - CanVertical, - CanWallJump - ) + CanVerticalWall ), "Kraid Zipline Activator Room": None } @@ -259,10 +253,7 @@ CanFly, all( IceBeam, - any( - CanVertical, - CanWallJump - ) + CanVerticalWall ), all( # this method requires some jump extends AdvancedLogic, @@ -336,10 +327,7 @@ CanBombTunnelBlock, WaveBeam ), - any( - CanVertical, - CanWallJump, - ) + CanVerticalWall, ), "Norfair Wave Beam": MissileCount(4), "Norfair Heated Room Below Wave - Left": None, @@ -395,8 +383,7 @@ "Norfair Larva Ceiling": None, "Norfair Right Shaft Bottom": all( any( - CanVertical, - CanWallJump, + CanVerticalWall, IceBeam ), CanBallJump @@ -405,15 +392,12 @@ ridley_main = { "Ridley Imago Super Missile": all( - any( - CanVertical, - CanWallJump - ), + CanVerticalWall, any( MissileCount(20), all( AdvancedLogic, - MissileTanks(1) + MissileTanks(1) # Imago does not drop super refills ), ChargeBeam ) From b8171ab5cdeedba116354ff9795e6f0e9a7f908c Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Wed, 14 Aug 2024 17:33:56 -0400 Subject: [PATCH 08/14] Miscellaneous logic fixes Fixes/tweaks for: - Kraid left shaft access - Norfair Larva Ceiling - Ridley speed puzzles access - Left of MB and Landing Site Ballspark - Chozodia Triple Crawling Pirates - Chozodia Original PB/next to OPB Also slightly renamed two Chozodia locations. --- locations.py | 4 ++-- logic.py | 8 +++----- rules.py | 31 +++++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/locations.py b/locations.py index f4aa1bf..588359b 100644 --- a/locations.py +++ b/locations.py @@ -129,11 +129,11 @@ def __init__(self, reg, id): "Chozodia Chozo Ghost Area Morph Tunnel Above Water": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 86), "Chozodia Chozo Ghost Area Underwater": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 87), "Chozodia Triple Crawling Pirates": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 88), #TODO renamed - "Chozodia West of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), #TODO renamed + "Chozodia Left of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), #TODO renamed "Chozodia Lava Dive": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 90), #TODO Renamed "Chozodia Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 91), "Chozodia Next to Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 92), - "Chozodia Southeast of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), #TODO Renamed + "Chozodia Right of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), #TODO Renamed "Chozodia Chozo Ghost Area Long Shinespark": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 94), "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), #TODO renamed "Chozodia Behind Workbot": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 96), #TODO Renamed diff --git a/logic.py b/logic.py index 2a7b629..45a39f4 100644 --- a/logic.py +++ b/logic.py @@ -296,10 +296,8 @@ def kraid_left_shaft_access(): return all( any( CanHorizontalIBJ, - all( - PowerGrip, - HiJump - ) + PowerGrip, + HiJump ), CanBallJump, CanBombTunnelBlock, @@ -614,7 +612,7 @@ def ridley_speed_puzzles_access(): return all( SpeedBooster, any( - CanVertical, + CanVerticalWall, IceBeam ) ) diff --git a/rules.py b/rules.py index ef8b1fb..a7be078 100644 --- a/rules.py +++ b/rules.py @@ -380,7 +380,7 @@ } norfair_bottom = { - "Norfair Larva Ceiling": None, + "Norfair Larva Ceiling": CanReachEntrance("Lower Norfair -> Bottom"), "Norfair Right Shaft Bottom": all( any( CanVerticalWall, @@ -523,7 +523,8 @@ tourian = { "Tourian Left of Mother Brain": all( - ChozoGhostBoss, # TODO: Double check if Mother Brain is also required + ChozoGhostBoss, + MotherBrainBoss, SpeedBooster, any( SpaceJump, @@ -559,7 +560,8 @@ crateria_main = { "Crateria Landing Site Ballspark": all( - ChozoGhostBoss, # TODO: Double check if Mother Brain is also required + ChozoGhostBoss, + MotherBrainBoss, CanBallspark, CanBallJump, any( @@ -600,6 +602,10 @@ Bomb, PowerBombCount(2) ), + any( + CanHiGrip, + CanFlyWall + ), any( AdvancedLogic, ChozodiaCombat @@ -623,7 +629,7 @@ SpeedBooster, GravitySuit ), - "Chozodia Lava Dive": all( # TODO split this lavadive into regular/advanced, current values are close to bare minimum + "Chozodia Lava Dive": all( # TODO split this lavadive into regular/advanced? current values are close to bare minimum ChozoGhostBoss, any( GravitySuit, @@ -685,11 +691,11 @@ CanTrickySparks ) ), - "Chozodia West of Glass Tube": all( + "Chozodia Left of Glass Tube": all( SpeedBooster, CanReachEntrance("Chozodia Glass Tube -> Chozo Ruins") # Required to access a save station after collecting to warp if necessary ), - "Chozodia Southeast of Glass Tube": all( + "Chozodia Right of Glass Tube": all( PowerBombs, CanFly ) @@ -727,8 +733,17 @@ } chozodia_cockpit = { - "Chozodia Original Power Bomb": None, - "Chozodia Next to Original Power Bomb": CanFly, + "Chozodia Original Power Bomb": any( + CanWallJump, + HiJump, + PowerGrip, + SpaceJump + ), # cannot IBJ to escape + "Chozodia Next to Original Power Bomb": all( + PowerBombs, + CanFly, + CanReachLocation("Chozodia Original Power Bomb") + ) } chozodia_mecha_ridley_hall = { From 828725dd44f45526108dd3abe611a20c2f69c6f5 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Thu, 15 Aug 2024 00:02:21 -0400 Subject: [PATCH 09/14] Fix Kraid bottom access Kraid Unknown, access to which determines left shaft -> bottom access, was in the wrong region --- locations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locations.py b/locations.py index 588359b..31eec43 100644 --- a/locations.py +++ b/locations.py @@ -45,7 +45,7 @@ def __init__(self, reg, id): "Kraid Save Room Tunnel": LocationData("Kraid Main", AP_MZM_ID_BASE + 20), #TODO renamed "Kraid Zipline Morph Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 21), #TODO renamed "Kraid Quad Ball Cannon Room": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 22), - "Kraid Unknown Item Statue": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 23), #TODO Renamed + "Kraid Unknown Item Statue": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 23), #TODO Renamed "Kraid Acid Ballspark": LocationData("Kraid Main", AP_MZM_ID_BASE + 24), "Kraid Speed Booster": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 25), "Kraid Under Acid Worm": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 26), #TODO renamed From 5664f95581c12039c2c5676cce384ccda182b3d0 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Fri, 16 Aug 2024 00:29:42 -0400 Subject: [PATCH 10/14] A few Brinstar changes - Varia Suit area now checks for horizontal IBJ and allows tricky sparks as valid for both locations - Made ripper climb tricky spark require advanced logic cause of hard, may change this later --- locations.py | 4 ++-- rules.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/locations.py b/locations.py index 31eec43..a5ea5df 100644 --- a/locations.py +++ b/locations.py @@ -27,9 +27,9 @@ def __init__(self, reg, id): "Brinstar Ballspark": LocationData("Brinstar Main", AP_MZM_ID_BASE + 5), #TODO Renamed "Brinstar Ripper Climb": LocationData("Brinstar Main", AP_MZM_ID_BASE + 6), # TODO Renamed "Brinstar Speed Booster Shortcut": LocationData("Brinstar Main", AP_MZM_ID_BASE + 7), #TODO Renamed - "Brinstar Varia Suit": LocationData("Brinstar Top", AP_MZM_ID_BASE + 8), + "Brinstar Varia Suit": LocationData("Brinstar Top", AP_MZM_ID_BASE + 8), #may change region "Brinstar Worm drop": LocationData("Brinstar Main", AP_MZM_ID_BASE + 9), - "Brinstar Acid near Varia": LocationData("Brinstar Top", AP_MZM_ID_BASE + 10), + "Brinstar Acid near Varia": LocationData("Brinstar Top", AP_MZM_ID_BASE + 10), #may change region "Brinstar First Missile": LocationData("Brinstar Main", AP_MZM_ID_BASE + 11), "Brinstar Behind Hive": LocationData("Brinstar Main", AP_MZM_ID_BASE + 12), "Brinstar Under Bridge": LocationData("Brinstar Main", AP_MZM_ID_BASE + 13), diff --git a/rules.py b/rules.py index a7be078..2d8ff88 100644 --- a/rules.py +++ b/rules.py @@ -58,7 +58,8 @@ CanIBJ, all( CanBallspark, - CanTrickySparks + CanTrickySparks, + AdvancedLogic # mzmr says this is doable but i might make it require screw + space, it's so hard ) ), "Brinstar Speed Booster Shortcut": all( @@ -89,7 +90,8 @@ brinstar_top = { "Brinstar Varia Suit": all( any( - CanFly, + SpaceJump, + CanHorizontalIBJ, CanHiGrip, CanTrickySparks ), @@ -109,8 +111,10 @@ ), "Brinstar Acid near Varia": all( any( - CanFly, - CanHiGrip + SpaceJump, + CanHorizontalIBJ, + CanHiGrip, + CanTrickySparks ), CanBallJump, CanLongBeam, @@ -205,7 +209,7 @@ KraidBoss, SpeedBooster ), - "Kraid Acid Fall": None, # doesn't require anything more than access to the region + "Kraid Acid Fall": None, "Kraid": all( any( UnknownItem2, From af743e554489c4a2c803f51e9da4f7ccb4dfcec3 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:49:03 -0400 Subject: [PATCH 11/14] Connect bottom Norfair to screw attack area --- logic.py | 12 ++++++++++++ regions.py | 1 + 2 files changed, 13 insertions(+) diff --git a/logic.py b/logic.py index 45a39f4..ad606c8 100644 --- a/logic.py +++ b/logic.py @@ -549,6 +549,18 @@ def bottom_norfair_to_ridley(): ) +def bottom_norfair_to_screw(): + return all( + RidleyBoss, + SpeedBooster, + CanBallCannon, + any( + IceBeam, + CanVerticalWall + ) + ) + + # LN elevator to the bottom long hall # connects to right shaft with no extra req's # this happens to cover the reqs for left pillar, fake floor, long room, and the ability to get to right shaft diff --git a/regions.py b/regions.py index 34d8923..92397e6 100644 --- a/regions.py +++ b/regions.py @@ -97,6 +97,7 @@ def create_regions_and_connections(world: MZMWorld): connect(multiworld, player, "Lower Norfair -> Kraid", "Lower Norfair", "Kraid Bottom", lower_norfair_to_kraid().create_rule(world)) connect(multiworld, player, "Lower Norfair -> Bottom", "Lower Norfair", "Norfair Bottom", lower_norfair_to_bottom_norfair().create_rule(world)) connect(multiworld, player, "Norfair -> Ridley Elevator", "Norfair Bottom", "Ridley Main", bottom_norfair_to_ridley().create_rule(world)) + connect(multiworld, player, "Norfair Bottom -> Screw Attack", "Norfair Bottom", "Norfair Screw Attack Area", bottom_norfair_to_screw().create_rule(world)) connect(multiworld, player, "Ridley Elevator -> Left Shaft", "Ridley Main", "Ridley Left Shaft", ridley_main_to_left_shaft().create_rule(world)) connect(multiworld, player, "Ridley Elevator -> Right Shaft Shortcut", "Ridley Main", "Ridley Right Shaft", ridley_main_to_right_shaft().create_rule(world)) connect(multiworld, player, "Ridley Left Shaft -> SW Puzzle", "Ridley Left Shaft", "Ridley SW Puzzle", ridley_left_shaft_to_sw_puzzle().create_rule(world)) From b5ed6150e8d16a9d1b08d28acbe78b1c4d8a4a89 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Tue, 20 Aug 2024 00:20:17 -0400 Subject: [PATCH 12/14] Fix some wrong assumptions about Lower Norfair --- locations.py | 2 +- logic.py | 11 +++++++++++ regions.py | 1 + rules.py | 27 ++++++++++++++++++++++++--- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/locations.py b/locations.py index a5ea5df..6528508 100644 --- a/locations.py +++ b/locations.py @@ -137,7 +137,7 @@ def __init__(self, reg, id): "Chozodia Chozo Ghost Area Long Shinespark": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 94), "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), #TODO renamed "Chozodia Behind Workbot": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 96), #TODO Renamed - "Chozodia Mothership Ceiling Near ZSS Start": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 97), + "Chozodia Ceiling Near Map Station": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 97), #TODO renamed "Chozodia Under Mecha Ridley Hallway": LocationData("Chozodia Mecha Ridley Hallway", AP_MZM_ID_BASE + 98), "Chozodia Southeast Corner In Hull": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 99), "Chozo Ghost": LocationData("Chozodia Ruins Test Area", None), diff --git a/logic.py b/logic.py index ad606c8..747e122 100644 --- a/logic.py +++ b/logic.py @@ -480,6 +480,13 @@ def lower_norfair_to_screwattack(): ) +def screw_to_lower_norfair(): + return any( + MissileCount(4), + ScrewAttack + ) + + def lower_norfair_to_kraid(): return all( ScrewAttack, @@ -528,6 +535,10 @@ def lower_norfair_to_bottom_norfair(): return all( MissileCount(2), SpeedBooster, + any( + VariaSuit, + Hellrun(1) + ), any( WaveBeam, CanTrickySparks diff --git a/regions.py b/regions.py index 92397e6..81055d9 100644 --- a/regions.py +++ b/regions.py @@ -98,6 +98,7 @@ def create_regions_and_connections(world: MZMWorld): connect(multiworld, player, "Lower Norfair -> Bottom", "Lower Norfair", "Norfair Bottom", lower_norfair_to_bottom_norfair().create_rule(world)) connect(multiworld, player, "Norfair -> Ridley Elevator", "Norfair Bottom", "Ridley Main", bottom_norfair_to_ridley().create_rule(world)) connect(multiworld, player, "Norfair Bottom -> Screw Attack", "Norfair Bottom", "Norfair Screw Attack Area", bottom_norfair_to_screw().create_rule(world)) + connect(multiworld, player, "Norfair Screw Attack -> Lower Norfair", "Norfair Screw Attack Area", "Lower Norfair", screw_to_lower_norfair().create_rule(world)) connect(multiworld, player, "Ridley Elevator -> Left Shaft", "Ridley Main", "Ridley Left Shaft", ridley_main_to_left_shaft().create_rule(world)) connect(multiworld, player, "Ridley Elevator -> Right Shaft Shortcut", "Ridley Main", "Ridley Right Shaft", ridley_main_to_right_shaft().create_rule(world)) connect(multiworld, player, "Ridley Left Shaft -> SW Puzzle", "Ridley Left Shaft", "Ridley SW Puzzle", ridley_left_shaft_to_sw_puzzle().create_rule(world)) diff --git a/rules.py b/rules.py index 2d8ff88..005368f 100644 --- a/rules.py +++ b/rules.py @@ -334,8 +334,29 @@ CanVerticalWall, ), "Norfair Wave Beam": MissileCount(4), - "Norfair Heated Room Below Wave - Left": None, - "Norfair Heated Room Below Wave - Right": None, + "Norfair Heated Room Below Wave - Left": all( + CanVerticalWall, + any( + VariaSuit, + Hellrun(2) + ), + any( + CanIBJ, + HiJump, + PowerGrip, + all( + IceBeam, + Bomb + ) + ) + ), + "Norfair Heated Room Below Wave - Right": all( + CanVerticalWall, + any( + VariaSuit, + Hellrun(2) + ) + ), } norfair_screwattack = { @@ -725,7 +746,7 @@ ) ), "Chozodia Behind Workbot": MissileCount(5), - "Chozodia Mothership Ceiling Near ZSS Start": all( + "Chozodia Ceiling Near Map Station": all( Missiles, any( PowerBombs, From b807f8771335af6ccd1a3551d8d512e7675e6c07 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:01:02 -0400 Subject: [PATCH 13/14] New region for Original PB, various cleanup --- locations.py | 5 ++--- logic.py | 36 +++++++++++++++++++++++++++++------- regions.py | 4 ++-- rules.py | 15 ++++----------- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/locations.py b/locations.py index 6528508..a00f6fa 100644 --- a/locations.py +++ b/locations.py @@ -16,7 +16,6 @@ def __init__(self, reg, id): # Location numbers/order and some names from Biospark's MZM Randomizer. # Events in any region must be at the end of its table for the client to work correctly -# TODO: Double check that these are all correctly assigned to their right regions brinstar_location_table = { "Brinstar Morph Ball": LocationData("Brinstar Start", AP_MZM_ID_BASE + 0), @@ -131,8 +130,8 @@ def __init__(self, reg, id): "Chozodia Triple Crawling Pirates": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 88), #TODO renamed "Chozodia Left of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), #TODO renamed "Chozodia Lava Dive": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 90), #TODO Renamed - "Chozodia Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 91), - "Chozodia Next to Original Power Bomb": LocationData("Chozodia Mothership Cockpit", AP_MZM_ID_BASE + 92), + "Chozodia Original Power Bomb": LocationData("Chozodia Original Power Bomb Room", AP_MZM_ID_BASE + 91), + "Chozodia Next to Original Power Bomb": LocationData("Chozodia Original Power Bomb Room", AP_MZM_ID_BASE + 92), "Chozodia Right of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), #TODO Renamed "Chozodia Chozo Ghost Area Long Shinespark": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 94), "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), #TODO renamed diff --git a/logic.py b/logic.py index 747e122..993c86d 100644 --- a/logic.py +++ b/logic.py @@ -157,7 +157,6 @@ def any(*args: Requirement): Requirement.setting_atleast("ibj_in_logic", 2) ) CanWallJump = Requirement.setting_atleast("walljumps_in_logic", 1) -#CanAdvancedWallJump = Requirement.setting_atleast("walljumps_in_logic", 2) #TODO CanTrickySparks = all( Requirement.setting_enabled("tricky_shinesparks"), SpeedBooster, @@ -356,7 +355,6 @@ def norfair_upper_right_shaft(): ) -# used for one item and the ridley shortcut def norfair_behind_ice_beam(): return all( any( @@ -572,9 +570,6 @@ def bottom_norfair_to_screw(): ) -# LN elevator to the bottom long hall -# connects to right shaft with no extra req's -# this happens to cover the reqs for left pillar, fake floor, long room, and the ability to get to right shaft def ridley_main_to_left_shaft(): return all( SuperMissiles, @@ -631,6 +626,7 @@ def ridley_left_shaft_to_sw_puzzle(): ) +# The alcove to the right of the right shaft def ridley_speed_puzzles_access(): return all( SpeedBooster, @@ -722,7 +718,8 @@ def chozo_ruins_to_chozodia_tube(): CanFly ) -# Relevant for region/elevator rando + +# Specifically getting to the room with Crateria Upper Door location. Might need another empty region for region rando def chozodia_tube_to_chozo_ruins(): return all( any( @@ -819,7 +816,32 @@ def mothership_central_to_cockpit(): ) -# From cockpit to Mecha Ridley hallway +def cockpit_to_original_pb(): + return all( + any( + CanWallJump, + HiJump, + PowerGrip, + SpaceJump + ), # cannot IBJ to escape to cockpit + any( + CanIBJ, + all( + PowerGrip, + any( + CanFlyWall, + HiJump + ) + ), + all( + AdvancedLogic, + IceBeam, + CanBallJump + ) + ) + ) + + # This one stupid room is so randomly complicated lol def cockpit_to_mecha_ridley(): return all( diff --git a/regions.py b/regions.py index 81055d9..90913cb 100644 --- a/regions.py +++ b/regions.py @@ -29,7 +29,6 @@ def connect(world: MultiWorld, player: int, entrance_name: str, source: str, tar def create_regions_and_connections(world: MZMWorld): - # create all regions and populate with locations player = world.player multiworld = world.multiworld @@ -67,6 +66,7 @@ def create_regions_and_connections(world: MZMWorld): create_region(multiworld, player, "Chozodia Under Tube") create_region(multiworld, player, "Chozodia Mothership Central") create_region(multiworld, player, "Chozodia Mothership Cockpit") + create_region(multiworld, player, "Chozodia Original Power Bomb Room") create_region(multiworld, player, "Chozodia Mecha Ridley Hallway") create_region(multiworld, player, "Mission Accomplished!") @@ -77,7 +77,6 @@ def create_regions_and_connections(world: MZMWorld): connect(multiworld, player, "Brinstar Past Hives -> Top", "Brinstar Past Hives", "Brinstar Top", brinstar_pasthives_to_brinstar_top().create_rule(world)) connect(multiworld, player, "Brinstar Top -> Past Hives", "Brinstar Top", "Brinstar Past Hives", CanEnterMediumMorphTunnel.create_rule(world)) connect(multiworld, player, "Brinstar -> Kraid Elevator", "Brinstar Start", "Kraid Main", CanSingleBombBlock.create_rule(world)) - #TODO: account for layout patches in Brinstar -> Norfair elevator connect(multiworld, player, "Brinstar -> Norfair Elevator", "Brinstar Main", "Norfair Main", CanBombTunnelBlock.create_rule(world)) connect(multiworld, player, "Brinstar -> Tourian Elevator", "Brinstar Main", "Tourian", all(MorphBall, KraidBoss, RidleyBoss).create_rule(world)) connect(multiworld, player, "Brinstar -> Crateria Ballcannon", "Brinstar Start", "Upper Crateria", brinstar_crateria_ballcannon().create_rule(world)) @@ -119,4 +118,5 @@ def create_regions_and_connections(world: MZMWorld): connect(multiworld, player, "Chozodia Glass Tube -> Chozo Ruins", "Chozodia Glass Tube", "Chozodia Ruins", chozodia_tube_to_chozo_ruins().create_rule(world)) connect(multiworld, player, "Chozozia Glass Tube -> Mothership Central", "Chozodia Glass Tube", "Chozodia Mothership Central", chozodia_tube_to_mothership_central().create_rule(world)) connect(multiworld, player, "Chozodia Mothership -> Cockpit", "Chozodia Mothership Central", "Chozodia Mothership Cockpit", mothership_central_to_cockpit().create_rule(world)) + connect(multiworld, player, "Chozodia Cockpit -> Original PB", "Chozodia Mothership Cockpit", "Chozodia Original Power Bomb Room", cockpit_to_original_pb().create_rule(world)) connect(multiworld, player, "Chozodia Cockpit -> Mecha Ridley", "Chozodia Mothership Cockpit", "Chozodia Mecha Ridley Hallway", cockpit_to_mecha_ridley().create_rule(world)) diff --git a/rules.py b/rules.py index 005368f..d8cf628 100644 --- a/rules.py +++ b/rules.py @@ -465,7 +465,6 @@ ) } -# obviously, requires speed booster ridley_right_speed_puzzles = { "Ridley Bomb Puzzle": all( Bomb, @@ -757,17 +756,11 @@ "Chozodia Southeast Corner In Hull": PowerBombs } -chozodia_cockpit = { - "Chozodia Original Power Bomb": any( - CanWallJump, - HiJump, - PowerGrip, - SpaceJump - ), # cannot IBJ to escape +chozodia_pb_area = { + "Chozodia Original Power Bomb": None, "Chozodia Next to Original Power Bomb": all( PowerBombs, - CanFly, - CanReachLocation("Chozodia Original Power Bomb") + CanFly ) } @@ -823,7 +816,7 @@ **chozodia_ruins_test, **chozodia_under_tube, **chozodia_mothership, - **chozodia_cockpit, + **chozodia_pb_area, **chozodia_mecha_ridley_hall } From b1fb542f4a1a2441f508b102b97308322f87a752 Mon Sep 17 00:00:00 2001 From: NoiseCrush <168460988+NoiseCrush@users.noreply.github.com> Date: Fri, 23 Aug 2024 18:47:03 -0400 Subject: [PATCH 14/14] Remove unnecessary comments --- locations.py | 96 ++++++++++++++++++++++++++-------------------------- logic.py | 1 - 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/locations.py b/locations.py index a00f6fa..ea52ae2 100644 --- a/locations.py +++ b/locations.py @@ -22,61 +22,61 @@ def __init__(self, reg, id): "Brinstar Morph Ball Cannon": LocationData("Brinstar Start", AP_MZM_ID_BASE + 1), "Brinstar Long Beam": LocationData("Brinstar Main", AP_MZM_ID_BASE + 2), "Brinstar Ceiling E-Tank": LocationData("Brinstar Start", AP_MZM_ID_BASE + 3), - "Brinstar Main Shaft Left Alcove": LocationData("Brinstar Main", AP_MZM_ID_BASE + 4), #TODO Renamed - "Brinstar Ballspark": LocationData("Brinstar Main", AP_MZM_ID_BASE + 5), #TODO Renamed - "Brinstar Ripper Climb": LocationData("Brinstar Main", AP_MZM_ID_BASE + 6), # TODO Renamed - "Brinstar Speed Booster Shortcut": LocationData("Brinstar Main", AP_MZM_ID_BASE + 7), #TODO Renamed - "Brinstar Varia Suit": LocationData("Brinstar Top", AP_MZM_ID_BASE + 8), #may change region + "Brinstar Main Shaft Left Alcove": LocationData("Brinstar Main", AP_MZM_ID_BASE + 4), + "Brinstar Ballspark": LocationData("Brinstar Main", AP_MZM_ID_BASE + 5), + "Brinstar Ripper Climb": LocationData("Brinstar Main", AP_MZM_ID_BASE + 6), + "Brinstar Speed Booster Shortcut": LocationData("Brinstar Main", AP_MZM_ID_BASE + 7), + "Brinstar Varia Suit": LocationData("Brinstar Top", AP_MZM_ID_BASE + 8), "Brinstar Worm drop": LocationData("Brinstar Main", AP_MZM_ID_BASE + 9), - "Brinstar Acid near Varia": LocationData("Brinstar Top", AP_MZM_ID_BASE + 10), #may change region + "Brinstar Acid near Varia": LocationData("Brinstar Top", AP_MZM_ID_BASE + 10), "Brinstar First Missile": LocationData("Brinstar Main", AP_MZM_ID_BASE + 11), "Brinstar Behind Hive": LocationData("Brinstar Main", AP_MZM_ID_BASE + 12), "Brinstar Under Bridge": LocationData("Brinstar Main", AP_MZM_ID_BASE + 13), - "Brinstar Post-Hive In Wall": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 14), #TODO renamed - "Brinstar Upper Pillar": LocationData("Brinstar Top", AP_MZM_ID_BASE + 15), #TODO renamed + "Brinstar Post-Hive In Wall": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 14), + "Brinstar Upper Pillar": LocationData("Brinstar Top", AP_MZM_ID_BASE + 15), "Brinstar Behind Bombs": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 16), "Brinstar Bomb": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 17), - "Brinstar Post-Hive Pillar": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 18) #TODO renamed + "Brinstar Post-Hive Pillar": LocationData("Brinstar Past Hives", AP_MZM_ID_BASE + 18) } kraid_location_table = { - "Kraid Behind Giant Hoppers": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 19), #TODO Renamed - "Kraid Save Room Tunnel": LocationData("Kraid Main", AP_MZM_ID_BASE + 20), #TODO renamed - "Kraid Zipline Morph Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 21), #TODO renamed + "Kraid Behind Giant Hoppers": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 19), + "Kraid Save Room Tunnel": LocationData("Kraid Main", AP_MZM_ID_BASE + 20), + "Kraid Zipline Morph Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 21), "Kraid Quad Ball Cannon Room": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 22), - "Kraid Unknown Item Statue": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 23), #TODO Renamed + "Kraid Unknown Item Statue": LocationData("Kraid Left Shaft", AP_MZM_ID_BASE + 23), "Kraid Acid Ballspark": LocationData("Kraid Main", AP_MZM_ID_BASE + 24), "Kraid Speed Booster": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 25), - "Kraid Under Acid Worm": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 26), #TODO renamed - "Kraid Right Hall Pillar": LocationData("Kraid Main", AP_MZM_ID_BASE + 27), #TODO renamed + "Kraid Under Acid Worm": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 26), + "Kraid Right Hall Pillar": LocationData("Kraid Main", AP_MZM_ID_BASE + 27), "Kraid Acid Fall": LocationData("Kraid Bottom", AP_MZM_ID_BASE + 28), - "Kraid Zipline Activator Room": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 29), #TODO renamed + "Kraid Zipline Activator Room": LocationData("Kraid Acid Worm Area", AP_MZM_ID_BASE + 29), "Kraid Speed Jump": LocationData("Kraid Main", AP_MZM_ID_BASE + 30), "Kraid Upper Right Morph Ball Cannon": LocationData("Kraid Main", AP_MZM_ID_BASE + 31), "Kraid": LocationData("Kraid Bottom", None) } norfair_location_table = { - "Norfair Lava Dive Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 32), #TODO Renamed - "Norfair Lava Dive Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 33), #TODO renamed + "Norfair Lava Dive Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 32), + "Norfair Lava Dive Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 33), "Norfair Screw Attack": LocationData("Norfair Screw Attack Area", AP_MZM_ID_BASE + 34), - "Norfair Next to Screw Attack": LocationData("Norfair Screw Attack Area", AP_MZM_ID_BASE + 35), #TODO renamed - "Norfair Hallway to Crateria": LocationData("Norfair Main", AP_MZM_ID_BASE + 36), #TODO renamed + "Norfair Next to Screw Attack": LocationData("Norfair Screw Attack Area", AP_MZM_ID_BASE + 35), + "Norfair Hallway to Crateria": LocationData("Norfair Main", AP_MZM_ID_BASE + 36), "Norfair Under Crateria Elevator": LocationData("Norfair Main", AP_MZM_ID_BASE + 37), "Norfair Wave Beam": LocationData("Lower Norfair", AP_MZM_ID_BASE + 38), - "Norfair Bomb Trap": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 39), #TODO may change region - "Norfair Heated Room Below Wave - Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 40), #TODO Renamed - "Norfair Heated Room Below Wave - Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 41), #TODO Renamed - "Norfair Heated Room Under Brinstar Elevator": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 42), #TODO may change region - "Norfair Behind Lower Super Missile Door - Right": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 43), #TODO Renamed - "Norfair Behind Lower Super Missile Door - Left": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 44), #TODO renamed + "Norfair Bomb Trap": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 39), + "Norfair Heated Room Below Wave - Left": LocationData("Lower Norfair", AP_MZM_ID_BASE + 40), + "Norfair Heated Room Below Wave - Right": LocationData("Lower Norfair", AP_MZM_ID_BASE + 41), + "Norfair Heated Room Under Brinstar Elevator": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 42), + "Norfair Behind Lower Super Missile Door - Right": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 43), + "Norfair Behind Lower Super Missile Door - Left": LocationData("Norfair Behind Super Door", AP_MZM_ID_BASE + 44), "Norfair Ice Beam": LocationData("Norfair Upper Right Shaft", AP_MZM_ID_BASE + 45), "Norfair Heated Room above Ice Beam": LocationData("Norfair Upper Right Shaft", AP_MZM_ID_BASE + 46), "Norfair Hi-Jump": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 47), "Norfair Big Room": LocationData("Norfair Right Shaft", AP_MZM_ID_BASE + 48), "Norfair Behind Top Chozo Statue": LocationData("Norfair Behind Ice Beam", AP_MZM_ID_BASE + 49), - "Norfair Larva Ceiling": LocationData("Norfair Bottom", AP_MZM_ID_BASE + 50), #TODO Renamed - "Norfair Right Shaft Near Hi-Jump": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 51), #TODO Renamed + "Norfair Larva Ceiling": LocationData("Norfair Bottom", AP_MZM_ID_BASE + 50), + "Norfair Right Shaft Near Hi-Jump": LocationData("Norfair Lower Right Shaft", AP_MZM_ID_BASE + 51), "Norfair Right Shaft Bottom": LocationData("Norfair Bottom", AP_MZM_ID_BASE + 52) } @@ -84,21 +84,21 @@ def __init__(self, reg, id): "Ridley Southwest Puzzle Top": LocationData("Ridley SW Puzzle", AP_MZM_ID_BASE + 53), "Ridley Southwest Puzzle Bottom": LocationData("Ridley SW Puzzle", AP_MZM_ID_BASE + 54), "Ridley West Pillar": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 55), - "Ridley Behind Unknown Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 56), #TODO Renamed - "Ridley Unknown Item Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 57), #TODO Renamed - "Ridley Fake Floor": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 58), #TODO Renamed - "Ridley Upper Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 59), #TODO may change region - "Ridley Lower Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 60), #TODO may change region + "Ridley Behind Unknown Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 56), + "Ridley Unknown Item Statue": LocationData("Ridley Room", AP_MZM_ID_BASE + 57), + "Ridley Fake Floor": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 58), + "Ridley Upper Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 59), + "Ridley Lower Ball Cannon Puzzle": LocationData("Central Ridley", AP_MZM_ID_BASE + 60), "Ridley Imago Super Missile": LocationData("Ridley Main", AP_MZM_ID_BASE + 61), "Ridley After Sidehopper Hall Upper": LocationData("Central Ridley", AP_MZM_ID_BASE + 62), "Ridley After Sidehopper Hall Lower": LocationData("Central Ridley", AP_MZM_ID_BASE + 63), "Ridley Long Hall": LocationData("Ridley Left Shaft", AP_MZM_ID_BASE + 64), - "Ridley Center Pillar": LocationData("Central Ridley", AP_MZM_ID_BASE + 65), #TODO Renamed - "Ridley Ball Room Lower": LocationData("Central Ridley", AP_MZM_ID_BASE + 66), #TODO Renamed - "Ridley Ball Room Upper": LocationData("Central Ridley", AP_MZM_ID_BASE + 67), #TODO Renamed - "Ridley Fake Lava Under Floor": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 68), #TODO Renamed - "Ridley Under Owls": LocationData("Central Ridley", AP_MZM_ID_BASE + 69), #TODO Renamed - "Ridley Northeast Corner": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 70), #TODO Renamed + "Ridley Center Pillar": LocationData("Central Ridley", AP_MZM_ID_BASE + 65), + "Ridley Ball Room Lower": LocationData("Central Ridley", AP_MZM_ID_BASE + 66), + "Ridley Ball Room Upper": LocationData("Central Ridley", AP_MZM_ID_BASE + 67), + "Ridley Fake Lava Under Floor": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 68), + "Ridley Under Owls": LocationData("Central Ridley", AP_MZM_ID_BASE + 69), + "Ridley Northeast Corner": LocationData("Ridley Right Shaft", AP_MZM_ID_BASE + 70), "Ridley Bomb Puzzle": LocationData("Ridley Speed Puzzles", AP_MZM_ID_BASE + 71), "Ridley Speed Jump": LocationData("Ridley Speed Puzzles", AP_MZM_ID_BASE + 72), "Ridley": LocationData("Ridley Room", None) @@ -115,7 +115,7 @@ def __init__(self, reg, id): "Crateria Power Grip": LocationData("Upper Crateria", AP_MZM_ID_BASE + 76), "Crateria Moat": LocationData("Crateria", AP_MZM_ID_BASE + 77), "Crateria Statue Water": LocationData("Upper Crateria", AP_MZM_ID_BASE + 78), - "Crateria Unknown Item Statue": LocationData("Upper Crateria", AP_MZM_ID_BASE + 79), #TODO renamed + "Crateria Unknown Item Statue": LocationData("Upper Crateria", AP_MZM_ID_BASE + 79), "Crateria East Ballspark": LocationData("Upper Crateria", AP_MZM_ID_BASE + 80), "Crateria Northeast Corner": LocationData("Upper Crateria", AP_MZM_ID_BASE + 81) } @@ -124,19 +124,19 @@ def __init__(self, reg, id): "Chozodia Upper Crateria Door": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 82), "Chozodia Bomb Maze": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 83), "Chozodia Zoomer Maze": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 84), - "Chozodia Ruins East of Upper Crateria Door": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 85), #TODO renamed + "Chozodia Ruins East of Upper Crateria Door": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 85), "Chozodia Chozo Ghost Area Morph Tunnel Above Water": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 86), "Chozodia Chozo Ghost Area Underwater": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 87), - "Chozodia Triple Crawling Pirates": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 88), #TODO renamed - "Chozodia Left of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), #TODO renamed - "Chozodia Lava Dive": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 90), #TODO Renamed + "Chozodia Triple Crawling Pirates": LocationData("Chozodia Ruins", AP_MZM_ID_BASE + 88), + "Chozodia Left of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 89), + "Chozodia Lava Dive": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 90), "Chozodia Original Power Bomb": LocationData("Chozodia Original Power Bomb Room", AP_MZM_ID_BASE + 91), "Chozodia Next to Original Power Bomb": LocationData("Chozodia Original Power Bomb Room", AP_MZM_ID_BASE + 92), - "Chozodia Right of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), #TODO Renamed + "Chozodia Right of Glass Tube": LocationData("Chozodia Under Tube", AP_MZM_ID_BASE + 93), "Chozodia Chozo Ghost Area Long Shinespark": LocationData("Chozodia Ruins Test Area", AP_MZM_ID_BASE + 94), - "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), #TODO renamed - "Chozodia Behind Workbot": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 96), #TODO Renamed - "Chozodia Ceiling Near Map Station": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 97), #TODO renamed + "Chozodia Pirate Pitfall Trap": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 95), + "Chozodia Behind Workbot": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 96), + "Chozodia Ceiling Near Map Station": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 97), "Chozodia Under Mecha Ridley Hallway": LocationData("Chozodia Mecha Ridley Hallway", AP_MZM_ID_BASE + 98), "Chozodia Southeast Corner In Hull": LocationData("Chozodia Mothership Central", AP_MZM_ID_BASE + 99), "Chozo Ghost": LocationData("Chozodia Ruins Test Area", None), diff --git a/logic.py b/logic.py index 993c86d..e467997 100644 --- a/logic.py +++ b/logic.py @@ -842,7 +842,6 @@ def cockpit_to_original_pb(): ) -# This one stupid room is so randomly complicated lol def cockpit_to_mecha_ridley(): return all( CanBombTunnelBlock,