MSU Scrolling bug
Crystaroller Stairs fixed More Full ER support Added DungeonGen check for hangers without enough hooks DungeonGen doesn't consider BK door problems unless starting from origin --This could cause some longer gen times - as the origin is hooked up last Skull 3 Exit - attempt to fix
This commit is contained in:
@@ -287,15 +287,25 @@ def within_dungeon(world, player):
|
|||||||
|
|
||||||
enabled_entrances = []
|
enabled_entrances = []
|
||||||
dungeon_layouts = []
|
dungeon_layouts = []
|
||||||
for key, sector_list, entrance_list in dungeon_sectors:
|
sector_queue = collections.deque(dungeon_sectors)
|
||||||
|
last_key = None
|
||||||
|
while len(sector_queue) > 0:
|
||||||
|
key, sector_list, entrance_list = sector_queue.popleft()
|
||||||
origin_list = list(entrance_list)
|
origin_list = list(entrance_list)
|
||||||
find_enabled_origins(sector_list, enabled_entrances, origin_list)
|
find_enabled_origins(sector_list, enabled_entrances, origin_list)
|
||||||
origin_list = remove_drop_origins(origin_list)
|
origin_list = remove_drop_origins(origin_list)
|
||||||
ds = generate_dungeon(sector_list, origin_list, world, player)
|
if len(origin_list) <= 0:
|
||||||
find_new_entrances(ds, connections, potentials, enabled_entrances)
|
if last_key == key:
|
||||||
ds.name = key
|
raise Exception('Infinte loop detected %s' % key)
|
||||||
layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list
|
sector_queue.append((key, sector_list, entrance_list))
|
||||||
dungeon_layouts.append((ds, layout_starts))
|
last_key = key
|
||||||
|
else:
|
||||||
|
ds = generate_dungeon(sector_list, origin_list, world, player)
|
||||||
|
find_new_entrances(ds, connections, potentials, enabled_entrances)
|
||||||
|
ds.name = key
|
||||||
|
layout_starts = origin_list if len(entrance_list) <= 0 else entrance_list
|
||||||
|
dungeon_layouts.append((ds, layout_starts))
|
||||||
|
last_key = None
|
||||||
|
|
||||||
combine_layouts(dungeon_layouts, entrances_map)
|
combine_layouts(dungeon_layouts, entrances_map)
|
||||||
world.dungeon_layouts[player] = {}
|
world.dungeon_layouts[player] = {}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ def generate_dungeon(available_sectors, entrance_region_names, world, player):
|
|||||||
def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_doors, world, player):
|
def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_doors, world, player):
|
||||||
# step 1 create dungeon: Dict<DoorName|Origin, GraphPiece>
|
# step 1 create dungeon: Dict<DoorName|Origin, GraphPiece>
|
||||||
dungeon = {}
|
dungeon = {}
|
||||||
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(), proposed_map, valid_doors, world, player)
|
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(), proposed_map, valid_doors, True, world, player)
|
||||||
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
|
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
|
||||||
doors_to_connect = set()
|
doors_to_connect = set()
|
||||||
hanger_set = set()
|
hanger_set = set()
|
||||||
@@ -110,7 +110,7 @@ def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_do
|
|||||||
if not door.stonewall and door not in proposed_map.keys():
|
if not door.stonewall and door not in proposed_map.keys():
|
||||||
hanger_set.add(door)
|
hanger_set.add(door)
|
||||||
parent = parent_region(door, world, player).parent_region
|
parent = parent_region(door, world, player).parent_region
|
||||||
o_state = extend_reachable_state_improved([parent], ExplorationState(), proposed_map, valid_doors, world, player)
|
o_state = extend_reachable_state_improved([parent], ExplorationState(), proposed_map, valid_doors, False, world, player)
|
||||||
o_state_cache[door.name] = o_state
|
o_state_cache[door.name] = o_state
|
||||||
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
|
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
|
||||||
dungeon[door.name] = piece
|
dungeon[door.name] = piece
|
||||||
@@ -170,7 +170,7 @@ def check_blue_states(hanger_set, dungeon, o_state_cache, proposed_map, valid_do
|
|||||||
def explore_blue_state(door, dungeon, o_state, proposed_map, valid_doors, world, player):
|
def explore_blue_state(door, dungeon, o_state, proposed_map, valid_doors, world, player):
|
||||||
parent = parent_region(door, world, player).parent_region
|
parent = parent_region(door, world, player).parent_region
|
||||||
blue_start = ExplorationState(CrystalBarrier.Blue)
|
blue_start = ExplorationState(CrystalBarrier.Blue)
|
||||||
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, world, player)
|
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, False, world, player)
|
||||||
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
|
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
|
||||||
|
|
||||||
|
|
||||||
@@ -244,6 +244,18 @@ def check_valid(dungeon, hangers, hooks, proposed_map, doors_to_connect, all_reg
|
|||||||
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
|
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
|
||||||
return False
|
return False
|
||||||
# todo: stonewall - check that there's no hook-only that is without a matching hanger
|
# todo: stonewall - check that there's no hook-only that is without a matching hanger
|
||||||
|
must_hang = defaultdict(list)
|
||||||
|
all_hooks = set()
|
||||||
|
for key in hooks.keys():
|
||||||
|
for hook in hooks[key]:
|
||||||
|
all_hooks.add(hook[0])
|
||||||
|
for key in hangers.keys():
|
||||||
|
for hanger in hangers[key]:
|
||||||
|
if hanger not in all_hooks:
|
||||||
|
must_hang[key].append(hanger)
|
||||||
|
for key in must_hang.keys():
|
||||||
|
if len(must_hang[key]) > len(hooks[key]):
|
||||||
|
return False
|
||||||
outstanding_doors = defaultdict(list)
|
outstanding_doors = defaultdict(list)
|
||||||
for d in doors_to_connect:
|
for d in doors_to_connect:
|
||||||
if d not in proposed_map.keys():
|
if d not in proposed_map.keys():
|
||||||
@@ -595,9 +607,9 @@ class ExplorationState(object):
|
|||||||
elif not self.in_door_list(door, self.avail_doors):
|
elif not self.in_door_list(door, self.avail_doors):
|
||||||
self.append_door_to_list(door, self.avail_doors)
|
self.append_door_to_list(door, self.avail_doors)
|
||||||
|
|
||||||
def add_all_doors_check_proposed(self, region, proposed_map, valid_doors, world, player):
|
def add_all_doors_check_proposed(self, region, proposed_map, valid_doors, isOrigin, world, player):
|
||||||
for door in get_doors(world, region, player):
|
for door in get_doors(world, region, player):
|
||||||
if self.can_traverse_bk_check(door):
|
if self.can_traverse_bk_check(door, isOrigin):
|
||||||
if door.controller is not None:
|
if door.controller is not None:
|
||||||
door = door.controller
|
door = door.controller
|
||||||
if door.dest is None and door not in proposed_map.keys() and door in valid_doors:
|
if door.dest is None and door not in proposed_map.keys() and door in valid_doors:
|
||||||
@@ -659,12 +671,12 @@ class ExplorationState(object):
|
|||||||
return self.crystal == CrystalBarrier.Either or door.crystal == self.crystal
|
return self.crystal == CrystalBarrier.Either or door.crystal == self.crystal
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def can_traverse_bk_check(self, door):
|
def can_traverse_bk_check(self, door, isOrigin):
|
||||||
if door.blocked:
|
if door.blocked:
|
||||||
return False
|
return False
|
||||||
if door.crystal not in [CrystalBarrier.Null, CrystalBarrier.Either]:
|
if door.crystal not in [CrystalBarrier.Null, CrystalBarrier.Either]:
|
||||||
return self.crystal == CrystalBarrier.Either or door.crystal == self.crystal
|
return self.crystal == CrystalBarrier.Either or door.crystal == self.crystal
|
||||||
return not door.bigKey or len(self.found_locations) > 0
|
return not isOrigin or not door.bigKey or len(self.found_locations) > 0
|
||||||
# return not door.bigKey or len([x for x in self.found_locations if '- Prize' not in x.name]) > 0
|
# return not door.bigKey or len([x for x in self.found_locations if '- Prize' not in x.name]) > 0
|
||||||
|
|
||||||
def validate(self, door, region, world):
|
def validate(self, door, region, world):
|
||||||
@@ -733,11 +745,11 @@ def extend_reachable_state(search_regions, state, world, player):
|
|||||||
return local_state
|
return local_state
|
||||||
|
|
||||||
|
|
||||||
def extend_reachable_state_improved(search_regions, state, proposed_map, valid_doors, world, player):
|
def extend_reachable_state_improved(search_regions, state, proposed_map, valid_doors, isOrigin, world, player):
|
||||||
local_state = state.copy()
|
local_state = state.copy()
|
||||||
for region in search_regions:
|
for region in search_regions:
|
||||||
local_state.visit_region(region)
|
local_state.visit_region(region)
|
||||||
local_state.add_all_doors_check_proposed(region, proposed_map, valid_doors, world, player)
|
local_state.add_all_doors_check_proposed(region, proposed_map, valid_doors, isOrigin, world, player)
|
||||||
while len(local_state.avail_doors) > 0:
|
while len(local_state.avail_doors) > 0:
|
||||||
explorable_door = local_state.next_avail_door()
|
explorable_door = local_state.next_avail_door()
|
||||||
if explorable_door.door in proposed_map:
|
if explorable_door.door in proposed_map:
|
||||||
@@ -747,7 +759,7 @@ def extend_reachable_state_improved(search_regions, state, proposed_map, valid_d
|
|||||||
if connect_region is not None:
|
if connect_region is not None:
|
||||||
if valid_region_to_explore(connect_region, world) and not local_state.visited(connect_region):
|
if valid_region_to_explore(connect_region, world) and not local_state.visited(connect_region):
|
||||||
local_state.visit_region(connect_region)
|
local_state.visit_region(connect_region)
|
||||||
local_state.add_all_doors_check_proposed(connect_region, proposed_map, valid_doors, world, player)
|
local_state.add_all_doors_check_proposed(connect_region, proposed_map, valid_doors, isOrigin, world, player)
|
||||||
return local_state
|
return local_state
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
Rom.py
13
Rom.py
@@ -18,7 +18,7 @@ from EntranceShuffle import door_addresses, exit_ids
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = 'f96bdced8c89426bd4d1380db8a02220'
|
RANDOMIZERBASEHASH = '1292e65465342d79bee038eb58270e64'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -543,8 +543,15 @@ def patch_rom(world, player, rom):
|
|||||||
for paired_door in world.paired_doors[player]:
|
for paired_door in world.paired_doors[player]:
|
||||||
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
rom.write_bytes(paired_door.address_a(world, player), paired_door.rom_data_a(world, player))
|
||||||
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
rom.write_bytes(paired_door.address_b(world, player), paired_door.rom_data_b(world, player))
|
||||||
if world.fix_skullwoods_exit:
|
if world.fix_skullwoods_exit and world.shuffle in ['vanilla', 'simple', 'restricted', 'dungeonssimple']:
|
||||||
rom.write_int16(0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
|
connect = world.get_entrance('Skull Woods Final Section', player).connected_region
|
||||||
|
exit_name = None
|
||||||
|
for ext in connect.exits:
|
||||||
|
if ext.connected_region.name == 'Skull Woods Forest (West)':
|
||||||
|
exit_name = ext.name
|
||||||
|
break
|
||||||
|
if exit_name is not None and exit_name == 'Skull Woods Final Section Exit':
|
||||||
|
rom.write_int16(0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
|
||||||
# todo: fix other exits if ER enabled and similar situation happens
|
# todo: fix other exits if ER enabled and similar situation happens
|
||||||
|
|
||||||
write_custom_shops(rom, world, player)
|
write_custom_shops(rom, world, player)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
!sub = "sec : sbc"
|
!sub = "sec : sbc"
|
||||||
|
|
||||||
; Free RAM notes
|
; Free RAM notes
|
||||||
; Normal doors use $0127 for scrolling indicator
|
; Normal doors use $FE for scrolling indicator
|
||||||
; Normal doors use $AB to store the trap door indicator
|
; Normal doors use $AB to store the trap door indicator
|
||||||
; Spiral doors use $045e to store stair type
|
; Spiral doors use $045e to store stair type
|
||||||
; Gfx uses $b1 to for sub-sub-sub-module thing
|
; Gfx uses $b1 to for sub-sub-sub-module thing
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ dw $0207
|
|||||||
org $279E00
|
org $279E00
|
||||||
SpiralOffset:
|
SpiralOffset:
|
||||||
; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler
|
; 0 1 2 3 4 5 6 7 8 9 a b c d e f --Offset Ruler
|
||||||
db $00,$01,$02,$00,$00,$03,$00,$04,$00,$05,$07,$00,$08,$00,$0b,$00
|
db $00,$01,$02,$00,$03,$00,$00,$04,$00,$05,$07,$00,$08,$00,$0b,$00
|
||||||
db $00,$0c,$00,$00,$00,$0d,$0e,$0f,$00,$00,$11,$00,$13,$14,$15,$00
|
db $00,$0c,$00,$00,$00,$0d,$0e,$0f,$00,$00,$11,$00,$13,$14,$15,$00
|
||||||
db $00,$00,$00,$00,$00,$00,$16,$19,$1b,$00,$00,$00,$00,$00,$00,$00
|
db $00,$00,$00,$00,$00,$00,$16,$19,$1b,$00,$00,$00,$00,$00,$00,$00
|
||||||
db $00,$1c,$00,$00,$1f,$00,$00,$00,$20,$00,$21,$00,$00,$00,$00,$22
|
db $00,$1c,$00,$00,$1f,$00,$00,$00,$20,$00,$21,$00,$00,$00,$00,$22
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ ShiftLowCoord:
|
|||||||
{
|
{
|
||||||
lda $01 : and.b #$03 ; high byte index
|
lda $01 : and.b #$03 ; high byte index
|
||||||
jsr CalcOpposingShift
|
jsr CalcOpposingShift
|
||||||
lda $0127 : and.b #$f0 : cmp.b #$20 : bne .lowDone
|
lda $fe : and.b #$f0 : cmp.b #$20 : bne .lowDone
|
||||||
lda OppCoordIndex,y : tax
|
lda OppCoordIndex,y : tax
|
||||||
lda #$80 : !add $20,x : sta $20,x
|
lda #$80 : !add $20,x : sta $20,x
|
||||||
.lowDone
|
.lowDone
|
||||||
@@ -166,7 +166,7 @@ ShiftLowCoord:
|
|||||||
; q - quadrant, if set, then quadrant needs to be modified
|
; q - quadrant, if set, then quadrant needs to be modified
|
||||||
CalcOpposingShift:
|
CalcOpposingShift:
|
||||||
{
|
{
|
||||||
stz $0127 ; set up (can you zero out 127 alone?)
|
stz $fe ; set up (can you zero out 127 alone?)
|
||||||
cmp.b $04 : beq .noOffset ; (equal, no shifts to do)
|
cmp.b $04 : beq .noOffset ; (equal, no shifts to do)
|
||||||
phy : tay ; reserve these
|
phy : tay ; reserve these
|
||||||
lda $04 : tax : tya : !sub $04 : sta $04 : cmp.b #$00 : bpl .shiftPos
|
lda $04 : tax : tya : !sub $04 : sta $04 : cmp.b #$00 : bpl .shiftPos
|
||||||
@@ -174,8 +174,8 @@ CalcOpposingShift:
|
|||||||
cpx.b #$01 : beq .skipNegQuad
|
cpx.b #$01 : beq .skipNegQuad
|
||||||
ora #$08
|
ora #$08
|
||||||
.skipNegQuad
|
.skipNegQuad
|
||||||
sta $0127 : lda $04 : cmp.b #$FE : beq .done ;already set $0127
|
sta $fe : lda $04 : cmp.b #$FE : beq .done ;already set $0127
|
||||||
lda $0127 : eor #$60
|
lda $fe : eor #$60
|
||||||
bra .setDone
|
bra .setDone
|
||||||
|
|
||||||
.shiftPos
|
.shiftPos
|
||||||
@@ -183,10 +183,10 @@ CalcOpposingShift:
|
|||||||
cpy.b #$01 : beq .skipPosQuad
|
cpy.b #$01 : beq .skipPosQuad
|
||||||
ora #$08
|
ora #$08
|
||||||
.skipPosQuad
|
.skipPosQuad
|
||||||
sta $0127 : lda $04 : cmp.b #$02 : bcs .done ;already set $0127
|
sta $fe : lda $04 : cmp.b #$02 : bcs .done ;already set $0127
|
||||||
lda $0127 : eor #$60
|
lda $fe : eor #$60
|
||||||
|
|
||||||
.setDone sta $0127
|
.setDone sta $fe
|
||||||
.done ply
|
.done ply
|
||||||
.noOffset rts
|
.noOffset rts
|
||||||
}
|
}
|
||||||
@@ -194,9 +194,9 @@ CalcOpposingShift:
|
|||||||
|
|
||||||
ShiftQuad:
|
ShiftQuad:
|
||||||
{
|
{
|
||||||
lda $0127 : and #$08 : cmp.b #$00 : beq .quadDone
|
lda $fe : and #$08 : cmp.b #$00 : beq .quadDone
|
||||||
lda ShiftQuadIndex,y : tax ; X should be set to either 1 (vertical) or 2 (horizontal) (for a9,aa quadrant)
|
lda ShiftQuadIndex,y : tax ; X should be set to either 1 (vertical) or 2 (horizontal) (for a9,aa quadrant)
|
||||||
lda $0127 : and #$01 : cmp.b #$00 : beq .decQuad
|
lda $fe : and #$01 : cmp.b #$00 : beq .decQuad
|
||||||
inc $02
|
inc $02
|
||||||
txa : sta $a8, x ; alter a9/aa
|
txa : sta $a8, x ; alter a9/aa
|
||||||
bra .quadDone
|
bra .quadDone
|
||||||
@@ -224,8 +224,8 @@ ShiftCameraBounds:
|
|||||||
{
|
{
|
||||||
lda CamBoundIndex,y : tax ; should be 0 for horz travel (vert bounds) or 4 for vert travel (horz bounds)
|
lda CamBoundIndex,y : tax ; should be 0 for horz travel (vert bounds) or 4 for vert travel (horz bounds)
|
||||||
rep #$30
|
rep #$30
|
||||||
lda $0127 : and #$00f0 : asl #2 : sta $06
|
lda $fe : and #$00f0 : asl #2 : sta $06
|
||||||
lda $0127 : and #$0001 : cmp #$0000 : beq .subIt
|
lda $fe : and #$0001 : cmp #$0000 : beq .subIt
|
||||||
lda $0618, x : !add $06 : sta $0618, x
|
lda $0618, x : !add $06 : sta $0618, x
|
||||||
lda $061A, x : !add $06 : sta $061A, x
|
lda $061A, x : !add $06 : sta $061A, x
|
||||||
sep #$30
|
sep #$30
|
||||||
@@ -239,18 +239,18 @@ ShiftCameraBounds:
|
|||||||
|
|
||||||
AdjustTransition:
|
AdjustTransition:
|
||||||
{
|
{
|
||||||
lda $0127 : and #$00F0 : lsr
|
lda $fe : and #$00f0 : lsr
|
||||||
sep #$20 : cmp $0126 : bcc .reset
|
sep #$20 : cmp $0126 : bcc .reset
|
||||||
rep #$20
|
rep #$20
|
||||||
phy : ldy #$06 ; operating on vertical registers during horizontal trans
|
phy : ldy #$06 ; operating on vertical registers during horizontal trans
|
||||||
cpx.b #$02 : bcs .horizontalScrolling
|
cpx.b #$02 : bcs .horizontalScrolling
|
||||||
ldy #$00 ; operate on horizontal regs during vert trans
|
ldy #$00 ; operate on horizontal regs during vert trans
|
||||||
.horizontalScrolling
|
.horizontalScrolling
|
||||||
lda $0127 : and #$0001 : asl : tax
|
lda $fe : and #$0001 : asl : tax
|
||||||
lda.l OffsetTable,x : adc $00E2,y : and.w #$FFFE : sta $00E2,y : sta $00E0,y
|
lda.l OffsetTable,x : adc $00E2,y : and.w #$FFFE : sta $00E2,y : sta $00E0,y
|
||||||
ply : bra .done
|
ply : bra .done
|
||||||
.reset ; clear the 0127 variable so to not disturb intra-tile doors
|
.reset ; clear the 0127 variable so to not disturb intra-tile doors
|
||||||
stz $0127
|
stz $fe
|
||||||
.done
|
.done
|
||||||
rep #$20 : lda $00 : and #$01fc
|
rep #$20 : lda $00 : and #$01fc
|
||||||
rtl
|
rtl
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user