Lobby logic improvements

Cutoff entrance rug re-work
This commit is contained in:
aerinon
2020-09-21 16:38:15 -06:00
parent d2ea578df8
commit 99f262cc72
11 changed files with 108 additions and 69 deletions

View File

@@ -1186,6 +1186,7 @@ class Door(object):
self.deadEnd = False
self.passage = True
self.dungeonLink = None
self.bk_shuffle_req = False
# self.incognitoPos = -1
# self.sectorLink = False
@@ -1328,6 +1329,13 @@ class Door(object):
self.portalAble = True
return self
def dead_end(self, allowPassage=False):
self.deadEnd = True
if allowPassage:
self.passage = True
else:
self.passage = False
def __eq__(self, other):
return isinstance(other, self.__class__) and self.name == other.name
@@ -1552,6 +1560,12 @@ class Portal(object):
else:
return 0x12
def __str__(self):
return str(self.__unicode__())
def __unicode__(self):
return f'{self.name}:{self.door.name}'
class DungeonInfo(object):
def __init__(self, name):

View File

@@ -41,7 +41,8 @@ def link_doors(world, player):
for entrance, ext in straight_staircases:
connect_two_way(world, entrance, ext, player)
choose_portals(world, player)
if world.intensity[player] >= 3:
choose_portals(world, player)
if world.doorShuffle[player] == 'vanilla':
for entrance, ext in open_edges:
@@ -312,6 +313,7 @@ def choose_portals(world, player):
if world.doorShuffle[player] in ['basic', 'crossed']:
cross_flag = world.doorShuffle[player] == 'crossed'
bk_shuffle = world.bigkeyshuffle[player]
# roast incognito doors
world.get_room(0x60, player).delete(5)
world.get_room(0x60, player).change(2, DoorKind.DungeonEntrance)
@@ -350,13 +352,15 @@ def choose_portals(world, player):
sanc.destination = True
clean_up_portal_assignment(portal_assignment, dungeon, sanc, master_door_list, outstanding_portals)
for target_region, possible_portals in info.required_passage.items():
candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag)
candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag,
bk_shuffle=bk_shuffle)
choice, portal = assign_portal(candidates, possible_portals, world, player)
portal.destination = True
clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals)
dead_end_choices = info.total - 1 - len(portal_assignment[dungeon])
for i in range(0, dead_end_choices):
candidates = find_portal_candidates(master_door_list, dungeon, dead_end_allowed=True, crossed=cross_flag)
candidates = find_portal_candidates(master_door_list, dungeon, dead_end_allowed=True,
crossed=cross_flag, bk_shuffle=bk_shuffle)
possible_portals = outstanding_portals if not info.sole_entrance else [x for x in outstanding_portals if x != info.sole_entrance]
choice, portal = assign_portal(candidates, possible_portals, world, player)
if choice.deadEnd:
@@ -364,7 +368,8 @@ def choose_portals(world, player):
clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals)
the_rest = info.total - len(portal_assignment[dungeon])
for i in range(0, the_rest):
candidates = find_portal_candidates(master_door_list, dungeon, crossed=cross_flag)
candidates = find_portal_candidates(master_door_list, dungeon, crossed=cross_flag,
bk_shuffle=bk_shuffle)
choice, portal = assign_portal(candidates, outstanding_portals, world, player)
clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals)
@@ -408,23 +413,23 @@ def connect_portal(portal, world, player):
world.regions.remove(placeholder)
def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False):
def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, bk_shuffle=False):
filter_list = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req]
if need_passage:
if crossed:
ret = [x for x in door_list if x.passage and not x.deadEnd]
return [x for x in ret if x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon]
return [x for x in filter_list if x.passage and (x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon)]
else:
return [x for x in door_list if x.passage and x.entrance.parent_region.dungeon.name == dungeon and not x.deadEnd]
return [x for x in filter_list if x.passage and x.entrance.parent_region.dungeon.name == dungeon]
elif dead_end_allowed:
if crossed:
return [x for x in door_list if x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon]
return [x for x in filter_list if x.dungeonLink is None or x.entrance.parent_region.dungeon.name == dungeon]
else:
return [x for x in door_list if x.entrance.parent_region.dungeon.name == dungeon]
return [x for x in filter_list if x.entrance.parent_region.dungeon.name == dungeon]
else:
if crossed:
return [x for x in door_list if (not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon) and not x.deadEnd]
return [x for x in filter_list if (not x.dungeonLink or x.entrance.parent_region.dungeon.name == dungeon) and not x.deadEnd]
else:
return [x for x in door_list if x.entrance.parent_region.dungeon.name == dungeon and not x.deadEnd]
return [x for x in filter_list if x.entrance.parent_region.dungeon.name == dungeon and not x.deadEnd]
def assign_portal(candidates, possible_portals, world, player):
@@ -765,7 +770,7 @@ def cross_dungeon(world, player):
possible_portals = []
for portal_name in dungeon_portals[d_name]:
portal = world.get_portal(portal_name, player)
if portal.door == 'Sanctuary S':
if portal.door.name == 'Sanctuary S':
possible_portals.clear()
possible_portals.append(portal)
break
@@ -1499,7 +1504,7 @@ def determine_init_crystal(initial, state, start_regions):
elif start_region in state.visited_orange:
return CrystalBarrier.Orange
else:
raise Exception('Can\'t get to %s from initial state', start_region.name)
raise Exception(f'Can\'t get to {start_region.name} from initial state')
def explore_state(state, world, player):

View File

@@ -1295,33 +1295,41 @@ def create_doors(world, player):
]
world.dungeon_portals[player] += dungeon_portals
world.get_door('Sanctuary S', player).deadEnd = True
world.get_door('Sanctuary S', player).dead_end(allowPassage=True)
world.get_door('TR Big Chest Entrance SE', player).passage = False
world.get_door('Sewers Secret Room Key Door S', player).dungeonLink = 'Hyrule Castle'
world.get_door('Desert Cannonball S', player).deadEnd = True
world.get_door('Desert Boss SW', player).deadEnd = True
world.get_door('Desert Cannonball S', player).dead_end()
world.get_door('Desert Boss SW', player).dead_end()
world.get_door('Desert Boss SW', player).dungeonLink = 'Desert Palace'
world.get_door('Skull 1 Lobby S', player).dungeonLink = 'Skull Woods'
world.get_door('Skull Map Room SE', player).dungeonLink = 'Skull Woods'
world.get_door('Skull Spike Corner SW', player).dungeonLink = 'Skull Woods'
world.get_door('Skull Spike Corner SW', player).deadEnd = True
world.get_door('Thieves Pot Alcove Bottom SW', player).deadEnd = True
world.get_door('Ice Conveyor SW', player).deadEnd = True
world.get_door('Mire Right Bridge SE', player).deadEnd = True
world.get_door('TR Roller Room SW', player).deadEnd = True
world.get_door('TR Tile Room SE', player).deadEnd = True
world.get_door('TR Boss SW', player).deadEnd = True
world.get_door('Skull Spike Corner SW', player).dead_end()
world.get_door('Thieves Pot Alcove Bottom SW', player).dead_end()
world.get_door('Ice Conveyor SW', player).dead_end(allowPassage=True)
world.get_door('Mire Right Bridge SE', player).dead_end(allowPassage=True)
world.get_door('TR Roller Room SW', player).dead_end()
world.get_door('TR Tile Room SE', player).dead_end()
world.get_door('TR Boss SW', player).dead_end()
world.get_door('TR Boss SW', player).dungeonLink = 'Turtle Rock'
world.get_door('GT Petting Zoo SE', player).deadEnd = True
world.get_door('GT DMs Room SW', player).deadEnd = True
world.get_door('GT Petting Zoo SE', player).dead_end()
world.get_door('GT DMs Room SW', player).dead_end()
world.get_door("GT Bob\'s Room SE", player).passage = False
world.get_door('PoD Mimics 2 SW', player).bk_shuffle_req = True
world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo)
# can't unlink from boss right now
world.get_door("Hera Lobby S", player).dungeonLink = 'Tower of Hera'
world.get_door('Hera Lobby S', player).dungeonLink = 'Tower of Hera'
# can't unlink from skull woods right now
world.get_door('Skull 2 West Lobby S', player).dungeonLink = 'Skull Woods'
world.get_door('Ice Spike Cross SE', player).dungeonLink = 'linkIceFalls'
world.get_door('Ice Tall Hint SE', player).dungeonLink = 'linkIceFalls'
world.get_door('Ice Switch Room SE', player).dungeonLink = 'linkIceFalls'
world.get_door('Ice Cross Bottom SE', player).dungeonLink = 'linkIceFalls2'
world.get_door('Ice Conveyor SW', player).dungeonLink = 'linkIceFalls2'
def create_paired_doors(world, player):
world.paired_doors[player] = [

View File

@@ -193,11 +193,12 @@ def gen_dungeon_info(name, available_sectors, entrance_regions, all_regions, pro
start = ExplorationState(dungeon=name)
start.big_key_special = bk_special
group_flags, door_map = find_bk_groups(name, available_sectors, proposed_map, bk_special)
bk_flag = False if world.bigkeyshuffle[player] and not bk_special else bk_needed
def exception(d):
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
original_state = extend_reachable_state_improved(entrance_regions, start, proposed_map, all_regions,
valid_doors, bk_needed, world, player, exception)
valid_doors, bk_flag, world, player, exception)
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map, exception)
either_crystal = True # if all hooks from the origin are either, explore all bits with either
for hook, crystal in dungeon['Origin'].hooks.items():
@@ -396,13 +397,14 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a
if len(dungeon.keys()) <= 1 and len(proposed_map.keys()) < len(doors_to_connect):
return False
# origin has no more hooks, but not all doors have been proposed
possible_bks = len(dungeon['Origin'].possible_bk_locations)
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):
return False
if not world.bigkeyshuffle[player]:
possible_bks = len(dungeon['Origin'].possible_bk_locations)
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):
return False
for key in hangers.keys():
if len(hooks[key]) > 0 and len(hangers[key]) == 0:
return False
@@ -428,7 +430,7 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a
if len(outstanding_doors[key]) > 0 and len(hangers[key]) == 0 and len(hooks[opp_key]) == 0:
return False
all_visited = set()
bk_possible = not bk_needed
bk_possible = not bk_needed or (world.bigkeyshuffle[player] and not bk_special)
for piece in dungeon.values():
all_visited.update(piece.visited_regions)
if not bk_possible and len(piece.possible_bk_locations) > 0:
@@ -501,11 +503,12 @@ def valid_path(name, starting_regions, target, valid_doors, proposed_map, all_re
start = ExplorationState(dungeon=name)
start.big_key_special = bk_special
bk_flag = False if world.bigkeyshuffle[player] and not bk_special else bk_needed
def exception(d):
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
original_state = extend_reachable_state_improved(starting_regions, start, proposed_map, all_regions,
valid_doors, bk_needed, world, player, exception)
valid_doors, bk_flag, world, player, exception)
for exp_door in original_state.unattached_doors:
if not exp_door.door.blocked:

View File

@@ -1141,10 +1141,13 @@ def check_rules_deep(original_counter, key_layout, world, player):
big_avail = counter.big_key_opened
big_maybe_not_found = not counter.big_key_opened
if not key_layout.big_key_special and not big_avail:
for location in counter.free_locations:
if location not in key_logic.bk_restricted:
big_avail = True
break
if world.bigkeyshuffle[player]:
big_avail = True
else:
for location in counter.free_locations:
if location not in key_logic.bk_restricted:
big_avail = True
break
outstanding_big_locs = {x for x in big_locations if x not in counter.free_locations}
if big_maybe_not_found:
if len(outstanding_big_locs) == 0:

View File

@@ -24,7 +24,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path, parse_player_names
__version__ = '0.1.0-dev'
__version__ = '0.2.0.0-u'
class EnemizerError(RuntimeError):
pass

View File

@@ -680,13 +680,13 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'GT Hookshot East Platform', 'Ganon\'s Tower', None, ['GT Hookshot EN', 'GT Hookshot East-North Path', 'GT Hookshot East-South Path']),
create_dungeon_region(player, 'GT Hookshot North Platform', 'Ganon\'s Tower', None, ['GT Hookshot NW', 'GT Hookshot North-East Path', 'GT Hookshot North-South Path']),
create_dungeon_region(player, 'GT Hookshot South Platform', 'Ganon\'s Tower', None, ['GT Hookshot ES', 'GT Hookshot South-East Path', 'GT Hookshot South-North Path', 'GT Hookshot Platform Blue Barrier']),
create_dungeon_region(player, 'GT Hookshot South Entry', 'Ganon\'s Tower', None, ['GT Hookshot SW', 'GT Hookshot Entry Blue Barrier', ]),
create_dungeon_region(player, 'GT Hookshot South Entry', 'Ganon\'s Tower', None, ['GT Hookshot SW', 'GT Hookshot Entry Blue Barrier', 'GT Hookshot Entry Boomerang Path']),
create_dungeon_region(player, 'GT Map Room', 'Ganon\'s Tower', ['Ganons Tower - Map Chest'], ['GT Map Room WS']),
create_dungeon_region(player, 'GT Double Switch Entry', 'Ganon\'s Tower', None, ['GT Double Switch NW', 'GT Double Switch Orange Barrier', 'GT Double Switch Orange Barrier 2']),
create_dungeon_region(player, 'GT Double Switch Switches', 'Ganon\'s Tower', None, ['GT Double Switch Blue Path', 'GT Double Switch Orange Path']),
create_dungeon_region(player, 'GT Double Switch Transition', 'Ganon\'s Tower', None, ['GT Double Switch Transition Blue']),
create_dungeon_region(player, 'GT Double Switch Key Spot', 'Ganon\'s Tower', ['Ganons Tower - Double Switch Pot Key'], ['GT Double Switch Key Blue Path', 'GT Double Switch Key Orange Path']),
create_dungeon_region(player, 'GT Double Switch Exit', 'Ganon\'s Tower', None, ['GT Double Switch EN', 'GT Double Switch Blue Barrier', 'GT Hookshot Entry Boomerang Path']),
create_dungeon_region(player, 'GT Double Switch Exit', 'Ganon\'s Tower', None, ['GT Double Switch EN', 'GT Double Switch Blue Barrier']),
create_dungeon_region(player, 'GT Spike Crystals', 'Ganon\'s Tower', None, ['GT Spike Crystals WN', 'GT Spike Crystals Warp']),
create_dungeon_region(player, 'GT Warp Maze - Left Section', 'Ganon\'s Tower', None, ['GT Warp Maze - Left Section Warp']),
create_dungeon_region(player, 'GT Warp Maze - Mid Section', 'Ganon\'s Tower', None, ['GT Warp Maze - Mid Section Left Warp', 'GT Warp Maze - Mid Section Right Warp']),
@@ -736,7 +736,7 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'GT Staredown', 'Ganon\'s Tower', None, ['GT Staredown WS', 'GT Staredown Up Ladder']),
create_dungeon_region(player, 'GT Falling Torches', 'Ganon\'s Tower', None, ['GT Falling Torches Down Ladder', 'GT Falling Torches NE', 'GT Falling Torches Hole']),
create_dungeon_region(player, 'GT Mini Helmasaur Room', 'Ganon\'s Tower', ['Ganons Tower - Mini Helmasaur Room - Left',
'Ganons Tower - Mini Helmasaur Room - Right', 'Ganons Tower - Mini Helmasuar Key Drop'], ['GT Mini Helmasaur Room SE', 'GT Mini Helmasaur Room WN']),
'Ganons Tower - Mini Helmasaur Room - Right', 'Ganons Tower - Mini Helmasaur Key Drop'], ['GT Mini Helmasaur Room SE', 'GT Mini Helmasaur Room WN']),
create_dungeon_region(player, 'GT Bomb Conveyor', 'Ganon\'s Tower', None, ['GT Bomb Conveyor EN', 'GT Bomb Conveyor SW']),
create_dungeon_region(player, 'GT Crystal Circles', 'Ganon\'s Tower', ['Ganons Tower - Pre-Moldorm Chest'], ['GT Crystal Circles NW', 'GT Crystal Circles SW']),
create_dungeon_region(player, 'GT Left Moldorm Ledge', 'Ganon\'s Tower', None, ['GT Left Moldorm Ledge Drop Down', 'GT Left Moldorm Ledge NW']),
@@ -909,7 +909,7 @@ key_only_locations = {
'Ganons Tower - Conveyor Cross Pot Key': 'Small Key (Ganons Tower)',
'Ganons Tower - Double Switch Pot Key': 'Small Key (Ganons Tower)',
'Ganons Tower - Conveyor Star Pits Pot Key': 'Small Key (Ganons Tower)',
'Ganons Tower - Mini Helmasuar Key Drop': 'Small Key (Ganons Tower)'
'Ganons Tower - Mini Helmasaur Key Drop': 'Small Key (Ganons Tower)'
}
dungeon_events = [

4
Rom.py
View File

@@ -22,7 +22,7 @@ from EntranceShuffle import door_addresses, exit_ids
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'b9e578ef0af231041070bd9049a55646'
RANDOMIZERBASEHASH = '98e8426901b441858631ae444c12d4fc'
class JsonRom(object):
@@ -2167,7 +2167,7 @@ def patch_shuffled_dark_sanc(world, rom, player):
# 24B118 and 20BB32
compass_r_addr = 0x123118 # a9 90 24 8f 9a c7 7e
# compass_w_addr = 0x103b32 # e2 20 ad 0c 04 c9 00 d0
compass_w_addr = 0x103b42 # e2 20 ad 0c 04 c9 00 d0
compass_w_addr = 0x103b53 # e2 20 ad 0c 04 c9 00 d0
def compass_code_good(rom):

View File

@@ -108,7 +108,7 @@ nop : stz $0dd0, X : rts
org $20820E
jsl MirrorCheckOverride2
;org $208270
org $208278
org $20827C
jsl MirrorCheckOverride2
org $07a955 ; <- Bank07.asm : around 6564 (JP is a bit different) (STZ $05FC : STZ $05FD)
jsl BlockEraseFix
@@ -134,7 +134,7 @@ jsl SuctionOverworldFix
; also rando's hooks.asm line 1360
; 106e4e -> goes to a0ee4e
;org $a0ee8a ; <- 6FC4C - headsup_display.asm : 836 (LDA $7EF36E : AND.w #$00FF : ADD.w #$0007 : AND.w #$FFF8 : TAX)
org $a0ee9a
org $a0eeab
jsl DrHudOverride
org $0ded04 ; <- rando's hooks.asm line 2192 - 6ED04 - equipment.asm : 1963 (REP #$30)
jsl DrHudDungeonItemsAdditions

View File

@@ -87,22 +87,28 @@ SuctionOverworldFix:
stz $49
+ rtl
CutoffEntranceRug:
pha
lda.l DRMode : beq +
lda $04 : cmp #$000A : bne +
lda $a0 : cmp #$00BC : beq .check ;; TT Alcove
cmp #$00A2 : beq .check ; Mire Bridges
cmp #$001A : beq .check ; pod falling
cmp #$0049 : beq .check ; SW torch room
cmp #$0014 : beq .check ; TR Pipe room
cmp #$00C2 : bne + ; Mire Hub
.check
lda $0c : cmp #$0006 : !bge .skip
lda $0e : cmp #$0008 : !bge .skip
cmp #$0004 : !blt .skip
bra +
.skip pla : rtl
+ pla : lda $9B52, y : sta $7E2000, x ; what we wrote over
rtl
; TT Alcove, Mire bridges, pod falling, SW torch room, TR Pipe room, Bob's Room, Ice Many Pots, Mire Hub
; swamp waterfall
CutoffRooms:
db $bc, $a2, $1a, $49, $14, $8c, $9f, $c2
db $66
CutoffEntranceRug:
pha : phx
lda.l DRMode : beq .norm
lda $04 : cmp #$000A : beq +
cmp #$000C : bne .norm
+ lda $a0 : sep #$20 : ldx #$0000
- cmp.l CutoffRooms, x : beq .check
inx : cpx #$0009 : !blt - ; CutoffRoom Count is here!
rep #$20
.norm plx : pla : lda $9B52, y : sta $7E2000, x ; what we wrote over
rtl
.check
rep #$20
lda $0c : cmp #$0006 : !bge .skip
lda $0e : cmp #$0008 : !bge .skip
cmp #$0004 : !blt .skip
bra .norm
.skip plx : pla : rtl

File diff suppressed because one or more lines are too long