Merge branch 'OverworldShuffleDev' into OverworldShuffle
This commit is contained in:
@@ -26,6 +26,7 @@ class World(object):
|
||||
self.owCrossed = owCrossed.copy()
|
||||
self.owKeepSimilar = {}
|
||||
self.owMixed = owMixed.copy()
|
||||
self.owWhirlpoolShuffle = {}
|
||||
self.owFluteShuffle = {}
|
||||
self.shuffle = shuffle.copy()
|
||||
self.doorShuffle = doorShuffle.copy()
|
||||
@@ -76,6 +77,7 @@ class World(object):
|
||||
self.spoiler = Spoiler(self)
|
||||
self.lamps_needed_for_dark_rooms = 1
|
||||
self.owswaps = {}
|
||||
self.owwhirlpools = {}
|
||||
self.owedges = []
|
||||
self._owedge_cache = {}
|
||||
self.owflutespots = {}
|
||||
@@ -105,6 +107,7 @@ class World(object):
|
||||
set_player_attr('_region_cache', {})
|
||||
set_player_attr('player_names', [])
|
||||
set_player_attr('owswaps', [[],[],[]])
|
||||
set_player_attr('owwhirlpools', [])
|
||||
set_player_attr('remote_items', False)
|
||||
set_player_attr('required_medallions', ['Ether', 'Quake'])
|
||||
set_player_attr('swamp_patch_required', False)
|
||||
@@ -112,7 +115,7 @@ class World(object):
|
||||
set_player_attr('ganon_at_pyramid', True)
|
||||
set_player_attr('ganonstower_vanilla', True)
|
||||
set_player_attr('sewer_light_cone', self.mode[player] == 'standard')
|
||||
set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or ((self.mode[player] == 'inverted') != (0x05 in self.owswaps[player][0] and self.owMixed[player])))
|
||||
set_player_attr('fix_trock_doors', self.shuffle[player] != 'vanilla' or ((self.mode[player] == 'inverted') != 0x05 in self.owswaps[player][0]))
|
||||
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] or self.doorShuffle[player] not in ['vanilla'])
|
||||
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||
@@ -120,7 +123,7 @@ class World(object):
|
||||
set_player_attr('can_access_trock_front', None)
|
||||
set_player_attr('can_access_trock_big_chest', None)
|
||||
set_player_attr('can_access_trock_middle', None)
|
||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'nologic'] or shuffle[player] in ['lite', 'lean', 'crossed', 'insanity', 'madness_legacy'])
|
||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'nologic'] or shuffle[player] in ['lean', 'crossed', 'insanity', 'madness_legacy'])
|
||||
set_player_attr('mapshuffle', False)
|
||||
set_player_attr('compassshuffle', False)
|
||||
set_player_attr('keyshuffle', False)
|
||||
@@ -2693,6 +2696,7 @@ class Spoiler(object):
|
||||
'ow_crossed': self.world.owCrossed,
|
||||
'ow_keepsimilar': self.world.owKeepSimilar,
|
||||
'ow_mixed': self.world.owMixed,
|
||||
'ow_whirlpool': self.world.owWhirlpoolShuffle,
|
||||
'ow_fluteshuffle': self.world.owFluteShuffle,
|
||||
'shuffle': self.world.shuffle,
|
||||
'shuffleganon': self.world.shuffle_ganon,
|
||||
@@ -2784,6 +2788,7 @@ class Spoiler(object):
|
||||
outfile.write('Keep Similar OW Edges Together:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_keepsimilar'][player] else 'No'))
|
||||
outfile.write('Crossed OW:'.ljust(line_width) + '%s\n' % self.metadata['ow_crossed'][player])
|
||||
outfile.write('Swapped OW (Mixed):'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_mixed'][player] else 'No'))
|
||||
outfile.write('Whirlpool Shuffle:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['ow_whirlpool'][player] else 'No'))
|
||||
outfile.write('Flute Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_fluteshuffle'][player])
|
||||
outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player])
|
||||
outfile.write('Shuffle GT/Ganon:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['shuffleganon'][player] else 'No'))
|
||||
@@ -2807,6 +2812,7 @@ class Spoiler(object):
|
||||
if self.startinventory:
|
||||
outfile.write('Starting Inventory:'.ljust(line_width))
|
||||
outfile.write('\n'.ljust(line_width+1).join(self.startinventory))
|
||||
|
||||
outfile.write('\n\nRequirements:\n\n')
|
||||
for dungeon, medallion in self.medallions.items():
|
||||
outfile.write(f'{dungeon}:'.ljust(line_width) + '%s Medallion\n' % medallion)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
### 0.2.1.0
|
||||
- Implemented Whirlpool Shuffle
|
||||
|
||||
### 0.2.0.0
|
||||
- Massive overhaul of ER algorithm
|
||||
- Added 2 new ER modes (Lite and Lean)
|
||||
|
||||
3
CLI.py
3
CLI.py
@@ -94,7 +94,7 @@ def parse_cli(argv, no_defaults=False):
|
||||
playerargs = parse_cli(shlex.split(getattr(ret, f"p{player}")), True)
|
||||
|
||||
for name in ['logic', 'mode', 'swords', 'goal', 'difficulty', 'item_functionality',
|
||||
'ow_shuffle', 'ow_crossed', 'ow_keepsimilar', 'ow_mixed', 'ow_fluteshuffle',
|
||||
'ow_shuffle', 'ow_crossed', 'ow_keepsimilar', 'ow_mixed', 'ow_whirlpool', 'ow_fluteshuffle',
|
||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
|
||||
'bombbag', 'shuffleganon',
|
||||
@@ -149,6 +149,7 @@ def parse_settings():
|
||||
"ow_crossed": "none",
|
||||
"ow_keepsimilar": False,
|
||||
"ow_mixed": False,
|
||||
"ow_whirlpool": False,
|
||||
"ow_fluteshuffle": "vanilla",
|
||||
"shuffle": "vanilla",
|
||||
"shufflelinks": False,
|
||||
|
||||
2
Main.py
2
Main.py
@@ -87,6 +87,7 @@ def main(args, seed=None, fish=None):
|
||||
world.crystals_ganon_orig = args.crystals_ganon.copy()
|
||||
world.crystals_gt_orig = args.crystals_gt.copy()
|
||||
world.owKeepSimilar = args.ow_keepsimilar.copy()
|
||||
world.owWhirlpoolShuffle = args.ow_whirlpool.copy()
|
||||
world.owFluteShuffle = args.ow_fluteshuffle.copy()
|
||||
world.open_pyramid = args.openpyramid.copy()
|
||||
world.boss_shuffle = args.shufflebosses.copy()
|
||||
@@ -406,6 +407,7 @@ def copy_world(world):
|
||||
ret.crystals_ganon_orig = world.crystals_ganon_orig.copy()
|
||||
ret.crystals_gt_orig = world.crystals_gt_orig.copy()
|
||||
ret.owKeepSimilar = world.owKeepSimilar.copy()
|
||||
ret.owWhirlpoolShuffle = world.owWhirlpoolShuffle.copy()
|
||||
ret.owFluteShuffle = world.owFluteShuffle.copy()
|
||||
ret.open_pyramid = world.open_pyramid.copy()
|
||||
ret.boss_shuffle = world.boss_shuffle.copy()
|
||||
|
||||
@@ -138,6 +138,7 @@ def roll_settings(weights):
|
||||
ret.ow_crossed = get_choice('overworld_crossed')
|
||||
ret.ow_keepsimilar = get_choice('overworld_keepsimilar') == 'on'
|
||||
ret.ow_mixed = get_choice('overworld_swap') == 'on'
|
||||
ret.ow_whirlpool = get_choice('whirlpool_shuffle') == 'on'
|
||||
overworld_flute = get_choice('flute_shuffle')
|
||||
ret.ow_fluteshuffle = overworld_flute if overworld_flute != 'none' else 'vanilla'
|
||||
entrance_shuffle = get_choice('entrance_shuffle')
|
||||
|
||||
104
OWEdges.py
104
OWEdges.py
@@ -969,7 +969,7 @@ OWTileRegions = bidict({
|
||||
})
|
||||
|
||||
OWTileGroups = {
|
||||
("Woods", "Regular"): (
|
||||
("Woods", "Regular", "None"): (
|
||||
[
|
||||
0x00, 0x2d, 0x80
|
||||
],
|
||||
@@ -977,7 +977,7 @@ OWTileGroups = {
|
||||
0x40, 0x6d
|
||||
]
|
||||
),
|
||||
("Lumberjack", "Regular"): (
|
||||
("Lumberjack", "Regular", "None"): (
|
||||
[
|
||||
0x02
|
||||
],
|
||||
@@ -985,7 +985,7 @@ OWTileGroups = {
|
||||
0x42
|
||||
]
|
||||
),
|
||||
("West Mountain", "Regular"): (
|
||||
("West Mountain", "Regular", "None"): (
|
||||
[
|
||||
0x03
|
||||
],
|
||||
@@ -993,7 +993,7 @@ OWTileGroups = {
|
||||
0x43
|
||||
]
|
||||
),
|
||||
("East Mountain", "Regular"): (
|
||||
("East Mountain", "Regular", "None"): (
|
||||
[
|
||||
0x05
|
||||
],
|
||||
@@ -1001,23 +1001,31 @@ OWTileGroups = {
|
||||
0x45
|
||||
]
|
||||
),
|
||||
("East Mountain", "Entrance"): (
|
||||
("East Mountain", "Entrance", "None"): (
|
||||
[
|
||||
0x07,
|
||||
0x07
|
||||
],
|
||||
[
|
||||
0x47
|
||||
]
|
||||
),
|
||||
("Lake", "Regular"): (
|
||||
("Lake", "Regular", "Zora"): (
|
||||
[
|
||||
0x0f, 0x35, 0x81
|
||||
0x0f, 0x81
|
||||
],
|
||||
[
|
||||
0x4f, 0x75
|
||||
0x4f
|
||||
]
|
||||
),
|
||||
("Mountain Entry", "Regular"): (
|
||||
("Lake", "Regular", "Lake"): (
|
||||
[
|
||||
0x35
|
||||
],
|
||||
[
|
||||
0x75
|
||||
]
|
||||
),
|
||||
("Mountain Entry", "Regular", "None"): (
|
||||
[
|
||||
0x0a
|
||||
],
|
||||
@@ -1025,7 +1033,7 @@ OWTileGroups = {
|
||||
0x4a
|
||||
]
|
||||
),
|
||||
("Woods Pass", "Regular"): (
|
||||
("Woods Pass", "Regular", "None"): (
|
||||
[
|
||||
0x10
|
||||
],
|
||||
@@ -1033,7 +1041,7 @@ OWTileGroups = {
|
||||
0x50
|
||||
]
|
||||
),
|
||||
("Fortune", "Regular"): (
|
||||
("Fortune", "Regular", "None"): (
|
||||
[
|
||||
0x11
|
||||
],
|
||||
@@ -1041,15 +1049,39 @@ OWTileGroups = {
|
||||
0x51
|
||||
]
|
||||
),
|
||||
("Whirlpools", "Regular"): (
|
||||
("Whirlpools", "Regular", "Pond"): (
|
||||
[
|
||||
0x12, 0x15, 0x33, 0x3f
|
||||
0x12
|
||||
],
|
||||
[
|
||||
0x52, 0x55, 0x73, 0x7f
|
||||
0x52
|
||||
]
|
||||
),
|
||||
("Castle", "Entrance"): (
|
||||
("Whirlpools", "Regular", "Witch"): (
|
||||
[
|
||||
0x15
|
||||
],
|
||||
[
|
||||
0x55
|
||||
]
|
||||
),
|
||||
("Whirlpools", "Regular", "CWhirlpool"): (
|
||||
[
|
||||
0x33
|
||||
],
|
||||
[
|
||||
0x73
|
||||
]
|
||||
),
|
||||
("Whirlpools", "Regular", "Southeast"): (
|
||||
[
|
||||
0x3f
|
||||
],
|
||||
[
|
||||
0x7f
|
||||
]
|
||||
),
|
||||
("Castle", "Entrance", "None"): (
|
||||
[
|
||||
0x13, 0x14
|
||||
],
|
||||
@@ -1057,7 +1089,7 @@ OWTileGroups = {
|
||||
0x53, 0x54
|
||||
]
|
||||
),
|
||||
("Castle", "Regular"): (
|
||||
("Castle", "Regular", "None"): (
|
||||
[
|
||||
0x1a, 0x1b
|
||||
],
|
||||
@@ -1065,7 +1097,7 @@ OWTileGroups = {
|
||||
0x5a, 0x5b
|
||||
]
|
||||
),
|
||||
("Witch", "Regular"): (
|
||||
("Witch", "Regular", "None"): (
|
||||
[
|
||||
0x16
|
||||
],
|
||||
@@ -1073,7 +1105,7 @@ OWTileGroups = {
|
||||
0x56
|
||||
]
|
||||
),
|
||||
("Water Approach", "Regular"): (
|
||||
("Water Approach", "Regular", "None"): (
|
||||
[
|
||||
0x17
|
||||
],
|
||||
@@ -1081,7 +1113,7 @@ OWTileGroups = {
|
||||
0x57
|
||||
]
|
||||
),
|
||||
("Village", "Regular"): (
|
||||
("Village", "Regular", "None"): (
|
||||
[
|
||||
0x18
|
||||
],
|
||||
@@ -1089,7 +1121,7 @@ OWTileGroups = {
|
||||
0x58
|
||||
]
|
||||
),
|
||||
("Wooden Bridge", "Regular"): (
|
||||
("Wooden Bridge", "Regular", "None"): (
|
||||
[
|
||||
0x1d
|
||||
],
|
||||
@@ -1097,7 +1129,7 @@ OWTileGroups = {
|
||||
0x5d
|
||||
]
|
||||
),
|
||||
("Eastern", "Regular"): (
|
||||
("Eastern", "Regular", "None"): (
|
||||
[
|
||||
0x1e
|
||||
],
|
||||
@@ -1105,7 +1137,7 @@ OWTileGroups = {
|
||||
0x5e
|
||||
]
|
||||
),
|
||||
("Blacksmith", "Regular"): (
|
||||
("Blacksmith", "Regular", "None"): (
|
||||
[
|
||||
0x22
|
||||
],
|
||||
@@ -1113,7 +1145,7 @@ OWTileGroups = {
|
||||
0x62
|
||||
]
|
||||
),
|
||||
("Dunes", "Regular"): (
|
||||
("Dunes", "Regular", "None"): (
|
||||
[
|
||||
0x25
|
||||
],
|
||||
@@ -1121,7 +1153,7 @@ OWTileGroups = {
|
||||
0x65
|
||||
]
|
||||
),
|
||||
("Game", "Regular"): (
|
||||
("Game", "Regular", "None"): (
|
||||
[
|
||||
0x28, 0x29
|
||||
],
|
||||
@@ -1129,7 +1161,7 @@ OWTileGroups = {
|
||||
0x68, 0x69
|
||||
]
|
||||
),
|
||||
("Grove", "Regular"): (
|
||||
("Grove", "Regular", "None"): (
|
||||
[
|
||||
0x2a
|
||||
],
|
||||
@@ -1137,7 +1169,7 @@ OWTileGroups = {
|
||||
0x6a
|
||||
]
|
||||
),
|
||||
("Central Bonk Rocks", "Regular"): (
|
||||
("Central Bonk Rocks", "Regular", "None"): (
|
||||
[
|
||||
0x2b
|
||||
],
|
||||
@@ -1145,7 +1177,7 @@ OWTileGroups = {
|
||||
0x6b
|
||||
]
|
||||
),
|
||||
# ("Links", "Regular"): (
|
||||
# ("Links", "Regular", "None"): (
|
||||
# [
|
||||
# 0x2c
|
||||
# ],
|
||||
@@ -1153,7 +1185,7 @@ OWTileGroups = {
|
||||
# 0x6c
|
||||
# ]
|
||||
# ),
|
||||
("Tree Line", "Regular"): (
|
||||
("Tree Line", "Regular", "None"): (
|
||||
[
|
||||
0x2e
|
||||
],
|
||||
@@ -1161,7 +1193,7 @@ OWTileGroups = {
|
||||
0x6e
|
||||
]
|
||||
),
|
||||
("Nook", "Regular"): (
|
||||
("Nook", "Regular", "None"): (
|
||||
[
|
||||
0x2f
|
||||
],
|
||||
@@ -1169,7 +1201,7 @@ OWTileGroups = {
|
||||
0x6f
|
||||
]
|
||||
),
|
||||
("Desert", "Regular"): (
|
||||
("Desert", "Regular", "None"): (
|
||||
[
|
||||
0x30, 0x3a
|
||||
],
|
||||
@@ -1177,7 +1209,7 @@ OWTileGroups = {
|
||||
0x70, 0x7a
|
||||
]
|
||||
),
|
||||
("Grove Approach", "Regular"): (
|
||||
("Grove Approach", "Regular", "None"): (
|
||||
[
|
||||
0x32
|
||||
],
|
||||
@@ -1185,7 +1217,7 @@ OWTileGroups = {
|
||||
0x72
|
||||
]
|
||||
),
|
||||
("Hype", "Regular"): (
|
||||
("Hype", "Regular", "None"): (
|
||||
[
|
||||
0x34
|
||||
],
|
||||
@@ -1193,7 +1225,7 @@ OWTileGroups = {
|
||||
0x74
|
||||
]
|
||||
),
|
||||
("Shopping Mall", "Regular"): (
|
||||
("Shopping Mall", "Regular", "None"): (
|
||||
[
|
||||
0x37
|
||||
],
|
||||
@@ -1201,7 +1233,7 @@ OWTileGroups = {
|
||||
0x77
|
||||
]
|
||||
),
|
||||
("Swamp", "Regular"): (
|
||||
("Swamp", "Regular", "None"): (
|
||||
[
|
||||
0x3b
|
||||
],
|
||||
@@ -1209,7 +1241,7 @@ OWTileGroups = {
|
||||
0x7b
|
||||
]
|
||||
),
|
||||
("South Pass", "Regular"): (
|
||||
("South Pass", "Regular", "None"): (
|
||||
[
|
||||
0x3c
|
||||
],
|
||||
|
||||
@@ -3,7 +3,7 @@ from BaseClasses import OWEdge, WorldType, RegionType, Direction, Terrain, PolSl
|
||||
from Regions import mark_dark_world_regions, mark_light_world_regions
|
||||
from OWEdges import OWTileRegions, OWTileGroups, OWEdgeGroups, OWExitTypes, OpenStd, parallel_links, IsParallel
|
||||
|
||||
__version__ = '0.2.0.0-u'
|
||||
__version__ = '0.2.1.0-u'
|
||||
|
||||
def link_overworld(world, player):
|
||||
# setup mandatory connections
|
||||
@@ -187,6 +187,44 @@ def link_overworld(world, player):
|
||||
trimmed_groups = performSwap(trimmed_groups, crossed_edges)
|
||||
assert len(crossed_edges) == 0, 'Not all edges were crossed successfully: ' + ', '.join(crossed_edges)
|
||||
|
||||
# whirlpool shuffle
|
||||
logging.getLogger('').debug('Shuffling whirlpools')
|
||||
|
||||
if not world.owWhirlpoolShuffle[player]:
|
||||
for (_, from_whirlpool, from_region), (_, to_whirlpool, to_region) in default_whirlpool_connections:
|
||||
connect_simple(world, from_whirlpool, to_region, player)
|
||||
connect_simple(world, to_whirlpool, from_region, player)
|
||||
else:
|
||||
whirlpool_candidates = [[],[]]
|
||||
for (from_owid, from_whirlpool, from_region), (to_owid, to_whirlpool, to_region) in default_whirlpool_connections:
|
||||
if world.owCrossed[player] != 'none':
|
||||
whirlpool_candidates[0].append(tuple((from_owid, from_whirlpool, from_region)))
|
||||
whirlpool_candidates[0].append(tuple((to_owid, to_whirlpool, to_region)))
|
||||
else:
|
||||
if world.get_region(from_region, player).type == RegionType.LightWorld:
|
||||
whirlpool_candidates[0].append(tuple((from_owid, from_whirlpool, from_region)))
|
||||
else:
|
||||
whirlpool_candidates[1].append(tuple((from_owid, from_whirlpool, from_region)))
|
||||
|
||||
if world.get_region(to_region, player).type == RegionType.LightWorld:
|
||||
whirlpool_candidates[0].append(tuple((to_owid, to_whirlpool, to_region)))
|
||||
else:
|
||||
whirlpool_candidates[1].append(tuple((to_owid, to_whirlpool, to_region)))
|
||||
|
||||
# shuffle happens here
|
||||
world.owwhirlpools[player] = [None] * 8
|
||||
whirlpool_map = [ 0x35, 0x0f, 0x15, 0x33, 0x12, 0x3f, 0x55, 0x7f ]
|
||||
for whirlpools in whirlpool_candidates:
|
||||
random.shuffle(whirlpools)
|
||||
while len(whirlpools):
|
||||
from_owid, from_whirlpool, from_region = whirlpools.pop()
|
||||
to_owid, to_whirlpool, to_region = whirlpools.pop()
|
||||
connect_simple(world, from_whirlpool, to_region, player)
|
||||
connect_simple(world, to_whirlpool, from_region, player)
|
||||
world.owwhirlpools[player][next(i for i, v in enumerate(whirlpool_map) if v == to_owid)] = from_owid
|
||||
world.owwhirlpools[player][next(i for i, v in enumerate(whirlpool_map) if v == from_owid)] = to_owid
|
||||
world.spoiler.set_overworld(from_whirlpool, to_whirlpool, 'both', player)
|
||||
|
||||
# layout shuffle
|
||||
logging.getLogger('').debug('Shuffling overworld layout')
|
||||
connected_edges = []
|
||||
@@ -387,22 +425,33 @@ def connect_two_way(world, edgename1, edgename2, player, connected_edges=None):
|
||||
|
||||
def shuffle_tiles(world, groups, result_list, player):
|
||||
swapped_edges = list()
|
||||
valid_whirlpool_parity = False
|
||||
|
||||
# tile shuffle happens here
|
||||
removed = list()
|
||||
for group in groups.keys():
|
||||
if random.randint(0, 1):
|
||||
removed.append(group)
|
||||
|
||||
# save shuffled tiles to list
|
||||
for group in groups.keys():
|
||||
if group not in removed:
|
||||
(owids, lw_regions, dw_regions) = groups[group]
|
||||
(exist_owids, exist_lw_regions, exist_dw_regions) = result_list
|
||||
exist_owids.extend(owids)
|
||||
exist_lw_regions.extend(lw_regions)
|
||||
exist_dw_regions.extend(dw_regions)
|
||||
result_list = [exist_owids, exist_lw_regions, exist_dw_regions]
|
||||
while not valid_whirlpool_parity:
|
||||
# tile shuffle happens here
|
||||
removed = list()
|
||||
for group in groups.keys():
|
||||
# if group[0] in ['Links', 'Central Bonk Rocks', 'Castle']: # TODO: Standard + Inverted
|
||||
if random.randint(0, 1):
|
||||
removed.append(group)
|
||||
|
||||
# save shuffled tiles to list
|
||||
new_results = [[],[],[]]
|
||||
for group in groups.keys():
|
||||
if group not in removed:
|
||||
(owids, lw_regions, dw_regions) = groups[group]
|
||||
(exist_owids, exist_lw_regions, exist_dw_regions) = new_results
|
||||
exist_owids.extend(owids)
|
||||
exist_lw_regions.extend(lw_regions)
|
||||
exist_dw_regions.extend(dw_regions)
|
||||
|
||||
# check whirlpool parity
|
||||
valid_whirlpool_parity = world.owCrossed[player] != 'none' or len(set(new_results[0]) & set({0x0f, 0x12, 0x15, 0x33, 0x35, 0x3f, 0x55, 0x7f})) % 2 == 0
|
||||
|
||||
(exist_owids, exist_lw_regions, exist_dw_regions) = result_list
|
||||
exist_owids.extend(new_results[0])
|
||||
exist_lw_regions.extend(new_results[1])
|
||||
exist_dw_regions.extend(new_results[2])
|
||||
|
||||
# replace LW edges with DW
|
||||
ignore_list = list() #TODO: Remove ignore_list when special OW areas are included in pool
|
||||
@@ -426,36 +475,62 @@ def shuffle_tiles(world, groups, result_list, player):
|
||||
|
||||
def reorganize_tile_groups(world, player):
|
||||
groups = {}
|
||||
for (name, groupType) in OWTileGroups.keys():
|
||||
for (name, groupType, whirlpoolGroup) in OWTileGroups.keys():
|
||||
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks'] \
|
||||
or (world.mode[player] == 'standard' and world.shuffle[player] in ['lite', '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'):
|
||||
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']:
|
||||
groups[(name,)] = ([], [], [])
|
||||
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
|
||||
groups[(name, whirlpoolGroup)] = ([], [], [])
|
||||
else:
|
||||
groups[(name,)] = ([], [], [])
|
||||
else:
|
||||
groups[(name, groupType)] = ([], [], [])
|
||||
if world.owWhirlpoolShuffle[player] or world.owCrossed[player] != 'none':
|
||||
groups[(name, groupType, whirlpoolGroup)] = ([], [], [])
|
||||
else:
|
||||
groups[(name, groupType)] = ([], [], [])
|
||||
|
||||
for (name, groupType) in OWTileGroups.keys():
|
||||
for (name, groupType, whirlpoolGroup) in OWTileGroups.keys():
|
||||
if world.mode[player] != 'standard' or name not in ['Castle', 'Links', 'Central Bonk Rocks'] \
|
||||
or (world.mode[player] == 'standard' and world.shuffle[player] in ['lite', 'lean', 'crossed', 'insanity'] and name == 'Castle' and groupType == 'Entrance'):
|
||||
(lw_owids, dw_owids) = OWTileGroups[(name, groupType,)]
|
||||
or (world.mode[player] == 'standard' and world.shuffle[player] in ['lean', 'crossed', 'insanity'] and name == 'Castle' and groupType == 'Entrance'):
|
||||
(lw_owids, dw_owids) = OWTileGroups[(name, groupType, whirlpoolGroup)]
|
||||
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'simple', 'restricted']:
|
||||
(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)
|
||||
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(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, whirlpoolGroup)] = (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:
|
||||
(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)
|
||||
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
|
||||
|
||||
def remove_reserved(world, groupedlist, connected_edges, player):
|
||||
@@ -733,17 +808,7 @@ temporary_mandatory_connections = [
|
||||
]
|
||||
|
||||
# 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 = [# Whirlpool Connections
|
||||
('C Whirlpool', 'River Bend Water'),
|
||||
('River Bend Whirlpool', 'C Whirlpool Water'),
|
||||
('Lake Hylia Whirlpool', 'Zora Waterfall Water'),
|
||||
('Zora Whirlpool', 'Lake Hylia Water'),
|
||||
('Kakariko Pond Whirlpool', 'Octoballoon Water'),
|
||||
('Octoballoon Whirlpool', 'Kakariko Pond Area'),
|
||||
('Qirn Jump Whirlpool', 'Bomber Corner Water'),
|
||||
('Bomber Corner Whirlpool', 'Qirn Jump Water'),
|
||||
|
||||
# Intra-tile OW Connections
|
||||
mandatory_connections = [# Intra-tile OW Connections
|
||||
('Lost Woods Bush (West)', 'Lost Woods East Area'), #pearl
|
||||
('Lost Woods Bush (East)', 'Lost Woods West Area'), #pearl
|
||||
('West Death Mountain Drop', 'West Death Mountain (Bottom)'),
|
||||
@@ -967,6 +1032,13 @@ mandatory_connections = [# Whirlpool Connections
|
||||
('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water') #fake flipper
|
||||
]
|
||||
|
||||
default_whirlpool_connections = [
|
||||
((0x33, 'C Whirlpool', 'C Whirlpool Water'), (0x15, 'River Bend Whirlpool', 'River Bend Water')),
|
||||
((0x35, 'Lake Hylia Whirlpool', 'Lake Hylia Water'), (0x0f, 'Zora Whirlpool', 'Zora Waterfall Water')),
|
||||
((0x12, 'Kakariko Pond Whirlpool', 'Kakariko Pond Area'), (0x3f, 'Octoballoon Whirlpool', 'Octoballoon Water')),
|
||||
((0x55, 'Qirn Jump Whirlpool', 'Qirn Jump Water'), (0x7f, 'Bomber Corner Whirlpool', 'Bomber Corner Water'))
|
||||
]
|
||||
|
||||
default_flute_connections = [
|
||||
0x0b, 0x16, 0x18, 0x2c, 0x2f, 0x38, 0x3b, 0x3f
|
||||
]
|
||||
|
||||
@@ -93,6 +93,8 @@ Every transition independently is a candidate to be chosen as a cross-world conn
|
||||
|
||||
Note: Only parallel connections (a connection that also exists in the opposite world) are considered for cross-world connections, which means that the same connection in the opposite world will also connect cross-world.
|
||||
|
||||
Note: If Whirlpool Shuffle is enabled, those connections can be cross-world but do not count towards the 9 transitions that are crossed.
|
||||
|
||||
Motive: Why 9 connections? To imitate the effect of the 9 standard portals that exist.
|
||||
|
||||
### Chaos
|
||||
@@ -111,6 +113,10 @@ OW tiles are randomly chosen to become a part of the opposite world. When on the
|
||||
|
||||
Note: Tiles are put into groups that must be shuffled together when certain settings are enabled. For instance, if ER is disabled, then any tiles that have a connector cave that leads to another tile, those tiles must swap together; (an exception to this is the Old Man Rescue cave which has been modified similar to how Inverted modifies it, Old Man Rescue is ALWAYS accessible from the Light World)
|
||||
|
||||
## Whirlpool Shuffle (--ow_whirlpool)
|
||||
|
||||
When enabled, the whirlpool connections are shuffled. If Crossed OW is enabled, the whirlpools can also be cross-world as well. For Limited Crossed OW, this doesn't count towards the limited number of crossed edge transitions.
|
||||
|
||||
## Flute Shuffle (--ow_fluteshuffle)
|
||||
|
||||
When enabled, new flute spots are generated and gives the player the option to cancel out of the flute menu by pressing X.
|
||||
|
||||
7
Rom.py
7
Rom.py
@@ -33,7 +33,7 @@ from source.classes.SFX import randomize_sfx
|
||||
|
||||
|
||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||
RANDOMIZERBASEHASH = 'c6c2a2d5d89a3c84871f58806bbb3acf'
|
||||
RANDOMIZERBASEHASH = 'e9dea70e0a0b15bfa0ff7ecd63228a0c'
|
||||
|
||||
|
||||
class JsonRom(object):
|
||||
@@ -644,6 +644,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(snes_to_pc(0x0AB793 + o), data[11] & 0xff) # Y low byte
|
||||
rom.write_byte(snes_to_pc(0x0AB79B + o), data[11] // 0x100) # Y high byte
|
||||
|
||||
# patch whirlpools
|
||||
if world.owWhirlpoolShuffle[player]:
|
||||
owFlags |= 0x01
|
||||
write_int16s(rom, snes_to_pc(0x02EA5C), world.owwhirlpools[player])
|
||||
|
||||
# patch overworld edges
|
||||
inverted_buffer = [0] * 0x82
|
||||
owMode = 0
|
||||
|
||||
@@ -14,6 +14,10 @@ jsl OWEdgeTransition : nop #4 ;LDA $02A4E3,X : ORA $7EF3CA
|
||||
;org $02e238 ;LDX #$9E : - DEX : DEX : CMP $DAEE,X : BNE -
|
||||
;jsl OWSpecialTransition : nop #5
|
||||
|
||||
; whirlpool shuffle cross world change
|
||||
org $02b3bd
|
||||
jsl OWWhirlpoolUpdate ;JSL $02EA6C
|
||||
|
||||
; flute menu cancel
|
||||
org $0ab7af ;LDA $F2 : ORA $F0 : AND #$C0
|
||||
jml OWFluteCancel2 : nop
|
||||
@@ -123,6 +127,14 @@ OWWorldCheck16:
|
||||
plx : and.w #$00ff : rtl
|
||||
}
|
||||
|
||||
OWWhirlpoolUpdate:
|
||||
{
|
||||
jsl $02ea6c ; what we wrote over
|
||||
lda.l OWFlags : and #$01 : beq +
|
||||
ldx $8a : jsr OWWorldUpdate
|
||||
+ rtl
|
||||
}
|
||||
|
||||
OWFluteCancel:
|
||||
{
|
||||
lda.l OWFlags+1 : and #$01 : bne +
|
||||
@@ -341,32 +353,39 @@ OWNewDestination:
|
||||
sep #$30 : lda OWOppSlotOffset,y : !add $04 : asl : and #$7f : sta $700
|
||||
|
||||
; crossed OW shuffle
|
||||
LDA.l OWMode+1 : AND.b #!FLAG_OW_CROSSED : beq .return
|
||||
ldx $05 : lda.l OWTileWorldAssoc,x : cmp.l $7ef3ca : beq .return
|
||||
sta.l $7ef3ca ; change world
|
||||
lda #$38 : sta $012f ; play sfx - #$3b is an alternative
|
||||
|
||||
; toggle bunny mode
|
||||
+ lda $7ef357 : bne .nobunny
|
||||
lda.l InvertedMode : bne .inverted
|
||||
lda $7ef3ca : and.b #$40 : bra +
|
||||
.inverted lda $7ef3ca : and.b #$40 : eor #$40
|
||||
+ cmp #$40 : bne .nobunny
|
||||
; turn into bunny
|
||||
lda $5d : cmp #$04 : beq + ; if swimming, continue
|
||||
lda #$17 : sta $5d
|
||||
+ lda #$01 : sta $02e0 : sta $56
|
||||
bra .return
|
||||
|
||||
.nobunny
|
||||
lda $5d : cmp #$17 : bne + ; retain current state unless bunny
|
||||
stz $5d
|
||||
+ stz $02e0 : stz $56
|
||||
lda.l OWMode+1 : and.b #!FLAG_OW_CROSSED : beq .return
|
||||
ldx $05 : jsr OWWorldUpdate
|
||||
|
||||
.return
|
||||
lda $05 : sta $8a
|
||||
rep #$30 : rts
|
||||
}
|
||||
OWWorldUpdate: ; x = owid of destination screen
|
||||
{
|
||||
lda.l OWTileWorldAssoc,x : cmp.l $7ef3ca : beq .return
|
||||
sta.l $7ef3ca ; change world
|
||||
lda #$38 : sta $012f ; play sfx - #$3b is an alternative
|
||||
|
||||
; toggle bunny mode
|
||||
+ lda $7ef357 : bne .nobunny
|
||||
lda.l InvertedMode : bne .inverted
|
||||
lda $7ef3ca : and.b #$40 : bra +
|
||||
.inverted lda $7ef3ca : and.b #$40 : eor #$40
|
||||
+ cmp #$40 : bne .nobunny
|
||||
; turn into bunny
|
||||
lda $5d : cmp #$04 : beq + ; if swimming, continue
|
||||
lda #$17 : sta $5d
|
||||
+ lda #$01 : sta $02e0 : sta $56
|
||||
bra .return
|
||||
|
||||
.nobunny
|
||||
lda $5d : cmp #$17 : bne + ; retain current state unless bunny
|
||||
stz $5d
|
||||
+ stz $02e0 : stz $56
|
||||
|
||||
.return
|
||||
rts
|
||||
}
|
||||
OWSpecialTransition:
|
||||
{
|
||||
LDX #$9E
|
||||
@@ -531,7 +550,7 @@ OWNorthEdges:
|
||||
; Min Max Width Mid OW Slot/OWID VRAM *FREE* Dest Index
|
||||
dw $00a0, $00a0, $0000, $00a0, $0000, $0000, $0000, $0040 ;Lost Woods
|
||||
dw $0458, $0540, $00e8, $04cc, $0a0a, $0000, $0000, $0000
|
||||
dw $0f70, $0f90, $0020, $0f80, $0f0f, $0000, $0000, $0041
|
||||
dw $0f38, $0f60, $0028, $0f4c, $0f0f, $0000, $0000, $0041
|
||||
dw $0058, $0058, $0000, $0058, $1010, $0000, $0000, $0001
|
||||
dw $0178, $0178, $0000, $0178, $1010, $0000, $0000, $0002
|
||||
dw $0388, $0388, $0000, $0388, $1111, $0000, $0000, $0003
|
||||
|
||||
Binary file not shown.
@@ -15,6 +15,9 @@
|
||||
overworld_swap:
|
||||
on: 1
|
||||
off: 1
|
||||
whirlpool_shuffle:
|
||||
on: 1
|
||||
off: 1
|
||||
flute_shuffle:
|
||||
vanilla: 0
|
||||
balanced: 1
|
||||
|
||||
@@ -133,6 +133,10 @@
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
},
|
||||
"ow_whirlpool": {
|
||||
"action": "store_true",
|
||||
"type": "bool"
|
||||
},
|
||||
"ow_fluteshuffle": {
|
||||
"choices": [
|
||||
"vanilla",
|
||||
|
||||
@@ -221,6 +221,9 @@
|
||||
"ow_mixed": [
|
||||
"Overworld tiles are randomly chosen to become part of the opposite world."
|
||||
],
|
||||
"ow_whirlpool": [
|
||||
"Whirlpools will be shuffled and paired together."
|
||||
],
|
||||
"ow_fluteshuffle": [
|
||||
"This randomizes the flute spot destinations.",
|
||||
"Vanilla: All flute spots remain unchanged.",
|
||||
|
||||
@@ -123,13 +123,18 @@
|
||||
"randomizer.overworld.crossed.grouped": "Grouped",
|
||||
"randomizer.overworld.crossed.limited": "Limited",
|
||||
"randomizer.overworld.crossed.chaos": "Chaos",
|
||||
|
||||
"randomizer.overworld.keepsimilar": "Keep Similar Edges Together",
|
||||
|
||||
"randomizer.overworld.mixed": "Tile Swap (Mixed)",
|
||||
|
||||
"randomizer.overworld.whirlpool": "Whirlpool Shuffle",
|
||||
|
||||
"randomizer.overworld.overworldflute": "Flute Shuffle",
|
||||
"randomizer.overworld.overworldflute.vanilla": "Vanilla",
|
||||
"randomizer.overworld.overworldflute.balanced": "Balanced",
|
||||
"randomizer.overworld.overworldflute.random": "Random",
|
||||
|
||||
|
||||
"randomizer.entrance.openpyramid": "Pre-open Pyramid Hole",
|
||||
"randomizer.entrance.shuffleganon": "Include Ganon's Tower and Pyramid Hole in shuffle pool",
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
"type": "checkbox",
|
||||
"default": true
|
||||
},
|
||||
"whirlpool": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
},
|
||||
"overworldflute": {
|
||||
"type": "selectbox",
|
||||
"default": "vanilla",
|
||||
|
||||
@@ -79,6 +79,7 @@ SETTINGSTOPROCESS = {
|
||||
"crossed": "ow_crossed",
|
||||
"keepsimilar": "ow_keepsimilar",
|
||||
"mixed": "ow_mixed",
|
||||
"whirlpool": "ow_whirlpool",
|
||||
"overworldflute": "ow_fluteshuffle"
|
||||
},
|
||||
"entrance": {
|
||||
|
||||
@@ -33,7 +33,7 @@ def overworld_page(parent):
|
||||
packAttrs = {"side":LEFT, "pady":(18,0)}
|
||||
elif key == "overworldflute":
|
||||
packAttrs["pady"] = (20,0)
|
||||
elif key == "mixed":
|
||||
elif key in ["whirlpool", "mixed"]:
|
||||
packAttrs = {"anchor":W, "padx":(79,0)}
|
||||
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
Reference in New Issue
Block a user