Fixed some minor issues

Started work on Straight Stairs
This commit is contained in:
aerinon
2020-04-01 12:48:04 -06:00
parent c968621ba3
commit 01bff51707
13 changed files with 294 additions and 425 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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),

View File

@@ -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']]
def opposite_h_type(h_type):
type_map = {
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):
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:

3
Rom.py
View File

@@ -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:

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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
StraightStairLayerFix:
{
lda DRMode : beq +
lda $ee : rtl
+ lda $01c322, x : rtl
}

206
asm/scroll.asm Normal file
View File

@@ -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

View File

@@ -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
}