Aga Tower preliminary check in

This commit is contained in:
aerinon
2019-09-20 21:24:46 -06:00
parent 1aa2d904d3
commit 5eb0e6e379
13 changed files with 287 additions and 121 deletions

View File

@@ -752,14 +752,8 @@ class Dungeon(object):
self.bosses = dict() self.bosses = dict()
self.player = player self.player = player
self.world = None self.world = None
self.paths = None
self.path_completion = dict()
self.key_number = len(small_keys)
self.big_key_required = True if self.big_key else False
self.chunks = list()
self.unlinked_doors = set([]) self.entrance_regions = []
self.chests = 0
@property @property
def boss(self): def boss(self):
@@ -861,12 +855,10 @@ class Door(object):
# logical properties # logical properties
# self.connected = False # combine with Dest? # self.connected = False # combine with Dest?
self.dest = None self.dest = None
self.parentChunk = None
self.blocked = False # Indicates if the door is normally blocked off. (Sanc door or always closed) self.blocked = False # Indicates if the door is normally blocked off. (Sanc door or always closed)
self.smallKey = False # There's a small key door on this side self.smallKey = False # There's a small key door on this side
self.bigKey = False # There's a big key door on this side self.bigKey = False # There's a big key door on this side
self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door) self.ugly = False # Indicates that it can't be seen from the front (e.g. back of a big key door)
self.landing = False
def getAddress(self): def getAddress(self):
if self.type == DoorType.Normal: if self.type == DoorType.Normal:
@@ -904,17 +896,15 @@ class Sector(object):
def polarity(self): def polarity(self):
polarity = [0, 0, 0] polarity = [0, 0, 0]
for door in self.outstanding_doors: for door in self.outstanding_doors:
if not door.landing: idx, inc = pol_idx[door.direction]
idx, inc = pol_idx[door.direction] polarity[idx] = pol_inc[inc](polarity[idx])
polarity[idx] = pol_inc[inc](polarity[idx])
return polarity return polarity
def magnitude(self): def magnitude(self):
magnitude = [0, 0, 0] magnitude = [0, 0, 0]
for door in self.outstanding_doors: for door in self.outstanding_doors:
if not door.landing: idx, inc = pol_idx[door.direction]
idx, inc = pol_idx[door.direction] magnitude[idx] = magnitude[idx] + 1
magnitude[idx] = magnitude[idx] + 1
return magnitude return magnitude
def outflow(self): def outflow(self):

View File

@@ -3,7 +3,8 @@ import collections
import logging import logging
from BaseClasses import RegionType, DoorType, Direction, Sector, pol_idx from BaseClasses import RegionType, DoorType, Direction, Sector, pol_idx
from Dungeons import hyrule_castle_regions, eastern_regions, desert_regions, hera_regions from Dungeons import hyrule_castle_regions, eastern_regions, desert_regions, hera_regions, tower_regions
from Dungeons import dungeon_regions
def link_doors(world, player): def link_doors(world, player):
@@ -14,7 +15,7 @@ def link_doors(world, player):
for edge_a, edge_b in interior_doors: for edge_a, edge_b in interior_doors:
connect_two_way(world, edge_a, edge_b, player) connect_two_way(world, edge_a, edge_b, player)
# These connection are here because they are currently unable to be shuffled # These connections are here because they are currently unable to be shuffled
for entrance, ext in straight_staircases: for entrance, ext in straight_staircases:
connect_two_way(world, entrance, ext, player) connect_two_way(world, entrance, ext, player)
for entrance, ext in open_edges: for entrance, ext in open_edges:
@@ -161,11 +162,13 @@ def within_dungeon(world, player):
dungeon_region_starts_ep = ['Eastern Lobby'] 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_dp = ['Desert Back Lobby', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby']
dungeon_region_starts_th = ['Hera Lobby'] dungeon_region_starts_th = ['Hera Lobby']
dungeon_region_starts_at = ['Tower Lobby']
dungeon_region_lists = [ dungeon_region_lists = [
(dungeon_region_starts_es, hyrule_castle_regions), (dungeon_region_starts_es, hyrule_castle_regions),
(dungeon_region_starts_ep, eastern_regions), (dungeon_region_starts_ep, eastern_regions),
(dungeon_region_starts_dp, desert_regions), (dungeon_region_starts_dp, desert_regions),
(dungeon_region_starts_th, hera_regions) (dungeon_region_starts_th, hera_regions),
(dungeon_region_starts_at, tower_regions),
] ]
for start_list, region_list in dungeon_region_lists: for start_list, region_list in dungeon_region_lists:
shuffle_dungeon(world, player, start_list, region_list) shuffle_dungeon(world, player, start_list, region_list)
@@ -199,7 +202,7 @@ def shuffle_dungeon(world, player, start_region_names, dungeon_region_names):
# into the dungeon), or puts them late in the dungeon (so they probably are part # into the dungeon), or puts them late in the dungeon (so they probably are part
# of a loop). Panic if neither of these happens. # of a loop). Panic if neither of these happens.
random.shuffle(available_doors) random.shuffle(available_doors)
available_doors.sort(key=lambda door: 1 if door.blocked else 2 if door.ugly else 0) available_doors.sort(key=lambda door: 1 if door.blocked else 0 if door.ugly else 2)
door = available_doors.pop() door = available_doors.pop()
logger.info('Linking %s', door.name) logger.info('Linking %s', door.name)
# Find an available region that has a compatible door # Find an available region that has a compatible door
@@ -328,28 +331,39 @@ def doors_fit_mandatory_pair(pair_list, a, b):
def cross_dungeon(world, player): def cross_dungeon(world, player):
hc = convert_to_sectors(hyrule_castle_regions, world, player) hc = convert_to_sectors(dungeon_regions['Hyrule Castle'], world, player)
ep = convert_to_sectors(eastern_regions, world, player) ep = convert_to_sectors(dungeon_regions['Eastern'], world, player)
dp = convert_to_sectors(desert_regions, world, player) dp = convert_to_sectors(dungeon_regions['Desert'], world, player)
th = convert_to_sectors(hera_regions, world, player) th = convert_to_sectors(dungeon_regions['Hera'], world, player)
world_split = split_up_sectors(hc + ep + dp + th, default_dungeon_sets) at = convert_to_sectors(dungeon_regions['Tower'], world, player)
dp_split = split_up_sectors(world_split.pop(2), desert_default_entrance_sets) dungeon_split = split_up_sectors(hc + ep + dp + th + at, default_dungeon_sets)
world_split.extend(dp_split) dp_split = split_up_sectors(dungeon_split.pop(2), desert_default_entrance_sets)
dungeon_sectors = []
# todo - adjust dungeon item pools # todo - adjust dungeon item pools
for sector_list in world_split: for idx, sector_list in enumerate(dungeon_split):
shuffle_dungeon_no_repeats(world, player, sector_list) dungeon_sectors.append((sector_list, entrance_sets[idx]))
for idx, sector_list in enumerate(dp_split):
dungeon_sectors.append((sector_list, desert_default_entrance_sets[idx]))
for sector_list, entrance_list in dungeon_sectors:
shuffle_dungeon_no_repeats(world, player, sector_list, entrance_list)
def experiment(world, player): def experiment(world, player):
hc = convert_to_sectors(hyrule_castle_regions, world, player) hc = convert_to_sectors(dungeon_regions['Hyrule Castle'], world, player)
ep = convert_to_sectors(eastern_regions, world, player) ep = convert_to_sectors(dungeon_regions['Eastern'], world, player)
dp = convert_to_sectors(desert_regions, world, player) dp = convert_to_sectors(dungeon_regions['Desert'], world, player)
th = convert_to_sectors(hera_regions, world, player) th = convert_to_sectors(dungeon_regions['Hera'], world, player)
dungeon_sectors = [hc, ep, th] at = convert_to_sectors(dungeon_regions['Tower'], world, player)
dungeon_sectors = []
for idx, sector_list in enumerate([hc, ep, th, at]):
dungeon_sectors.append((sector_list, entrance_sets[idx]))
dp_split = split_up_sectors(dp, desert_default_entrance_sets) dp_split = split_up_sectors(dp, desert_default_entrance_sets)
dungeon_sectors.extend(dp_split) for idx, sector_list in enumerate(dp_split):
for sector_list in dungeon_sectors: dungeon_sectors.append((sector_list, desert_default_entrance_sets[idx]))
shuffle_dungeon_no_repeats(world, player, sector_list)
for sector_list, entrance_list in dungeon_sectors:
shuffle_dungeon_no_repeats(world, player, sector_list, entrance_list)
def convert_regions(region_names, world, player): def convert_regions(region_names, world, player):
@@ -378,7 +392,7 @@ def convert_to_sectors(region_names, world, player):
exits.extend(connect_region.exits) exits.extend(connect_region.exits)
else: else:
door = world.check_for_door(ext.name, player) door = world.check_for_door(ext.name, player)
if door is not None and not door.landing: if door is not None:
outstanding_doors.append(door) outstanding_doors.append(door)
sector = Sector() sector = Sector()
sector.regions.extend(region_chunk) sector.regions.extend(region_chunk)
@@ -515,79 +529,111 @@ def find_proposal(proposal, buckets, candidates):
# code below is for an algorithm without restarts # code below is for an algorithm without restarts
# "simple" thing that would probably reduce the number of restarts: def shuffle_dungeon_no_repeats(world, player, available_sectors, entrance_region_names):
# When you pick a region check for all existing connections to other regions
# first via region.exits (which is a list of non-door exits from the current region)
# then for each Entrance in that list it may have a connected_region (or not)
# but make sure the connected_region is a Dungeon type so the search doesn't venture out into the overworld.
# Then, once you have this region chunk, add all the doors and do the normal loop.
# Nuts, normal loop
def shuffle_dungeon_no_repeats(world, player, available_sectors):
logger = logging.getLogger('') logger = logging.getLogger('')
random.shuffle(available_sectors) random.shuffle(available_sectors)
for sector in available_sectors: for sector in available_sectors:
random.shuffle(sector.outstanding_doors) random.shuffle(sector.outstanding_doors)
while len(available_sectors) > 0: entrance_regions = []
# Pick a random region and make its doors the open set # current_sector = None
sector = available_sectors.pop() for region_name in entrance_region_names:
current_sector = sector entrance_regions.append(world.get_region(region_name, player))
# Loop until all available doors are used reachable_doors, visited_regions = extend_reachable(entrance_regions, [], world, player)
while len(current_sector.outstanding_doors) > 0: # Loop until all available doors are used
# Pick a random available door to connect while len(reachable_doors) > 0:
random.shuffle(current_sector.outstanding_doors) # Pick a random available door to connect
door = current_sector.outstanding_doors.pop() door = random.choice(reachable_doors)
logger.info('Linking %s', door.name) sector = find_sector_for_door(door, available_sectors)
# Find an available region that has a compatible door sector.outstanding_doors.remove(door)
compatibles = find_all_compatible_door_in_sectors_ex(door, available_sectors) # door_connected = False
while len(compatibles) > 0: logger.info('Linking %s', door.name)
connect_sector, connect_door = compatibles.pop() # Find an available region that has a compatible door
logger.info(' Found possible new sector via %s', connect_door.name) compatibles = find_all_compatible_door_in_sectors_ex(door, available_sectors, reachable_doors)
# Check if valid while len(compatibles) > 0:
if is_valid(door, connect_door, current_sector, connect_sector, available_sectors): connect_sector, connect_door = compatibles.pop()
# Apply connection and add the new region's doors to the available list logger.info(' Found possible new sector via %s', connect_door.name)
maybe_connect_two_way(world, door, connect_door, player) # Check if valid
connect_sector.outstanding_doors.remove(connect_door) if is_valid(door, connect_door, sector, connect_sector, available_sectors):
# Apply connection and add the new region's doors to the available list
maybe_connect_two_way(world, door, connect_door, player)
reachable_doors.remove(door)
connect_sector.outstanding_doors.remove(connect_door)
if sector != connect_sector: # combine if not the same
available_sectors.remove(connect_sector) available_sectors.remove(connect_sector)
current_sector.outstanding_doors.extend(connect_sector.outstanding_doors) sector.outstanding_doors.extend(connect_sector.outstanding_doors)
current_sector.regions.extend(connect_sector.regions) sector.regions.extend(connect_sector.regions)
break if not door.blocked:
logger.info(' Not Linking %s to %s', door.name, connect_door.name) connect_region = world.get_entrance(door.dest.name, player).parent_region
if len(compatibles) == 0: # time to try again potential_new_doors, visited_regions = extend_reachable([connect_region], visited_regions, world, player)
current_sector.outstanding_doors.insert(0, door) reachable_doors.extend(potential_new_doors)
if len(current_sector.outstanding_doors) <= 1: break # skips else block below
raise Exception('Rejected last option due to dead end... infinite loop ensues') logger.info(' Not Linking %s to %s', door.name, connect_door.name)
else: if len(compatibles) == 0: # time to try again
# If there's no available region with a door, use an internal connection sector.outstanding_doors.insert(0, door)
# todo: find all possibles for this door first if len(reachable_doors) <= 1:
connect_door = find_compatible_door_in_list_old(world, door, current_sector.outstanding_doors, player) raise Exception('Rejected last option due to dead end... infinite loop ensues')
if connect_door is not None: else:
logger.info(' Adding loop via %s', connect_door.name) # If there's no available region with a door, use an internal connection
# Check if valid # todo: find all possibles for this door first
if is_loop_valid(door, connect_door, current_sector, len(available_sectors) == 0): connect_door = find_compatible_door_in_list_old(world, door, reachable_doors, player)
maybe_connect_two_way(world, door, connect_door, player) if connect_door is not None:
current_sector.outstanding_doors.remove(connect_door) logger.info(' Adding loop via %s', connect_door.name)
else: # Check if valid
logger.info(' Not Linking %s to %s', door.name, connect_door.name) if is_loop_valid(door, connect_door, sector, len(available_sectors) == 1):
current_sector.outstanding_doors.insert(0, door) maybe_connect_two_way(world, door, connect_door, player)
if len(current_sector.outstanding_doors) <= 2: reachable_doors.remove(door)
raise Exception('Rejected last option due to likely improper loops...') reachable_doors.remove(connect_door)
connect_sector = find_sector_for_door(connect_door, available_sectors)
connect_sector.outstanding_doors.remove(connect_door)
if sector != connect_sector: # combine if not the same
available_sectors.remove(connect_sector)
sector.outstanding_doors.extend(connect_sector.outstanding_doors)
sector.regions.extend(connect_sector.regions)
else: else:
raise Exception('Something has gone terribly wrong') logger.info(' Not Linking %s to %s', door.name, connect_door.name)
sector.outstanding_doors.insert(0, door)
if len(reachable_doors) <= 2:
raise Exception('Rejected last option due to likely improper loops...')
else:
raise Exception('Something has gone terribly wrong')
# Check that we used everything, we failed otherwise # Check that we used everything, we failed otherwise
if len(available_sectors) > 0 or len(current_sector.outstanding_doors) > 0: if len(available_sectors) != 1:
logger.warning('Failed to add all regions/doors to dungeon, generation will likely fail.') logger.warning('Failed to add all regions/doors to dungeon, generation will likely fail.')
def find_all_compatible_door_in_sectors_ex(door, sectors): def extend_reachable(search_regions, visited_regions, world, player):
region_list = list(search_regions)
visited_regions = visited_regions
reachable_doors = []
while len(region_list) > 0:
region = region_list.pop()
visited_regions.append(region)
for ext in region.exits:
if ext.connected_region is not None:
connect_region = ext.connected_region
if connect_region not in visited_regions and connect_region not in region_list:
region_list.append(connect_region)
else:
door = world.check_for_door(ext.name, player)
if door is not None and door.dest is None: # make sure it isn't a weird blocked door
reachable_doors.append(door)
return reachable_doors, visited_regions
def find_sector_for_door(door, sectors):
for sector in sectors:
if door in sector.outstanding_doors:
return sector
return None
def find_all_compatible_door_in_sectors_ex(door, sectors, reachable_doors):
result = [] result = []
for sector in sectors: for sector in sectors:
for proposed_door in sector.outstanding_doors: for proposed_door in sector.outstanding_doors:
if doors_compatible_ignore_keys(door, proposed_door): if doors_compatible_ignore_keys(door, proposed_door) and proposed_door not in reachable_doors:
result.append((sector, proposed_door)) result.append((sector, proposed_door))
return result return result
@@ -603,8 +649,8 @@ def doors_compatible_ignore_keys(a, b):
if a.type != b.type: if a.type != b.type:
return False return False
# todo: test spirals linking to each other # todo: test spirals linking to each other
# if a.type == DoorType.SpiralStairs: if a.type == DoorType.SpiralStairs:
# return True return True
return a.direction == switch_dir(b.direction) return a.direction == switch_dir(b.direction)
@@ -612,6 +658,8 @@ def doors_compatible_ignore_keys(a, b):
def is_valid(door_a, door_b, sector_a, sector_b, available_sectors): def is_valid(door_a, door_b, sector_a, sector_b, available_sectors):
if len(available_sectors) == 1: if len(available_sectors) == 1:
return True return True
if len(available_sectors) <= 2 and sector_a != sector_b:
return True
elif not are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, available_sectors): elif not are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, available_sectors):
return False return False
elif door_a.blocked and door_b.blocked: # I can't see this going well unless we are in loop generation... elif door_a.blocked and door_b.blocked: # I can't see this going well unless we are in loop generation...
@@ -647,12 +695,12 @@ def are_there_outstanding_doors_of_type(door_a, door_b, sector_a, sector_b, avai
if only_neutral_left: if only_neutral_left:
hooks_left = False hooks_left = False
for door in sector_a.outstanding_doors: for door in sector_a.outstanding_doors:
if door != door_a and pol_idx[door.direction][0] == idx: if door != door_a and door != door_b and pol_idx[door.direction][0] == idx:
hooks_left = True hooks_left = True
break break
if not hooks_left: if not hooks_left:
for door in sector_b.outstanding_doors: for door in sector_b.outstanding_doors:
if door != door_b and pol_idx[door.direction][0] == idx: if door != door_b and door != door_a and pol_idx[door.direction][0] == idx:
hooks_left = True hooks_left = True
break break
return hooks_left return hooks_left
@@ -683,11 +731,16 @@ spiral_staircases = [
('Hera Startile Wide Up Stairs', 'Hera 4F Down Stairs'), ('Hera Startile Wide Up Stairs', 'Hera 4F Down Stairs'),
('Hera 4F Up Stairs', 'Hera 5F Down Stairs'), ('Hera 4F Up Stairs', 'Hera 5F Down Stairs'),
('Hera 5F Up Stairs', 'Hera Boss Down Stairs'), ('Hera 5F Up Stairs', 'Hera Boss Down Stairs'),
('Tower Room 03 Up Stairs', 'Tower Lone Statue Down Stairs'),
('Tower Dark Chargers Up Stairs', 'Tower Dual Statues Down Stairs'),
('Tower Dark Archers Up Stairs', 'Tower Red Spears Down Stairs'),
('Tower Pacifist Run Up Stairs','Tower Push Statue Down Stairs'),
] ]
straight_staircases = [ straight_staircases = [
('Hyrule Castle Lobby North Stairs', 'Hyrule Castle Throne Room South Stairs'), ('Hyrule Castle Lobby North Stairs', 'Hyrule Castle Throne Room South Stairs'),
('Sewers Rope Room North Stairs', 'Sewers Dark Cross South Stairs') ('Sewers Rope Room North Stairs', 'Sewers Dark Cross South Stairs'),
('Tower Catwalk North Stairs', 'Tower Antechamber South Stairs')
] ]
open_edges = [ open_edges = [
@@ -743,6 +796,17 @@ interior_doors = [
('Hera Tridorm SE', 'Hera Torches NE'), ('Hera Tridorm SE', 'Hera Torches NE'),
('Hera Beetles WS', 'Hera Startile Corner ES'), ('Hera Beetles WS', 'Hera Startile Corner ES'),
('Hera Startile Corner NW', 'Hera Startile Wide SW'), ('Hera Startile Corner NW', 'Hera Startile Wide SW'),
('Tower Lobby NW', 'Tower Gold Knights SW'),
('Tower Gold Knights EN', 'Tower Room 03 WN'),
('Tower Lone Statue WN', 'Tower Dark Maze EN'),
('Tower Dark Maze ES', 'Tower Dark Chargers WS'),
('Tower Dual Statues WS', 'Tower Dark Pits ES'),
('Tower Dark Pits EN', 'Tower Dark Archers WS'),
('Tower Red Spears WN', 'Tower Red Guards EN'),
('Tower Red Guards SW', 'Tower Circle of Pots NW'),
('Tower Circle of Pots WS', 'Tower Pacifist Run ES'),
('Tower Push Statue WS', 'Tower Catwalk ES'),
('Tower Antechamber NW', 'Tower Altar SW'),
] ]
key_doors = [ key_doors = [
@@ -795,7 +859,8 @@ default_door_connections = [
default_one_way_connections = [ default_one_way_connections = [
('Sewers Pull Switch S', 'Sanctuary N'), ('Sewers Pull Switch S', 'Sanctuary N'),
('Eastern Eyegores NE', 'Eastern Boss SE'), ('Eastern Eyegores NE', 'Eastern Boss SE'),
('Desert Wall Slide NW', 'Desert Boss SW') ('Desert Wall Slide NW', 'Desert Boss SW'),
('Tower Altar NW', 'Tower Agahnim 1 SW')
] ]
# todo: these path rules are more complicated I think... # todo: these path rules are more complicated I think...
@@ -827,7 +892,8 @@ default_dungeon_sets = [
'Hyrule Dungeon Cellblock'], 'Hyrule Dungeon Cellblock'],
['Eastern Lobby', 'Eastern Boss'], ['Eastern Lobby', 'Eastern Boss'],
['Desert Back Lobby', 'Desert Boss', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'], ['Desert Back Lobby', 'Desert Boss', 'Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'],
['Hera Lobby', 'Hera Boss'] ['Hera Lobby', 'Hera Boss'],
['Tower Lobby', 'Tower Agahnim 1']
] ]
@@ -835,3 +901,19 @@ desert_default_entrance_sets = [
['Desert Back Lobby'], ['Desert Back Lobby'],
['Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby'] ['Desert Main Lobby', 'Desert West Lobby', 'Desert East Lobby']
] ]
# 'Skull': ['Skull 1 Lobby', 'Skull 2 Mummy Lobby', 'Skull 2 Key Lobby', 'Skull 3 Lobby'],
entrance_sets = [
['Hyrule Castle Lobby', 'Hyrule Castle West Lobby', 'Hyrule Castle East Lobby', 'Sewers Secret Room'],
['Eastern Lobby'],
['Hera Lobby'],
['Tower Lobby'],
# ['PoD Lobby'],
# ['Swamp Lobby'],
# ['TT Lobby'],
# ['Ice Lobby'],
# ['Mire Lobby'],
# ['TR Main Lobby', 'TR Eye Trap', 'TR Big Chest', 'TR Laser Bridge'],
# ['GT Lobby']
]

View File

@@ -213,6 +213,42 @@ def create_doors(world, player):
create_spiral_stairs(player, 'Hera Boss Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x07, 0, HTH, S, 0x61, 0xb0), create_spiral_stairs(player, 'Hera Boss Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x07, 0, HTH, S, 0x61, 0xb0),
create_door(player, 'Hera Boss Outer Hole', DoorType.Hole), create_door(player, 'Hera Boss Outer Hole', DoorType.Hole),
create_door(player, 'Hera Boss Inner Hole', DoorType.Hole), create_door(player, 'Hera Boss Inner Hole', DoorType.Hole),
# Castle Tower
create_dir_door(player, 'Tower Lobby NW', DoorType.Interior, Direction.North, 0xe0, Left, High),
create_dir_door(player, 'Tower Gold Knights SW', DoorType.Interior, Direction.South, 0xe0, Left, High),
create_dir_door(player, 'Tower Gold Knights EN', DoorType.Interior, Direction.East, 0xe0, Top, High),
create_dir_door(player, 'Tower Room 03 WN', DoorType.Interior, Direction.West, 0xe0, Bot, High),
small_key(create_spiral_stairs(player, 'Tower Room 03 Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xe0, 0, HTH, S, 0x1a, 0x6c)),
create_spiral_stairs(player, 'Tower Lone Statue Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xd0, 0, HTH, S, 0x11, 0x80),
create_dir_door(player, 'Tower Lone Statue WN', DoorType.Interior, Direction.West, 0xd0, Top, High),
create_dir_door(player, 'Tower Dark Maze EN', DoorType.Interior, Direction.East, 0xd0, Top, High),
small_key(create_dir_door(player, 'Tower Dark Maze ES', DoorType.Interior, Direction.East, 0xd0, Bot, High)),
small_key(create_dir_door(player, 'Tower Dark Chargers WS', DoorType.Interior, Direction.West, 0xd0, Bot, High)),
create_spiral_stairs(player, 'Tower Dark Chargers Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xd0, 0, HTH, X, 0x1b, 0x8c),
create_spiral_stairs(player, 'Tower Dual Statues Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xc0, 0, HTH, X, 0x12, 0xa0),
create_dir_door(player, 'Tower Dual Statues WS', DoorType.Interior, Direction.West, 0xc0, Bot, High),
create_dir_door(player, 'Tower Dark Pits ES', DoorType.Interior, Direction.East, 0xc0, Bot, High),
create_dir_door(player, 'Tower Dark Pits EN', DoorType.Interior, Direction.East, 0xc0, Top, High),
create_dir_door(player, 'Tower Dark Archers WS', DoorType.Interior, Direction.West, 0xc0, Top, High),
small_key(create_spiral_stairs(player, 'Tower Dark Archers Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xc0, 0, HTH, S, 0x1b, 0x6c)),
create_spiral_stairs(player, 'Tower Red Spears Down Stairs', DoorType.SpiralStairs, Direction.Down, 0xb0, 0, HTH, S, 0x12, 0x80),
create_dir_door(player, 'Tower Red Spears WN', DoorType.Interior, Direction.West, 0xb0, Top, High),
create_dir_door(player, 'Tower Red Guards EN', DoorType.Interior, Direction.East, 0xb0, Top, High),
create_dir_door(player, 'Tower Red Guards SW', DoorType.Interior, Direction.South, 0xb0, Left, High),
create_dir_door(player, 'Tower Circle of Pots NW', DoorType.Interior, Direction.North, 0xb0, Left, High),
small_key(create_dir_door(player, 'Tower Circle of Pots WS', DoorType.Interior, Direction.West, 0xb0, Bot, High)),
small_key(create_dir_door(player, 'Tower Pacifist Run ES', DoorType.Interior, Direction.East, 0xb0, Bot, High)),
create_spiral_stairs(player, 'Tower Pacifist Run Up Stairs', DoorType.SpiralStairs, Direction.Up, 0xb0, 0, LTH, S, 0x33, 0x8c),
create_spiral_stairs(player, 'Tower Push Statue Down Stairs', DoorType.SpiralStairs, Direction.Down, 0x40, 0, HTL, X, 0x12, 0xa0),
create_dir_door(player, 'Tower Push Statue WS', DoorType.Interior, Direction.West, 0x40, Bot, Low),
create_dir_door(player, 'Tower Catwalk ES', DoorType.Interior, Direction.East, 0x40, Bot, Low),
create_dir_door(player, 'Tower Catwalk North Stairs', DoorType.StraightStairs, Direction.North, 0x40, Left, High),
create_dir_door(player, 'Tower Antechamber South Stairs', DoorType.StraightStairs, Direction.South, 0x30, Left, High),
create_dir_door(player, 'Tower Antechamber NW', DoorType.Interior, Direction.North, 0x30, Left, High),
create_dir_door(player, 'Tower Altar SW', DoorType.Interior, Direction.South, 0x30, Left, High),
create_dir_door(player, 'Tower Altar NW', DoorType.Normal, Direction.North, 0x30, Left, High),
trap(blocked(create_dir_door(player, 'Tower Agahnim 1 SW', DoorType.Normal, Direction.South, 0x20, Left, High)), 0x2),
] ]

View File

@@ -30,7 +30,7 @@ def create_dungeons(world, player):
TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player)) TR = make_dungeon('Turtle Rock', 'Trinexx', ['Turtle Rock (Entrance)', 'Turtle Rock (First Section)', 'Turtle Rock (Chain Chomp Room)', 'Turtle Rock (Second Section)', 'Turtle Rock (Big Chest)', 'Turtle Rock (Crystaroller Room)', 'Turtle Rock (Dark Room)', 'Turtle Rock (Eye Bridge)', 'Turtle Rock (Trinexx)'], ItemFactory('Big Key (Turtle Rock)', player), ItemFactory(['Small Key (Turtle Rock)'] * 4, player), ItemFactory(['Map (Turtle Rock)', 'Compass (Turtle Rock)'], player))
if world.mode != 'inverted': if world.mode != 'inverted':
AT = make_dungeon('Agahnims Tower', 'Agahnim', ['Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), []) AT = make_dungeon('Agahnims Tower', 'Agahnim', tower_regions, None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), [])
GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player)) GT = make_dungeon('Ganons Tower', 'Agahnim2', ['Ganons Tower (Entrance)', 'Ganons Tower (Tile Room)', 'Ganons Tower (Compass Room)', 'Ganons Tower (Hookshot Room)', 'Ganons Tower (Map Room)', 'Ganons Tower (Firesnake Room)', 'Ganons Tower (Teleport Room)', 'Ganons Tower (Bottom)', 'Ganons Tower (Top)', 'Ganons Tower (Before Moldorm)', 'Ganons Tower (Moldorm)', 'Agahnim 2'], ItemFactory('Big Key (Ganons Tower)', player), ItemFactory(['Small Key (Ganons Tower)'] * 4, player), ItemFactory(['Map (Ganons Tower)', 'Compass (Ganons Tower)'], player))
else: else:
AT = make_dungeon('Inverted Agahnims Tower', 'Agahnim', ['Inverted Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), []) AT = make_dungeon('Inverted Agahnims Tower', 'Agahnim', ['Inverted Agahnims Tower', 'Agahnim 1'], None, ItemFactory(['Small Key (Agahnims Tower)'] * 2, player), [])
@@ -197,3 +197,26 @@ hera_regions = [
'Hera Startile Corner', 'Hera Startile Wide', 'Hera 4F', 'Hera Big Chest Landing', 'Hera 5F', 'Hera Startile Corner', 'Hera Startile Wide', 'Hera 4F', 'Hera Big Chest Landing', 'Hera 5F',
'Hera Fairies', 'Hera Boss' 'Hera Fairies', 'Hera Boss'
] ]
tower_regions = [
'Tower Lobby', 'Tower Gold Knights', 'Tower Room 03', 'Tower Lone Statue', 'Tower Dark Maze', 'Tower Dark Chargers',
'Tower Dual Statues', 'Tower Dark Pits', 'Tower Dark Archers', 'Tower Red Spears', 'Tower Red Guards',
'Tower Circle of Pots', 'Tower Pacifist Run', 'Tower Push Statue', 'Tower Catwalk', 'Tower Antechamber',
'Tower Altar', 'Tower Agahnim 1'
]
dungeon_regions = {
'Hyrule Castle': hyrule_castle_regions,
'Eastern': eastern_regions,
'Desert': desert_regions,
'Hera': hera_regions,
'Tower': tower_regions,
# 'PoD':
# 'Swamp':
# 'Skull':
# 'TT':
# 'Ice':
# 'Mire':
# 'TR':
# 'GT':
}

View File

@@ -2848,7 +2848,6 @@ mandatory_connections = [('Lake Hylia Central Island Pier', 'Lake Hylia Central
('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'), ('Hyrule Castle Ledge Courtyard Drop', 'Hyrule Castle Courtyard'),
('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'), ('Hyrule Castle Main Gate', 'Hyrule Castle Courtyard'),
('Sewer Drop', 'Sewers Secret Room'), ('Sewer Drop', 'Sewers Secret Room'),
('Agahnim 1', 'Agahnim 1'),
('Flute Spot 1', 'Death Mountain'), ('Flute Spot 1', 'Death Mountain'),
('Death Mountain Entrance Rock', 'Death Mountain Entrance'), ('Death Mountain Entrance Rock', 'Death Mountain Entrance'),
('Death Mountain Entrance Drop', 'Light World'), ('Death Mountain Entrance Drop', 'Light World'),
@@ -3527,7 +3526,7 @@ default_dungeon_connections = [('Desert Palace Entrance (South)', 'Desert Main L
('Hyrule Castle Exit (South)', 'Light World'), ('Hyrule Castle Exit (South)', 'Light World'),
('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (West)', 'Hyrule Castle Ledge'),
('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'), ('Hyrule Castle Exit (East)', 'Hyrule Castle Ledge'),
('Agahnims Tower', 'Agahnims Tower'), ('Agahnims Tower', 'Tower Lobby'),
('Agahnims Tower Exit', 'Hyrule Castle Ledge'), ('Agahnims Tower Exit', 'Hyrule Castle Ledge'),
('Thieves Town', 'Thieves Town (Entrance)'), ('Thieves Town', 'Thieves Town (Entrance)'),

9
Gui.py
View File

@@ -155,6 +155,14 @@ def guiMain(args=None):
logicLabel = Label(logicFrame, text='Game logic') logicLabel = Label(logicFrame, text='Game logic')
logicLabel.pack(side=LEFT) logicLabel.pack(side=LEFT)
swordsFrame = Frame(drowDownFrame)
swordsVar = StringVar()
swordsVar.set('random')
swordsOptionMenu = OptionMenu(swordsFrame, swordsVar, 'random', 'assured', 'swordless', 'vanilla')
swordsOptionMenu.pack(side=RIGHT)
swordsLabel = Label(swordsFrame, text='Swords')
swordsLabel.pack(side=LEFT)
goalFrame = Frame(drowDownFrame) goalFrame = Frame(drowDownFrame)
goalVar = StringVar() goalVar = StringVar()
goalVar.set('ganon') goalVar.set('ganon')
@@ -323,6 +331,7 @@ def guiMain(args=None):
guiargs.count = int(countVar.get()) if countVar.get() != '1' else None guiargs.count = int(countVar.get()) if countVar.get() != '1' else None
guiargs.mode = modeVar.get() guiargs.mode = modeVar.get()
guiargs.logic = logicVar.get() guiargs.logic = logicVar.get()
guiargs.swords = swordsVar.get()
guiargs.goal = goalVar.get() guiargs.goal = goalVar.get()
guiargs.difficulty = difficultyVar.get() guiargs.difficulty = difficultyVar.get()
guiargs.timer = timerVar.get() guiargs.timer = timerVar.get()

11
Main.py
View File

@@ -20,7 +20,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
from ItemList import generate_itempool, difficulties, fill_prizes from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path from Utils import output_path
__version__ = '0.6.3-pre' __version__ = '0.0.1-pre'
def main(args, seed=None): def main(args, seed=None):
start = time.clock() start = time.clock()
@@ -40,7 +40,7 @@ def main(args, seed=None):
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
logger.info('ALttP Entrance Randomizer Version %s - Seed: %s\n\n', __version__, world.seed) logger.info('ALttP Door Randomizer Version %s - Seed: %s\n\n', __version__, world.seed)
world.difficulty_requirements = difficulties[world.difficulty] world.difficulty_requirements = difficulties[world.difficulty]
@@ -83,6 +83,13 @@ def main(args, seed=None):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
set_rules(world, player) set_rules(world, player)
# todo: remove this later. this is for debugging
for player in range(1, world.players + 1):
all_state = world.get_all_state(keys=True)
for bossregion in ['Eastern Boss', 'Desert Boss', 'Hera Boss', 'Tower Agahnim 1']:
if world.get_region(bossregion, player) not in all_state.reachable_regions[player]:
raise Exception(bossregion + ' missing from generation')
logger.info('Placing Dungeon Prizes.') logger.info('Placing Dungeon Prizes.')
fill_prizes(world) fill_prizes(world)

View File

@@ -99,8 +99,7 @@ def create_regions(world, player):
create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']), create_lw_region(player, 'Hyrule Castle Courtyard', None, ['Hyrule Castle Secret Entrance Stairs', 'Hyrule Castle Entrance (South)']),
create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']), create_lw_region(player, 'Hyrule Castle Ledge', None, ['Hyrule Castle Entrance (East)', 'Hyrule Castle Entrance (West)', 'Agahnims Tower', 'Hyrule Castle Ledge Courtyard Drop']),
create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks create_dungeon_region(player, 'Sewer Drop', 'a drop\'s exit', None, ['Sewer Drop']), # This exists only to be referenced for access checks
create_dungeon_region(player, 'Agahnims Tower', 'Castle Tower', ['Castle Tower - Room 03', 'Castle Tower - Dark Maze'], ['Agahnim 1', 'Agahnims Tower Exit']),
create_dungeon_region(player, 'Agahnim 1', 'Castle Tower', ['Agahnim 1'], None),
create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']), create_cave_region(player, 'Old Man Cave', 'a connector', ['Old Man'], ['Old Man Cave Exit (East)', 'Old Man Cave Exit (West)']),
create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']), create_cave_region(player, 'Old Man House', 'a connector', None, ['Old Man House Exit (Bottom)', 'Old Man House Front to Back']),
create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']), create_cave_region(player, 'Old Man House Back', 'a connector', None, ['Old Man House Exit (Top)', 'Old Man House Back to Front']),
@@ -374,6 +373,24 @@ def create_regions(world, player):
create_dungeon_region(player, 'Hera Boss', 'Tower of Hera', ['Tower of Hera - Boss', 'Tower of Hera - Prize'], ['Hera Boss Down Stairs', 'Hera Boss Outer Hole', 'Hera Boss Inner Hole']), create_dungeon_region(player, 'Hera Boss', 'Tower of Hera', ['Tower of Hera - Boss', 'Tower of Hera - Prize'], ['Hera Boss Down Stairs', 'Hera Boss Outer Hole', 'Hera Boss Inner Hole']),
# AgaTower # AgaTower
create_dungeon_region(player, 'Tower Lobby', 'Castle Tower', None, ['Tower Lobby NW', 'Agahnims Tower Exit']),
create_dungeon_region(player, 'Tower Gold Knights', 'Castle Tower', None, ['Tower Gold Knights SW', 'Tower Gold Knights EN']),
create_dungeon_region(player, 'Tower Room 03', 'Castle Tower', ['Castle Tower - Room 03'], ['Tower Room 03 WN', 'Tower Room 03 Up Stairs']),
create_dungeon_region(player, 'Tower Lone Statue', 'Castle Tower', None, ['Tower Lone Statue Down Stairs', 'Tower Lone Statue WN']),
create_dungeon_region(player, 'Tower Dark Maze', 'Castle Tower', ['Castle Tower - Dark Maze'], ['Tower Dark Maze EN', 'Tower Dark Maze ES']),
create_dungeon_region(player, 'Tower Dark Chargers', 'Castle Tower', None, ['Tower Dark Chargers WS', 'Tower Dark Chargers Up Stairs']),
create_dungeon_region(player, 'Tower Dual Statues', 'Castle Tower', None, ['Tower Dual Statues Down Stairs', 'Tower Dual Statues WS']),
create_dungeon_region(player, 'Tower Dark Pits', 'Castle Tower', None, ['Tower Dark Pits ES', 'Tower Dark Pits EN']),
create_dungeon_region(player, 'Tower Dark Archers', 'Castle Tower', ['Castle Tower - Dark Archer Key Drop'], ['Tower Dark Archers WS', 'Tower Dark Archers Up Stairs']),
create_dungeon_region(player, 'Tower Red Spears', 'Castle Tower', None, ['Tower Red Spears Down Stairs', 'Tower Red Spears WN']),
create_dungeon_region(player, 'Tower Red Guards', 'Castle Tower', None, ['Tower Red Guards EN', 'Tower Red Guards SW']),
create_dungeon_region(player, 'Tower Circle of Pots', 'Castle Tower', ['Castle Tower - Circle of Pots Key Drop'], ['Tower Circle of Pots NW', 'Tower Circle of Pots WS']),
create_dungeon_region(player, 'Tower Pacifist Run', 'Castle Tower', None, ['Tower Pacifist Run ES', 'Tower Pacifist Run Up Stairs']),
create_dungeon_region(player, 'Tower Push Statue', 'Castle Tower', None, ['Tower Push Statue Down Stairs', 'Tower Push Statue WS']),
create_dungeon_region(player, 'Tower Catwalk', 'Castle Tower', None, ['Tower Catwalk ES', 'Tower Catwalk North Stairs']),
create_dungeon_region(player, 'Tower Antechamber', 'Castle Tower', None, ['Tower Antechamber South Stairs', 'Tower Antechamber NW']),
create_dungeon_region(player, 'Tower Altar', 'Castle Tower', None, ['Tower Altar SW', 'Tower Altar NW']),
create_dungeon_region(player, 'Tower Agahnim 1', 'Castle Tower', ['Agahnim 1'], ['Tower Agahnim 1 SW']),
# pod # pod
# tt # tt
@@ -383,8 +400,6 @@ def create_regions(world, player):
# tr # tr
# gt # gt
# sw # sw
] ]
for region_name, (room_id, shopkeeper, replaceable) in shop_table.items(): for region_name, (room_id, shopkeeper, replaceable) in shop_table.items():
@@ -504,6 +519,8 @@ key_only_locations = {
'Desert Palace - Desert Tiles 1 Pot Key': 'Small Key (Desert Palace)', 'Desert Palace - Desert Tiles 1 Pot Key': 'Small Key (Desert Palace)',
'Desert Palace - Beamos Hall Pot Key': 'Small Key (Desert Palace)', 'Desert Palace - Beamos Hall Pot Key': 'Small Key (Desert Palace)',
'Desert Palace - Desert Tiles 2 Pot Key': 'Small Key (Desert Palace)', 'Desert Palace - Desert Tiles 2 Pot Key': 'Small Key (Desert Palace)',
'Castle Tower - Dark Archer Key Drop': 'Small Key (Agahnims Tower)',
'Castle Tower - Circle of Pots Key Drop': 'Small Key (Agahnims Tower)',
} }
location_table = {'Mushroom': (0x180013, False, 'in the woods'), location_table = {'Mushroom': (0x180013, False, 'in the woods'),

2
Rom.py
View File

@@ -18,7 +18,7 @@ from EntranceShuffle import door_addresses
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '1cd7e88cb91720b52962a95662679c49' RANDOMIZERBASEHASH = '760a7c62303ab662427661e58ab74a2d'
class JsonRom(object): class JsonRom(object):

View File

@@ -171,7 +171,7 @@ def global_rules(world, player):
set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player)) set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player))
set_rule(world.get_location('Sahasrahla', player), lambda state: state.has('Green Pendant', player)) set_rule(world.get_location('Sahasrahla', player), lambda state: state.has('Green Pendant', player))
set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has_beam_sword(player) or state.has('Beat Agahnim 1', player)) # barrier gets removed after killing agahnim, relevant for entrance shuffle
set_rule(world.get_entrance('Agahnim 1', player), lambda state: state.has_sword(player) and state.has_key('Small Key (Agahnims Tower)', player, 2)) # set_rule(world.get_entrance('Agahnim 1', player), lambda state: state.has_sword(player) and state.has_key('Small Key (Agahnims Tower)', player, 2))
set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1', player)) set_defeat_dungeon_boss_rule(world.get_location('Agahnim 1', player))
set_rule(world.get_location('Castle Tower - Dark Maze', player), lambda state: state.has_key('Small Key (Agahnims Tower)', player)) set_rule(world.get_location('Castle Tower - Dark Maze', player), lambda state: state.has_key('Small Key (Agahnims Tower)', player))
set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has('Beat Agahnim 1', player)) set_rule(world.get_entrance('Top of Pyramid', player), lambda state: state.has('Beat Agahnim 1', player))
@@ -309,6 +309,8 @@ def global_rules(world, player):
set_rule(world.get_location('Eastern Palace - Boss', player), lambda state: world.get_location('Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state)) set_rule(world.get_location('Eastern Palace - Boss', player), lambda state: world.get_location('Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_location('Eastern Palace - Prize', player), lambda state: world.get_location('Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state)) set_rule(world.get_location('Eastern Palace - Prize', player), lambda state: world.get_location('Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state))
set_rule(world.get_entrance('Tower Altar NW', player), lambda state: state.has_sword(player))
# End of door rando rules. # End of door rando rules.
# set_rule(world.get_entrance('Sewers Door', player), lambda state: state.has_key('Small Key (Escape)', player)) # set_rule(world.get_entrance('Sewers Door', player), lambda state: state.has_key('Small Key (Escape)', player))
@@ -950,10 +952,11 @@ def no_glitches_rules(world, player):
add_conditional_lamp('Palace of Darkness Maze Door', 'Palace of Darkness (Entrance)', 'Entrance') add_conditional_lamp('Palace of Darkness Maze Door', 'Palace of Darkness (Entrance)', 'Entrance')
add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)', 'Location') add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)', 'Location')
add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)', 'Location') add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)', 'Location')
if world.mode != 'inverted': # todo: more lamp
add_conditional_lamp('Agahnim 1', 'Agahnims Tower', 'Entrance') # if :
add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower', 'Location') # add_conditional_lamp('Agahnim 1', 'Agahnims Tower', 'Entrance')
else: # add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower', 'Location')
if world.mode == 'inverted':
add_conditional_lamp('Agahnim 1', 'Inverted Agahnims Tower', 'Entrance') add_conditional_lamp('Agahnim 1', 'Inverted Agahnims Tower', 'Entrance')
add_conditional_lamp('Castle Tower - Dark Maze', 'Inverted Agahnims Tower', 'Location') add_conditional_lamp('Castle Tower - Dark Maze', 'Inverted Agahnims Tower', 'Location')
add_conditional_lamp('Old Man', 'Old Man Cave', 'Location') add_conditional_lamp('Old Man', 'Old Man Cave', 'Location')

View File

@@ -15,5 +15,3 @@ dw $3882, $3660, $1e81
org $1fd974 ;(PC: 0fd974) TT Bossway 0xbc org $1fd974 ;(PC: 0fd974) TT Bossway 0xbc
dw $1c82, $0081 dw $1c82, $0081

View File

@@ -7,7 +7,9 @@ RecordStairType: {
SpiralWarp: { SpiralWarp: {
lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon lda $040c : cmp.b #$ff : beq .abort ; abort if not in dungeon
cmp #$06 : bcs .abort ; abort if not supported yet -- todo: this needs to be altered/removed as more dungeons are implemented cmp #$14 : beq .check ; hera is okay
cmp #$0A : bcs .abort ; abort if not supported yet -- todo: this needs to be altered/removed as more dungeons are implemented
.check
lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A! lda $045e : cmp #$5e : beq .gtg ; abort if not spiral - intended room is in A!
cmp #$5f : beq .gtg cmp #$5f : beq .gtg
.abort .abort

File diff suppressed because one or more lines are too long