diff --git a/worlds/am2r/items.py b/worlds/am2r/items.py index 361c89e8a7d0..0af01a34c176 100644 --- a/worlds/am2r/items.py +++ b/worlds/am2r/items.py @@ -17,15 +17,15 @@ class AM2RItemData(NamedTuple): "Missile Launcher": AM2RItemData(ItemClassification.progression, 300, 0), "Super Missile": AM2RItemData(ItemClassification.filler, 16, 0), - "Super Missile Launcher": AM2RItemData(ItemClassification.progression, 300, 0), + "Super Missile Launcher": AM2RItemData(ItemClassification.progression, 301, 0), "Power Bomb": AM2RItemData(ItemClassification.filler, 18, 0), - "Power Bomb Launcher": AM2RItemData(ItemClassification.progression, 300, 0), + "Power Bomb Launcher": AM2RItemData(ItemClassification.progression, 302, 0), "Energy Tank": AM2RItemData(ItemClassification.filler, 17, 0), - "Morph Ball": AM2RItemData(ItemClassification.progression, 300, 0), - "Power Grip": AM2RItemData(ItemClassification.progression, 300, 0), + "Morph Ball": AM2RItemData(ItemClassification.progression, 303, 0), + "Power Grip": AM2RItemData(ItemClassification.progression, 304, 0), "Bombs": AM2RItemData(ItemClassification.progression, 0, 1), "Spider Ball": AM2RItemData(ItemClassification.progression, 2, 1), "Hi Jump": AM2RItemData(ItemClassification.progression, 4, 1), @@ -38,7 +38,7 @@ class AM2RItemData(NamedTuple): "Varia Suit": AM2RItemData(ItemClassification.progression, 5, 1), "Gravity Suit": AM2RItemData(ItemClassification.progression, 9, 1), - "Arm Cannon": AM2RItemData(ItemClassification.progression, 300, 0), + "Arm Cannon": AM2RItemData(ItemClassification.progression, 305, 0), "Charge Beam": AM2RItemData(ItemClassification.progression, 10, 1), "Wave Beam": AM2RItemData(ItemClassification.useful, 12, 1), "Spazer": AM2RItemData(ItemClassification.useful, 13, 1), @@ -52,6 +52,10 @@ class AM2RItemData(NamedTuple): "OHKO Trap": AM2RItemData(ItemClassification.trap, 25, 0), "Touhou Trap": AM2RItemData(ItemClassification.trap, 26, 0), + "EMP": AM2RItemData(ItemClassification.event, None, 0), # todo: This will be made in init as a event not in items I just needed this down somewhere + "Tower Activation": AM2RItemData(ItemClassification.event, None, 0), + "Geothermal": AM2RItemData(ItemClassification.event, None, 0), + "Metroid": AM2RItemData(ItemClassification.progression_skip_balancing, 19, 0) } diff --git a/worlds/am2r/locations.py b/worlds/am2r/locations.py index a445e1d43471..bd621ee4f846 100644 --- a/worlds/am2r/locations.py +++ b/worlds/am2r/locations.py @@ -8,7 +8,7 @@ class AM2RLocationData(NamedTuple): location_group: str = "region" -location_based_id = 8678000 +location_based_id = 108678000 location_table: Dict[str, AM2RLocationData] = { "Main Caves: Spider Ball Challenge Upper": AM2RLocationData("Main Caves", 53), @@ -67,15 +67,16 @@ class AM2RLocationData(NamedTuple): "Industrial Complex: Complex Side Tunnel": AM2RLocationData("Pre Industrial Complex", 200), "Industrial Complex: Behind the Green Door": AM2RLocationData("Pre Industrial Complex", 212), "Industrial Complex: Save Room": AM2RLocationData("Pre Industrial Complex", 203), - "Industrial Complex: Spazer Beam": AM2RLocationData("Pre Industrial Complex", 13), - "Industrial Complex: Sisyphus Spark": AM2RLocationData("Pre Industrial Complex", 204), - "Industrial Complex: Speed Booster": AM2RLocationData("Pre Industrial Complex", 7), + + "Industrial Complex: Spazer Beam": AM2RLocationData("Complex Sand", 13), + "Industrial Complex: Sisyphus Spark": AM2RLocationData("Complex Sand", 204), + "Industrial Complex: Speed Booster": AM2RLocationData("Complex Sand", 7), "Torizo Ascended: Boss": AM2RLocationData("Torizo Ascended", 6), "Industrial Complex: Conveyor Belt Room": AM2RLocationData("Industrial Complex", 205), "Industrial Complex: Doom Treadmill": AM2RLocationData("Industrial Complex", 201), - "Industrial Complex: Complex Hub Shinespark" AM2RLocationData("Industrial Complex", 208), + "Industrial Complex: Complex Hub Shinespark": AM2RLocationData("Industrial Complex", 208), "Industrial Complex: Complex Hub in the Floor": AM2RLocationData("Industrial Complex", 207), "Industrial Complex: Skippy Reward": AM2RLocationData("Industrial Complex", 206), diff --git a/worlds/am2r/options.py b/worlds/am2r/options.py index 064c5934eebf..0b2fcc7118a5 100644 --- a/worlds/am2r/options.py +++ b/worlds/am2r/options.py @@ -6,15 +6,45 @@ class LogicDificulty(Choice): """Easy: Assumes developer intended solutions and expects little to none trick knowledge and less than optimal use of ammos Required Tricks: Simple single wall Wall-Jumps, Knowledge of the Low% Super Missile block in Distribution Center - Required Damage: Hydro Station Nest Vines with 2 E-Tanks + Expected Damage: Hydro Station Nest Vines with 2 E-Tanks Normal: Assumes knowledge over the game and expects some trick knowledge Required Tricks: Simple Morph Glides, tricky single wall Wall-Jumps, Knowledge of Shinesparks to reach areas - Required Damage: Hydro Nest Vines (1E), Doom Treadmill Spikes, Spikes to Patricia(A4 Right Side Zeta)""" + Expected Damage: Hydro Nest Vines (1E), Doom Treadmill Spikes, Spikes to Patricia (A4 Right Side Zeta) + Hard: Assumes great technical skill over the game and expects a lot of trick knowledge + Required Tricks: + Expected Damage: Any stated above, Various Spike wall-jumps, spike paths to the A4 gammas, A5 Spiky Trial + """ display_name = "Logic Dificulty" default = 0 option_easy = 0 option_normal = 1 option_hard = 2 # todo add hard mode definitions + # option_insane = 3 # Maybe someday (the druid difficulty) + + +class LocationSettings(Choice): + """Chose what items you want in the pool + not including checks via the no_A6 will force them to be excluded + not adding Metroids will force them to be vanilla and will not randomize them into item locations + adding metroids but excluding A6 will leave the A6 and omega nest metroids vanilla but will leave the full amount in the pool""" + display_name = "Locations to Check" + default = 2 + option_items_no_A6 = 0 + option_items_and_A6 = 1 + option_add_metroids_no_A6 = 2 + option_add_metroids_and_A6 = 3 + + +class AreaBehavior(Choice): + """Chose how you want the areas to behave in the randomizer + Lava: Lava starts at the position allowing access to the Golden Temple with the lava going down upon receiving a percentage of the goal metroids + Standard: The only existing area blocker is the one preventing lab access + Area Randomizer: Enables the area randomizer behavior""" + display_name = "Area Behavior" + default = 1 + option_lava = 0 + option_standard = 1 + option_area_rando = 2 class AmmoLogic(Choice): @@ -29,6 +59,16 @@ class AmmoLogic(Choice): alias_easy = 0 +class ExpectedAmmoMultiplier(Range): + """This value is used as a percentage based multiplier for the expected ammo count rounded up + 100% is exactly enough ammo to kill an enemy without missing a shot + 300% is 3 times the amount of ammo needed to kill an enemy""" + display_name = "Expected Ammo Multiplier" + range_start = 100 + range_end = 250 + default = 150 + + class MetroidsInPool(Range): """Chose how many Metroids are in the item pool""" display_name = "Metroids in Pool" @@ -45,19 +85,6 @@ class MetroidsRequired(Range): default = 20 -class LocationSettings(Choice): - """Chose what items you want in the pool - not including checks via the no_A6 will force them to be excluded - not adding Metroids will force them to be vanilla and will not randomize them into item locations - adding metroids but excluding A6 will leave the A6 and omega nest metroids vanilla but will leave the full amount in the pool""" - display_name = "Locations to Check" - default = 2 - option_items_no_A6 = 0 - option_items_and_A6 = 1 - option_add_metroids_no_A6 = 2 - option_add_metroids_and_A6 = 3 - - class StartLocation(Toggle): """Randomize Starting Location""" display_name = "Randomize Start Location" @@ -124,12 +151,12 @@ class RemoveFloodTrap(Toggle): class RemoveTossTrap(Toggle): - """There is a pipebomb in your mailbox""" + """Is there a pipebomb in your mailbox?""" display_name = "Remove Toss Trap" class RemoveShortBeam(Toggle): - """Remove muscle memory trap""" + """Remove short beam trap""" display_name = "Remove Short Beam" @@ -152,10 +179,12 @@ class RemoveOHKOTrap(Toggle): class AM2ROptions(PerGameCommonOptions): logic_dificulty: LogicDificulty ammo_logic: AmmoLogic - metroids_required: MetroidsRequired + expected_ammo_multiplier: ExpectedAmmoMultiplier location_settings: LocationSettings - start_location: StartLocation - area_rando: AreaRando + area_behavior: AreaBehavior + metroids_required: MetroidsRequired + # start_location: StartLocation + # area_rando: AreaRando remove_power_grip: RemovePowerGrip remove_morph_ball: RemoveMorphBall remove_beam: RemoveBeam diff --git a/worlds/am2r/regions.py b/worlds/am2r/regions.py index d39b7cd67094..278a8c237d82 100644 --- a/worlds/am2r/regions.py +++ b/worlds/am2r/regions.py @@ -1,4 +1,4 @@ -from typing import List, Tuple, Dict, Set, Optional, Callable +from typing import Dict, Set am2r_regions: Dict[str, Set[str]] = { @@ -7,7 +7,9 @@ "GFS Thoth"}, "Lower Main Caves": {"The Tower", "Underwater Distribution Center", "Deep Caves"}, "GFS Thoth": {"Genesis"}, - "Guardian": {"Golden Temple", "Golden Temple Nest"}, + "Genesis": set(), + "Guardian": {"After Guardian"}, + "After Guardian": {"Golden Temple", "Golden Temple Nest"}, "Golden Temple": set(), "Golden Temple Nest": set(), "First Alpha": set(), @@ -16,7 +18,8 @@ "Arachnus": set(), "Inner Hydro Station": set(), "Industrial Complex Nest": {"Pre Industrial Complex"}, - "Pre Industrial Complex": {"Industrial Complex", "Torizo Ascended"}, + "Pre Industrial Complex": {"Complex Sand", "Torizo Ascended"}, + "Complex Sand": {"Industrial Complex"}, # added sand region because of the new launchers option since beam only wont work to leave "Torizo Ascended": set(), "Industrial Complex": set(), "Mines": set(), @@ -25,133 +28,23 @@ "Tester Upper": {"Tester"}, "Tester": set(), "Geothermal": set(), - "" + "Underwater Distribution Center": {"EMP", "Serris", "Underwater Distro Connection"}, + "EMP": {"Post EMP"}, + "Post EMP": {"Pipe Hell BL"}, + "Pipe Hell BL": {"Pipe Hell BR", "Pipe Hell L"}, + "Pipe Hell BR": {"Pipe Hell L", "Pipe Hell R"}, + "Pipe Hell L": {"Pipe Hell R", "Fast Travel"}, + "Pipe Hell R": {"Screw Attack", "Underwater Distro Connection"}, + "Serris": {"Ice Beam"}, + "Ice Beam": set(), + "Underwater Distro Connection": {}, + "Fast Travel": {"Golden Temple", "Complex Sand", "The Tower", "Gravity", "Underwater Distribution Center"}, + "Gravity": {"Pipe Hell Outside"}, + "Pipe Hell Outside": {"Pipe Hell R"}, + "Screw Attack": set(), + "Deep Caves": {"Omega Nest"}, + "Omega Nest": {"The Lab"}, + "The Lab": {"Research Station"}, + "Research Station": set() } - # A5 - connect(world, player, "Underwater Distribution Center", "EMP", logic.AM2R_can_bomb), - connect(world, player, "EMP", "Underwater Distribution Center", logic.AM2R_can_bomb), - - connect(world, player, "Underwater Distribution Center", "Serris"), - connect(world, player, "Serris", "Underwater Distribution Center", lambda state: state.has("Gravity Suit", player)), - - connect(world, player, "Ice Beam", "Serris"), - connect(world, player, "Serris", "Ice Beam", lambda state: state.has("Gravity Suit", player)), - - # Pipe Hell Fuckery - connect(world, player, "EMP", "Pipe Hell BL"), - connect(world, player, "Pipe Hell BL", "EMP"), - - connect(world, player, "Pipe Hell BL", "Pipe Hell BR"), - connect(world, player, "Pipe Hell BR", "Pipe Hell BL"), - - connect(world, player, "Pipe Hell L", "Pipe Hell BL", lambda state: state.has("Screw Attack", player)), - connect(world, player, "Pipe Hell BL", "Pipe Hell L", lambda state: state.has("Screw Attack", player)), - - connect(world, player, "Pipe Hell BR", "Pipe Hell L"), - connect(world, player, "Pipe Hell L", "Pipe Hell BR"), - - connect(world, player, "Pipe Hell BR", "Pipe Hell R", lambda state: state.has("Screw Attack", player)), - connect(world, player, "Pipe Hell R", "Pipe Hell BR", lambda state: state.has("Screw Attack", player)), - - connect(world, player, "Pipe Hell R", "Pipe Hell L", logic.AM2R_can_bomb), - connect(world, player, "Pipe Hell L", "Pipe Hell R", logic.AM2R_can_bomb), - - connect(world, player, "Pipe Hell L", "Fast Travel", lambda state: state.has("Screw Attack", player)), - connect(world, player, "Fast Travel", "Pipe Hell L", lambda state: state.has("Screw Attack", player)), - - connect(world, player, "Fast Travel", "Gravity", lambda state: state.has("Gravity Suit", player)), # one way transition due to crumbles - - connect(world, player, "Fast Travel", "Underwater Distribution Center"), - connect(world, player, "Underwater Distribution Center", "Fast Travel", lambda state: state.can_reach("Fast Travel", "Region", player)), - - connect(world, player, "Gravity", "Pipe Hell Outside", lambda state: state.has("Gravity Suit", player) and state.has("Space Jump", player)), - connect(world, player, "Pipe Hell Outside", "Gravity"), - - connect(world, player, "Pipe Hell Outside", "Pipe Hell R", logic.AM2R_can_bomb), - connect(world, player, "Pipe Hell R", "Pipe Hell Outside", lambda state: state.can_reach("Pipe Hell Outside", "Region", player)), - - connect(world, player, "Screw Attack", "Pipe Hell R", lambda state: state.has("Screw Attack", player) and logic.AM2R_can_schmove(state)), - connect(world, player, "Pipe Hell R", "Screw Attack", logic.AM2R_can_spider), - - connect(world, player, "Underwater Distribution Center", "Underwater Distro Connection", lambda state: state.has("Ice Beam", player) or (state.has("Gravity Suit", player) and state.has("Speed Booster", player))), - connect(world, player, "Underwater Distro Connection", "Underwater Distribution Center", lambda state: state.has("Ice Beam", player) or (state.has("Gravity Suit", player) and state.has("Speed Booster", player))), - - connect(world, player, "Underwater Distro Connection", "Pipe Hell R"), - connect(world, player, "Pipe Hell R", "Underwater Distro Connection", lambda state: state.has("Super Missile", player) or (state.has("Gravity Suit", player) and state.has("Speed Booster", player))) - - connect(world, player, "Deep Caves", "Omega Nest") - connect(world, player, "Omega Nest", "Deep Caves") - - connect(world, player, "Omega Nest", "The Lab", logic.AM2R_can_lab) # , logic.AM2R_can_lab - connect(world, player, "The Lab", "Omega Nest") - - connect(world, player, "The Lab", "Research Station") - - -def throwIfAnyLocationIsNotAssignedToARegion(regions: List[Region], regionNames: Set[str]): - existingRegions: Set[str] = set() - - for region in regions: - existingRegions.add(region.name) - - if regionNames - existingRegions: - raise Exception( - "AM2R: the following regions are used in locations: {}, but no such region exists".format( - regionNames - existingRegions)) - - -def create_location(player: int, location_data: LocationData, region: Region) -> Location: - location = Location(player, location_data.name, location_data.code, region) - location.access_rule = location_data.rule - - if id is None: - location.event = True - location.locked = True - - return location - - -def create_region(world: MultiWorld, player: int, locations_per_region: Dict[str, List[LocationData]],name: str) -> Region: - region = Region(name, player, world) - - if name in locations_per_region: - for location_data in locations_per_region[name]: - location = create_location(player, location_data, region) - region.locations.append(location) - - return region - - -def connect(world: MultiWorld, player: int, source: str, target: str, - rule: Optional[Callable[[CollectionState], bool]] = None): - sourceRegion = world.get_region(source, player) - targetRegion = world.get_region(target, player) - - connection = Entrance(player, "", sourceRegion) - - if rule: - connection.access_rule = rule - - sourceRegion.exits.append(connection) - connection.connect(targetRegion) - - -def split_location_datas_per_region(locations: Tuple[LocationData, ...]) -> Dict[str, List[LocationData]]: - per_region: Dict[str, List[AM2RLocationData]] = {} - - for location in locations: - per_region.setdefault(location.region, []).append(location) - - return per_region - -from typing import Dict, Set - -snailiad_regions: Dict[str, Set[str]] = { - "Menu": {"Snail Town"}, - "Snail Town": {"Mare Carelia", "Spiralis Silere", "Amastrida Abyssus", "Lux Lirata", "Shrine of Iris"}, - "Mare Carelia": {"Spiralis Silere"}, - "Spiralis Silere": {"Amastrida Abyssus"}, - "Amastrida Abyssus": {"Lux Lirata"}, - "Lux Lirata": set(), - "Shrine of Iris": set() -} \ No newline at end of file +# todo: Have someone other than me verify this @(V)ariable diff --git a/worlds/am2r/rules.py b/worlds/am2r/rules.py index 282eed23b590..c27ff725749c 100644 --- a/worlds/am2r/rules.py +++ b/worlds/am2r/rules.py @@ -1,4 +1,3 @@ -from random import Random from typing import Dict, TYPE_CHECKING from worlds.generic.Rules import set_rule, forbid_item @@ -42,8 +41,7 @@ def has_ammo(state: CollectionState, player: int, options: AM2ROptions, health: s_packs = state.count("Super Missile", player) m_count = 0 s_count = 0 - damage = 0 - health = health + 0 + health = ceil(health * (options.expected_ammo_multiplier / 100)) if options.missile_launcher == 0: # default starting 30 missiles m_count += 30 @@ -57,7 +55,7 @@ def has_ammo(state: CollectionState, player: int, options: AM2ROptions, health: if options.super_launcher: if state.has("Super Missile Launcher", player): # Super Launcher counts as 1 pack s_packs += 1 - else: # if no launcher, then you cant fire missiles and they should not be counted towards damage total + else: # if no launcher, then you cant fire supers and they should not be counted towards damage total s_packs = 0 if options.ammo_logic == 0: @@ -79,6 +77,9 @@ def has_powerbombs(state: CollectionState, player: int, options: AM2ROptions, pa if options.ammo_logic == 1: packs *= 2 + if not can_morph(state, player, options): + return False + if options.missile_launcher: packs -= 1 # launcher counts as 1 pack return state.has("Power Bomb Launcher", player) and state.has("Power Bomb", player, packs) @@ -86,18 +87,16 @@ def has_powerbombs(state: CollectionState, player: int, options: AM2ROptions, pa return state.has("Power Bomb", player, packs) -def can_break_blocks(state: CollectionState, player: int, options: AM2ROptions) -> bool: - if options.remove_beam: - return (state.has("Screw Attack", player) or - can_bomb(state, player, options, 2) or has_missiles(state, player, options, 2)) - else: - return True - - def has_energy(state: CollectionState, player: int, options: AM2ROptions, required: int) -> bool: num = required if options.logic_dificulty == 0: # literally baby mode num *= 2 + + if state.has("Varia Suit", player) and state.has("Gravity Suit", player): + num = ceil(num / 4) + elif state.has("Varia Suit", player) or state.has("Gravity Suit", player): + num = ceil(num / 2) + return state.has("Energy Tank", player, num) @@ -161,13 +160,207 @@ def can_schmove(state: CollectionState, player: int, options: AM2ROptions) -> bo def can_spider(state: CollectionState, player: int, options: AM2ROptions) -> bool: return has_spider(state, player, options) or can_fly(state, player, options) +def has_metroids(state: CollectionState, player: int, options: AM2ROptions) -> bool: + required = options.metroids_required + return state.has("Metroid", player, required) -def set_region_rules(world: AM2RWorld) -> None: - multiworld = world.multiworld +def can_ouch_jump(state: CollectionState, player: int, options: AM2ROptions, energy: int) -> bool: + if options.logic_dificulty != 0 and has_energy(state, player, options, energy): + return True + else: + return False + +def can_wall_jump(state: CollectionState, player: int, options: AM2ROptions) -> bool: + if options.logic_dificulty != 0: + return can_schmove(state, player, options) + else: + return True + +def can_ball(state: CollectionState, player: int, options: AM2ROptions) -> bool: + return can_bomb(state, player, options, 1) or has_missiles(state, player, options, 2) or has_supers(state, player, options, 3) + + +def set_region_rules(world: "AM2RWorld") -> None: player = world.player options = world.options + world.get_entrance("Main Caves -> First Alpha").access_rule = \ + lambda state: True + + world.get_entrance("Main Caves -> Guardian").access_rule = \ + lambda state: True + + world.get_entrance("Main Caves -> Hydro Station").access_rule = \ + lambda state: can_morph(state, player, options) + + world.get_entrance("Main Caves -> Mines").access_rule = \ + lambda state: has_supers(state, player, options, 1) and can_morph(state, player, options) + + world.get_entrance("Main Caves -> Industrial Complex Nest").access_rule = \ + lambda state: can_morph(state, player, options) + + world.get_entrance("Main Caves -> GFS Thoth").access_rule = \ + lambda state: True + + world.get_entrance("Main Caves -> Lower Main Caves").access_rule = \ + lambda state: can_morph_uppies(state, player, options) + + world.get_entrance("Lower Main Caves -> The Tower").access_rule = \ + lambda state: True + + world.get_entrance("Lower Main Caves -> Underwater Distribution Center").access_rule = \ + lambda state: ((can_morph(state, player, options) and has_powerbombs(state, player, options, 1) + or has_supers(state, player, options, 1)) and + (state.has("Ice Beam", player) and has_ammo(state, player, options, 1))) + + world.get_entrance("Lower Main Caves -> Deep Caves").access_rule = \ + lambda state: (can_morph(state, player, options) and has_powerbombs(state, player, options, 1) or + has_supers(state, player, options, 1)) + + world.get_entrance("GFS Thoth -> Genesis").access_rule = \ + lambda state: can_morph(state, player, options) and has_powerbombs(state, player, options, 2) + + world.get_entrance("Guardian -> After Guardian").access_rule = \ + lambda state: True + + world.get_entrance("After Guardian -> Golden Temple").access_rule = \ + lambda state: True + + world.get_entrance("After Guardian -> Golden Temple Nest").access_rule = \ + lambda state: True + + world.get_entrance("Hydro Station -> Hydro Nest").access_rule = \ + lambda state: (can_morph(state, player, options) and + (state.has("Hi Jump", player) and has_grip(state, player, options)) or + can_fly(state, player, options) or (can_ouch_jump(state, player, options, 0)) and has_grip(state, player, options)) + + world.get_entrance("Hydro Station -> Arachnus").access_rule = \ + lambda state: (can_morph(state, player, options) and has_missiles(state, player, options, 1) and + can_bomb(state, player, options, 1) and can_morph_uppies(state, player, options)) + + world.get_entrance("Hydro Station -> Inner Hydro Station").access_rule = \ + lambda state: can_bomb(state, player, options, 1) or state.has("Screw Attack", player) + + world.get_entrance("Hydro Station -> The Tower").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Screw Attack", player) + + world.get_entrance("Hydro Station -> The Lab").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Screw Attack", player) and has_metroids(state, player, options) + + world.get_entrance("Industrial Complex Nest -> Pre Industrial Complex").access_rule = \ + lambda state: ((can_bomb(state, player, options, 1) and can_morph_uppies(state, player, options)) or + (state.has("Hi Jump", player) and state.has("Speed Booster", player))) + + world.get_entrance("Pre Industrial Complex -> Complex Sand").access_rule = \ + lambda state: (can_morph(state, player, options) and ((can_spider(state, player, options) or can_fly(state, player, options) or + (can_ouch_jump(state, player, options, 1) and state.has("Hi Jump", player))) and + has_ammo(state, player, options, 1) or can_morph(state, player, options) and state.has("Bombs", player))) + + world.get_entrance("Pre Industrial Complex -> Torizo Ascended").access_rule = \ + lambda state: (can_spider(state, player, options) or can_hi(state, player, options)) + + world.get_entrance("Complex Sand -> Industrial Complex").access_rule = \ + lambda state: can_schmove(state, player, options) + + world.get_entrance("The Tower -> Tester Lower").access_rule = \ + lambda state: can_bomb(state, player, options, 2) and can_wall_jump(state, player, options) + + world.get_entrance("The Tower -> Tester Upper").access_rule = \ + lambda state: can_bomb(state, player, options, 2) and can_wall_jump(state, player, options) + + world.get_entrance("The Tower -> Geothermal").access_rule = \ + lambda state: True + + world.get_entrance("Tester Lower -> Tester").access_rule = \ + lambda state: True + + world.get_entrance("Tester Upper -> Tester").access_rule = \ + lambda state: True + + world.get_entrance("Underwater Distribution Center -> Underwater Distro Connection").access_rule = \ + lambda state: (state.has("Gravity Suit", player) and state.has("Speed Booster", player) or + state.has("Ice Beam", player) and has_ammo(state, player, options, 1) and + (state.has("Gravity Suit", player) and state.has("Speed Booster", player) or + has_supers(state, player, options, 1))) + + world.get_entrance("Underwater Distribution Center -> EMP").access_rule = \ + lambda state: True + + world.get_entrance("Underwater Distribution Center -> Serris").access_rule = \ + lambda state: True + + world.get_entrance("EMP -> Post EMP").access_rule = \ + lambda state: (can_bomb(state, player, options, 2) and state.has("Speed Booster", player) and + state.has("EMP", player) and can_ball(state, player, options)) + + world.get_entrance("Post EMP -> Pipe Hell BL").access_rule = \ + lambda state: can_bomb(state, player, options, 2) + + world.get_entrance("Pipe Hell BL -> Pipe Hell L").access_rule = \ + lambda state: state.has("Screw Attack", player) + + world.get_entrance("Pipe Hell BR -> Pipe Hell R").access_rule = \ + lambda state: state.has("Screw Attack", player) + + world.get_entrance("Pipe Hell BR -> Pipe Hell L").access_rule = \ + lambda state: can_morph(state, player, options) + + world.get_entrance("Pipe Hell L -> Pipe Hell R").access_rule = \ + lambda state: can_bomb(state, player, options, 1) + + world.get_entrance("Pipe Hell R -> Screw Attack").access_rule = \ + lambda state: (state.has("Screw Attack", player) and + can_schmove(state, player, options) and can_ball(state, player, options)) + + world.get_entrance("Pipe Hell R -> Underwater Distro Connection").access_rule = \ + lambda state: can_morph_uppies(state, player, options) + + world.get_entrance("Serris -> Ice Beam").access_rule = \ + lambda state: (state.has("Ice Beam", player) and has_ammo(state, player, options, 1) and + can_morph(state, player, options)) + + world.get_entrance("Fast Travel -> Golden Temple").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Screw Attack", player) + + world.get_entrance("Fast Travel -> Complex Sand").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Screw Attack", player) + + world.get_entrance("Fast Travel -> The Tower").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Screw Attack", player) + + world.get_entrance("Fast Travel -> Gravity").access_rule = \ + lambda state: can_morph(state, player, options) and (state.has("Gravity Suit", player) and state.has("Space Jump", player)) + + world.get_entrance("Pipe Hell L -> Fast Travel").access_rule = \ + lambda state: state.has("Screw Attack", player) + + world.get_entrance("Fast Travel -> Underwater Distribution Center").access_rule = \ + lambda state: can_ball(state, player, options) + + world.get_entrance("Gravity -> Pipe Hell Outside").access_rule = \ + lambda state: can_morph(state, player, options) and state.has("Gravity Suit", player) and state.has("Space Jump", player) + + world.get_entrance("Pipe Hell Outside -> Pipe Hell R").access_rule = \ + lambda state: can_ball(state, player, options) + + world.get_entrance("Deep Caves -> Omega Nest").access_rule = \ + lambda state: ((has_powerbombs(state, player, options, 1) or state.has("Screw Attack", player)) and + (state.has("Ice Beam", player) and has_ammo(state, player, options, 1)) and + (can_morph_uppies(state, player, options) and can_bomb(state, player, options, 1))) + + world.get_entrance("Omega Nest -> The Lab").access_rule = \ + lambda state: ((can_wall_jump(state, player, options) or state.has("Speed Booster", player)) and + can_bomb(state, player, options, 1) and can_fly(state, player, options) and + has_metroids(state, player, options)) + + world.get_entrance("The Lab -> Research Station").access_rule = \ + lambda state: (state.has("Ice Beam", player) and has_ammo(state, player, options, 10) and + state.has("Space Jump", player) and can_bomb(state, player, options, 1)) + +# todo: Have someone other than me verify this @Everyone + + def set_location_rules_easy(world: AM2RWorld) -> None: # currently every location is in a reachable state diff --git a/worlds/am2r/todo.py b/worlds/am2r/todo.py index 9c12a69bcb37..50e660c15991 100644 --- a/worlds/am2r/todo.py +++ b/worlds/am2r/todo.py @@ -1,2 +1,11 @@ -# todo update the get option value to use the new options definition so the console stops yelling at me -# todo eventually add the ability to area rando +# todo: Logic set for Easy +# todo: Logic set for Normal +# todo: Logic set for Hard +# todo: __init__.py just like all of it +# todo: check client.py to verify it wont explode with the new formating + +# @ANXvariable +# todo: please check the regions to make sure they are correct + +# @Everyone +# todo: region connection logic