diff --git a/BaseClasses.py b/BaseClasses.py index 9b403e91..ef44be7a 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -1161,7 +1161,7 @@ class Door(object): entrance.door = self def getAddress(self): - if self.type == DoorType.Normal: + if self.type in [DoorType.Normal, DoorType.StraightStairs]: 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 @@ -1175,9 +1175,11 @@ class Door(object): return base_address[self.direction] + self.edge_id * 3 def getTarget(self, src): - if self.type == DoorType.Normal: + if self.type in [DoorType.Normal, DoorType.StraightStairs]: bitmask = 4 * (self.layer ^ 1 if src.toggle else self.layer) bitmask += 0x08 * int(self.trapFlag) + if src.type == DoorType.StraightStairs: + bitmask += 0x40 return [self.roomIndex, bitmask + self.doorIndex] if self.type == DoorType.SpiralStairs: bitmask = int(self.layer) << 2 @@ -1187,8 +1189,10 @@ class Door(object): return [self.roomIndex, bitmask + self.quadrant, self.shiftX, self.shiftY] if self.type == DoorType.Open: bitmask = self.edge_id - bitmask += 0x10 * self.layer + bitmask += 0x10 * (self.layer ^ 1 if src.toggle else self.layer) bitmask += 0x80 + if src.type == DoorType.StraightStairs: + bitmask += 0x40 if src.type == DoorType.Open: bitmask += 0x20 * self.quadrant fraction = 0x10 * multiply_lookup[src.edge_width][self.edge_width] @@ -1205,7 +1209,6 @@ class Door(object): return (self.quadrant & 0x2) >> 1 return 0 - def dir(self, direction, room, doorIndex, layer): self.direction = direction self.roomIndex = room diff --git a/DoorShuffle.py b/DoorShuffle.py index 0b4c6598..8ca80966 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -28,8 +28,6 @@ def link_doors(world, player): connect_interior_doors(edge_a, edge_b, world, player) # These connections are here because they are currently unable to be shuffled - for entrance, ext in straight_staircases: - connect_two_way(world, entrance, ext, player) for exitName, regionName in falldown_pits: connect_simple_door(world, exitName, regionName, player) for exitName, regionName in dungeon_warps: @@ -53,10 +51,14 @@ def link_doors(world, player): if not world.experimental[player]: 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) within_dungeon(world, player) elif world.doorShuffle[player] == 'crossed': 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) cross_dungeon(world, player) else: logging.getLogger('').error('Invalid door shuffle setting: %s' % world.doorShuffle[player]) @@ -102,7 +104,8 @@ def create_door_spoiler(world, player): for ext in next.exits: door_a = ext.door connect = ext.connected_region - if door_a and door_a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open] and door_a not in done: + if door_a and door_a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, + DoorType.StraightStairs] and door_a not in done: done.add(door_a) door_b = door_a.dest if door_b: @@ -482,191 +485,6 @@ def aga_tower_enabled(enabled): return False -def within_dungeon_legacy(world, player): - # TODO: The "starts" regions need access logic - # Aerinon's note: I think this is handled already by ER Rules - may need to check correct requirements - dungeon_region_starts_es = ['Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Sewers Secret Room'] - dungeon_region_starts_ep = ['Eastern Lobby'] - dungeon_region_starts_dp = ['Desert Back Lobby', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'] - dungeon_region_starts_th = ['Hera Lobby'] - dungeon_region_starts_at = ['Tower Lobby'] - dungeon_region_starts_pd = ['PoD Lobby'] - dungeon_region_lists = [ - (dungeon_region_starts_es, hyrule_castle_regions), - (dungeon_region_starts_ep, eastern_regions), - (dungeon_region_starts_dp, desert_regions), - (dungeon_region_starts_th, hera_regions), - (dungeon_region_starts_at, tower_regions), - (dungeon_region_starts_pd, pod_regions), - ] - for start_list, region_list in dungeon_region_lists: - shuffle_dungeon(world, player, start_list, region_list) - - world.dungeon_layouts[player] = {} - for key in dungeon_regions.keys(): - world.dungeon_layouts[player][key] = (key, region_starts[key]) - - -def shuffle_dungeon(world, player, start_region_names, dungeon_region_names): - logger = logging.getLogger('') - # Part one - generate a random layout - available_regions = [] - for name in [r for r in dungeon_region_names if r not in start_region_names]: - available_regions.append(world.get_region(name, player)) - random.shuffle(available_regions) - - # "Ugly" doors are doors that we don't want to see from the front, because of some - # sort of unsupported key door. To handle them, make a map of "ugly regions" and - # never link across them. - ugly_regions = {} - next_ugly_region = 1 - - # Add all start regions to the open set. - available_doors = [] - for name in start_region_names: - logger.info("Starting in %s", name) - for door in get_doors(world, world.get_region(name, player), player): - ugly_regions[door.name] = 0 - available_doors.append(door) - - # Loop until all available doors are used - while len(available_doors) > 0: - # Pick a random available door to connect, prioritizing ones that aren't blocked. - # This makes them either get picked up through another door (so they head deeper - # into the dungeon), or puts them late in the dungeon (so they probably are part - # of a loop). Panic if neither of these happens. - random.shuffle(available_doors) - available_doors.sort(key=lambda door: 1 if door.blocked else 0 if door.ugly else 2) - door = available_doors.pop() - logger.info('Linking %s', door.name) - # Find an available region that has a compatible door - connect_region, connect_door = find_compatible_door_in_regions(world, door, available_regions, player) - # Also ignore compatible doors if they're blocked; these should only be used to - # create loops. - if connect_region is not None and not door.blocked: - logger.info(' Found new region %s via %s', connect_region.name, connect_door.name) - # Apply connection and add the new region's doors to the available list - maybe_connect_two_way(world, door, connect_door, player) - # Figure out the new room's ugliness region - new_room_ugly_region = ugly_regions[door.name] - if connect_door.ugly: - next_ugly_region += 1 - new_room_ugly_region = next_ugly_region - is_new_region = connect_region in available_regions - # Add the doors - for door in get_doors(world, connect_region, player): - ugly_regions[door.name] = new_room_ugly_region - if is_new_region: - available_doors.append(door) - # If an ugly door is anything but the connect door, panic and die - if door != connect_door and door.ugly: - logger.info('Failed because of ugly door, trying again.') - shuffle_dungeon(world, player, start_region_names, dungeon_region_names) - return - - # We've used this region and door, so don't use them again - if is_new_region: - available_regions.remove(connect_region) - if connect_door in available_doors: - available_doors.remove(connect_door) - else: - # If there's no available region with a door, use an internal connection - connect_door = find_compatible_door_in_list(ugly_regions, world, door, available_doors, player) - if connect_door is not None: - logger.info(' Adding loop via %s', connect_door.name) - maybe_connect_two_way(world, door, connect_door, player) - if connect_door in available_doors: - available_doors.remove(connect_door) - # Check that we used everything, and retry if we failed - if len(available_regions) > 0 or len(available_doors) > 0: - logger.info('Failed to add all regions to dungeon, trying again.') - shuffle_dungeon(world, player, start_region_names, dungeon_region_names) - return - - -# Connects a and b. Or don't if they're an unsupported connection type. -# TODO: This is gross, don't do it this way -def maybe_connect_two_way(world, a, b, player): - # Return on unsupported types. - if a.type in [DoorType.Open, DoorType.StraightStairs, DoorType.Hole, DoorType.Warp, DoorType.Ladder, - DoorType.Interior, DoorType.Logical]: - return - # Connect supported types - if a.type == DoorType.Normal or a.type == DoorType.SpiralStairs: - if a.blocked: - connect_one_way(world, b.name, a.name, player) - elif b.blocked: - connect_one_way(world, a.name, b.name, player) - else: - connect_two_way(world, a.name, b.name, player) - return - # If we failed to account for a type, panic - raise RuntimeError('Unknown door type ' + a.type.name) - - -# Finds a compatible door in regions, returns the region and door -def find_compatible_door_in_regions(world, door, regions, player): - if door.type in [DoorType.Hole, DoorType.Warp, DoorType.Logical]: - return door.dest, door - for region in regions: - for proposed_door in get_doors(world, region, player): - if doors_compatible(door, proposed_door): - return region, proposed_door - return None, None - - -def find_compatible_door_in_list(ugly_regions, world, door, doors, player): - if door.type in [DoorType.Hole, DoorType.Warp, DoorType.Logical]: - return door - for proposed_door in doors: - if ugly_regions[door.name] != ugly_regions[proposed_door.name]: - continue - if doors_compatible(door, proposed_door): - return proposed_door - - -def get_doors(world, region, player): - res = [] - for exit in region.exits: - door = world.check_for_door(exit.name, player) - if door is not None: - res.append(door) - return res - - -def get_entrance_doors(world, region, player): - res = [] - for exit in region.entrances: - door = world.check_for_door(exit.name, player) - if door is not None: - res.append(door) - return res - - -def doors_compatible(a, b): - if a.type != b.type: - return False - if a.type == DoorType.Open: - return doors_fit_mandatory_pair(open_edges, a, b) - if a.type == DoorType.StraightStairs: - return doors_fit_mandatory_pair(straight_staircases, a, b) - if a.type == DoorType.Interior: - return doors_fit_mandatory_pair(interior_doors, a, b) - if a.type == DoorType.Ladder: - return doors_fit_mandatory_pair(ladders, a, b) - if a.type == DoorType.Normal and (a.smallKey or b.smallKey or a.bigKey or b.bigKey): - return doors_fit_mandatory_pair(key_doors, a, b) - if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Logical]: - return False # these aren't compatible with anything - return a.direction == switch_dir(b.direction) - - -def doors_fit_mandatory_pair(pair_list, a, b): - for pair_a, pair_b in pair_list: - if (a.name == pair_a and b.name == pair_b) or (a.name == pair_b and b.name == pair_a): - return True - return False - # goals: # 1. have enough chests to be interesting (2 more than dungeon items) # 2. have a balanced amount of regions added (check) diff --git a/Doors.py b/Doors.py index d8c6c778..b0410660 100644 --- a/Doors.py +++ b/Doors.py @@ -900,7 +900,7 @@ def create_doors(world, player): create_door(player, 'TR Crystal Maze Blue Path', Lgcl), create_door(player, 'TR Crystal Maze Cane Path', Lgcl), create_door(player, 'TR Crystal Maze North Stairs', StrS).dir(No, 0xc4, Mid, High), - create_door(player, 'TR Final Abyss South Stairs', StrS).dir(No, 0xb4, Right, High), + create_door(player, 'TR Final Abyss South Stairs', StrS).dir(So, 0xb4, Mid, High), create_door(player, 'TR Final Abyss NW', Nrml).dir(No, 0xb4, Left, High).big_key().pos(0), create_door(player, 'TR Boss SW', Nrml).dir(So, 0xa4, Left, High).no_exit().trap(0x4).pos(0), diff --git a/DungeonGenerator.py b/DungeonGenerator.py index 6aae3436..1d0eb82b 100644 --- a/DungeonGenerator.py +++ b/DungeonGenerator.py @@ -515,52 +515,57 @@ def filter_for_potential_bk_locations(locations): and x.name not in key_only_locations.keys() and x.name not in ['Agahnim 1', 'Agahnim 2']] +type_map = { + Hook.Stairs: Hook.Stairs, + Hook.North: Hook.South, + Hook.South: Hook.North, + Hook.West: Hook.East, + Hook.East: Hook.West, +} + + def opposite_h_type(h_type): - type_map = { - Hook.Stairs: Hook.Stairs, - Hook.North: Hook.South, - Hook.South: Hook.North, - Hook.West: Hook.East, - Hook.East: Hook.West, - } return type_map[h_type] +hook_map = { + Direction.North: Hook.North, + Direction.South: Hook.South, + Direction.West: Hook.West, + Direction.East: Hook.East, +} + + +hanger_map = { + Direction.North: Hook.South, + Direction.South: Hook.North, + Direction.West: Hook.East, + Direction.East: Hook.West, +} + + def hook_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open]: - dir = { - Direction.North: Hook.North, - Direction.South: Hook.South, - Direction.West: Hook.West, - Direction.East: Hook.East, - } - return dir[door.direction] + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + return hook_map[door.direction] return None def hanger_from_door(door): if door.type == DoorType.SpiralStairs: return Hook.Stairs - if door.type in [DoorType.Normal, DoorType.Open]: - dir = { - Direction.North: Hook.South, - Direction.South: Hook.North, - Direction.West: Hook.East, - Direction.East: Hook.West, - } - return dir[door.direction] + if door.type in [DoorType.Normal, DoorType.Open, DoorType.StraightStairs]: + return hanger_map[door.direction] return None def connect_doors(a, b): # Return on unsupported types. - if a.type in [DoorType.StraightStairs, DoorType.Hole, DoorType.Warp, DoorType.Ladder, - DoorType.Interior, DoorType.Logical]: + if a.type in [DoorType.Hole, DoorType.Warp, DoorType.Ladder, DoorType.Interior, DoorType.Logical]: return # Connect supported types - if a.type == DoorType.Normal or a.type == DoorType.SpiralStairs or a.type == DoorType.Open: + if a.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open, DoorType.StraightStairs]: if a.blocked: connect_one_way(b.entrance, a.entrance) elif b.blocked: diff --git a/Rom.py b/Rom.py index 2f5d4054..709e2e0a 100644 --- a/Rom.py +++ b/Rom.py @@ -608,7 +608,8 @@ def patch_rom(world, rom, player, team, enemized): if world.doorShuffle[player] == 'basic': rom.write_byte(0x139004, 1) for door in world.doors: - if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs, DoorType.Open]: + if door.dest is not None and door.player == player and door.type in [DoorType.Normal, DoorType.SpiralStairs, + DoorType.Open, DoorType.StraightStairs]: rom.write_bytes(door.getAddress(), door.dest.getTarget(door)) for room in world.rooms: if room.player == player and room.modified: diff --git a/Tables.py b/Tables.py index 15f98f58..e67e20f4 100644 --- a/Tables.py +++ b/Tables.py @@ -19,7 +19,8 @@ normal_offset_table = { 0xb7: 0x79, 0xb8: 0x7A, 0xb9: 0x7B, 0xba: 0x7C, 0xbb: 0x7D, 0xbc: 0x7E, 0xbe: 0x7F, 0xbf: 0x80, 0xc1: 0x81, 0xc2: 0x82, 0xc3: 0x83, 0xc4: 0x84, 0xc5: 0x85, 0xc6: 0x86, 0xc7: 0x87, 0xc8: 0x88, 0xc9: 0x89, 0xcb: 0x8A, 0xcc: 0x8B, 0xce: 0x8C, 0xd1: 0x8D, 0xd2: 0x8E, 0xd5: 0x8F, 0xd6: 0x90, - 0xd8: 0x91, 0xd9: 0x92, 0xda: 0x93, 0xdb: 0x94, 0xdc: 0x95 + 0xd8: 0x91, 0xd9: 0x92, 0xda: 0x93, 0xdb: 0x94, 0xdc: 0x95, + 0x40: 0x96, 0x42: 0x97 # newcomers for str stairs } diff --git a/asm/doorrando.asm b/asm/doorrando.asm index 646580eb..f78c74c1 100644 --- a/asm/doorrando.asm +++ b/asm/doorrando.asm @@ -15,6 +15,7 @@ incsrc drhooks.asm ;Main Code org $278000 ;138000 incsrc normal.asm +incsrc scroll.asm incsrc spiral.asm incsrc gfx.asm incsrc keydoors.asm diff --git a/asm/doortables.asm b/asm/doortables.asm index 8071188c..e342f552 100644 --- a/asm/doortables.asm +++ b/asm/doortables.asm @@ -43,7 +43,7 @@ db $00,$01,$02,$00,$03,$00,$04,$00,$00,$00,$00,$00,$00,$05,$00,$00 db $00,$06,$07,$08,$09,$0A,$0B,$00,$00,$0C,$0D,$0E,$00,$0F,$10,$11 db $12,$13,$14,$15,$16,$00,$17,$00,$00,$00,$18,$19,$00,$00,$1A,$00 db $1B,$00,$1C,$1D,$1E,$1F,$20,$21,$22,$23,$24,$25,$00,$26,$27,$00 -db $00,$28,$00,$29,$2A,$2B,$2C,$00,$00,$2D,$2E,$2F,$30,$31,$32,$00 +db $96,$28,$97,$29,$2A,$2B,$2C,$00,$00,$2D,$2E,$2F,$30,$31,$32,$00 db $33,$34,$35,$36,$00,$00,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F,$40 db $41,$42,$43,$00,$00,$00,$44,$45,$46,$00,$47,$48,$49,$4A,$4B,$00 db $00,$4C,$00,$00,$00,$4D,$4E,$00,$00,$00,$00,$4F,$50,$51,$52,$53 @@ -208,14 +208,16 @@ dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Eastern Attic Start dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; TT Entrance Quad dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; TT SE Quad -; this should end at 27AE10 about -; some values you can hardcode +dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Aga 6F +dw $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003, $0003 ; Sewers Rope +; this should end at 27AE40 about (152 * 24 bytes = 3648 or E40) +; some values you can hardcode for spirals ;dw $0070, $36a0 ; ->HC Stairwell ;dw $0072, $4ff8 ; ->HC Map Room ;dw $0080, $1f50 ; ->zelda's cellblock org $27B000 -SpiralTable: +SpiralTable: ;113 4 byte entries - should end at 27B44C dw $0203, $8080 ;null row dw $0203, $8080 ;HC Backhallway dw $0203, $8080 ;Sewer Pull diff --git a/asm/drhooks.asm b/asm/drhooks.asm index df946455..c1f8a070 100644 --- a/asm/drhooks.asm +++ b/asm/drhooks.asm @@ -24,12 +24,19 @@ NotLinkDoor2: ; Staircase routine -org $01c3d4 ;(PC: c3d4) +org $01c3d4 ; <- c3d4 - Bank01.asm : 9762-4 (Dungeon_DetectStaircase-> STA $A0 : LDA $063D, X) jsl RecordStairType : nop org $02a1e7 ;(PC: 121e7) jsl SpiralWarp +org $029383 ; <- 11384 - Bank02.asm : 3629 (.walkingDownStaircase-> ADD $20 : STA $20) +jsl StraightStairsFix : nop +org $0293aa ; <- 113aa - Bank02.asm : 3653 (ADD $20 : STA $20) +jsl StraightStairsFix : nop +org $029396 ; <- 11384 - Bank02.asm : 3641 (LDA $01C322, X) +jsl StraightStairLayerFix + ; Graphics fix org $02895d Splicer: diff --git a/asm/edges.asm b/asm/edges.asm index a45da373..2b9c2228 100644 --- a/asm/edges.asm +++ b/asm/edges.asm @@ -114,173 +114,6 @@ MathEnd: sep #$30 rts - -; expects target quad in $05 (either 0 or 1) and target pixel in $04, target room should be in $a0 -; $06 is either $ff or $01/02 -; uses $00-$03 and $0e for calculation -; also set up $ac -ScrollY: ;change the Y offset variables - lda $a0 : and.b #$f0 : lsr #3 : sta $0603 : inc : sta $0607 - - lda $05 : bne + - lda $603 : sta $00 : stz $01 : bra ++ - + lda $607 : sta $00 : lda #$02 : sta $01 - ++ ; $01 now contains 0 or 2 and $00 contains the correct lat - - stz $0e - rep #$30 - lda $00 : pha - - lda $e8 : and #$01ff : sta $02 - lda $04 : jsr LimitYCamera : sta $00 - jsr CheckRoomLayoutY : bcc + - lda $00 : cmp #$0080 : !bge ++ - cmp #$0010 : !blt .cmpSrll - lda #$0010 : bra .cmpSrll - ++ cmp #$0100 : !bge .cmpSrll - lda #$0100 - .cmpSrll sta $00 - - ; figures out scroll amt - + lda $00 : cmp $02 : bne + - lda #$0000 : bra .next - + !blt + - !sub $02 : inc $0e : bra .next - + lda $02 : !sub $00 - - .next - sta $ab - jsr AdjustCameraBoundsY - - pla : sta $00 - sep #$30 - lda $04 : sta $20 - lda $00 : sta $21 : sta $0601 : sta $0605 - lda $01 : sta $aa - lda $0e : asl : ora $ac : sta $ac - lda $e9 : and #$01 : asl #2 : tax : lda $0603, x : sta $e9 - rts - -LimitYCamera: - cmp #$006c : !bge + - lda #$0000 : bra .end - + cmp #$017d : !blt + - lda #$0110 : bra .end - + !sub #$006c - .end rts - -CheckRoomLayoutY: - jsr LoadRoomLayout ;switches to 8-bit - cmp #$00 : beq .lock - cmp #$07 : beq .free - cmp #$01 : beq .free - cmp #$04 : !bge .lock - cmp #$02 : bne + - lda $06 : cmp #$ff : beq .lock - + cmp #$03 : bne .free - lda $06 : cmp #$ff : bne .lock - .free rep #$30 : clc : rts - .lock rep #$30 : sec : rts - -LoadRoomLayout: - lda $a0 : asl : !add $a0 : tax - lda $1f8001, x : sta $b8 - lda $1f8000, x : sta $b7 - sep #$30 - ldy #$01 : lda [$b7], y : and #$1c : lsr #2 - rts - -; expects target quad in $05 (either 0 or 1) and target pixel in $04, target room should be in $a0 -; uses $00-$03 and $0e for calculation -; also set up $ac -ScrollX: ;change the X offset variables - lda $a0 : and.b #$0f : asl : sta $060b : inc : sta $060f - - lda $05 : bne + - lda $60b : sta $00 : stz $01 : bra ++ - + lda $60f : sta $00 : lda #$01 : sta $01 - ++ ; $01 now contains 0 or 1 and $00 contains the correct long - - stz $0e ; pos/neg indicator - rep #$30 - lda $00 : pha - - lda $e2 : and #$01ff : sta $02 - lda $04 : jsr LimitXCamera : sta $00 - jsr CheckRoomLayoutX : bcc + - lda $00 : cmp #$0080 : !bge ++ - lda #$0000 : bra .cmpSrll - ++ lda #$0100 - .cmpSrll sta $00 - - ;figures out scroll amt - + lda $00 : cmp $02 : bne + - lda #$0000 : bra .next - + !blt + - !sub $02 : inc $0e : bra .next - + lda $02 : !sub $00 - - .next - sta $ab : lda $04 - - cmp #$0078 : !bge + - lda #$007f : bra ++ - + cmp #$0178 : !blt + - lda #$017f : bra ++ - + !add #$0007 - ++ sta $061c : inc #2 : sta $061e - - pla : sta $00 - sep #$30 - lda $04 : sta $22 - lda $00 : sta $23 : sta $0609 : sta $060d - lda $01 : sta $a9 - lda $0e : asl : ora $ac : sta $ac - lda $e3 : and #$01 : asl #2 : tax : lda $060b, x : sta $e3 - - rts - -LimitXCamera: - cmp #$0080 : !bge + - lda #$0000 : bra .end - + cmp #$0181 : !blt + - lda #$0180 - + !sub #$0080 - .end rts - -CheckRoomLayoutX: - jsr LoadRoomLayout ;switches to 8-bit - cmp #$04 : !blt .lock - cmp #$05 : bne + - lda $06 : cmp #$ff : beq .lock - + cmp #$06 : bne .free - lda $06 : cmp #$ff : bne .lock - .free rep #$30 : clc : rts - .lock rep #$30 : sec : rts - -AdjustCameraBoundsY: - jsr CheckRoomLayoutY : bcc .free - - ; layouts that are camera locked (quads only) - lda $04 : and #$00ff : cmp #$007d : !blt + - lda #$0088 : bra ++ - + cmp #$006d : !bge + - lda #$0078 : bra ++ - + !add #$000b - - ; I think we no longer need the $02 variable - ++ sta $02 : lda $04 : and #$0100 : !add $02 : bra .setBounds - - ; layouts where the camera is free - .free lda $04 : cmp #$006c : !bge + - lda #$0077 : bra .setBounds - + cmp #$017c : !blt + - lda #$0187 : bra .setBounds - + !add #$000b - .setBounds sta $0618 : inc #2 : sta $061a - rts - - ; don't need midpoint of edge Link is leaving (formerly in $06 - used by dir indicator) ; don't need width of edge Link is going to (currently in $0b) LoadNorthData: diff --git a/asm/normal.asm b/asm/normal.asm index 46865f61..30e19e0c 100644 --- a/asm/normal.asm +++ b/asm/normal.asm @@ -106,7 +106,11 @@ LoadRoomHorz: .normal jsr PrepScrollToNormal - .scroll jsr ScrollY + .scroll + lda $01 : and #$40 : pha + jsr ScrollY + pla : beq .end + ldy #$06 : jsr ApplyScroll .end plb ; restore db register rts @@ -135,7 +139,11 @@ LoadRoomVert: .normal jsr PrepScrollToNormal - .scroll jsr ScrollX + .scroll + lda $01 : and #$40 : pha + jsr ScrollX + pla : beq .end + ldy #$00 : jsr ApplyScroll .end plb ; restore db register rts @@ -198,33 +206,16 @@ PrepScrollToNormal: .end rts } -AdjustTransition: +StraightStairsFix: { - lda $ab : and #$01ff : beq .reset - phy : ldy #$06 ; operating on vertical registers during horizontal trans - cpx.b #$02 : bcs .horizontalScrolling - ldy #$00 ; operate on horizontal regs during vert trans - .horizontalScrolling - cmp #$0008 : bcs + - pha : lda $ab : and #$0200 : beq ++ - pla : bra .add - ++ pla : eor #$ffff : inc ; convert to negative - .add jsr AdjustCamAdd : ply : bra .reset - + lda $ab : and #$0200 : xba : tax - lda.l OffsetTable,x : jsr AdjustCamAdd - lda $ab : !sub #$0008 : sta $ab - ply : bra .done - .reset ; clear the $ab variable so to not disturb intra-tile doors - stz $ab - .done - lda $00 : and #$01fc - rtl + lda DRMode : bne + + !add $20 : sta $20 + + rtl } -AdjustCamAdd: - !add $00E2,y : pha - and #$01ff : cmp #$0111 : !blt + - cmp #$01f8 : !bge ++ - pla : and #$ff10 : pha : bra + - ++ pla : and #$ff00 : !add #$0100 : pha - + pla : sta $00E2,y : sta $00E0,y : rts \ No newline at end of file +StraightStairLayerFix: +{ + lda DRMode : beq + + lda $ee : rtl + + lda $01c322, x : rtl +} \ No newline at end of file diff --git a/asm/scroll.asm b/asm/scroll.asm new file mode 100644 index 00000000..44314532 --- /dev/null +++ b/asm/scroll.asm @@ -0,0 +1,206 @@ +AdjustTransition: +{ + lda $ab : and #$01ff : beq .reset + phy : ldy #$06 ; operating on vertical registers during horizontal trans + cpx.b #$02 : bcs .horizontalScrolling + ldy #$00 ; operate on horizontal regs during vert trans + .horizontalScrolling + cmp #$0008 : bcs + + pha : lda $ab : and #$0200 : beq ++ + pla : bra .add + ++ pla : eor #$ffff : inc ; convert to negative + .add jsr AdjustCamAdd : ply : bra .reset + + lda $ab : and #$0200 : xba : tax + lda.l OffsetTable,x : jsr AdjustCamAdd + lda $ab : !sub #$0008 : sta $ab + ply : bra .done + .reset ; clear the $ab variable so to not disturb intra-tile doors + stz $ab + .done + lda $00 : and #$01fc + rtl +} + +AdjustCamAdd: + !add $00E2,y : pha + and #$01ff : cmp #$0111 : !blt + + cmp #$01f8 : !bge ++ + pla : and #$ff10 : pha : bra + + ++ pla : and #$ff00 : !add #$0100 : pha + + pla : sta $00E2,y : sta $00E0,y : rts + +; expects target quad in $05 (either 0 or 1) and target pixel in $04, target room should be in $a0 +; $06 is either $ff or $01/02 +; uses $00-$03 and $0e for calculation +; also set up $ac +ScrollY: ;change the Y offset variables + lda $a0 : and.b #$f0 : lsr #3 : sta $0603 : inc : sta $0607 + + lda $05 : bne + + lda $603 : sta $00 : stz $01 : bra ++ + + lda $607 : sta $00 : lda #$02 : sta $01 + ++ ; $01 now contains 0 or 2 and $00 contains the correct lat + + stz $0e + rep #$30 + lda $00 : pha + + lda $e8 : and #$01ff : sta $02 + lda $04 : jsr LimitYCamera : sta $00 + jsr CheckRoomLayoutY : bcc + + lda $00 : cmp #$0080 : !bge ++ + cmp #$0010 : !blt .cmpSrll + lda #$0010 : bra .cmpSrll + ++ cmp #$0100 : !bge .cmpSrll + lda #$0100 + .cmpSrll sta $00 + + ; figures out scroll amt + + lda $00 : cmp $02 : bne + + lda #$0000 : bra .next + + !blt + + !sub $02 : inc $0e : bra .next + + lda $02 : !sub $00 + + .next + sta $ab + jsr AdjustCameraBoundsY + + pla : sta $00 + sep #$30 + lda $04 : sta $20 + lda $00 : sta $21 : sta $0601 : sta $0605 + lda $01 : sta $aa + lda $0e : asl : ora $ac : sta $ac + lda $e9 : and #$01 : asl #2 : tax : lda $0603, x : sta $e9 + rts + +LimitYCamera: + cmp #$006c : !bge + + lda #$0000 : bra .end + + cmp #$017d : !blt + + lda #$0110 : bra .end + + !sub #$006c + .end rts + +CheckRoomLayoutY: + jsr LoadRoomLayout ;switches to 8-bit + cmp #$00 : beq .lock + cmp #$07 : beq .free + cmp #$01 : beq .free + cmp #$04 : !bge .lock + cmp #$02 : bne + + lda $06 : cmp #$ff : beq .lock + + cmp #$03 : bne .free + lda $06 : cmp #$ff : bne .lock + .free rep #$30 : clc : rts + .lock rep #$30 : sec : rts + +AdjustCameraBoundsY: + jsr CheckRoomLayoutY : bcc .free + + ; layouts that are camera locked (quads only) + lda $04 : and #$00ff : cmp #$007d : !blt + + lda #$0088 : bra ++ + + cmp #$006d : !bge + + lda #$0078 : bra ++ + + !add #$000b + + ; I think we no longer need the $02 variable + ++ sta $02 : lda $04 : and #$0100 : !add $02 : bra .setBounds + + ; layouts where the camera is free + .free lda $04 : cmp #$006c : !bge + + lda #$0077 : bra .setBounds + + cmp #$017c : !blt + + lda #$0187 : bra .setBounds + + !add #$000b + .setBounds sta $0618 : inc #2 : sta $061a + rts + +LoadRoomLayout: + lda $a0 : asl : !add $a0 : tax + lda $1f8001, x : sta $b8 + lda $1f8000, x : sta $b7 + sep #$30 + ldy #$01 : lda [$b7], y : and #$1c : lsr #2 + rts + +; expects target quad in $05 (either 0 or 1) and target pixel in $04, target room should be in $a0 +; uses $00-$03 and $0e for calculation +; also set up $ac +ScrollX: ;change the X offset variables + lda $a0 : and.b #$0f : asl : sta $060b : inc : sta $060f + + lda $05 : bne + + lda $60b : sta $00 : stz $01 : bra ++ + + lda $60f : sta $00 : lda #$01 : sta $01 + ++ ; $01 now contains 0 or 1 and $00 contains the correct long + + stz $0e ; pos/neg indicator + rep #$30 + lda $00 : pha + + lda $e2 : and #$01ff : sta $02 + lda $04 : jsr LimitXCamera : sta $00 + jsr CheckRoomLayoutX : bcc + + lda $00 : cmp #$0080 : !bge ++ + lda #$0000 : bra .cmpSrll + ++ lda #$0100 + .cmpSrll sta $00 + + ;figures out scroll amt + + lda $00 : cmp $02 : bne + + lda #$0000 : bra .next + + !blt + + !sub $02 : inc $0e : bra .next + + lda $02 : !sub $00 + + .next + sta $ab : lda $04 + + cmp #$0078 : !bge + + lda #$007f : bra ++ + + cmp #$0178 : !blt + + lda #$017f : bra ++ + + !add #$0007 + ++ sta $061c : inc #2 : sta $061e + + pla : sta $00 + sep #$30 + lda $04 : sta $22 + lda $00 : sta $23 : sta $0609 : sta $060d + lda $01 : sta $a9 + lda $0e : asl : ora $ac : sta $ac + lda $e3 : and #$01 : asl #2 : tax : lda $060b, x : sta $e3 + + rts + +LimitXCamera: + cmp #$0080 : !bge + + lda #$0000 : bra .end + + cmp #$0181 : !blt + + lda #$0180 + + !sub #$0080 + .end rts + +CheckRoomLayoutX: + jsr LoadRoomLayout ;switches to 8-bit + cmp #$04 : !blt .lock + cmp #$05 : bne + + lda $06 : cmp #$ff : beq .lock + + cmp #$06 : bne .free + lda $06 : cmp #$ff : bne .lock + .free rep #$30 : clc : rts + .lock rep #$30 : sec : rts + +ApplyScroll: + rep #$30 + lda $ab : and #$01ff : sta $00 + lda $ab : and #$0200 : beq + + lda $00e2, y : !add $00 : bra .end + + lda $00e2, y : !sub $00 + .end + sta $00e2, y + sta $00e0, y + stz $ab : sep #$30 : rts \ No newline at end of file diff --git a/asm/spiral.asm b/asm/spiral.asm index d66d9304..0d041610 100644 --- a/asm/spiral.asm +++ b/asm/spiral.asm @@ -1,7 +1,8 @@ RecordStairType: { - sta $a0 - lda $0e : sta $045e - lda $063d, x + pha : lda DRMode : beq + + lda $0e : sta $045e : pla : bra .end + + pla : sta $a0 + .end lda $063d, x rtl }