diff --git a/BaseClasses.py b/BaseClasses.py index 1ee0afb9..6be6174b 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1071,7 +1071,7 @@ hook_dir_map = { def hook_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: return hook_dir_map[door.direction] return None @@ -1189,7 +1189,8 @@ class Door(object): # rom properties self.roomIndex = -1 - # 0,1,2 + Direction (N:0, W:3, S:6, E:9) for normal + # 0,1,2 for normal + # 0-7 for ladder # 0-4 for spiral offset thing self.doorIndex = -1 self.layer = -1 # 0 for normal floor, 1 for the inset layer @@ -1240,6 +1241,8 @@ class Door(object): return 0x13A000 + normal_offset_table[self.roomIndex] * 24 + (self.doorIndex + self.direction.value * 3) * 2 elif self.type == DoorType.SpiralStairs: return 0x13B000 + (spiral_offset_table[self.roomIndex] + self.doorIndex) * 4 + elif self.type == DoorType.Ladder: + return 0x13C700 + self.doorIndex * 2 elif self.type == DoorType.Open: base_address = { Direction.North: 0x13C500, @@ -1256,6 +1259,12 @@ class Door(object): if src.type == DoorType.StraightStairs: bitmask += 0x40 return [self.roomIndex, bitmask + self.doorIndex] + if self.type == DoorType.Ladder: + bitmask = 4 * (self.layer ^ 1 if src.toggle else self.layer) + bitmask += 0x08 * self.doorIndex + if src.type == DoorType.StraightStairs: + bitmask += 0x40 + return [self.roomIndex, bitmask + 0x03] if self.type == DoorType.SpiralStairs: bitmask = int(self.layer) << 2 bitmask += 0x10 * int(self.zeroHzCam) diff --git a/DoorShuffle.py b/DoorShuffle.py index 33e42e63..97e7d234 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -58,14 +58,14 @@ def link_doors_main(world, player): connect_simple_door(world, exitName, regionName, player) for exitName, regionName in dungeon_warps: connect_simple_door(world, exitName, regionName, player) - for ent, ext in ladders: - connect_two_way(world, ent, ext, player) if world.intensity[player] < 2: for entrance, ext in open_edges: connect_two_way(world, entrance, ext, player) for entrance, ext in straight_staircases: connect_two_way(world, entrance, ext, player) + for entrance, ext in ladders: + connect_two_way(world, entrance, ext, player) if world.intensity[player] < 3 or world.doorShuffle == 'vanilla': mirror_route = world.get_entrance('Sanctuary Mirror Route', player) @@ -107,6 +107,8 @@ def link_doors_main(world, player): connect_simple_door(world, exitName, regionName, player) for entrance, ext in spiral_staircases: connect_two_way(world, entrance, ext, player) + for entrance, ext in ladders: + connect_two_way(world, entrance, ext, player) for entrance, ext in default_door_connections: connect_two_way(world, entrance, ext, player) for ent, ext in default_one_way_connections: @@ -161,7 +163,7 @@ def create_door_spoiler(world, player): door_a = ext.door connect = ext.connected_region if door_a and door_a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, - DoorType.StraightStairs] and door_a not in done: + DoorType.StraightStairs, DoorType.Ladder] and door_a not in done: done.add(door_a) door_b = door_a.dest if door_b and not isinstance(door_b, Region): @@ -1324,11 +1326,10 @@ def combine_layouts(recombinant_builders, dungeon_builders, entrances_map): if recombine.master_sector is None: recombine.master_sector = builder.master_sector recombine.master_sector.name = recombine.name - recombine.pre_open_stonewall = builder.pre_open_stonewall + recombine.pre_open_stonewalls = builder.pre_open_stonewalls else: recombine.master_sector.regions.extend(builder.master_sector.regions) - if builder.pre_open_stonewall: - recombine.pre_open_stonewall = builder.pre_open_stonewall + recombine.pre_open_stonewalls.update(builder.pre_open_stonewalls) recombine.layout_starts = list(entrances_map[recombine.name]) dungeon_builders[recombine.name] = recombine @@ -2009,7 +2010,7 @@ class DROptions(Flag): Debug = 0x08 Rails = 0x10 # If on, draws rails OriginalPalettes = 0x20 - Reserved = 0x40 # Reserved for PoD sliding wall? + Open_PoD_Wall = 0x40 # If on, pre opens the PoD wall, no bow required Open_Desert_Wall = 0x80 # If on, pre opens the desert wall, no fire required @@ -2042,6 +2043,13 @@ logical_connections = [ ('PoD Basement Ledge Drop Down', 'PoD Stalfos Basement'), ('PoD Falling Bridge Path N', 'PoD Falling Bridge Ledge'), ('PoD Falling Bridge Path S', 'PoD Falling Bridge'), + ('PoD Bow Statue Crystal Path', 'PoD Bow Statue Moving Wall'), + ('PoD Bow Statue Moving Wall Path', 'PoD Bow Statue'), + ('PoD Bow Statue Moving Wall Cane Path', 'PoD Bow Statue'), + ('PoD Dark Pegs Hammer Path', 'PoD Dark Pegs Ladder'), + ('PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs'), + ('PoD Dark Pegs Ladder Cane Path', 'PoD Dark Pegs Switch'), + ('PoD Dark Pegs Switch Path', 'PoD Dark Pegs Ladder'), ('Swamp Lobby Moat', 'Swamp Entrance'), ('Swamp Entrance Moat', 'Swamp Lobby'), ('Swamp Trench 1 Approach Dry', 'Swamp Trench 1 Nexus'), diff --git a/Doors.py b/Doors.py index 9c40838f..3bc41766 100644 --- a/Doors.py +++ b/Doors.py @@ -395,8 +395,15 @@ def create_doors(world, player): create_door(player, 'PoD Mimics 2 SW', Nrml).dir(So, 0x1b, Left, High).pos(1).kill().portal(Z, 0x00), create_door(player, 'PoD Mimics 2 NW', Intr).dir(No, 0x1b, Left, High).pos(0), create_door(player, 'PoD Bow Statue SW', Intr).dir(So, 0x1b, Left, High).pos(0), - create_door(player, 'PoD Bow Statue Down Ladder', Lddr).no_entrance(), - create_door(player, 'PoD Dark Pegs Up Ladder', Lddr), + create_door(player, 'PoD Bow Statue Crystal Path', Lgcl), + create_door(player, 'PoD Bow Statue Moving Wall Path', Lgcl), + create_door(player, 'PoD Bow Statue Moving Wall Cane Path', Lgcl), + create_door(player, 'PoD Bow Statue Down Ladder', Lddr).dir(So, 0x1b, 1, High).no_entrance(), + create_door(player, 'PoD Dark Pegs Up Ladder', Lddr).dir(No, 0x0b, 0, High), + create_door(player, 'PoD Dark Pegs Hammer Path', Lgcl), + create_door(player, 'PoD Dark Pegs Ladder Hammer Path', Lgcl), + create_door(player, 'PoD Dark Pegs Ladder Cane Path', Lgcl), + create_door(player, 'PoD Dark Pegs Switch Path', Lgcl), create_door(player, 'PoD Dark Pegs WN', Intr).dir(We, 0x0b, Mid, High).small_key().pos(2), create_door(player, 'PoD Lonely Turtle SW', Intr).dir(So, 0x0b, Mid, High).pos(0), create_door(player, 'PoD Lonely Turtle EN', Intr).dir(Ea, 0x0b, Mid, High).small_key().pos(2), @@ -663,7 +670,7 @@ def create_doors(world, player): create_door(player, 'Ice Pengator Switch ES', Intr).dir(Ea, 0x1f, Bot, High).pos(1), create_door(player, 'Ice Dead End WS', Intr).dir(We, 0x1f, Bot, High).pos(1), create_door(player, 'Ice Big Key Push Block', Lgcl), - create_door(player, 'Ice Big Key Down Ladder', Lddr), + create_door(player, 'Ice Big Key Down Ladder', Lddr).dir(So, 0x1f, 3, High), create_door(player, 'Ice Stalfos Hint SE', Intr).dir(So, 0x3e, Right, High).pos(0), create_door(player, 'Ice Conveyor NE', Intr).dir(No, 0x3e, Right, High).no_exit().pos(0), create_door(player, 'Ice Conveyor SW', Nrml).dir(So, 0x3e, Left, High).small_key().pos(1).portal(Z, 0x20), @@ -679,7 +686,7 @@ def create_doors(world, player): create_door(player, 'Ice Spike Cross ES', Nrml).dir(Ea, 0x5e, Bot, High).small_key().pos(0), create_door(player, 'Ice Spike Cross WS', Intr).dir(We, 0x5e, Bot, High).pos(3), create_door(player, 'Ice Firebar ES', Intr).dir(Ea, 0x5e, Bot, High).pos(3), - create_door(player, 'Ice Firebar Down Ladder', Lddr), + create_door(player, 'Ice Firebar Down Ladder', Lddr).dir(So, 0x5e, 5, High), create_door(player, 'Ice Spike Cross NE', Intr).dir(No, 0x5e, Right, High).pos(1), create_door(player, 'Ice Falling Square SE', Intr).dir(So, 0x5e, Right, High).no_exit().pos(1), create_door(player, 'Ice Falling Square Hole', Hole), @@ -689,8 +696,8 @@ def create_doors(world, player): create_door(player, 'Ice Hammer Block Down Stairs', Sprl).dir(Dn, 0x3f, 0, HTH).ss(Z, 0x11, 0xb8, True, True).kill(), create_door(player, 'Ice Hammer Block ES', Intr).dir(Ea, 0x3f, Bot, High).pos(0), create_door(player, 'Ice Tongue Pull WS', Intr).dir(We, 0x3f, Bot, High).pos(0), - create_door(player, 'Ice Tongue Pull Up Ladder', Lddr), - create_door(player, 'Ice Freezors Up Ladder', Lddr), + create_door(player, 'Ice Tongue Pull Up Ladder', Lddr).dir(No, 0x3f, 2, High), + create_door(player, 'Ice Freezors Up Ladder', Lddr).dir(No, 0x7e, 4, High), create_door(player, 'Ice Freezors Hole', Hole), create_door(player, 'Ice Freezors Bomb Hole', Hole), # combine these two? -- they have to lead to the same spot create_door(player, 'Ice Freezors Ledge Hole', Hole), @@ -1078,8 +1085,8 @@ def create_doors(world, player): create_door(player, 'GT Torch Cross WN', Nrml).dir(We, 0x96, Top, High).pos(1), create_door(player, 'GT Torch Cross ES', Intr).dir(Ea, 0x96, Bot, High).pos(0), create_door(player, 'GT Staredown WS', Intr).dir(We, 0x96, Bot, High).pos(0), - create_door(player, 'GT Staredown Up Ladder', Lddr), - create_door(player, 'GT Falling Torches Down Ladder', Lddr), + create_door(player, 'GT Staredown Up Ladder', Lddr).dir(No, 0x96, 6, High), + create_door(player, 'GT Falling Torches Down Ladder', Lddr).dir(So, 0x3d, 7, High), create_door(player, 'GT Falling Torches NE', Intr).dir(No, 0x3d, Right, High).pos(0), create_door(player, 'GT Mini Helmasaur Room SE', Intr).dir(So, 0x3d, Right, High).pos(0), create_door(player, 'GT Falling Torches Hole', Hole), @@ -1156,9 +1163,11 @@ def create_doors(world, player): world.get_door('PoD Map Balcony WS', player).c_switch() world.get_door('PoD Map Balcony South Stairs', player).c_switch() world.get_door('PoD Bow Statue SW', player).c_switch() - world.get_door('PoD Bow Statue Down Ladder', player).c_switch() - world.get_door('PoD Dark Pegs Up Ladder', player).c_switch() + world.get_door('PoD Bow Statue Moving Wall Path', player).barrier(CrystalBarrier.Orange) + world.get_door('PoD Bow Statue Crystal Path', player).c_switch() world.get_door('PoD Dark Pegs WN', player).c_switch() + world.get_door('PoD Dark Pegs Switch Path', player).c_switch() + world.get_door('PoD Dark Pegs Hammer Path', player).c_switch() world.get_door('Swamp Crystal Switch EN', player).c_switch() world.get_door('Swamp Crystal Switch SE', player).c_switch() diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 4fd59d80..e320bbaf 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -55,19 +55,21 @@ def pre_validate(builder, entrance_region_names, split_dungeon, world, player): def generate_dungeon(builder, entrance_region_names, split_dungeon, world, player): - stonewall = check_for_stonewall(builder) + stonewalls = check_for_stonewalls(builder) sector = generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player) - if stonewall and not stonewall_valid(stonewall): - builder.pre_open_stonewall = stonewall + for stonewall in stonewalls: + if not stonewall_valid(stonewall): + builder.pre_open_stonewalls.add(stonewall) return sector -def check_for_stonewall(builder): +def check_for_stonewalls(builder): + stonewalls = set() for sector in builder.sectors: for door in sector.outstanding_doors: if door.stonewall: - return door - return None + stonewalls.add(door) + return stonewalls def generate_dungeon_main(builder, entrance_region_names, split_dungeon, world, player): @@ -418,8 +420,7 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a true_origin_hooks = [x for x in dungeon['Origin'].hooks.keys() if not x.bigKey or possible_bks > 0 or not bk_needed] if len(true_origin_hooks) == 0 and len(proposed_map.keys()) < len(doors_to_connect): return False - if len(true_origin_hooks) == 0 and bk_needed and possible_bks == 0 and len(proposed_map.keys()) == len( - doors_to_connect): + if len(true_origin_hooks) == 0 and bk_needed and possible_bks == 0 and len(proposed_map.keys()) == len(doors_to_connect): return False for key in hangers.keys(): if len(hooks[key]) > 0 and len(hangers[key]) == 0: @@ -694,17 +695,17 @@ hang_dir_map = { def hanger_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: return hang_dir_map[door.direction] return None def connect_doors(a, b): # Return on unsupported types. - if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Ladder, DoorType.Interior, DoorType.Logical]: + if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Interior, DoorType.Logical]: return # Connect supported types - if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs]: + if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: if a.blocked: connect_one_way(b.entrance, a.entrance) elif b.blocked: @@ -1171,7 +1172,7 @@ class DungeonBuilder(object): self.path_entrances = None # used for pathing/key doors, I think self.split_flag = False - self.pre_open_stonewall = None # used by stonewall system + self.pre_open_stonewalls = set() # used by stonewall system self.candidates = None self.key_doors_num = None diff --git a/Dungeons.py b/Dungeons.py index c33b38e8..9229140c 100644 --- a/Dungeons.py +++ b/Dungeons.py @@ -213,8 +213,8 @@ pod_regions = [ 'PoD Map Balcony', 'PoD Conveyor', 'PoD Mimics 1', 'PoD Jelly Hall', 'PoD Warp Hint', 'PoD Warp Room', 'PoD Stalfos Basement', 'PoD Basement Ledge', 'PoD Big Key Landing', 'PoD Falling Bridge', 'PoD Falling Bridge Ledge', 'PoD Dark Maze', 'PoD Big Chest Balcony', 'PoD Compass Room', 'PoD Dark Basement', - 'PoD Harmless Hellway', 'PoD Mimics 2', 'PoD Bow Statue', 'PoD Dark Pegs', 'PoD Lonely Turtle', 'PoD Turtle Party', - 'PoD Dark Alley', 'PoD Callback', 'PoD Boss', 'Palace of Darkness Portal' + 'PoD Harmless Hellway', 'PoD Mimics 2', 'PoD Bow Statue', 'PoD Bow Statue Moving Wall', 'PoD Dark Pegs', 'PoD Dark Pegs Ladder', 'PoD Dark Pegs Switch', + 'PoD Lonely Turtle', 'PoD Turtle Party', 'PoD Dark Alley', 'PoD Callback', 'PoD Boss', 'Palace of Darkness Portal' ] swamp_regions = [ diff --git a/README.md b/README.md index 5e3292e2..46d692f5 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Doors are not shuffled. #### Level 1 Normal door and spiral staircases are shuffled #### Level 2 -Same as Level 1 plus open edges and straight staircases are shuffled. +Same as Level 1 plus open edges and both types of straight staircases are shuffled. #### Level 3 Same as Level 2 plus Dungeon Lobbies are shuffled diff --git a/Regions.py b/Regions.py index ce4281c0..5d8a1769 100644 --- a/Regions.py +++ b/Regions.py @@ -401,8 +401,11 @@ def create_dungeon_regions(world, player): create_dungeon_region(player, 'PoD Dark Basement', 'Palace of Darkness', ['Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right'], ['PoD Dark Basement W Up Stairs', 'PoD Dark Basement E Up Stairs']), create_dungeon_region(player, 'PoD Harmless Hellway', 'Palace of Darkness', ['Palace of Darkness - Harmless Hellway'], ['PoD Harmless Hellway NE', 'PoD Harmless Hellway SE']), create_dungeon_region(player, 'PoD Mimics 2', 'Palace of Darkness', None, ['PoD Mimics 2 SW', 'PoD Mimics 2 NW']), - create_dungeon_region(player, 'PoD Bow Statue', 'Palace of Darkness', None, ['PoD Bow Statue SW', 'PoD Bow Statue Down Ladder']), - create_dungeon_region(player, 'PoD Dark Pegs', 'Palace of Darkness', None, ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs WN']), + create_dungeon_region(player, 'PoD Bow Statue', 'Palace of Darkness', None, ['PoD Bow Statue SW', 'PoD Bow Statue Crystal Path']), + create_dungeon_region(player, 'PoD Bow Statue Moving Wall', 'Palace of Darkness', None, ['PoD Bow Statue Moving Wall Path', 'PoD Bow Statue Down Ladder', 'PoD Bow Statue Moving Wall Cane Path']), + create_dungeon_region(player, 'PoD Dark Pegs', 'Palace of Darkness', None, ['PoD Dark Pegs Hammer Path', 'PoD Dark Pegs WN']), + create_dungeon_region(player, 'PoD Dark Pegs Ladder', 'Palace of Darkness', None, ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs Ladder Cane Path']), + create_dungeon_region(player, 'PoD Dark Pegs Switch', 'Palace of Darkness', None, ['PoD Dark Pegs Switch Path']), create_dungeon_region(player, 'PoD Lonely Turtle', 'Palace of Darkness', None, ['PoD Lonely Turtle SW', 'PoD Lonely Turtle EN']), create_dungeon_region(player, 'PoD Turtle Party', 'Palace of Darkness', None, ['PoD Turtle Party ES', 'PoD Turtle Party NW']), create_dungeon_region(player, 'PoD Dark Alley', 'Palace of Darkness', None, ['PoD Dark Alley NE']), @@ -762,7 +765,8 @@ def create_dungeon_regions(world, player): world.get_region('PoD Arena Main', player).crystal_switch = True world.get_region('PoD Arena Bridge', player).crystal_switch = True # RANGED Weapon Required world.get_region('PoD Sexy Statue', player).crystal_switch = True - world.get_region('PoD Bow Statue', player).crystal_switch = True # LADDER not accessible (maybe with cane) + world.get_region('PoD Bow Statue', player).crystal_switch = True + world.get_region('PoD Dark Pegs Switch', player).crystal_switch = True world.get_region('PoD Dark Pegs', player).crystal_switch = True world.get_region('Swamp Crystal Switch', player).crystal_switch = True world.get_region('Thieves Spike Switch', player).crystal_switch = True diff --git a/Rom.py b/Rom.py index 63cdcd46..4b97fc4e 100644 --- a/Rom.py +++ b/Rom.py @@ -27,7 +27,7 @@ from EntranceShuffle import door_addresses, exit_ids JAP10HASH = '03a63945398191337e896e5771f77173' -RANDOMIZERBASEHASH = '30147375153cc57197805eddf38c2a23' +RANDOMIZERBASEHASH = 'bffd4e834049ca5f5295601436fc6009' class JsonRom(object): @@ -685,7 +685,7 @@ def patch_rom(world, rom, player, team, enemized): for door in world.doors: if door.dest is not None and isinstance(door.dest, Door) and\ door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs, - DoorType.Open, DoorType.StraightStairs]: + DoorType.Open, DoorType.StraightStairs, DoorType.Ladder]: rom.write_bytes(door.getAddress(), door.dest.getTarget(door)) for paired_door in world.paired_doors[player]: rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player)) @@ -693,9 +693,11 @@ def patch_rom(world, rom, player, team, enemized): if world.doorShuffle[player] != 'vanilla': for builder in world.dungeon_layouts[player].values(): - if builder.pre_open_stonewall: - if builder.pre_open_stonewall.name == 'Desert Wall Slide NW': + for stonewall in builder.pre_open_stonewalls: + if stonewall.name == 'Desert Wall Slide NW': dr_flags |= DROptions.Open_Desert_Wall + elif stonewall.name == 'PoD Bow Statue Down Ladder': + dr_flags |= DROptions.Open_PoD_Wall for name, pair in boss_indicator.items(): dungeon_id, boss_door = pair opposite_door = world.get_door(boss_door, player).dest diff --git a/Rules.py b/Rules.py index ceeeecbf..3049dd5b 100644 --- a/Rules.py +++ b/Rules.py @@ -180,8 +180,10 @@ def global_rules(world, player): set_rule(world.get_entrance('PoD Mimics 2 NW', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Bow Statue Down Ladder', player), lambda state: state.can_shoot_arrows(player)) set_rule(world.get_entrance('PoD Map Balcony Drop Down', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('PoD Dark Pegs WN', player), lambda state: state.has('Hammer', player)) - set_rule(world.get_entrance('PoD Dark Pegs Up Ladder', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Ladder Hammer Path', player), lambda state: state.has('Hammer', player)) + set_rule(world.get_entrance('PoD Dark Pegs Ladder Cane Path', player), lambda state: state.has('Cane of Somaria', player)) + set_rule(world.get_entrance('PoD Bow Statue Moving Wall Cane Path', player), lambda state: state.has('Cane of Somaria', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Palace of Darkness - Prize', player)) @@ -723,7 +725,9 @@ def no_glitches_rules(world, player): 'PoD Callback': {'sewer': False, 'entrances': ['PoD Callback WS', 'PoD Callback Warp'], 'locations': []}, 'PoD Turtle Party': {'sewer': False, 'entrances': ['PoD Turtle Party ES', 'PoD Turtle Party NW'], 'locations': []}, 'PoD Lonely Turtle': {'sewer': False, 'entrances': ['PoD Lonely Turtle SW', 'PoD Lonely Turtle EN'], 'locations': []}, - 'PoD Dark Pegs': {'sewer': False, 'entrances': ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs WN'], 'locations': []}, + 'PoD Dark Pegs': {'sewer': False, 'entrances': ['PoD Dark Pegs Hammer Path', 'PoD Dark Pegs WN'], 'locations': []}, + 'PoD Dark Pegs Ladder': {'sewer': False, 'entrances': ['PoD Dark Pegs Up Ladder', 'PoD Dark Pegs Ladder Hammer Path', 'PoD Dark Pegs Ladder Cane Path'], 'locations': []}, + 'PoD Dark Pegs Switch': {'sewer': False, 'entrances': ['PoD Dark Pegs Switch Path'], 'locations': []}, 'PoD Dark Basement': {'sewer': False, 'entrances': ['PoD Dark Basement W Up Stairs', 'PoD Dark Basement E Up Stairs'], 'locations': ['Palace of Darkness - Dark Basement - Left', 'Palace of Darkness - Dark Basement - Right']}, 'PoD Dark Maze': {'sewer': False, 'entrances': ['PoD Dark Maze EN', 'PoD Dark Maze E'], 'locations': ['Palace of Darkness - Dark Maze - Top', 'Palace of Darkness - Dark Maze - Bottom']}, 'Eastern Dark Square': {'sewer': False, 'entrances': ['Eastern Dark Square NW', 'Eastern Dark Square Key Door WN', 'Eastern Dark Square EN'], 'locations': []}, diff --git a/asm/doorrando.asm b/asm/doorrando.asm index 7de554fd..807095c7 100644 --- a/asm/doorrando.asm +++ b/asm/doorrando.asm @@ -7,6 +7,8 @@ ; Free RAM notes ; Normal doors use $AB-AC for scrolling indicator ; Normal doors use $FE to store the trap door indicator +; Normal doors use $045e to store Y coordinate when transitioning to in-room stairs +; Normal doors use $045f to determine the order in which supertile quadrants are drawn ; Spiral doors use $045e to store stair type ; Gfx uses $b1 to for sub-sub-sub-module thing @@ -35,7 +37,7 @@ incsrc edges.asm incsrc math.asm incsrc hudadditions.asm incsrc dr_lobby.asm -warnpc $279700 +warnpc $279C00 incsrc doortables.asm warnpc $288000 diff --git a/asm/doortables.asm b/asm/doortables.asm index 40276be2..2c0140ea 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -1,4 +1,4 @@ -org $279700 +org $279C00 KeyDoorOffset: ; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler dw $0000,$0001,$0003,$0000,$0006,$0000,$000b,$0000,$0000,$0000,$000c,$000d,$0010,$0011,$0012,$0000 @@ -58,7 +58,7 @@ db $9f org $27A000 DoorTable: -;; NW 00 N 01 N 02 WN 00 W 01 WS 02 SW 00 S 01 SE 02 EN 00 E 01 ES 02 - Door ruler +;; NW 00 N 01 NE 02 WN 00 W 01 WS 02 SW 00 S 01 SE 02 EN 00 E 01 ES 02 - Door ruler dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Default/Garbage row dw $0003, $0003, $0003, $0450, $0003, $0003, $0003, $0003, $0003, $0452, $0003, $0003 ; HC Back Hall (x01) dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Sewer Switches (x02) @@ -227,7 +227,7 @@ dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, ;dw $0080, $1f50 ; ->zelda's cellblock org $27B000 -SpiralTable: ;113 4 byte entries - should end at 27B44C +SpiralTable: ;113 4 byte entries - should end at 27B1C4 dw $0203, $8080 ;null row dw $0203, $8080 ;HC Backhallway dw $0203, $8080 ;Sewer Pull @@ -557,6 +557,20 @@ MultDivInfo: ; (1, 2, 3, 4, 5, 6, 10, 20) db $01, $02, $03, $04, $05, $06, $0a, $14 ; indices: 0-7 +; In-room stairs in North/South pairs. From left to right: +; PoD, IP right side, IP Freezor chest and GT +org $27C700 +InroomStairsTable: +dw $0003,$0003, $0003,$0003, $0003,$0003, $0003,$0003 + +org $27C720 +InroomStairsRoom: +db $0B,$1B, $3F,$1F, $7E,$5E, $96,$3D +InroomStairsX: +dw $0190, $0160, $0040, $0178 +InroomStairsY: +dw $0058, $0148, $0198, $0190 + ; dungeon tables ; HC HC EP DP AT SP PD MM SW IP TH TT TR GT diff --git a/asm/drhooks.asm b/asm/drhooks.asm index 43802ce7..1aa62dde 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -46,8 +46,19 @@ org $029396 ; <- 11396 - Bank02.asm : 3641 (LDA $01C322, X) jsl StraightStairLayerFix org $02c06d ; <- Bank02.asm : 9874 (LDX $0418, CMP.b #$02) jsl DoorToStraight : nop +org $02c092 ; STA $0020, Y : LDX #$00 +jsl DoorToInroom : nop +org $02c0f8 ; CMP $02C034, X +jsl DoorToInroomEnd org $02941a ; <- Bank02.asm : 3748 module 7.12.11 (LDA $0464 : BNE BRANCH_$11513 : INC $B0 : RTS) jsl StraightStairsTrapDoor : rts +org $028b54 ; <- Bank02.asm : 2200 (JSL UseImplicitRegIndexedLocalJumpTable) +jsl InroomStairsTrapDoor + +org $0289a0 ; JSL $0091C4 +jsl QuadrantLoadOrderBeforeScroll +org $02bd9c ; JSL $0091C4 +jsl QuadrantLoadOrderAfterScroll ; Graphics fix diff --git a/asm/edges.asm b/asm/edges.asm index 2b9c2228..58852b12 100644 --- a/asm/edges.asm +++ b/asm/edges.asm @@ -52,14 +52,20 @@ LoadEdgeRoomVert: lda $03 : sta $a0 sty $06 and.b #$f0 : lsr #3 : !sub $21 : !add $06 : sta $02 - ldy #$01 : jsr ShiftVariablesMainDir lda $04 : and #$80 : bne .edge lda $04 : sta $01 ; load up flags in $01 + and #$03 : cmp #$03 : beq .inroom + ldy #$01 : jsr ShiftVariablesMainDir jsr PrepScrollToNormal bra .scroll + .inroom + jsr ScrollToInroomStairs + rts + .edge + ldy #$01 : jsr ShiftVariablesMainDir lda $04 : and #$10 : beq + lda #$01 + sta $ee ; layer stuff diff --git a/asm/normal.asm b/asm/normal.asm index 5d8b6043..56fee909 100644 --- a/asm/normal.asm +++ b/asm/normal.asm @@ -31,6 +31,13 @@ WarpUp: jsr Cleanup rtl +; Checks if $a0 is equal to . If it is, opens its stonewall if it's there +macro StonewallCheck(Room) + lda $a0 : cmp.b # : bne ?end + lda.l *2+$7ef000 : ora #$80 : sta.l *2+$7ef000 + ?end +endmacro + WarpDown: lda.l DRMode : beq .end lda $040c : cmp.b #$ff : beq .end @@ -38,6 +45,7 @@ WarpDown: jsr CalcIndex !add #$0c : ldy #$ff ; offsets in A, Y jsr LoadRoomVert + %StonewallCheck($43) .end jsr Cleanup rtl @@ -130,15 +138,20 @@ LoadRoomVert: .gtg ;Good to Go! pla ; Throw away normal room (don't fill up the stack) lda $a0 : and.b #$F0 : lsr #3 : !sub $21 : !add $06 : sta $02 - ldy #$01 : jsr ShiftVariablesMainDir - lda $01 : and #$80 : beq .normal + lda $01 : and #$80 : beq .notEdge + ldy #$01 : jsr ShiftVariablesMainDir ldy $06 : cpy #$ff : beq + lda $01 : jsr LoadSouthMidpoint : bra ++ + lda $01 : jsr LoadNorthMidpoint ++ jsr PrepScrollToEdge : bra .scroll + .notEdge + lda $01 : and #$03 : cmp #$03 : bne .normal + jsr ScrollToInroomStairs + bra .end .normal + ldy #$01 : jsr ShiftVariablesMainDir jsr PrepScrollToNormal .scroll lda $01 : and #$40 : pha @@ -180,6 +193,68 @@ ShiftVariablesMainDir: rts } +; Normal Flags should be in $01 +ScrollToInroomStairs: +{ + jsr PrepScrollToInroomStairs + ldy #$01 : jsr ShiftVariablesMainDir + jsr ScrollX + ldy #$00 : jsr ApplyScroll + lda $a0 : and #$0f : cmp #$0f : bne + + stz $e0 : stz $e2 ; special case camera fix + lda #$1f : sta $e1 : sta $e3 + + + rts +} + +; Direction should be in $06, Shift Value (see above) in $02 and other info in $01 +; Sets $02, $04, $05, $ee, $045e, $045f and things related to Y coordinate +PrepScrollToInroomStairs: +{ + lda $01 : and #$30 : lsr #3 : tay + lda.w InroomStairsX,y : sta $04 + lda.w InroomStairsX+1,y : sta $05 + lda $06 : cmp #$ff : beq .south + lda.w InroomStairsY+1,y : bne + + inc $045f ; flag indicating special screen transition + dec $02 ; shift variables further + stz $aa + lda $a8 : and #%11111101 : sta $a8 + stz $0613 ; North scroll target + inc $0603 : inc $0607 + dec $0619 : dec $061b + + + lda.w InroomStairsY,y : !add #$20 : sta $20 + !sub #$38 : sta $045e + lda $01 : and #$40 : beq + + lda $20 : !add #$20 : sta $20 + stz $045f + + + dec $21 + %StonewallCheck($1b) + bra ++ + .south + lda.w InroomStairsY+1,y : beq + + inc $045f ; flag indicating special screen transition + inc $02 ; shift variables further + lda #$02 : sta $aa + lda $a8 : ora #%00000010 : sta $a8 + inc $0611 ; South scroll target + dec $0603 : dec $0607 + inc $0619 : inc $061b + + + lda.w InroomStairsY,y : !sub #$20 : sta $20 + !add #$38 : sta $045e + lda $01 : and #$40 : beq + + lda $20 : !sub #$20 : sta $20 + stz $045f + + + inc $21 + ++ + lda $01 : and #$04 : lsr #2 : sta $ee : bne + + stz $0476 + + rts +} ; Target pixel should be in A, other info in $01 ; Sets $04 $05 and $ee @@ -214,6 +289,7 @@ StraightStairsAdj: { stx $0464 : sty $012e ; what we wrote over lda.l DRMode : beq + + lda $045e : bne .toInroom jsr GetTileAttribute : tax lda $11 : cmp #$12 : beq .goingNorth lda $a2 : cmp #$51 : bne ++ @@ -234,6 +310,9 @@ StraightStairsAdj: pla : !add #$f6 : pha ++ pla : !add $0464 : sta $0464 + rtl + .toInroom + lda #$32 : sta $0464 : stz $045e + rtl } GetTileAttribute: @@ -283,11 +362,32 @@ DoorToStraight: rtl } +DoorToInroom: +{ + ldx $045e : bne .end + sta $0020, y ; what we wrote over + .end + ldx #$00 ; what we wrote over + rtl +} + +DoorToInroomEnd: +{ + ldy $045e : beq .vanilla + cmp $045e : bne .return + stz $045e ; clear + .return + rtl + .vanilla + cmp $02c034, x ; what we wrote over + rtl +} + StraightStairsTrapDoor: { lda $0464 : bne + ; reset function - phk : pea.w .jslrtsreturn-1 + .reset phk : pea.w .jslrtsreturn-1 pea.w $02802c jml $028c73 ; $10D71 .reset label of Bank02 .jslrtsreturn @@ -300,5 +400,15 @@ StraightStairsTrapDoor: inc $0468 : stz $068e : stz $0690 ++ rtl + jsl Dungeon_ApproachFixedColor ; what we wrote over - .end rtl + rtl +} + +InroomStairsTrapDoor: +{ + lda $0200 : cmp #$05 : beq .reset + lda $b0 : jml $008781 ; what we wrote over (essentially) + .reset + pla : pla : pla + jsl StraightStairsTrapDoor_reset + jml $028b15 ; just some RTS in bank 02 } \ No newline at end of file diff --git a/asm/overrides.asm b/asm/overrides.asm index b29c6bc1..d47d565f 100644 --- a/asm/overrides.asm +++ b/asm/overrides.asm @@ -37,6 +37,8 @@ OnFileLoadOverride: jsl OnFileLoad ; what I wrote over lda.l DRFlags : and #$80 : beq + ;flag is off lda $7ef086 : ora #$80 : sta $7ef086 + + lda.l DRFlags : and #$40 : beq + ;flag is off + lda $7ef036 : ora #$80 : sta $7ef036 + lda.l DRFlags : and #$02 : beq + lda $7ef353 : bne + lda #$01 : sta $7ef353 diff --git a/asm/scroll.asm b/asm/scroll.asm index 299b995a..8ee6e315 100644 --- a/asm/scroll.asm +++ b/asm/scroll.asm @@ -203,4 +203,18 @@ ApplyScroll: .end sta $00e2, y sta $00e0, y - stz $ab : sep #$30 : rts \ No newline at end of file + stz $ab : sep #$30 : rts + +QuadrantLoadOrderBeforeScroll: + lda $045f : beq .end + lda #$08 : sta $045c ; start with opposite quadrant row + .end + jsl $0091c4 ; what we overwrote + rtl + +QuadrantLoadOrderAfterScroll: + lda $045f : beq .end + stz $045c : stz $045f ; draw other row and clear flag + .end + jsl $0091c4 ; what we overwrote + rtl \ No newline at end of file diff --git a/asm/spiral.asm b/asm/spiral.asm index 2329c33b..0d13c4e7 100644 --- a/asm/spiral.asm +++ b/asm/spiral.asm @@ -2,9 +2,10 @@ RecordStairType: { pha lda.l DRMode : beq .norm lda $040c : cmp #$ff : beq .norm - lda $0e : sta $045e - cmp #$26 : beq .norm ; skipping in-floor staircases - pla : bra + + lda $0e + cmp #$25 : bcc ++ ; don't record straight staircases + sta $045e + ++ pla : bra + .norm pla : sta $a0 + lda $063d, x rtl @@ -15,8 +16,13 @@ SpiralWarp: { lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A! cmp #$5f : beq .gtg + cmp #$26 : beq .inroom .abort stz $045e : lda $a2 : and #$0f : rtl ; clear,run hijacked code and get out + .inroom + jsr InroomStairsWarp + lda $a2 : and #$0f ; this is the code we are hijacking + rtl .gtg phb : phk : plb : phx : phy ; push stuff @@ -70,6 +76,13 @@ SpiralWarp: { lda $01 : and #$20 : sta $07 ; zeroVtCam check ldy #$01 : jsr SetCamera + jsr StairCleanup + ply : plx : plb ; pull the stuff we pushed + lda $a2 : and #$0f ; this is the code we are hijacking + rtl +} + +StairCleanup: { stz $045e ; clear the staircase flag ; animated tiles fix @@ -81,9 +94,7 @@ SpiralWarp: { jsl DecompDungAnimatedTiles + stz $047a - ply : plx : plb ; pull the stuff we pushed - lda $a2 : and #$0f ; this is the code we are hijacking - rtl + rts } ;Sets the offset in A @@ -105,7 +116,7 @@ LookupSpiralOffset: { lda $a9 : ora $aa : and #$03 : beq .quad0 cmp #$01 : beq .quad1 cmp #$02 : beq .quad2 - cmp #$03 : beq .quad3 + bra .quad3 .quad0 inc $01 : lda $a2 cmp #$0c : beq .q0diff ;gt ent @@ -138,6 +149,103 @@ LookupSpiralOffset: { rts } +InroomStairsWarp: { + phb : phk : plb : phx : phy ; push stuff + ; find stairs by room and store index in X + lda $a0 : ldx #$07 + .loop + cmp.w InroomStairsRoom,x + beq .found + dex + bne .loop + .found + rep #$30 + txa : and #$00ff : asl : tay + lda.w InroomStairsTable,y : sta $00 + sep #$30 + sta $a0 + + ; set position and everything else based on target door type + txa : and #$01 : eor #$01 : sta $07 + ; should be the same as lda $0462 : and #$04 : lsr #2 : eor #$01 : sta $07 + lda $01 : and #$80 : beq .notEdge + lda $07 : sta $03 : beq + + lda $01 : jsr LoadSouthMidpoint : sta $22 : lda #$e0 + bra ++ + + + lda $01 : jsr LoadNorthMidpoint : sta $22 : lda #$1b + ++ + sta $20 + lda $01 : and #$20 : beq + + lda #$01 + + + sta $02 + stz $07 + lda $01 : and #$10 : lsr #4 + brl .layer + .notEdge + lda $01 : and #$03 : cmp #$03 : bne .normal + lda $01 : and #$30 : lsr #3 : tay + lda.w InroomStairsX,y : sta $22 + lda.w InroomStairsX+1,y : sta $02 + lda.w InroomStairsY+1,y : sta $03 + lda.w InroomStairsY,y + ldy $07 : beq + + !add #$07 + + + sta $20 + %StonewallCheck($1b) + inc $07 + lda $01 : and #$04 : lsr #2 + bra .layer + .normal + lda $01 : sta $fe ; trap door + lda $07 : sta $03 : beq + + lda #$e0 + ldy $a0 : cpy #$51 : bne ++ ; special fix for throne room + !sub #$18 + bra ++ + + + %StonewallCheck($43) + lda #$1b + ++ + sta $20 + inc $07 : stz $02 : lda #$78 : sta $22 + lda $01 : and #$03 : beq ++ + cmp #$02 : !bge + + lda #$f8 : sta $22 : stz $07 : bra ++ + + inc $02 + ++ + lda $01 : and #$04 : lsr #2 + + .layer + sta $ee + bne + + stz $0476 + + + + lda $02 : !sub $a9 + beq .skipXQuad + sta $06 : !add $a9 : sta $a9 + ldy #$00 : jsr ShiftQuadSimple + .skipXQuad + lda $aa : lsr : sta $06 : lda $03 : !sub $06 + beq .skipYQuad + sta $06 : asl : !add $aa : sta $aa + ldy #$01 : jsr ShiftQuadSimple + .skipYQuad + + ldy #$00 : jsr SetCamera ; horizontal camera + ldy #$01 : sty $07 : jsr SetCamera ; vertical camera + lda $20 : cmp #$e0 : bcc + + lda $e8 : bne + + lda #$10 : sta $e8 ; adjust vertical camera at bottom + + + jsr StairCleanup + ply : plx : plb ; pull the stuff we pushed + rts +} + ShiftQuadSimple: { lda.w CoordIndex,y : tax lda $20,x : beq .skip diff --git a/data/base2current.bps b/data/base2current.bps index 74ee4e9a..71800df8 100644 Binary files a/data/base2current.bps and b/data/base2current.bps differ diff --git a/resources/app/cli/lang/en.json b/resources/app/cli/lang/en.json index a0fa6296..556a0d13 100644 --- a/resources/app/cli/lang/en.json +++ b/resources/app/cli/lang/en.json @@ -202,7 +202,7 @@ "intensity" : [ "Door Shuffle Intensity Level (default: %(default)s)", "1: Shuffles normal doors and spiral staircases", - "2: And shuffles open edges and straight staircases", + "2: And shuffles open edges and both types of straight staircases", "3: And shuffles dungeon lobbies", "random: Picks one of those at random" ], diff --git a/resources/app/gui/lang/en.json b/resources/app/gui/lang/en.json index b3140d40..5351cd42 100644 --- a/resources/app/gui/lang/en.json +++ b/resources/app/gui/lang/en.json @@ -60,7 +60,7 @@ "randomizer.dungeon.dungeonintensity": "Intensity Level", "randomizer.dungeon.dungeonintensity.1": "1: Normal Supertile and Spiral Stairs", - "randomizer.dungeon.dungeonintensity.2": "2: Open Edges and Straight Stairs", + "randomizer.dungeon.dungeonintensity.2": "2: Open Edges, Straight Stairs and In-Room Stairs", "randomizer.dungeon.dungeonintensity.3": "3: Dungeon Lobbies", "randomizer.dungeon.dungeonintensity.random": "Random", diff --git a/resources/app/gui/randomize/dungeon/widgets.json b/resources/app/gui/randomize/dungeon/widgets.json index be7a3422..d3699ee2 100644 --- a/resources/app/gui/randomize/dungeon/widgets.json +++ b/resources/app/gui/randomize/dungeon/widgets.json @@ -19,7 +19,7 @@ "random" ], "config": { - "width": 35 + "width": 45 } }, "potshuffle": { "type": "checkbox" },