Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2022-05-10 08:10:27 -05:00
18 changed files with 379 additions and 370 deletions

View File

@@ -147,7 +147,7 @@ class World(object):
set_player_attr('crystals_needed_for_gt', 7) set_player_attr('crystals_needed_for_gt', 7)
set_player_attr('crystals_ganon_orig', {}) set_player_attr('crystals_ganon_orig', {})
set_player_attr('crystals_gt_orig', {}) set_player_attr('crystals_gt_orig', {})
set_player_attr('open_pyramid', False) set_player_attr('open_pyramid', 'auto')
set_player_attr('treasure_hunt_icon', 'Triforce Piece') set_player_attr('treasure_hunt_icon', 'Triforce Piece')
set_player_attr('treasure_hunt_count', 0) set_player_attr('treasure_hunt_count', 0)
set_player_attr('treasure_hunt_total', 0) set_player_attr('treasure_hunt_total', 0)
@@ -317,6 +317,19 @@ class World(object):
def is_bombshop_start(self, player): def is_bombshop_start(self, player):
return self.is_tile_swapped(0x2c, player) and (self.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] or not self.shufflelinks[player]) return self.is_tile_swapped(0x2c, player) and (self.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] or not self.shufflelinks[player])
def is_pyramid_open(self, player):
if self.open_pyramid[player] == 'yes':
return True
elif self.open_pyramid[player] == 'no':
return False
else:
if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
return False
elif self.goal[player] in ['crystals', 'trinity']:
return True
else:
return False
def check_for_door(self, doorname, player): def check_for_door(self, doorname, player):
if isinstance(doorname, Door): if isinstance(doorname, Door):
return doorname return doorname
@@ -1265,7 +1278,7 @@ class CollectionState(object):
# In the future, this can be used to check if the player starts without bombs # In the future, this can be used to check if the player starts without bombs
def can_use_bombs(self, player): def can_use_bombs(self, player):
return (not self.world.bombbag[player] or self.has('Bomb Upgrade (+10)', player)) and ((hasattr(self.world,"override_bomb_check") and self.world.override_bomb_check) or self.can_farm_bombs(player)) return (not self.world.bombbag[player] or self.has('Bomb Upgrade (+10)', player) or self.has('Bomb Upgrade (+5)', player, 2)) and ((hasattr(self.world,"override_bomb_check") and self.world.override_bomb_check) or self.can_farm_bombs(player))
def can_hit_crystal(self, player): def can_hit_crystal(self, player):
return (self.can_use_bombs(player) return (self.can_use_bombs(player)
@@ -2225,7 +2238,6 @@ class Door(object):
class WorldType(IntEnum): class WorldType(IntEnum):
Light = 0 Light = 0
Dark = 1 Dark = 1
Special = 2
@unique @unique
@@ -2241,6 +2253,8 @@ class OWEdge(object):
self.type = DoorType.Open self.type = DoorType.Open
self.direction = direction self.direction = direction
self.terrain = terrain self.terrain = terrain
self.specialEntrance = False
self.specialExit = False
self.deadEnd = False self.deadEnd = False
# rom properties # rom properties
@@ -2254,6 +2268,7 @@ class OWEdge(object):
self.zeroHzCam = False self.zeroHzCam = False
self.zeroVtCam = False self.zeroVtCam = False
self.edge_id = edge_id self.edge_id = edge_id
self.specialID = 0x0
self.midpoint = 0x0 self.midpoint = 0x0
self.linkOpp = 0x0 self.linkOpp = 0x0
@@ -2265,12 +2280,10 @@ class OWEdge(object):
self.unknownX = 0x0 self.unknownX = 0x0
self.unknownY = 0x0 self.unknownY = 0x0
if self.owIndex < 0x40: if self.owIndex < 0x40 or self.owIndex >= 0x80:
self.worldType = WorldType.Light self.worldType = WorldType.Light
elif self.owIndex < 0x80:
self.worldType = WorldType.Dark
else: else:
self.worldType = WorldType.Special self.worldType = WorldType.Dark
# logical properties # logical properties
# self.connected = False # combine with Dest? # self.connected = False # combine with Dest?
@@ -2288,7 +2301,7 @@ class OWEdge(object):
return base_address[self.direction] + (self.edge_id * 16) return base_address[self.direction] + (self.edge_id * 16)
def getTarget(self): def getTarget(self):
return self.dest.edge_id return self.dest.specialID if self.dest.specialExit else self.dest.edge_id
def dead_end(self): def dead_end(self):
self.deadEnd = True self.deadEnd = True
@@ -2298,6 +2311,16 @@ class OWEdge(object):
self.vramLoc = vram_loc self.vramLoc = vram_loc
return self return self
def special_entrance(self, special_id):
self.specialEntrance = True
self.specialID = special_id
return self
def special_exit(self, special_id):
self.specialExit = True
self.specialID = special_id
return self
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, self.__class__) and self.name == other.name return isinstance(other, self.__class__) and self.name == other.name
@@ -3045,7 +3068,7 @@ class Spoiler(object):
if self.metadata['shuffle'][player] != 'vanilla' or self.metadata['ow_mixed'][player]: if self.metadata['shuffle'][player] != 'vanilla' or self.metadata['ow_mixed'][player]:
outfile.write('Overworld Map:'.ljust(line_width) + '%s\n' % self.metadata['overworld_map'][player]) outfile.write('Overworld Map:'.ljust(line_width) + '%s\n' % self.metadata['overworld_map'][player])
if self.metadata['goal'][player] != 'trinity': if self.metadata['goal'][player] != 'trinity':
outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % yn(self.metadata['open_pyramid'][player])) outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player])
outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player]) outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player])
if self.metadata['door_shuffle'][player] != 'vanilla': if self.metadata['door_shuffle'][player] != 'vanilla':
outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player]) outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player])
@@ -3338,7 +3361,7 @@ class Settings(object):
| (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0), | (counter_mode[w.dungeon_counters[p]] << 1) | (1 if w.experimental[p] else 0),
((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3) ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3)
| (0x4 if w.open_pyramid[p] else 0) | access_mode[w.accessibility[p]], | (0x4 if w.is_pyramid_open(p) else 0) | access_mode[w.accessibility[p]],
(0x80 if w.bigkeyshuffle[p] else 0) | (0x40 if w.keyshuffle[p] else 0) (0x80 if w.bigkeyshuffle[p] else 0) | (0x40 if w.keyshuffle[p] else 0)
| (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0) | (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0)

View File

@@ -1,5 +1,10 @@
# Changelog # Changelog
### 0.2.7.2
- Special OW Area are now shuffled in Layout Shuffle (Zora/Hobo/Pedestal)
- Fixed some broken water region graph modelling, fixed some reachability logic
- Some minor code simplifications
### 0.2.7.1 ### 0.2.7.1
- Map checks in Mixed OWR now will show the proper tile images when screens are swapped (ie. Pyramid shows in the LW if that screen is swapped) - Map checks in Mixed OWR now will show the proper tile images when screens are swapped (ie. Pyramid shows in the LW if that screen is swapped)
- Added mystery seed number to spoiler log, so it is easier to match a spoiler log to a rom filename - Added mystery seed number to spoiler log, so it is easier to match a spoiler log to a rom filename

2
CLI.py
View File

@@ -144,7 +144,7 @@ def parse_settings():
"restrict_boss_items": "none", "restrict_boss_items": "none",
# Shuffle Ganon defaults to TRUE # Shuffle Ganon defaults to TRUE
"openpyramid": False, "openpyramid": "auto",
"shuffleganon": True, "shuffleganon": True,
"ow_shuffle": "vanilla", "ow_shuffle": "vanilla",
"ow_crossed": "none", "ow_crossed": "none",

View File

@@ -1668,7 +1668,7 @@ def get_starting_entrances(world, player, force_starting_world=True):
# get entrances from list of regions # get entrances from list of regions
entrances = list() entrances = list()
for region_name in regions: for region_name in regions:
if world.shuffle[player] == 'simple' and region_name in OWTileRegions and OWTileRegions[region_name] in [0x03, 0x05, 0x07]: if world.shuffle[player] == 'simple' and region_name in OWTileRegions.keys() and OWTileRegions[region_name] in [0x03, 0x05, 0x07]:
continue continue
region = world.get_region(region_name, player) region = world.get_region(region_name, player)
if not force_starting_world or region.type == (RegionType.LightWorld if not invFlag else RegionType.DarkWorld): if not force_starting_world or region.type == (RegionType.LightWorld if not invFlag else RegionType.DarkWorld):
@@ -1710,7 +1710,7 @@ def get_distant_entrances(world, start_entrance, player):
# get entrances from remaining regions # get entrances from remaining regions
candidates = list() candidates = list()
for region_name in [r for r in regions if r not in explored_regions]: for region_name in [r for r in regions if r not in explored_regions]:
if OWTileRegions[region_name] in [0x03, 0x05, 0x07]: if region_name in OWTileRegions.keys() and OWTileRegions[region_name] in [0x03, 0x05, 0x07]:
continue continue
region = world.get_region(region_name, player) region = world.get_region(region_name, player)
for exit in region.exits: for exit in region.exits:

View File

@@ -184,7 +184,6 @@ def roll_settings(weights):
if ret.dungeon_counters == 'default': if ret.dungeon_counters == 'default':
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off' ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
ret.shufflelinks = get_choice('shufflelinks') == 'on'
ret.pseudoboots = get_choice('pseudoboots') == 'on' ret.pseudoboots = get_choice('pseudoboots') == 'on'
ret.shopsanity = get_choice('shopsanity') == 'on' ret.shopsanity = get_choice('shopsanity') == 'on'
ret.keydropshuffle = get_choice('keydropshuffle') == 'on' ret.keydropshuffle = get_choice('keydropshuffle') == 'on'
@@ -200,12 +199,13 @@ def roll_settings(weights):
'triforce-hunt': 'triforcehunt', 'triforce-hunt': 'triforcehunt',
'trinity': 'trinity' 'trinity': 'trinity'
}[goal] }[goal]
ret.openpyramid = goal in ['fast_ganon', 'trinity'] if ret.shuffle in ['vanilla', 'dungeonsfull', 'dungeonssimple'] else False
ret.openpyramid = get_choice('open_pyramid') if 'open_pyramid' in weights else 'auto'
ret.shuffleganon = get_choice('shuffleganon') == 'on' ret.shuffleganon = get_choice('shuffleganon') == 'on'
ret.shufflelinks = get_choice('shufflelinks') == 'on'
ret.crystals_gt = get_choice('tower_open') ret.crystals_gt = get_choice('tower_open')
ret.crystals_ganon = get_choice('ganon_open') ret.crystals_ganon = get_choice('ganon_open')
goal_min = get_choice_default('triforce_goal_min', default=20) goal_min = get_choice_default('triforce_goal_min', default=20)

View File

@@ -38,7 +38,7 @@ NP = IsParallel.No
def create_owedges(world, player): def create_owedges(world, player):
edges = [ edges = [
# name, owID,dir,type,edge_id,(owSlot) vram # name, owID,dir,type,edge_id,(owSlot) vram
create_owedge(player, 'Lost Woods NW', 0x00, No, Ld, 0x00) .coordInfo(0x00a0, 0x0284), create_owedge(player, 'Lost Woods NW', 0x00, No, Ld, 0x00) .coordInfo(0x00a0, 0x0284).special_entrance(0x80),
create_owedge(player, 'Lost Woods SW', 0x00, So, Ld, 0x01, 0x08).coordInfo(0x0058, 0x2000), create_owedge(player, 'Lost Woods SW', 0x00, So, Ld, 0x01, 0x08).coordInfo(0x0058, 0x2000),
create_owedge(player, 'Lost Woods SC', 0x00, So, Ld, 0x02, 0x08).coordInfo(0x0178, 0x2020), create_owedge(player, 'Lost Woods SC', 0x00, So, Ld, 0x02, 0x08).coordInfo(0x0178, 0x2020),
create_owedge(player, 'Lost Woods SE', 0x00, So, Ld, 0x03, 0x09).coordInfo(0x0388, 0x2060), create_owedge(player, 'Lost Woods SE', 0x00, So, Ld, 0x03, 0x09).coordInfo(0x0388, 0x2060),
@@ -53,7 +53,7 @@ def create_owedges(world, player):
create_owedge(player, 'Death Mountain TR Pegs WN', 0x07, We, Ld, 0x02) .coordInfo(0x0078, 0x00e0), create_owedge(player, 'Death Mountain TR Pegs WN', 0x07, We, Ld, 0x02) .coordInfo(0x0078, 0x00e0),
create_owedge(player, 'Mountain Entry NW', 0x0a, No, Ld, 0x01) .coordInfo(0x04cc, 0x180a), create_owedge(player, 'Mountain Entry NW', 0x0a, No, Ld, 0x01) .coordInfo(0x04cc, 0x180a),
create_owedge(player, 'Mountain Entry SE', 0x0a, So, Ld, 0x04) .coordInfo(0x0518, 0x1012), create_owedge(player, 'Mountain Entry SE', 0x0a, So, Ld, 0x04) .coordInfo(0x0518, 0x1012),
create_owedge(player, 'Zora Waterfall NE', 0x0f, No, Ld, 0x02) .coordInfo(0x0f80, 0x009a), create_owedge(player, 'Zora Waterfall NE', 0x0f, No, Ld, 0x02) .coordInfo(0x0f80, 0x009a).special_entrance(0x82),
create_owedge(player, 'Zora Waterfall SE', 0x0f, So, Ld, 0x05) .coordInfo(0x0f80, 0x1020), create_owedge(player, 'Zora Waterfall SE', 0x0f, So, Ld, 0x05) .coordInfo(0x0f80, 0x1020),
create_owedge(player, 'Lost Woods Pass NW', 0x10, No, Ld, 0x03) .coordInfo(0x0058, 0x1800), create_owedge(player, 'Lost Woods Pass NW', 0x10, No, Ld, 0x03) .coordInfo(0x0058, 0x1800),
create_owedge(player, 'Lost Woods Pass NE', 0x10, No, Ld, 0x04) .coordInfo(0x0178, 0x181e), create_owedge(player, 'Lost Woods Pass NE', 0x10, No, Ld, 0x04) .coordInfo(0x0178, 0x181e),
@@ -132,7 +132,7 @@ def create_owedges(world, player):
create_owedge(player, 'Links House ES', 0x2c, Ea, Ld, 0x17) .coordInfo(0x0b80, 0x08c0), create_owedge(player, 'Links House ES', 0x2c, Ea, Ld, 0x17) .coordInfo(0x0b80, 0x08c0),
create_owedge(player, 'Stone Bridge NC', 0x2d, No, Ld, 0x14) .coordInfo(0x0af0, 0x180e), create_owedge(player, 'Stone Bridge NC', 0x2d, No, Ld, 0x14) .coordInfo(0x0af0, 0x180e),
create_owedge(player, 'Stone Bridge SC', 0x2d, So, Ld, 0x19) .coordInfo(0x0ae0, 0x100c), create_owedge(player, 'Stone Bridge SC', 0x2d, So, Ld, 0x19) .coordInfo(0x0ae0, 0x100c),
create_owedge(player, 'Stone Bridge WC', 0x2d, We, Wr, 0x17) .coordInfo(0x0b1c, 0x061c), create_owedge(player, 'Stone Bridge WC', 0x2d, We, Wr, 0x17) .coordInfo(0x0b1c, 0x061c).special_entrance(0x81),
create_owedge(player, 'Stone Bridge WS', 0x2d, We, Ld, 0x18) .coordInfo(0x0b80, 0x08e0), create_owedge(player, 'Stone Bridge WS', 0x2d, We, Ld, 0x18) .coordInfo(0x0b80, 0x08e0),
create_owedge(player, 'Stone Bridge EN', 0x2d, Ea, Ld, 0x18) .coordInfo(0x0a90, 0x01c0), create_owedge(player, 'Stone Bridge EN', 0x2d, Ea, Ld, 0x18) .coordInfo(0x0a90, 0x01c0),
create_owedge(player, 'Stone Bridge EC', 0x2d, Ea, Wr, 0x19) .coordInfo(0x0b3c, 0x0640), create_owedge(player, 'Stone Bridge EC', 0x2d, Ea, Wr, 0x19) .coordInfo(0x0b3c, 0x0640),
@@ -317,9 +317,9 @@ def create_owedges(world, player):
create_owedge(player, 'Bomber Corner NE', 0x7f, No, Ld, 0x41) .coordInfo(0x0f50, 0x181c), create_owedge(player, 'Bomber Corner NE', 0x7f, No, Ld, 0x41) .coordInfo(0x0f50, 0x181c),
create_owedge(player, 'Bomber Corner WC', 0x7f, We, Wr, 0x49) .coordInfo(0x0f30, 0x05e0), create_owedge(player, 'Bomber Corner WC', 0x7f, We, Wr, 0x49) .coordInfo(0x0f30, 0x05e0),
create_owedge(player, 'Bomber Corner WS', 0x7f, We, Ld, 0x4a) .coordInfo(0x0f94, 0x0860), create_owedge(player, 'Bomber Corner WS', 0x7f, We, Ld, 0x4a) .coordInfo(0x0f94, 0x0860),
create_owedge(player, 'Master Sword Meadow SC', 0x80, So, Ld, 0x40) .coordInfo(0x0080, 0x0000), create_owedge(player, 'Master Sword Meadow SC', 0x80, So, Ld, 0x40) .coordInfo(0x0080, 0x0000).special_exit(0x80),
create_owedge(player, 'Hobo EC', 0x80, Ea, Wr, 0x4a) .coordInfo(0x008c, 0x0020), create_owedge(player, 'Hobo EC', 0x80, Ea, Wr, 0x4a) .coordInfo(0x008c, 0x0020).special_exit(0x81),
create_owedge(player, 'Zoras Domain SW', 0x81, So, Ld, 0x41, 0x89).coordInfo(0x02a4, 0x1782) create_owedge(player, 'Zoras Domain SW', 0x81, So, Ld, 0x41, 0x89).coordInfo(0x02a4, 0x1782).special_exit(0x82)
] ]
world.owedges += edges world.owedges += edges
@@ -439,16 +439,16 @@ OWEdgeGroups = {
['Octoballoon NE'] ['Octoballoon NE']
] ]
), ),
# (Op, LW, Vt, Ld, NP, 1): ( (Op, LW, Vt, Ld, NP, 1): (
# [ [
# ['Master Sword Meadow SC'], ['Master Sword Meadow SC'],
# ['Zoras Domain SW'] ['Zoras Domain SW']
# ], ],
# [ [
# ['Lost Woods NW'], ['Lost Woods NW'],
# ['Zora Waterfall NE'] ['Zora Waterfall NE']
# ] ]
# ), ),
(Op, LW, Hz, Ld, PL, 2): ( (Op, LW, Hz, Ld, PL, 2): (
[ [
['Kakariko Fortune EN', 'Kakariko Fortune ES'], ['Kakariko Fortune EN', 'Kakariko Fortune ES'],
@@ -505,14 +505,14 @@ OWEdgeGroups = {
['Statues WC'] ['Statues WC']
] ]
), ),
# (Op, LW, Hz, Wr, NP, 1): ( (Op, LW, Hz, Wr, NP, 1): (
# [ [
# ['Hobo EC'] ['Hobo EC']
# ], ],
# [ [
# ['Stone Bridge WC'] ['Stone Bridge WC']
# ] ]
# ), ),
(Op, LW, Vt, Wr, PL, 1): ( (Op, LW, Vt, Wr, PL, 1): (
[ [
['Tree Line SC'], ['Tree Line SC'],
@@ -627,6 +627,10 @@ OWEdgeGroups = {
['Hype Cave WN', 'Hype Cave WS'] ['Hype Cave WN', 'Hype Cave WS']
] ]
), ),
(Op, DW, Vt, Ld, NP, 1): (
[ ],
[ ]
),
(Op, DW, Hz, Ld, NP, 2): ( (Op, DW, Hz, Ld, NP, 2): (
[ [
['Dig Game EC', 'Dig Game ES'] ['Dig Game EC', 'Dig Game ES']
@@ -675,6 +679,10 @@ OWEdgeGroups = {
['Hype Cave WC'] ['Hype Cave WC']
] ]
), ),
(Op, DW, Hz, Wr, NP, 1): (
[ ],
[ ]
),
(Op, DW, Vt, Wr, PL, 1): ( (Op, DW, Vt, Wr, PL, 1): (
[ [
['Dark Tree Line SC'], ['Dark Tree Line SC'],
@@ -1585,7 +1593,8 @@ OWExitTypes = {
'Lake Hylia West Pier', 'Lake Hylia West Pier',
'Lake Hylia Northeast Water Drop', 'Lake Hylia Northeast Water Drop',
'Lake Hylia East Pier', 'Lake Hylia East Pier',
'Lake Hylia Water D Entry', 'Lake Hylia Water D Approach',
'Lake Hylia Water D Leave',
'Desert Pass Ladder (South)', 'Desert Pass Ladder (South)',
'Desert Pass Rocks (North)', 'Desert Pass Rocks (North)',
'Desert Pass Rocks (South)', 'Desert Pass Rocks (South)',
@@ -1854,6 +1863,7 @@ OWExitTypes = {
'South Shore East Mirror Spot', 'South Shore East Mirror Spot',
'Lake Hylia Island Mirror Spot', 'Lake Hylia Island Mirror Spot',
'Lake Hylia Water Mirror Spot', 'Lake Hylia Water Mirror Spot',
'Lake Hylia Water D Mirror Spot',
'Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island Mirror Spot',
'Ice Cave Mirror Spot', 'Ice Cave Mirror Spot',
'Desert Pass Ledge Mirror Spot', 'Desert Pass Ledge Mirror Spot',

View File

@@ -5,7 +5,7 @@ from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSl
from Regions import mark_dark_world_regions, mark_light_world_regions from Regions import mark_dark_world_regions, mark_light_world_regions
from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel
version_number = '0.2.7.1' version_number = '0.2.7.2'
version_branch = '' version_branch = ''
__version__ = '%s%s' % (version_number, version_branch) __version__ = '%s%s' % (version_number, version_branch)
@@ -13,8 +13,6 @@ def link_overworld(world, player):
# setup mandatory connections # setup mandatory connections
for exitname, regionname in mandatory_connections: for exitname, regionname in mandatory_connections:
connect_simple(world, exitname, regionname, player) connect_simple(world, exitname, regionname, player)
for exitname, destname in temporary_mandatory_connections:
connect_two_way(world, exitname, destname, player)
def performSwap(groups, swaps): def performSwap(groups, swaps):
def getParallel(edgename): def getParallel(edgename):
@@ -290,7 +288,7 @@ def link_overworld(world, player):
trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player) trimmed_groups = remove_reserved(world, trimmed_groups, connected_edges, player)
groups = reorganize_groups(world, trimmed_groups, player) groups = reorganize_groups(world, trimmed_groups, player)
tries = 10 tries = 20
valid_layout = False valid_layout = False
connected_edge_cache = connected_edges.copy() connected_edge_cache = connected_edges.copy()
while not valid_layout and tries > 0: while not valid_layout and tries > 0:
@@ -541,18 +539,13 @@ def shuffle_tiles(world, groups, result_list, player):
exist_dw_regions.extend(new_results[2]) exist_dw_regions.extend(new_results[2])
# replace LW edges with DW # replace LW edges with DW
ignore_list = list() #TODO: Remove ignore_list when special OW areas are included in pool
for edgeset in temporary_mandatory_connections:
for edge in edgeset:
ignore_list.append(edge)
if world.owCrossed[player] != 'polar': if world.owCrossed[player] != 'polar':
# in polar, the actual edge connections remain vanilla # in polar, the actual edge connections remain vanilla
def getSwappedEdges(world, lst, player): def getSwappedEdges(world, lst, player):
for regionname in lst: for regionname in lst:
region = world.get_region(regionname, player) region = world.get_region(regionname, player)
for exit in region.exits: for exit in region.exits:
if exit.spot_type == 'OWEdge' and exit.name not in ignore_list: if exit.spot_type == 'OWEdge':
swapped_edges.append(exit.name) swapped_edges.append(exit.name)
getSwappedEdges(world, result_list[1], player) getSwappedEdges(world, result_list[1], player)
@@ -561,7 +554,17 @@ def shuffle_tiles(world, groups, result_list, player):
return swapped_edges return swapped_edges
def reorganize_tile_groups(world, player): def reorganize_tile_groups(world, player):
def can_shuffle_group(name, groupType): def get_group_key(group):
#(name, groupType, whirlpoolGroup) = group
new_group = list(group)
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']:
new_group[1] = None
if not world.owWhirlpoolShuffle[player] and world.owCrossed[player] == 'none':
new_group[2] = None
return tuple(new_group)
def can_shuffle_group(group):
(name, groupType, whirlpoolGroup) = group
return name not in ['Castle', 'Links', 'Central Bonk Rocks'] \ return name not in ['Castle', 'Links', 'Central Bonk Rocks'] \
or (world.mode[player] != 'standard' and (name != 'Castle' \ or (world.mode[player] != 'standard' and (name != 'Castle' \
or world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] \ or world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] \
@@ -570,60 +573,22 @@ def reorganize_tile_groups(world, player):
or (world.mode[player] == 'standard' and world.shuffle[player] in ['lean', 'crossed', 'insanity'] and name == 'Castle' and groupType == 'Entrance') or (world.mode[player] == 'standard' and world.shuffle[player] in ['lean', 'crossed', 'insanity'] and name == 'Castle' and groupType == 'Entrance')
groups = {} groups = {}
for (name, groupType, whirlpoolGroup) in OWTileGroups.keys(): for group in OWTileGroups.keys():
if can_shuffle_group(name, groupType): if can_shuffle_group(group):
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']: groups[get_group_key(group)] = ([], [], [])
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
groups[(name, whirlpoolGroup)] = ([], [], [])
else:
groups[(name,)] = ([], [], [])
else:
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
groups[(name, groupType, whirlpoolGroup)] = ([], [], [])
else:
groups[(name, groupType)] = ([], [], [])
for (name, groupType, whirlpoolGroup) in OWTileGroups.keys(): for group in OWTileGroups.keys():
if can_shuffle_group(name, groupType): if can_shuffle_group(group):
(lw_owids, dw_owids) = OWTileGroups[(name, groupType, whirlpoolGroup)] (lw_owids, dw_owids) = OWTileGroups[group]
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']: (exist_owids, exist_lw_regions, exist_dw_regions) = groups[get_group_key(group)]
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name, whirlpoolGroup)]
exist_owids.extend(lw_owids) exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids) exist_owids.extend(dw_owids)
for owid in lw_owids: for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid]) exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids: for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid]) exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name, whirlpoolGroup)] = (exist_owids, exist_lw_regions, exist_dw_regions) groups[get_group_key(group)] = (exist_owids, exist_lw_regions, exist_dw_regions)
else:
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name,)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name,)] = (exist_owids, exist_lw_regions, exist_dw_regions)
else:
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name, groupType, whirlpoolGroup)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name, groupType, whirlpoolGroup)] = (exist_owids, exist_lw_regions, exist_dw_regions)
else:
(exist_owids, exist_lw_regions, exist_dw_regions) = groups[(name, groupType)]
exist_owids.extend(lw_owids)
exist_owids.extend(dw_owids)
for owid in lw_owids:
exist_lw_regions.extend(OWTileRegions.inverse[owid])
for owid in dw_owids:
exist_dw_regions.extend(OWTileRegions.inverse[owid])
groups[(name, groupType)] = (exist_owids, exist_lw_regions, exist_dw_regions)
return groups return groups
def remove_reserved(world, groupedlist, connected_edges, player): def remove_reserved(world, groupedlist, connected_edges, player):
@@ -661,158 +626,37 @@ def remove_reserved(world, groupedlist, connected_edges, player):
return new_grouping return new_grouping
def reorganize_groups(world, groups, player): def reorganize_groups(world, groups, player):
def get_group_key(group):
#(std, region, axis, terrain, parallel, count) = group
new_group = list(group)
if world.mode[player] != "standard":
new_group[0] = None
if world.owShuffle[player] != 'parallel':
new_group[4] = None
if not world.owKeepSimilar[player]:
new_group[5] = None
return tuple(new_group)
# predefined shuffle groups get reorganized here # predefined shuffle groups get reorganized here
# this restructures the candidate pool based on the chosen settings # this restructures the candidate pool based on the chosen settings
if world.owShuffle[player] == 'full':
if world.owKeepSimilar[player]:
if world.mode[player] == 'standard':
# tuple goes to (A,B,C,D,_,F)
for grouping in (groups,): for grouping in (groups,):
new_grouping = {} new_grouping = {}
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, _, count) = group new_grouping[get_group_key(group)] = ([], [])
new_grouping[(std, region, axis, terrain, count)] = ([], [])
for group in grouping.keys(): for group in grouping.keys():
(std, region, axis, terrain, _, count) = group new_group = get_group_key(group)
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,B,C,D,_,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, _, count) = group
new_grouping[(region, axis, terrain, count)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, _, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
if world.mode[player] == 'standard':
# tuple goes to (A,B,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, region, axis, terrain, _, _) = group
new_grouping[(std, region, axis, terrain)] = ([], [])
for group in grouping.keys():
(std, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group] (forward_edges, back_edges) = grouping[group]
if not world.owKeepSimilar[player]:
forward_edges = [[i] for l in forward_edges for i in l] forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l] back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[new_group]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain)]
exist_forward_edges.extend(forward_edges) exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges) exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain)] = (exist_forward_edges, exist_back_edges) new_grouping[new_group] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values()) return list(new_grouping.values())
else:
# tuple goes to (_,B,C,D,_,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, _, _) = group
new_grouping[(region, axis, terrain)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, _, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
elif world.owShuffle[player] == 'parallel':
if world.owKeepSimilar[player]:
if world.mode[player] == 'standard':
# tuple stays (A,B,C,D,E,F)
for grouping in (groups,):
return list(grouping.values())
else:
# tuple goes to (_,B,C,D,E,F)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, parallel, count) = group
new_grouping[(region, axis, terrain, parallel, count)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, parallel, count) = group
(forward_edges, back_edges) = grouping[group]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, parallel, count)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, parallel, count)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
if world.mode[player] == 'standard':
# tuple goes to (A,B,C,D,E,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(std, region, axis, terrain, parallel, _) = group
new_grouping[(std, region, axis, terrain, parallel)] = ([], [])
for group in grouping.keys():
(std, region, axis, terrain, parallel, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(std, region, axis, terrain, parallel)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(std, region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
# tuple goes to (_,B,C,D,E,_)
for grouping in (groups,):
new_grouping = {}
for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = group
new_grouping[(region, axis, terrain, parallel)] = ([], [])
for group in grouping.keys():
(_, region, axis, terrain, parallel, _) = group
(forward_edges, back_edges) = grouping[group]
forward_edges = [[i] for l in forward_edges for i in l]
back_edges = [[i] for l in back_edges for i in l]
(exist_forward_edges, exist_back_edges) = new_grouping[(region, axis, terrain, parallel)]
exist_forward_edges.extend(forward_edges)
exist_back_edges.extend(back_edges)
new_grouping[(region, axis, terrain, parallel)] = (exist_forward_edges, exist_back_edges)
return list(new_grouping.values())
else:
raise NotImplementedError('Shuffling not supported yet')
def create_flute_exits(world, player): def create_flute_exits(world, player):
for region in (r for r in world.regions if r.player == player and r.terrain == Terrain.Land and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']): for region in (r for r in world.regions if r.player == player and r.terrain == Terrain.Land and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):
@@ -1095,9 +939,7 @@ def validate_layout(world, player):
while unreachable_count != len(unreachable_regions): while unreachable_count != len(unreachable_regions):
# find unreachable regions # find unreachable regions
unreachable_regions = {} unreachable_regions = {}
flat_sectors = [[r for l in s for r in l] for s in world.owsectors[player]] for region_name in list(OWTileRegions.copy().keys()):
for sector in flat_sectors:
for region_name in sector:
if region_name not in explored_regions and region_name not in isolated_regions: if region_name not in explored_regions and region_name not in isolated_regions:
region = base_world.get_region(region_name, player) region = base_world.get_region(region_name, player)
unreachable_regions[region_name] = region unreachable_regions[region_name] = region
@@ -1142,13 +984,6 @@ test_connections = [
#('Links House NE', 'Lost Woods Pass SW') #('Links House NE', 'Lost Woods Pass SW')
] ]
temporary_mandatory_connections = [
# Special OW Areas
('Lost Woods NW', 'Master Sword Meadow SC'),
('Zora Waterfall NE', 'Zoras Domain SW'),
('Stone Bridge WC', 'Hobo EC'),
]
# these are connections that cannot be shuffled and always exist. They link together separate parts of the world we need to divide into regions # these are connections that cannot be shuffled and always exist. They link together separate parts of the world we need to divide into regions
mandatory_connections = [# Intra-tile OW Connections mandatory_connections = [# Intra-tile OW Connections
('Lost Woods Bush (West)', 'Lost Woods East Area'), #pearl ('Lost Woods Bush (West)', 'Lost Woods East Area'), #pearl
@@ -1245,7 +1080,8 @@ mandatory_connections = [# Intra-tile OW Connections
('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'), ('Lake Hylia Central Island Pier', 'Lake Hylia Central Island'),
('Lake Hylia West Pier', 'Lake Hylia Area'), ('Lake Hylia West Pier', 'Lake Hylia Area'),
('Lake Hylia East Pier', 'Lake Hylia Northeast Bank'), ('Lake Hylia East Pier', 'Lake Hylia Northeast Bank'),
('Lake Hylia Water D Entry', 'Lake Hylia Water'), #flippers ('Lake Hylia Water D Approach', 'Lake Hylia Water D'),
('Lake Hylia Water D Leave', 'Lake Hylia Water'), #flippers
('Desert Pass Ledge Drop', 'Desert Pass Area'), ('Desert Pass Ledge Drop', 'Desert Pass Area'),
('Desert Pass Rocks (North)', 'Desert Pass Southeast'), #glove ('Desert Pass Rocks (North)', 'Desert Pass Southeast'), #glove
('Desert Pass Rocks (South)', 'Desert Pass Area'), #glove ('Desert Pass Rocks (South)', 'Desert Pass Area'), #glove
@@ -1704,6 +1540,7 @@ ow_connections = {
('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'), ('Lake Hylia Island Mirror Spot', 'Lake Hylia Island'),
('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'), ('Lake Hylia Central Island Mirror Spot', 'Lake Hylia Central Island'),
('Lake Hylia Water Mirror Spot', 'Lake Hylia Water'), ('Lake Hylia Water Mirror Spot', 'Lake Hylia Water'),
('Lake Hylia Water D Mirror Spot', 'Lake Hylia Water D'),
('Lake Hylia Teleporter', 'Ice Palace Area') ('Lake Hylia Teleporter', 'Ice Palace Area')
], [ ], [
('Lake Hylia Island Pier', 'Lake Hylia Island'), ('Lake Hylia Island Pier', 'Lake Hylia Island'),
@@ -1752,14 +1589,14 @@ parallelsimilar_connections = [('Maze Race ES', 'Kakariko Suburb WS'),
] ]
# non shuffled overworld # non shuffled overworld
default_connections = [#('Lost Woods NW', 'Master Sword Meadow SC'), default_connections = [('Lost Woods NW', 'Master Sword Meadow SC'),
('Lost Woods SW', 'Lost Woods Pass NW'), ('Lost Woods SW', 'Lost Woods Pass NW'),
('Lost Woods SC', 'Lost Woods Pass NE'), ('Lost Woods SC', 'Lost Woods Pass NE'),
('Lost Woods SE', 'Kakariko Fortune NE'), ('Lost Woods SE', 'Kakariko Fortune NE'),
('Lost Woods EN', 'Lumberjack WN'), ('Lost Woods EN', 'Lumberjack WN'),
('Lumberjack SW', 'Mountain Entry NW'), ('Lumberjack SW', 'Mountain Entry NW'),
('Mountain Entry SE', 'Kakariko Pond NE'), ('Mountain Entry SE', 'Kakariko Pond NE'),
#('Zora Waterfall NE', 'Zoras Domain SW'), ('Zora Waterfall NE', 'Zoras Domain SW'),
('Lost Woods Pass SW', 'Kakariko NW'), ('Lost Woods Pass SW', 'Kakariko NW'),
('Lost Woods Pass SE', 'Kakariko NC'), ('Lost Woods Pass SE', 'Kakariko NC'),
('Kakariko Fortune SC', 'Kakariko NE'), ('Kakariko Fortune SC', 'Kakariko NE'),
@@ -1808,7 +1645,7 @@ default_connections = [#('Lost Woods NW', 'Master Sword Meadow SC'),
('Stone Bridge SC', 'Lake Hylia NW'), ('Stone Bridge SC', 'Lake Hylia NW'),
('Stone Bridge EN', 'Tree Line WN'), ('Stone Bridge EN', 'Tree Line WN'),
('Stone Bridge EC', 'Tree Line WC'), ('Stone Bridge EC', 'Tree Line WC'),
#('Stone Bridge WC', 'Hobo EC'), ('Stone Bridge WC', 'Hobo EC'),
('Tree Line SC', 'Lake Hylia NC'), ('Tree Line SC', 'Lake Hylia NC'),
('Tree Line SE', 'Lake Hylia NE'), ('Tree Line SE', 'Lake Hylia NE'),
('Desert EC', 'Desert Pass WC'), ('Desert EC', 'Desert Pass WC'),

View File

@@ -111,8 +111,8 @@ def create_regions(world, player):
create_lw_region(player, 'Lake Hylia Northeast Bank', None, ['Lake Hylia Northeast Water Drop', 'Ice Lake Northeast Mirror Spot', 'Lake Hylia NE']), create_lw_region(player, 'Lake Hylia Northeast Bank', None, ['Lake Hylia Northeast Water Drop', 'Ice Lake Northeast Mirror Spot', 'Lake Hylia NE']),
create_lw_region(player, 'Lake Hylia Central Island', None, ['Lake Hylia Central Water Drop', 'Capacity Upgrade', 'Ice Palace Mirror Spot', 'Lake Hylia Teleporter']), create_lw_region(player, 'Lake Hylia Central Island', None, ['Lake Hylia Central Water Drop', 'Capacity Upgrade', 'Ice Palace Mirror Spot', 'Lake Hylia Teleporter']),
create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island'], ['Lake Hylia Island Water Drop']), create_lw_region(player, 'Lake Hylia Island', ['Lake Hylia Island'], ['Lake Hylia Island Water Drop']),
create_lw_region(player, 'Lake Hylia Water', None, ['Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia West Pier', 'Lake Hylia East Pier', 'Lake Hylia NC', 'Lake Hylia EC', 'Lake Hylia Whirlpool'], 'Light World', Terrain.Water), create_lw_region(player, 'Lake Hylia Water', None, ['Lake Hylia Central Island Pier', 'Lake Hylia Island Pier', 'Lake Hylia West Pier', 'Lake Hylia East Pier', 'Lake Hylia Water D Approach', 'Lake Hylia NC', 'Lake Hylia EC', 'Lake Hylia Whirlpool'], 'Light World', Terrain.Water),
create_lw_region(player, 'Lake Hylia Water D', None, ['Lake Hylia Water D Entry', 'Ice Lake Moat Mirror Spot'], 'Light World', Terrain.Water), create_lw_region(player, 'Lake Hylia Water D', None, ['Lake Hylia Water D Leave', 'Ice Lake Moat Mirror Spot'], 'Light World', Terrain.Water),
create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Shopping Mall Mirror Spot', 'Ice Cave SE', 'Ice Cave SW']), create_lw_region(player, 'Ice Cave Area', None, ['Ice Rod Cave', 'Good Bee Cave', '20 Rupee Cave', 'Shopping Mall Mirror Spot', 'Ice Cave SE', 'Ice Cave SW']),
create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Pass Ladder (South)', 'Middle Aged Man', 'Desert Fairy', '50 Rupee Cave', 'Swamp Nook Mirror Spot', 'Desert Pass WS', 'Desert Pass EC', 'Desert Pass Rocks (North)']), create_lw_region(player, 'Desert Pass Area', ['Middle Aged Man'], ['Desert Pass Ladder (South)', 'Middle Aged Man', 'Desert Fairy', '50 Rupee Cave', 'Swamp Nook Mirror Spot', 'Desert Pass WS', 'Desert Pass EC', 'Desert Pass Rocks (North)']),
create_lw_region(player, 'Middle Aged Man', ['Purple Chest'], None), create_lw_region(player, 'Middle Aged Man', ['Purple Chest'], None),
@@ -213,7 +213,7 @@ def create_regions(world, player):
create_dw_region(player, 'Ice Lake Ledge (West)', None, ['Ice Lake Southwest Water Drop', 'South Shore Mirror Spot', 'Ice Lake WS']), create_dw_region(player, 'Ice Lake Ledge (West)', None, ['Ice Lake Southwest Water Drop', 'South Shore Mirror Spot', 'Ice Lake WS']),
create_dw_region(player, 'Ice Lake Ledge (East)', None, ['Ice Lake Southeast Water Drop', 'South Shore East Mirror Spot', 'Ice Lake ES']), create_dw_region(player, 'Ice Lake Ledge (East)', None, ['Ice Lake Southeast Water Drop', 'South Shore East Mirror Spot', 'Ice Lake ES']),
create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Ice Lake Moat Bomb Jump', 'Lake Hylia Island Mirror Spot', 'Ice Lake NC', 'Ice Lake EC'], 'Dark World', Terrain.Water), create_dw_region(player, 'Ice Lake Water', None, ['Ice Lake Northeast Pier', 'Ice Lake Moat Bomb Jump', 'Lake Hylia Island Mirror Spot', 'Ice Lake NC', 'Ice Lake EC'], 'Dark World', Terrain.Water),
create_dw_region(player, 'Ice Lake Moat', None, ['Ice Lake Moat Water Entry', 'Ice Lake Northeast Pier Hop', 'Lake Hylia Water Mirror Spot']), create_dw_region(player, 'Ice Lake Moat', None, ['Ice Lake Moat Water Entry', 'Ice Lake Northeast Pier Hop', 'Lake Hylia Water Mirror Spot', 'Lake Hylia Water D Mirror Spot']),
create_dw_region(player, 'Ice Palace Area', None, ['Ice Palace', 'Ice Palace Teleporter', 'Lake Hylia Central Island Mirror Spot']), create_dw_region(player, 'Ice Palace Area', None, ['Ice Palace', 'Ice Palace Teleporter', 'Lake Hylia Central Island Mirror Spot']),
create_dw_region(player, 'Shopping Mall Area', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Ice Cave Mirror Spot', 'Shopping Mall SW', 'Shopping Mall SE']), create_dw_region(player, 'Shopping Mall Area', None, ['Dark Lake Hylia Ledge Fairy', 'Dark Lake Hylia Ledge Hint', 'Dark Lake Hylia Ledge Spike Cave', 'Ice Cave Mirror Spot', 'Shopping Mall SW', 'Shopping Mall SE']),
create_dw_region(player, 'Swamp Nook Area', None, ['Desert Pass Ledge Mirror Spot', 'Desert Pass Mirror Spot', 'Swamp Nook EC', 'Swamp Nook ES']), create_dw_region(player, 'Swamp Nook Area', None, ['Desert Pass Ledge Mirror Spot', 'Desert Pass Mirror Spot', 'Swamp Nook EC', 'Swamp Nook ES']),

11
Rom.py
View File

@@ -33,7 +33,7 @@ from source.classes.SFX import randomize_sfx
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '4a1dfc4fa793b8659a95d579f6a5a925' RANDOMIZERBASEHASH = '538bf256ff03bb7576991114395eeccc'
class JsonRom(object): class JsonRom(object):
@@ -698,9 +698,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
inverted_buffer[b] ^= 0x1 inverted_buffer[b] ^= 0x1
# set world flag # set world flag
world_flag = 0x00 if b >= 0x40 else 0x40 world_flag = 0x00 if b >= 0x40 and b < 0x80 else 0x40
rom.write_byte(0x153A00 + b, world_flag) rom.write_byte(0x153A00 + b, world_flag)
if b % 0x40 in megatiles: if b & 0xBF in megatiles:
rom.write_byte(0x153A00 + b + 1, world_flag) rom.write_byte(0x153A00 + b + 1, world_flag)
rom.write_byte(0x153A00 + b + 8, world_flag) rom.write_byte(0x153A00 + b + 8, world_flag)
rom.write_byte(0x153A00 + b + 9, world_flag) rom.write_byte(0x153A00 + b + 9, world_flag)
@@ -708,7 +708,8 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
for edge in world.owedges: for edge in world.owedges:
if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player: if edge.dest is not None and isinstance(edge.dest, OWEdge) and edge.player == player:
write_int16(rom, edge.getAddress() + 0x0a, edge.vramLoc) write_int16(rom, edge.getAddress() + 0x0a, edge.vramLoc)
write_int16(rom, edge.getAddress() + 0x0e, edge.getTarget()) if not edge.specialExit:
rom.write_byte(0x1539e0 + (edge.specialID - 0x80) * 2 if edge.specialEntrance else edge.getAddress() + 0x0e, edge.getTarget())
write_int16(rom, 0x150002, owMode) write_int16(rom, 0x150002, owMode)
write_int16(rom, 0x150004, owFlags) write_int16(rom, 0x150004, owFlags)
@@ -1287,7 +1288,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest rom.write_bytes(0x50563, [0x3F, 0x14]) # disable below ganon chest
rom.write_byte(0x50599, 0x00) # disable below ganon chest rom.write_byte(0x50599, 0x00) # disable below ganon chest
rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest rom.write_bytes(0xE9A5, [0x7E, 0x00, 0x24]) # disable below ganon chest
rom.write_byte(0x18008B, 0x01 if world.open_pyramid[player] or world.goal[player] == 'trinity' else 0x00) # pre-open Pyramid Hole rom.write_byte(0x18008B, 0x01 if world.is_pyramid_open(player) else 0x00) # pre-open Pyramid Hole
rom.write_byte(0x18008C, 0x01 if world.crystals_needed_for_gt[player] == 0 else 0x00) # GT pre-opened if crystal requirement is 0 rom.write_byte(0x18008C, 0x01 if world.crystals_needed_for_gt[player] == 0 else 0x00) # GT pre-opened if crystal requirement is 0
rom.write_byte(0x18008F, 0x01 if world.is_atgt_swapped(player) else 0x00) # AT/GT swapped rom.write_byte(0x18008F, 0x01 if world.is_atgt_swapped(player) else 0x00) # AT/GT swapped
rom.write_byte(0xF5D73, 0xF0) # bees are catchable rom.write_byte(0xF5D73, 0xF0) # bees are catchable

View File

@@ -844,7 +844,7 @@ def default_rules(world, player):
set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia Central Water Drop', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia Island Water Drop', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Lake Hylia Water D Entry', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia Water D Leave', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Ice Cave SW', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Ice Cave SW', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Octoballoon Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Octoballoon Water Drop', player), lambda state: state.has('Flippers', player))
set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player)) set_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), lambda state: state.has('Flippers', player))
@@ -1046,7 +1046,7 @@ def ow_rules(world, 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))
set_rule(world.get_entrance('Top of Pyramid (Inner)', player), lambda state: state.has('Beat Agahnim 1', player)) set_rule(world.get_entrance('Top of Pyramid (Inner)', player), lambda state: state.has('Beat Agahnim 1', player))
else: else:
set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) set_rule(world.get_entrance('Inverted Pyramid Hole', player), lambda state: world.is_pyramid_open(player) or state.has('Beat Agahnim 2', player))
set_rule(world.get_entrance('Pyramid Hole', player), lambda state: False) set_rule(world.get_entrance('Pyramid Hole', player), lambda state: False)
set_rule(world.get_entrance('Pyramid Entrance', player), lambda state: False) set_rule(world.get_entrance('Pyramid Entrance', player), lambda state: False)
@@ -1186,6 +1186,7 @@ def ow_rules(world, player):
set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player) and state.has('Flippers', player)) set_rule(world.get_entrance('Lake Hylia Island Mirror Spot', player), lambda state: state.has_Mirror(player) and state.has_Pearl(player) and state.has('Flippers', player))
set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Central Island Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Lake Hylia Water Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Lake Hylia Water Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Lake Hylia Water D Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('South Shore Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('South Shore Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('South Shore East Mirror Spot', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('South Shore East Mirror Spot', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Lake Hylia Teleporter', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('Lake Hylia Teleporter', player), lambda state: state.can_lift_heavy_rocks(player))

38
Text.py
View File

@@ -94,44 +94,44 @@ Triforce_texts = [
'This was meant to be a trapezoid', 'This was meant to be a trapezoid',
# these ones are from web randomizer # these ones are from web randomizer
"\n G G", "\n G G",
"All your base\nare belong\nto us.", " All your base\n are belong\n to us.",
"You have ended\nthe domination\nof Dr. Wily", " You have ended\n the domination\n of Dr. Wily",
" Thanks for\n playing!!!", " Thanks for\n playing!!!",
"\n You Win!", "\n You Win!",
" Thank you!\n Your quest\n is over.", " Thank you!\n Your quest\n is over.",
" A winner\n is you!", " A winner\n is you!",
"\n WINNER!!", "\n WINNER!!",
"\n I'm sorry\n\n but your\n princess is in\n another castle", "\n I'm sorry\n\nbut our princess is\n in another castle",
"\n Success!", "\n Success!",
" Whelp…\n that just\n happened", " Whelp…\n that just\n happened",
" Oh hey…\n it's you", " Oh hey…\n it's you",
"\n Wheeeeee!!", "\n Wheeeeee!!",
" Time for\n another one?", " Time for\n another one?",
"and\n\n scene", " And\n\n scene",
"\n GOT EM!!", "\n GOT EM!!",
"\nTHE VALUUUE!!!", "\n THE VALUUUE!!!",
"Cool seed,\n\nright?", " Cool seed,\n\n right?",
"\n We did it!", "\n We did it!",
" Spam those\n emotes in\n wilds chat", " Spam those\n emotes in\n wilds chat",
"\n O M G", "\n O M G",
" Hello. Will\n you be my\n friend?", " Hello. Will you\n you be my friend?",
" Beetorp\n was\n here!", " Beetorp\n was\n here!",
"The Wind Fish\nwill wake\nsoon. Hoot!", " The Wind Fish\n will wake soon.\n Hoot!",
"Meow Meow Meow\nMeow Meow Meow\n Oh My God!", " Meow Meow Meow\n Meow Meow Meow\n Oh My God!",
"Ahhhhhhhhh\nYa ya yaaaah\nYa ya yaaah", " Ahhhhhhhhh\n Ya ya yaaaah\n Ya ya yaaah",
".done\n\n.comment lol", " .done\n\n .comment lol",
"You get to\ndrink from\nthe firehose", " You get to\n drink from\n the firehose",
"Do you prefer\n bacon, pork,\n or ham?", " Do you prefer\n bacon, pork,\n or ham?",
"You get one\nwish. Choose\nwisely, hero!", " You get one\n wish. Choose\n wisely, hero!",
"Can you please\nbreak us three\nup? Thanks.", " Can you please\n break us three\n up? Thanks.",
" Pick us up\n before we\n get dizzy!", " Pick us up\n before we\n get dizzy!",
"Thank you,\nMikey. Youre\n2 minutes late", " Thank you,\n Mikey. Youre\n 2 minutes late",
"This was a\n7000 series\ntrain.", " This was a\n 7000 series\n train.",
" I'd buy\n that for\n a rupee!", " I'd buy\n that for\n a rupee!",
" Did you like\n that bow\n placement?", " Did you like\n that bow\n placement?",
"I promise the\nnext seed will\nbe better.", " I promise the\n next seed will\n be better.",
"\n Honk.", "\n Honk.",
"Breakfast\nis served!", " Breakfast\n is served!",
] ]
BombShop2_texts = ['Bombs!\nBombs!\nBiggest!\nBestest!\nGreatest!\nBoomest!'] BombShop2_texts = ['Bombs!\nBombs!\nBiggest!\nBestest!\nGreatest!\nBoomest!']
Sahasrahla2_texts = ['You already got my item, idiot.', 'Why are you still talking to me?', 'This text won\'t change.', 'Have you met my brother, Hasarahshla?'] Sahasrahla2_texts = ['You already got my item, idiot.', 'Why are you still talking to me?', 'This text won\'t change.', 'Have you met my brother, Hasarahshla?']

View File

@@ -9,10 +9,35 @@ OWReserved:
dw 0 dw 0
;Hooks ;Hooks
org $02a929
OWDetectTransitionReturn:
org $02a939
OverworldHandleTransitions_SpecialTrigger:
JSL OWDetectEdgeTransition
BCS OWDetectTransitionReturn
org $02a999 org $02a999
jsl OWEdgeTransition : nop #4 ;LDA $02A4E3,X : ORA $7EF3CA jsl OWEdgeTransition : nop #4 ;LDA $02A4E3,X : ORA $7EF3CA
;org $02e238 ;LDX #$9E : - DEX : DEX : CMP $DAEE,X : BNE -
;jsl OWSpecialTransition : nop #5 org $04e8ae
JSL OWDetectSpecialTransition
RTL : NOP
org $02e809
JSL OWSpecialExit
org $02bfe8
JSL OWAdjustExitPosition
org $02c1a9
JSL OWEndScrollTransition
org $04E881
Overworld_LoadSpecialOverworld_RoomId:
org $04E8B4
Overworld_LoadSpecialOverworld:
org $05af75 org $05af75
jsl OWPreserveMirrorSprite : nop #2 ; LDA $7EF3CA : BNE $05AFDF jsl OWPreserveMirrorSprite : nop #2 ; LDA $7EF3CA : BNE $05AFDF
@@ -107,10 +132,14 @@ org $1bed95 ; < ? - palettes.asm:748 ()
jsl.l OWWorldCheck16 : nop jsl.l OWWorldCheck16 : nop
org $02b16e ; AND #$3F : ORA 7EF3CA org $02b16e ; AND #$3F : ORA 7EF3CA
and #$7f : eor #$40 : nop #2 ; something to do with mirroring and simply toggling world to opposite one: TODO: better comment and #$7f : eor #$40 : nop #2
;Code ;Code
org $aa8800 org $aa8800
OWTransitionDirection:
dw 3, 2, 1, 0 ; $02 after $02A932
OWEdgeDataOffset:
dw OWSouthEdges, OWEastEdges, OWSouthEdges
OWCoordIndex: ; Horizontal 1st OWCoordIndex: ; Horizontal 1st
db 2, 2, 0, 0 ; Coordinate Index $20-$23 db 2, 2, 0, 0 ; Coordinate Index $20-$23
OWOppCoordIndex: ; Horizontal 1st OWOppCoordIndex: ; Horizontal 1st
@@ -304,47 +333,99 @@ LoadMapDarkOrMixed:
dw $0C00-$01F0 ; top right dw $0C00-$01F0 ; top right
dw 0,0,0,0,0,0 dw 0,0,0,0,0,0
dw $0800+$01F0 ; bottom left dw $0800+$01F0 ; bottom left
dw $0400+$0210 ; bottom dw $0400+$0210 ; bottom right
} }
org $aa9000 org $aa9000
OWDetectEdgeTransition:
{
STZ.w $06FC
LDA.l OWMode : ORA.l OWMode+1 : BEQ .normal
JSR OWShuffle
LDA.w $06FA : BMI .special
.normal
REP #$31 : LDX.b $02 : LDA.b $84 ; what we wrote over
RTL
.special
REP #$30
AND.w #$0003 : TAY : ASL : TAX
LDA.w #$007F : STA.w $06FA
JSR OWLoadSpecialArea
SEC
RTL
}
OWDetectSpecialTransition:
{
STZ.w $06FC
LDA.l OWMode : BEQ .normal
LDA.l OWSpecialDestIndex,X : BIT.w #$0080 : BNE .special
STA.w $06FA
LDA.l OWEdgeDataOffset,X : STA.w $06F8
PLA : SEP #$30 : PLA ; delete 3 bytes from stack
JSL Link_CheckForEdgeScreenTransition : BCS .return ; Link_CheckForEdgeScreenTransition
LDA.l $04E879,X : STA.b $00 : CMP.b #$08 : BNE .hobo
LSR : STA.b $20 : STZ.b $E8 ; move Link and camera to edge
LDA.b #$06 : STA.b $02
STZ.w $0418
BRA .continue
.hobo
STA.b $02 : STA.w $0418
ASL : STA.b $22 : STZ.b $E2 ; move Link and camera to edge
LDA.b #$0A : STA.b $23 : STA.b $E3
.continue
STZ.b $03
; copied from DeleteCertainAncillaeStopDashing at $028A0E
JSL Ancilla_TerminateSelectInteractives
LDA.w $0372 : BEQ .not_dashing
STZ.b $4D : STZ.b $46
LDA.b #$FF : STA.b $29 : STA.b $C7
STZ.b $3D : STZ.b $5E : STZ.w $032B : STZ.w $0372 : STZ.b $5D
.not_dashing
PLA : REP #$31 : PLA ; delete 3 bytes from stack
LDX.b $02
LDA.b $84
JML OverworldHandleTransitions_SpecialTrigger+6
.special
AND.w #$0003 : TAY : ASL : TAX
.normal
JSR OWLoadSpecialArea
.return
RTL
}
OWEdgeTransition: OWEdgeTransition:
{ {
php : phy LDA.l OWMode : ORA.l OWMode+1 : BEQ .normal
lda.l OWMode : ora.l OWMode+1 : beq + LDY.w $06FA : CPY.b #$7F
jsl OWShuffle : bra .return BEQ .normal
+ jsl OWVanilla REP #$10
.return LDX.w $06F8
ply : plp : rtl PHB : PHK : PLB
JSR OWNewDestination
PLB
SEP #$30
RTL
.normal
LDA.l $02A4E3,X : ORA.l $7EF3CA ; what we wrote over
RTL
} }
OWVanilla: OWSpecialExit:
{ {
lda $02a4e3,X : ora $7ef3ca : rtl LDA.l OWMode+1 : AND.b #!FLAG_OW_CROSSED : BEQ .return
JSR OWWorldUpdate
.return
LDA.l $7EFD40,X ; what we wrote over
RTL
} }
OWShuffle: OWShuffle:
{ {
;Assume you're at links house = $2c ;determine direction of edge transition
;transitioning right will result in X = $2d phx : lsr.w $0700
;transitioning left will result in X = $2b tyx : lda.l OWTransitionDirection,X : sta.w $0418
;up X = $24
;down X = $34
;compares X to determine direction of edge transition
phx : lsr $700 : cpx $700 : !blt .upOrLeft
dex : cpx $700 : bne .downEdge
lda #$3 : sta $418 : bra .setOWID ;right
.downEdge
lda #$1 : sta $418 : bra .setOWID ;down
.upOrLeft
inx : cpx $700 : bne .upEdge
lda #$2 : sta $418 : bra .setOWID ;left
.upEdge
lda #$0 : sta $418 ;up
.setOWID .setOWID
;look up transitions in current area in table OWEdgeOffsets ;look up transitions in current area in table OWEdgeOffsets
;offset is (8bytes * OW Slot ID) + (2bytes * direction) ;offset is (8bytes * OW Slot ID) + (2bytes * direction)
asl : rep #$20 : pha : sep #$20 ;2 bytes per direction asl : rep #$20 : and.w #$00ff : pha : sep #$20 ;2 bytes per direction
lda $8a : and #$40 : !add $700 : rep #$30 : and #$00ff : asl #3 lda $8a : and #$40 : !add $700 : rep #$30 : and #$00ff : asl #3
adc 1,S : tax adc 1,S : tax
asl $700 : pla asl $700 : pla
@@ -368,25 +449,25 @@ OWShuffle:
pla : dec : bne .nextTransition : bra .noTransition pla : dec : bne .nextTransition : bra .noTransition
.newDestination .newDestination
pla : sep #$30 : plx : lda $8a : bra .return pla : sep #$30 : plx : rts
.noTransition .noTransition
sep #$30 : plx : jsl OWVanilla sep #$30 : plx
lda.b #$7f : sta.w $06fa
.return .return
rtl rts
} }
OWSearchTransition: OWSearchTransition:
{ {
;A-16 XY-16 ;A-16 XY-16
lda $418 : bne + ;north lda $418 : bne + ;north
lda.l OWNorthEdges,x : dec lda.l OWNorthEdges,x : dec
cmp $22 : !bge .nomatch cmp $22 : !bge .exitloop
lda.l OWNorthEdges+2,x : cmp $22 : !blt .nomatch lda.l OWNorthEdges+2,x : cmp $22 : !blt .exitloop
;MATCH ;MATCH
lda.l OWNorthEdges+14,x : tay ;y = record id of dest lda.l OWNorthEdges+14,x : tay ;y = record id of dest
sep #$20 : lda #OWSouthEdges>>16 : phb : pha : plb ldx.w #OWSouthEdges ;x = address of table
ldx #OWSouthEdges : jsr OWNewDestination : plb ;x = address of table
bra .matchfound bra .matchfound
+ dec : bne + ;south + dec : bne + ;south
lda.l OWSouthEdges,x : dec lda.l OWSouthEdges,x : dec
@@ -394,29 +475,25 @@ OWSearchTransition:
lda.l OWSouthEdges+2,x : cmp $22 : !blt .exitloop lda.l OWSouthEdges+2,x : cmp $22 : !blt .exitloop
;MATCH ;MATCH
lda.l OWSouthEdges+14,x : tay ;y = record id of dest lda.l OWSouthEdges+14,x : tay ;y = record id of dest
sep #$20 : lda #OWNorthEdges>>16 : phb : pha : plb : phx ldx.w #OWNorthEdges ;x = address of table
ldx #OWNorthEdges : jsr OWNewDestination : plx : plb ;x = address of table
bra .matchfound bra .matchfound
.nomatch
bra .exitloop
+ dec : bne + ; west + dec : bne + ; west
lda.l OWWestEdges,x : dec lda.l OWWestEdges,x : dec
cmp $20 : !bge .exitloop cmp $20 : !bge .exitloop
lda.l OWWestEdges+2,x : cmp $20 : !blt .exitloop lda.l OWWestEdges+2,x : cmp $20 : !blt .exitloop
;MATCH ;MATCH
lda.l OWWestEdges+14,x : tay ;y = record id of dest lda.l OWWestEdges+14,x : tay ;y = record id of dest
sep #$20 : lda #OWEastEdges>>16 : phb : pha : plb ldx.w #OWEastEdges ;x = address of table
ldx #OWEastEdges : jsr OWNewDestination : plb ;x = address of table
bra .matchfound bra .matchfound
+ lda.l OWEastEdges,x : dec ;east + lda.l OWEastEdges,x : dec ;east
cmp $20 : !bge .exitloop cmp $20 : !bge .exitloop
lda.l OWEastEdges+2,x : cmp $20 : !blt .exitloop lda.l OWEastEdges+2,x : cmp $20 : !blt .exitloop
;MATCH ;MATCH
lda.l OWEastEdges+14,x : tay ;y = record id of dest lda.l OWEastEdges+14,x : tay ;y = record id of dest
sep #$20 : lda #OWWestEdges>>16 : phb : pha : plb ldx.w #OWWestEdges ;x = address of table
ldx #OWWestEdges : jsr OWNewDestination : plb ;x = address of table
.matchfound .matchfound
stx $06f8 : sty $06fa : sec : rts
plx : pla : pea $0001 : phx plx : pla : pea $0001 : phx
sec : rts sec : rts
@@ -449,10 +526,11 @@ OWNewDestination:
++ lda $84 : !add 1,s : sta $84 : pla : pla ++ lda $84 : !add 1,s : sta $84 : pla : pla
.adjustMainAxis .adjustMainAxis
;LDA $84 : SEC : SBC #$0400 : AND #$0F80 : ASL : XBA : STA $88 ; vram LDA $84 : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA $88 ; vram
LDA $84 : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA $88
LDA $84 : SEC : SBC #$0010 : AND #$003E : LSR : STA $86 LDA $84 : SEC : SBC #$0010 : AND #$003E : LSR : STA $86
LDA.w $000F,X : AND.w #$00FF : STA.w $06FC ; position to walk to after transition (if non-zero)
pla : pla : sep #$10 : ldy $418 pla : pla : sep #$10 : ldy $418
ldx OWCoordIndex,y : lda $20,x : and #$fe00 : pha ldx OWCoordIndex,y : lda $20,x : and #$fe00 : pha
lda $20,x : and #$01ff : pha ;s1 = relative cur, s3 = ow cur lda $20,x : and #$01ff : pha ;s1 = relative cur, s3 = ow cur
@@ -496,7 +574,7 @@ OWNewDestination:
ldx OWOppBGIndex,y : lda $e0,x : !add 1,s : sta $e0,x ldx OWOppBGIndex,y : lda $e0,x : !add 1,s : sta $e0,x
lda $418 : asl : tax : lda $610,x : !add 1,s : sta $610,x : pla lda $418 : asl : tax : lda $610,x : !add 1,s : sta $610,x : pla
sep #$30 : lda OWOppSlotOffset,y : !add $04 : asl : and #$7f : sta $700 sep #$30 : lda $04 : and #$3f : !add OWOppSlotOffset,y : asl : sta $700
; crossed OW shuffle ; crossed OW shuffle
lda.l OWMode+1 : and.b #!FLAG_OW_CROSSED : beq .return lda.l OWMode+1 : and.b #!FLAG_OW_CROSSED : beq .return
@@ -504,13 +582,18 @@ OWNewDestination:
.return .return
lda $05 : sta $8a lda $05 : sta $8a
;bra +
; nop #8
; jsl $02EA41
; nop #8
;+
rep #$30 : rts rep #$30 : rts
} }
OWLoadSpecialArea:
{
LDA.l Overworld_LoadSpecialOverworld_RoomId,X : STA.b $A0
JSL Overworld_LoadSpecialOverworld
LDA.l OWMode+1 : AND.b #!FLAG_OW_CROSSED : BEQ .return
TYX : LDA.l OWSpecialDestSlot,X : TAX
JSR OWWorldUpdate
.return
RTS
}
OWWorldUpdate: ; x = owid of destination screen OWWorldUpdate: ; x = owid of destination screen
{ {
lda.l OWTileWorldAssoc,x : cmp.l $7ef3ca : beq .return lda.l OWTileWorldAssoc,x : cmp.l $7ef3ca : beq .return
@@ -545,10 +628,29 @@ OWWorldUpdate: ; x = owid of destination screen
.return .return
rts rts
} }
OWSpecialTransition: OWAdjustExitPosition:
{ {
LDX #$9E LDA.w $06FC : CMP.b #$60 : BEQ .stone_bridge
- DEX : DEX : CMP $DAEE,X : BNE - CMP.b #$B0 : BNE .normal
LDA.b #$80 : STA.b $20 : STZ.b $21
BRA .normal
.stone_bridge
LDA.b #$A0 : STA.b $E2
LDA.b #$3D : STA.w $061C
LDA.b #$3B : STA.w $061E
INC.b $23 : INC.w $061D : INC.w $061F
.normal
INC.b $11 : STZ.b $B0 ; what we wrote over
RTL
}
OWEndScrollTransition:
{
LDY.w $06FC : BEQ .normal
CMP.w $06FC
RTL
.normal
CMP.l $02C176,X ; what we wrote over
RTL
} }
;Data ;Data
@@ -556,7 +658,7 @@ org $aaa000
OWEdgeOffsets: OWEdgeOffsets:
;2 bytes per each direction per each OW Slot, order is NSWE per value at $0418 ;2 bytes per each direction per each OW Slot, order is NSWE per value at $0418
;AABB, A = offset to the transition table, B = number of transitions ;AABB, A = offset to the transition table, B = number of transitions
dw $0001, $0000, $0000, $0000 ;OW Slot 00, OWID 0x00 Lost Woods dw $0000, $0000, $0000, $0000 ;OW Slot 00, OWID 0x00 Lost Woods
dw $0000, $0000, $0000, $0001 ;OW Slot 01, OWID 0x00 dw $0000, $0000, $0000, $0001 ;OW Slot 01, OWID 0x00
dw $0000, $0001, $0001, $0000 ;OW Slot 02, OWID 0x02 Lumberjack dw $0000, $0001, $0001, $0000 ;OW Slot 02, OWID 0x02 Lumberjack
dw $0000, $0000, $0000, $0000 dw $0000, $0000, $0000, $0000
@@ -572,7 +674,7 @@ dw $0000, $0000, $0000, $0000
dw $0000, $0000, $0000, $0301 dw $0000, $0000, $0000, $0301
dw $0000, $0000, $0301, $0000 dw $0000, $0000, $0301, $0000
dw $0000, $0000, $0000, $0000 dw $0000, $0000, $0000, $0000
dw $0201, $0501, $0000, $0000 ;Zora dw $0000, $0501, $0000, $0000 ;Zora
dw $0302, $0602, $0000, $0000 dw $0302, $0602, $0000, $0000
dw $0501, $0801, $0000, $0402 dw $0501, $0801, $0000, $0402
@@ -606,7 +708,7 @@ dw $1101, $0000, $1201, $1301
dw $0000, $1502, $1301, $0000 dw $0000, $1502, $1301, $0000
dw $1201, $1701, $0000, $1403 dw $1201, $1701, $0000, $1403
dw $1301, $1801, $1403, $1701 ;Links dw $1301, $1801, $1403, $1701 ;Links
dw $1401, $1901, $1702, $1802 ;Hobo dw $1401, $1901, $1801, $1802 ;Hobo
dw $1501, $1a02, $1902, $0000 dw $1501, $1a02, $1902, $0000
dw $1601, $0000, $0000, $0000 dw $1601, $0000, $0000, $0000
@@ -704,12 +806,15 @@ dw $0000, $4001, $0000, $0000
dw $0000, $0000, $0000, $4a01 dw $0000, $0000, $0000, $4a01
dw $0000, $4101, $0000, $0000 dw $0000, $4101, $0000, $0000
OWSpecialDestSlot:
db $80, $80, $81
org $aaa800 ;PC 152800 org $aaa800 ;PC 152800
OWNorthEdges: OWNorthEdges:
; Min Max Width Mid OW Slot/OWID VRAM *FREE* Dest Index ; Min Max Width Mid OW Slot/OWID VRAM *FREE* Dest Index
dw $00a0, $00a0, $0000, $00a0, $0000, $0000, $0000, $0040 ;Lost Woods dw $00a0, $00a0, $0000, $00a0, $0000, $0000, $0000, $B040 ;Lost Woods (exit only)
dw $0458, $0540, $00e8, $04cc, $0a0a, $0000, $0000, $0000 dw $0458, $0540, $00e8, $04cc, $0a0a, $0000, $0000, $0000
dw $0f38, $0f60, $0028, $0f4c, $0f0f, $0000, $0000, $0041 dw $0f38, $0f60, $0028, $0f4c, $0f0f, $0000, $0000, $2041 ;Waterfall (exit only)
dw $0058, $0058, $0000, $0058, $1010, $0000, $0000, $0001 dw $0058, $0058, $0000, $0058, $1010, $0000, $0000, $0001
dw $0178, $0178, $0000, $0178, $1010, $0000, $0000, $0002 dw $0178, $0178, $0000, $0178, $1010, $0000, $0000, $0002
dw $0388, $0388, $0000, $0388, $1111, $0000, $0000, $0003 dw $0388, $0388, $0000, $0388, $1111, $0000, $0000, $0003
@@ -838,8 +943,8 @@ dw $06a0, $07b0, $0110, $0728, $7373, $0000, $0000, $003e
dw $0830, $09b0, $0180, $08f0, $7474, $0000, $0000, $003f dw $0830, $09b0, $0180, $08f0, $7474, $0000, $0000, $003f
dw $0e78, $0e88, $0010, $0e80, $7777, $0000, $0000, $0040 dw $0e78, $0e88, $0010, $0e80, $7777, $0000, $0000, $0040
dw $0ee0, $0fc0, $00e0, $0f50, $7777, $0000, $0000, $0041 dw $0ee0, $0fc0, $00e0, $0f50, $7777, $0000, $0000, $0041
dw $0080, $0080, $0000, $0080, $8080, $0000, $0000, $0000 ;Pedestal dw $0080, $0080, $0000, $0080, $8080, $0000, $0000, $0000 ;Pedestal (unused)
dw $0288, $02c0, $0038, $02a4, $8189, $0000, $0000, $0002 ;Zora dw $0288, $02c0, $0038, $02a4, $8189, $0000, $0000, $0002 ;Zora (unused)
OWWestEdges: OWWestEdges:
dw $0070, $00a0, $0030, $0088, $0202, $0000, $0000, $0000 dw $0070, $00a0, $0030, $0088, $0202, $0000, $0000, $0000
dw $0068, $0078, $0010, $0070, $0505, $0000, $0000, $0001 dw $0068, $0078, $0010, $0070, $0505, $0000, $0000, $0001
@@ -864,7 +969,7 @@ dw $0b60, $0ba0, $0040, $0b80, $2a2a, $0000, $0000, $0013
dw $0ab0, $0ad0, $0020, $0ac0, $2c2c, $0000, $0000, $0014 dw $0ab0, $0ad0, $0020, $0ac0, $2c2c, $0000, $0000, $0014
dw $0af0, $0b40, $0050, $0b18, $2c2c, $0000, $0000, $0015 dw $0af0, $0b40, $0050, $0b18, $2c2c, $0000, $0000, $0015
dw $0b78, $0ba0, $0028, $0b8c, $2c2c, $0000, $0000, $0016 dw $0b78, $0ba0, $0028, $0b8c, $2c2c, $0000, $0000, $0016
dw $0b10, $0b28, $0018, $0b1c, $2d2d, $0000, $0000, $004a dw $0b10, $0b28, $0018, $0b1c, $2d2d, $0000, $0000, $604a ;Stone Bridge (exit only)
dw $0b68, $0b98, $0030, $0b80, $2d2d, $0000, $0000, $0017 dw $0b68, $0b98, $0030, $0b80, $2d2d, $0000, $0000, $0017
dw $0a68, $0ab8, $0050, $0a90, $2e2e, $0000, $0000, $0018 dw $0a68, $0ab8, $0050, $0a90, $2e2e, $0000, $0000, $0018
dw $0b00, $0b78, $0078, $0b3c, $2e2e, $0000, $0000, $0019 dw $0b00, $0b78, $0078, $0b3c, $2e2e, $0000, $0000, $0019
@@ -991,7 +1096,11 @@ dw $0e28, $0fb8, $0190, $0ef0, $7b7b, $0000, $0000, $0047
dw $0f78, $0fb8, $0040, $0f98, $7c7c, $0000, $0000, $0048 dw $0f78, $0fb8, $0040, $0f98, $7c7c, $0000, $0000, $0048
dw $0f20, $0f40, $0020, $0f30, $757e, $0000, $0000, $0049 dw $0f20, $0f40, $0020, $0f30, $757e, $0000, $0000, $0049
dw $0f70, $0fb8, $0048, $0f94, $757e, $0000, $0000, $004a dw $0f70, $0fb8, $0048, $0f94, $757e, $0000, $0000, $004a
dw $0058, $00c0, $0068, $008c, $8080, $0000, $0000, $0017 ;Hobo dw $0058, $00c0, $0068, $008c, $8080, $0000, $0000, $0017 ;Hobo (unused)
org $aab9e0 ;PC 1539e0
OWSpecialDestIndex:
dw $0080, $0081, $0082
org $aaba00 ;PC 153a00 org $aaba00 ;PC 153a00
OWTileWorldAssoc: OWTileWorldAssoc:
@@ -1011,6 +1120,7 @@ db $40, $40, $40, $40, $40, $40, $40, $40
db $40, $40, $40, $40, $40, $40, $40, $40 db $40, $40, $40, $40, $40, $40, $40, $40
db $40, $40, $40, $40, $40, $40, $40, $40 db $40, $40, $40, $40, $40, $40, $40, $40
db $40, $40, $40, $40, $40, $40, $40, $40 db $40, $40, $40, $40, $40, $40, $40, $40
db $00, $00
org $aabb00 ;PC 153b00 org $aabb00 ;PC 153b00
OWTileMapAlt: OWTileMapAlt:
@@ -1031,3 +1141,5 @@ db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0 db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0

Binary file not shown.

View File

@@ -53,6 +53,10 @@
lean: 2 lean: 2
crossed: 3 crossed: 3
insanity: 1 insanity: 1
open_pyramid:
auto: 1
yes: 0
no: 0
shufflelinks: shufflelinks:
on: 1 on: 1
off: 1 off: 1

View File

@@ -218,8 +218,11 @@
] ]
}, },
"openpyramid": { "openpyramid": {
"action": "store_true", "choices": [
"type": "bool" "auto",
"yes",
"no"
]
}, },
"rom": {}, "rom": {},
"loglevel": { "loglevel": {

View File

@@ -138,6 +138,9 @@
"randomizer.entrance.openpyramid": "Pre-open Pyramid Hole", "randomizer.entrance.openpyramid": "Pre-open Pyramid Hole",
"randomizer.entrance.openpyramid.auto": "Auto",
"randomizer.entrance.openpyramid.yes": "Yes",
"randomizer.entrance.openpyramid.no": "No",
"randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool", "randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool",
"randomizer.entrance.shufflelinks": "Include Link's House in the shuffle pool", "randomizer.entrance.shufflelinks": "Include Link's House in the shuffle pool",
"randomizer.entrance.overworld_map": "Overworld Map", "randomizer.entrance.overworld_map": "Overworld Map",

View File

@@ -1,6 +1,16 @@
{ {
"widgets": { "widgets": {
"openpyramid": { "type": "checkbox" }, "openpyramid": {
"type": "selectbox",
"options": [
"auto",
"yes",
"no"
],
"config": {
"width": 10
}
},
"shuffleganon": { "type": "checkbox" }, "shuffleganon": { "type": "checkbox" },
"shufflelinks": { "type": "checkbox" }, "shufflelinks": { "type": "checkbox" },
"overworld_map": { "overworld_map": {

View File

@@ -27,7 +27,7 @@ def entrando_page(parent):
for key in dictWidgets: for key in dictWidgets:
self.widgets[key] = dictWidgets[key] self.widgets[key] = dictWidgets[key]
packAttrs = {"anchor":E} packAttrs = {"anchor":E}
if self.widgets[key].type == "checkbox": if self.widgets[key].type == "checkbox" or key == "openpyramid":
packAttrs["anchor"] = W packAttrs["anchor"] = W
self.widgets[key].pack(packAttrs) self.widgets[key].pack(packAttrs)