Merge branch 'OverworldShuffleDev' into OverworldShuffle
This commit is contained in:
@@ -1299,11 +1299,7 @@ class CollectionState(object):
|
||||
def can_flute(self, player):
|
||||
if self.world.mode[player] == 'standard' and not self.has('Zelda Delivered', player):
|
||||
return False # can't flute in rain state
|
||||
if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], self.world.precollected_items)):
|
||||
return True
|
||||
lw = self.world.get_region('Kakariko Area', player)
|
||||
return self.has('Ocarina (Activated)', player) or (self.has('Ocarina', player) and lw.can_reach(self)
|
||||
and self.is_not_bunny(lw, player))
|
||||
return self.has('Ocarina (Activated)', player)
|
||||
|
||||
def can_melt_things(self, player):
|
||||
return self.has('Fire Rod', player) or (self.has('Bombos', player) and self.has_sword(player))
|
||||
@@ -2876,6 +2872,7 @@ class Spoiler(object):
|
||||
'dungeon_counters': self.world.dungeon_counters,
|
||||
'item_pool': self.world.difficulty,
|
||||
'item_functionality': self.world.difficulty_adjustments,
|
||||
'beemizer': self.world.beemizer,
|
||||
'gt_crystals': self.world.crystals_needed_for_gt,
|
||||
'ganon_crystals': self.world.crystals_needed_for_ganon,
|
||||
'open_pyramid': self.world.open_pyramid,
|
||||
@@ -3055,25 +3052,33 @@ class Spoiler(object):
|
||||
if self.world.players > 1:
|
||||
outfile.write('\nPlayer %d: %s\n' % (player, self.world.get_player_names(player)))
|
||||
outfile.write('Settings Code:'.ljust(line_width) + '%s\n' % self.metadata["code"][player])
|
||||
outfile.write('Logic:'.ljust(line_width) + '%s\n' % self.metadata['logic'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Mode:'.ljust(line_width) + '%s\n' % self.metadata['mode'][player])
|
||||
outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player])
|
||||
outfile.write('Logic:'.ljust(line_width) + '%s\n' % self.metadata['logic'][player])
|
||||
outfile.write('Goal:'.ljust(line_width) + '%s\n' % self.metadata['goal'][player])
|
||||
if self.metadata['goal'][player] in ['triforcehunt', 'trinity', 'ganonhunt']:
|
||||
outfile.write('Triforce Pieces Required:'.ljust(line_width) + '%s\n' % self.metadata['triforcegoal'][player])
|
||||
outfile.write('Triforce Pieces Total:'.ljust(line_width) + '%s\n' % self.metadata['triforcepool'][player])
|
||||
outfile.write('Crystals Required for GT:'.ljust(line_width) + '%s\n' % str(self.world.crystals_gt_orig[player]))
|
||||
outfile.write('Crystals Required for Ganon:'.ljust(line_width) + '%s\n' % str(self.world.crystals_ganon_orig[player]))
|
||||
outfile.write('Swords:'.ljust(line_width) + '%s\n' % self.metadata['weapons'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Accessibility:'.ljust(line_width) + '%s\n' % self.metadata['accessibility'][player])
|
||||
outfile.write('Restricted Boss Items:'.ljust(line_width) + '%s\n' % self.metadata['restricted_boss_items'][player])
|
||||
outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player])
|
||||
outfile.write('Item Functionality:'.ljust(line_width) + '%s\n' % self.metadata['item_functionality'][player])
|
||||
outfile.write('Difficulty:'.ljust(line_width) + '%s\n' % self.metadata['item_pool'][player])
|
||||
outfile.write('Flute Mode:'.ljust(line_width) + '%s\n' % self.metadata['flute_mode'][player])
|
||||
outfile.write('Bow Mode:'.ljust(line_width) + '%s\n' % self.metadata['bow_mode'][player])
|
||||
outfile.write('Take Any Caves:'.ljust(line_width) + '%s\n' % self.metadata['take_any'][player])
|
||||
outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % yn(self.metadata['shopsanity'][player]))
|
||||
outfile.write('Beemizer:'.ljust(line_width) + '%s\n' % self.metadata['beemizer'][player])
|
||||
outfile.write('Bombbag:'.ljust(line_width) + '%s\n' % yn(self.metadata['bombbag'][player]))
|
||||
outfile.write('Pseudoboots:'.ljust(line_width) + '%s\n' % yn(self.metadata['pseudoboots'][player]))
|
||||
outfile.write('\n')
|
||||
outfile.write('Shopsanity:'.ljust(line_width) + '%s\n' % yn(self.metadata['shopsanity'][player]))
|
||||
outfile.write('Bonk Drops:'.ljust(line_width) + '%s\n' % yn(self.metadata['bonk_drops'][player]))
|
||||
outfile.write('Pottery Mode:'.ljust(line_width) + '%s\n' % self.metadata['pottery'][player])
|
||||
outfile.write('Pot Shuffle (Legacy):'.ljust(line_width) + '%s\n' % yn(self.metadata['potshuffle'][player]))
|
||||
outfile.write('Enemy Drop Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['dropshuffle'][player]))
|
||||
outfile.write('Take Any Caves:'.ljust(line_width) + '%s\n' % self.metadata['take_any'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Overworld Layout Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_shuffle'][player])
|
||||
if self.metadata['ow_shuffle'][player] != 'vanilla':
|
||||
outfile.write('Free Terrain:'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_terrain'][player]))
|
||||
@@ -3083,35 +3088,37 @@ class Spoiler(object):
|
||||
outfile.write('OW Tile Flip (Mixed):'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_mixed'][player]))
|
||||
outfile.write('Whirlpool Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['ow_whirlpool'][player]))
|
||||
outfile.write('Flute Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['ow_fluteshuffle'][player])
|
||||
outfile.write('Bonk Drops:'.ljust(line_width) + '%s\n' % yn(self.metadata['bonk_drops'][player]))
|
||||
outfile.write('\n')
|
||||
outfile.write('Entrance Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['shuffle'][player])
|
||||
if self.metadata['shuffle'][player] != 'vanilla':
|
||||
outfile.write('Shuffle GT/Ganon:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffleganon'][player]))
|
||||
outfile.write('Shuffle Links:'.ljust(line_width) + '%s\n' % yn(self.metadata['shufflelinks'][player]))
|
||||
outfile.write('Shuffle Tavern:'.ljust(line_width) + '%s\n' % yn(self.metadata['shuffletavern'][player]))
|
||||
outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][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('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['mapshuffle'][player]))
|
||||
outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['compassshuffle'][player]))
|
||||
outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player])
|
||||
outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['bigkeyshuffle'][player]))
|
||||
outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Door Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['door_shuffle'][player])
|
||||
if self.metadata['door_shuffle'][player] != 'vanilla':
|
||||
outfile.write('Intensity:'.ljust(line_width) + '%s\n' % self.metadata['intensity'][player])
|
||||
outfile.write('Door Type Mode:'.ljust(line_width) + '%s\n' % self.metadata['door_type_mode'][player])
|
||||
outfile.write('Trap Door Mode:'.ljust(line_width) + '%s\n' % self.metadata['trap_door_mode'][player])
|
||||
outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player])
|
||||
outfile.write('Decouple Doors:'.ljust(line_width) + '%s\n' % yn(self.metadata['decoupledoors'][player]))
|
||||
outfile.write('Experimental:'.ljust(line_width) + '%s\n' % yn(self.metadata['experimental'][player]))
|
||||
outfile.write('Dungeon Counters:'.ljust(line_width) + '%s\n' % self.metadata['dungeon_counters'][player])
|
||||
outfile.write('Enemy Drop Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['dropshuffle'][player]))
|
||||
outfile.write('Pottery Mode:'.ljust(line_width) + '%s\n' % self.metadata['pottery'][player])
|
||||
outfile.write('Pot Shuffle (Legacy):'.ljust(line_width) + '%s\n' % yn(self.metadata['potshuffle'][player]))
|
||||
outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['mapshuffle'][player]))
|
||||
outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['compassshuffle'][player]))
|
||||
outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player])
|
||||
outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['bigkeyshuffle'][player]))
|
||||
outfile.write('\n')
|
||||
outfile.write('Boss Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['boss_shuffle'][player])
|
||||
outfile.write('Enemy Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['enemy_shuffle'][player])
|
||||
outfile.write('Enemy Health:'.ljust(line_width) + '%s\n' % self.metadata['enemy_health'][player])
|
||||
outfile.write('Enemy Damage:'.ljust(line_width) + '%s\n' % self.metadata['enemy_damage'][player])
|
||||
outfile.write('\n')
|
||||
outfile.write('Pseudoboots:'.ljust(line_width) + '%s\n' % yn(self.metadata['pseudoboots'][player]))
|
||||
outfile.write('Hints:'.ljust(line_width) + '%s\n' % yn(self.metadata['hints'][player]))
|
||||
outfile.write('Race:'.ljust(line_width) + '%s\n' % yn(self.world.settings.world_rep['meta']['race']))
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.3.0.5
|
||||
- Major reorganization to GUI Options
|
||||
- Corrected various fake world behavior in glitched modes
|
||||
- Fixed various issues with glitched mode logic
|
||||
- Various minor logic fixes
|
||||
|
||||
## 0.3.0.4
|
||||
- \~Merged in DR v1.2.0.14~
|
||||
- Fixed issue with enemy drops on OW enemies
|
||||
|
||||
8
Gui.py
8
Gui.py
@@ -144,14 +144,14 @@ def guiMain(args=None):
|
||||
self.pages["randomizer"].pages["entrance"] = entrando_page(self.pages["randomizer"].notebook)
|
||||
self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["entrance"], text="Entrances")
|
||||
|
||||
# Dungeons
|
||||
self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook)
|
||||
self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeons")
|
||||
|
||||
# Enemizer
|
||||
self.pages["randomizer"].pages["enemizer"],self.settings = enemizer_page(self.pages["randomizer"].notebook,self.settings)
|
||||
self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["enemizer"], text="Enemizer")
|
||||
|
||||
# Dungeon Shuffle
|
||||
self.pages["randomizer"].pages["dungeon"] = dungeon_page(self.pages["randomizer"].notebook)
|
||||
self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["dungeon"], text="Dungeon Shuffle")
|
||||
|
||||
# Multiworld
|
||||
# self.pages["randomizer"].pages["multiworld"],self.settings = multiworld_page(self.pages["randomizer"].notebook,self.settings)
|
||||
# self.pages["randomizer"].notebook.add(self.pages["randomizer"].pages["multiworld"], text="Multiworld")
|
||||
|
||||
17
ItemList.py
17
ItemList.py
@@ -212,6 +212,20 @@ def generate_itempool(world, player):
|
||||
loc.locked = True
|
||||
loc.forced_item = loc.item
|
||||
|
||||
if not world.is_tile_swapped(0x18, player):
|
||||
region = world.get_region('Kakariko Area',player)
|
||||
|
||||
loc = Location(player, "Flute Activation", parent=region)
|
||||
region.locations.append(loc)
|
||||
world.dynamic_locations.append(loc)
|
||||
|
||||
world.clear_location_cache()
|
||||
|
||||
world.push_item(loc, ItemFactory('Ocarina (Activated)', player), False)
|
||||
loc.event = True
|
||||
loc.locked = True
|
||||
loc.forced_item = loc.item
|
||||
|
||||
world.get_location('Ganon', player).event = True
|
||||
world.get_location('Ganon', player).locked = True
|
||||
world.push_item(world.get_location('Agahnim 1', player), ItemFactory('Beat Agahnim 1', player), False)
|
||||
@@ -1433,6 +1447,9 @@ def make_customizer_pool(world, player):
|
||||
place_item('Master Sword Pedestal', 'Triforce')
|
||||
|
||||
guaranteed_items = alwaysitems + ['Magic Mirror', 'Moon Pearl']
|
||||
if world.is_tile_swapped(0x18, player) or world.flute_mode[player] == 'active':
|
||||
guaranteed_items.remove('Ocarina')
|
||||
guaranteed_items.append('Ocarina (Activated)')
|
||||
missing_items = []
|
||||
if world.shopsanity[player]:
|
||||
guaranteed_items.extend(['Blue Potion', 'Green Potion', 'Red Potion'])
|
||||
|
||||
2
Main.py
2
Main.py
@@ -785,7 +785,7 @@ def create_playthrough(world):
|
||||
# get locations containing progress items
|
||||
prog_locations = [location for location in world.get_filled_locations() if location.item.advancement
|
||||
or world.goal[location.player] == 'completionist']
|
||||
optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile']
|
||||
optional_locations = ['Trench 1 Switch', 'Trench 2 Switch', 'Ice Block Drop', 'Skull Star Tile', 'Flute Activation']
|
||||
optional_locations.extend(['Hyrule Castle Courtyard Tree Pull', 'Mountain Entry Area Tree Pull']) # adding pre-aga tree pulls
|
||||
optional_locations.extend(['Lumberjack Area Crab Drop', 'South Pass Area Crab Drop']) # adding pre-aga bush crabs
|
||||
state_cache = [None]
|
||||
|
||||
@@ -1182,6 +1182,7 @@ OWTileRegions = bidict({
|
||||
'East Dark Death Mountain (Top)': 0x45,
|
||||
'East Dark Death Mountain (Bottom Left)': 0x45,
|
||||
'East Dark Death Mountain (Bottom)': 0x45,
|
||||
'East Dark Death Mountain (Bushes)': 0x45,
|
||||
'Dark Death Mountain Ledge': 0x45,
|
||||
'Dark Death Mountain Isolated Ledge': 0x45,
|
||||
'Dark Death Mountain Floating Island': 0x45,
|
||||
|
||||
@@ -512,5 +512,5 @@ mirror_clips = [
|
||||
|
||||
mirror_offsets = [
|
||||
(['DM Offset Mirror', 'DDM Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Courtyard Northeast', 'Pyramid Crack'], ['Pyramid Area', 'Hyrule Castle Courtyard']),
|
||||
(['DM To HC Ledge Offset Mirror', 'DDM To HC Ledge Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', None], ['Pyramid Area', None])
|
||||
(['DM To HC Ledge Offset Mirror', 'DDM To Pyramid Offset Mirror'], ['West Death Mountain (Bottom)', 'West Dark Death Mountain (Bottom)'], ['Hyrule Castle Ledge', 'Pyramid Area'], ['Pyramid Area', 'Hyrule Castle Area'])
|
||||
]
|
||||
@@ -7,7 +7,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
|
||||
from OverworldGlitchRules import create_owg_connections
|
||||
from Utils import bidict
|
||||
|
||||
version_number = '0.3.0.4'
|
||||
version_number = '0.3.0.5'
|
||||
# branch indicator is intentionally different across branches
|
||||
version_branch = ''
|
||||
|
||||
@@ -973,27 +973,26 @@ def can_reach_smith(world, player):
|
||||
region = world.get_region(region_name, player)
|
||||
for exit in region.exits:
|
||||
if not found and exit.connected_region is not None:
|
||||
if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], world.precollected_items)) and exit.spot_type == 'Flute':
|
||||
fluteregion = exit.connected_region
|
||||
for flutespot in fluteregion.exits:
|
||||
if exit.spot_type == 'Flute':
|
||||
if any(map(lambda i: i.name == 'Ocarina (Activated)', world.precollected_items)):
|
||||
for flutespot in exit.connected_region.exits:
|
||||
if flutespot.connected_region and flutespot.connected_region.name not in explored_regions:
|
||||
explore_region(flutespot.connected_region.name, flutespot.connected_region)
|
||||
elif exit.connected_region.name not in explored_regions \
|
||||
and exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld] \
|
||||
and exit.access_rule(blank_state):
|
||||
explore_region(exit.connected_region.name, exit.connected_region)
|
||||
elif exit.name == 'Sanctuary S':
|
||||
sanc_region = exit.connected_region
|
||||
if len(sanc_region.exits) and sanc_region.exits[0].name == 'Sanctuary Exit':
|
||||
explore_region(sanc_region.exits[0].connected_region.name, sanc_region.exits[0].connected_region)
|
||||
elif exit.connected_region.name == 'Blacksmiths Hut' and exit.access_rule(blank_state):
|
||||
found = True
|
||||
return
|
||||
elif exit.connected_region.name not in explored_regions:
|
||||
if (region.type == RegionType.Dungeon and exit.connected_region.name.endswith(' Portal')) \
|
||||
or (exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld] \
|
||||
and exit.access_rule(blank_state)):
|
||||
explore_region(exit.connected_region.name, exit.connected_region)
|
||||
|
||||
blank_state = CollectionState(world)
|
||||
if world.mode[player] == 'standard':
|
||||
blank_state.collect(ItemFactory('Zelda Delivered', player), True)
|
||||
if world.logic[player] in ['noglitches', 'minorglitches'] and world.get_region('Frog Prison', player).type == (RegionType.DarkWorld if not invFlag else RegionType.LightWorld):
|
||||
if world.logic[player] in ['noglitches', 'minorglitches'] and not world.is_tile_swapped(0x29, player):
|
||||
blank_state.collect(ItemFactory('Titans Mitts', player), True)
|
||||
blank_state.collect(ItemFactory('Moon Pearl', player), True)
|
||||
|
||||
found = False
|
||||
explored_regions = list()
|
||||
@@ -1004,6 +1003,10 @@ def can_reach_smith(world, player):
|
||||
explore_region(start_region)
|
||||
if not found:
|
||||
if not invFlag:
|
||||
if world.intensity[player] >= 3 and world.doorShuffle[player] != 'vanilla':
|
||||
sanc_mirror = world.get_entrance('Sanctuary Mirror Route', player)
|
||||
explore_region(sanc_mirror.connected_region.name, sanc_mirror.connected_region)
|
||||
else:
|
||||
explore_region('Sanctuary')
|
||||
else:
|
||||
explore_region('Dark Sanctuary Hint')
|
||||
@@ -1089,7 +1092,7 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F
|
||||
region = base_world.get_region(region_name, player)
|
||||
for exit in region.exits:
|
||||
if exit.connected_region is not None:
|
||||
if any(map(lambda i: i.name in ['Ocarina', 'Ocarina (Activated)'], base_world.precollected_items)) and exit.spot_type == 'Flute':
|
||||
if any(map(lambda i: i.name == 'Ocarina (Activated)', base_world.precollected_items)) and exit.spot_type == 'Flute':
|
||||
fluteregion = exit.connected_region
|
||||
for flutespot in fluteregion.exits:
|
||||
if flutespot.connected_region and flutespot.connected_region.name not in explored_regions:
|
||||
@@ -1448,11 +1451,6 @@ mandatory_connections = [('Old Man S&Q', 'Old Man House'),
|
||||
('Bomber Corner Pier', 'Bomber Corner Area'),
|
||||
|
||||
# OWG In-Bounds Connections
|
||||
('Stone Bridge EC Cliff Water Drop', 'Stone Bridge Water'), #fake flipper
|
||||
('Tree Line WC Cliff Water Drop', 'Tree Line Water'), #fake flipper,
|
||||
|
||||
('Hammer Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), #fake flipper
|
||||
('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water'), #fake flipper
|
||||
('Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Bank'),
|
||||
('Ice Lake Moat Bomb Jump', 'Ice Lake Moat')
|
||||
]
|
||||
@@ -1552,12 +1550,20 @@ ow_connections = {
|
||||
('Stone Bridge East Ledge Drop', 'Stone Bridge North Area'), # OWG
|
||||
('Hammer Bridge North Ledge Drop', 'Hammer Bridge North Area'), # OWG
|
||||
('Stone Bridge Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG
|
||||
('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area') # OWG
|
||||
('Hammer Bridge South Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG
|
||||
('Stone Bridge EC Cliff Water Drop', 'Stone Bridge Water'), # fake flipper
|
||||
('Hammer Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), # fake flipper
|
||||
('Tree Line WC Cliff Water Drop', 'Tree Line Water'), # fake flipper
|
||||
('Dark Tree Line WC Cliff Water Drop', 'Dark Tree Line Water') # fake flipper
|
||||
], [
|
||||
('Stone Bridge East Ledge Drop', 'Hammer Bridge North Area'), # OWG
|
||||
('Hammer Bridge North Ledge Drop', 'Stone Bridge North Area'), # OWG
|
||||
('Stone Bridge Cliff Ledge Drop', 'Hammer Bridge South Area'), # OWG
|
||||
('Hammer Bridge South Cliff Ledge Drop', 'Stone Bridge South Area') # OWG
|
||||
('Hammer Bridge South Cliff Ledge Drop', 'Stone Bridge South Area'), # OWG
|
||||
('Stone Bridge EC Cliff Water Drop', 'Hammer Bridge Water'), # fake flipper
|
||||
('Hammer Bridge EC Cliff Water Drop', 'Stone Bridge Water'), # fake flipper
|
||||
('Tree Line WC Cliff Water Drop', 'Dark Tree Line Water'), # fake flipper
|
||||
('Dark Tree Line WC Cliff Water Drop', 'Tree Line Water') # fake flipper
|
||||
]),
|
||||
0x2e: ([
|
||||
('Tree Line Ledge Drop', 'Tree Line Area'), # OWG
|
||||
|
||||
11
Rom.py
11
Rom.py
@@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127
|
||||
|
||||
|
||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||
RANDOMIZERBASEHASH = '0a3d1d4bbec659013be5ed876c2658bd'
|
||||
RANDOMIZERBASEHASH = '92c16c60f26218c9aec838ce204c0b1e'
|
||||
|
||||
|
||||
class JsonRom(object):
|
||||
@@ -936,6 +936,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
if should_be_bunny(old_man_house, world.mode[player]):
|
||||
rom.write_bytes(0x13fff4, [0xe4, 0x00])
|
||||
|
||||
old_man_cave = world.get_entrance('Old Man Cave Exit (East)', player)
|
||||
if old_man_cave.connected_region.type == RegionType.DarkWorld:
|
||||
rom.write_byte(0x13fff6, 0x40)
|
||||
|
||||
# patch doors
|
||||
if world.doorShuffle[player] not in ['vanilla', 'basic']:
|
||||
rom.write_byte(0x138002, 2)
|
||||
@@ -1364,7 +1368,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x180212, warningflags) # Warning flags
|
||||
|
||||
# assorted fixes
|
||||
rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1
|
||||
rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world[player] else 0x00) # remain in real dark world when dying in dark world dungeon before killing aga1
|
||||
rom.write_byte(0x180169, 0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence.
|
||||
if world.is_atgt_swapped(player):
|
||||
rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted
|
||||
@@ -2308,10 +2312,9 @@ def write_strings(rom, world, player, team):
|
||||
# of how many exist. This supports many settings well.
|
||||
items_to_hint = RelevantItems.copy()
|
||||
flute_item = 'Ocarina'
|
||||
if world.is_tile_swapped(0x18, player):
|
||||
if world.is_tile_swapped(0x18, player) or world.flute_mode[player] == 'active':
|
||||
items_to_hint.remove(flute_item)
|
||||
flute_item = 'Ocarina (Activated)'
|
||||
items_to_hint.append(flute_item)
|
||||
if world.owShuffle[player] != 'vanilla' or world.owMixed[player]:
|
||||
# Adding a guaranteed hint for the Flute in overworld shuffle.
|
||||
this_location = world.find_items_not_key_only(flute_item, player)
|
||||
|
||||
12
Rules.py
12
Rules.py
@@ -70,6 +70,13 @@ def set_rules(world, player):
|
||||
elif world.goal[player] == 'completionist':
|
||||
add_rule(world.get_location('Ganon', player), lambda state: state.everything(player))
|
||||
|
||||
if not world.is_tile_swapped(0x18, player):
|
||||
if not world.is_copied_world:
|
||||
# Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory
|
||||
# kak_region = self.world.get_region('Kakariko Area', player)
|
||||
# add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player) and state.is_not_bunny(kak_region, player))
|
||||
add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player))
|
||||
|
||||
# if swamp and dam have not been moved we require mirror for swamp palace
|
||||
if not world.swamp_patch_required[player]:
|
||||
add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(player))
|
||||
@@ -1214,6 +1221,7 @@ def ow_bunny_rules(world, player):
|
||||
add_bunny_rule(world.get_entrance('Lake Hylia Northeast Water Drop', player), player)
|
||||
add_bunny_rule(world.get_entrance('Lake Hylia Central Water Drop', player), player)
|
||||
add_bunny_rule(world.get_entrance('Lake Hylia Island Water Drop', player), player)
|
||||
add_bunny_rule(world.get_entrance('Lake Hylia Water D Leave', player), player)
|
||||
add_bunny_rule(world.get_entrance('Ice Cave SW', player), player)
|
||||
add_bunny_rule(world.get_entrance('Octoballoon Water Drop', player), player)
|
||||
add_bunny_rule(world.get_entrance('Octoballoon Waterfall Water Drop', player), player)
|
||||
@@ -1368,9 +1376,9 @@ def add_conditional_lamps(world, player):
|
||||
is_dark = False
|
||||
if not world.sewer_light_cone[player]:
|
||||
is_dark = True
|
||||
elif world.doorShuffle[player] != 'crossed' and not info['sewer']:
|
||||
elif world.doorShuffle[player] not in ['partitioned', 'crossed'] and not info['sewer']:
|
||||
is_dark = True
|
||||
elif world.doorShuffle[player] == 'crossed':
|
||||
elif world.doorShuffle[player] in ['partitioned', 'crossed']:
|
||||
sewer_builder = world.dungeon_layouts[player]['Hyrule Castle']
|
||||
is_dark = region not in sewer_builder.master_sector.region_set()
|
||||
if is_dark:
|
||||
|
||||
@@ -860,16 +860,17 @@ OWNewDestination:
|
||||
{
|
||||
tya : sta $4202 : lda #16 : sta $4203 ;wait 8 cycles
|
||||
rep #$20 : txa : nop : !add $4216 : tax ;a = offset to dest record
|
||||
lda.w $0006,x : sta $06 ;set coord
|
||||
lda.w $0008,x : sta $04 ;save dest OW slot/ID
|
||||
lda.w $000a,x : sta $84 ;VRAM
|
||||
ldy $20 : lda $418 : dec #2 : bpl + : ldy $22 : + sty $06
|
||||
|
||||
;;22 e0 e2 61c 61e - X
|
||||
;;20 e6 e8 618 61a - Y
|
||||
;keep current position if within incoming gap
|
||||
lda.w $0000,x : and #$01ff : pha : lda.w $0002,x : and #$01ff : pha
|
||||
ldy $20 : lda $418 : dec #2 : bpl + : ldy $22
|
||||
+ tya : and #$01ff : cmp 3,s : !blt .adjustMainAxis
|
||||
LDA.l OWMode : AND.w #$0007 : BEQ .noLayoutShuffle ;temporary fix until VRAM issues are solved
|
||||
lda.w $0006,x : sta $06 ;set coord
|
||||
lda.w $000a,x : sta $84 ;VRAM
|
||||
tya : and #$01ff : cmp 3,s : !blt .adjustMainAxis
|
||||
dec : cmp 1,s : !bge .adjustMainAxis
|
||||
inc : pha : lda $06 : and #$fe00 : !add 1,s : sta $06 : pla
|
||||
|
||||
@@ -885,6 +886,7 @@ OWNewDestination:
|
||||
LDA $84 : SEC : SBC #$0400 : AND #$0F00 : ASL : XBA : STA $88 ; vram
|
||||
LDA $84 : SEC : SBC #$0010 : AND #$003E : LSR : STA $86
|
||||
|
||||
.noLayoutShuffle
|
||||
LDA.w $000F,X : AND.w #$00FF : STA.w $06FC ; position to walk to after transition (if non-zero)
|
||||
|
||||
LDY.w #$0000
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,22 @@
|
||||
{
|
||||
"startHeader": {
|
||||
"usestartinventory": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [10,0],
|
||||
"pady": [10,10]
|
||||
}
|
||||
}
|
||||
},
|
||||
"customHeader": {
|
||||
"usecustompool": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [10,0],
|
||||
"pady": [10,10]
|
||||
}
|
||||
}
|
||||
},
|
||||
"itemList1": {
|
||||
"bow": {
|
||||
"type": "textbox",
|
||||
|
||||
@@ -57,21 +57,7 @@
|
||||
"randomizer.dungeon.smallkeyshuffle.wild": "Randomized",
|
||||
"randomizer.dungeon.smallkeyshuffle.universal": "Universal",
|
||||
"randomizer.dungeon.bigkeyshuffle": "Big Keys",
|
||||
"randomizer.dungeon.keydropshuffle": "Key Drop Shuffle (Legacy)",
|
||||
"randomizer.dungeon.decoupledoors": "Decouple Doors",
|
||||
"randomizer.dungeon.dropshuffle": "Shuffle Enemy Key Drops",
|
||||
"randomizer.dungeon.potshuffle": "Pot Shuffle (Legacy)",
|
||||
"randomizer.dungeon.pottery": "Pottery",
|
||||
"randomizer.dungeon.pottery.none": "None",
|
||||
"randomizer.dungeon.pottery.keys": "Key Pots",
|
||||
"randomizer.dungeon.pottery.cave": "Cave Pots",
|
||||
"randomizer.dungeon.pottery.cavekeys": "Cave+Key Pots",
|
||||
"randomizer.dungeon.pottery.reduced": "Reduced Dungeon Pots (Dynamic)",
|
||||
"randomizer.dungeon.pottery.clustered": "Clustered Dungeon Pots (Dynamic)",
|
||||
"randomizer.dungeon.pottery.nonempty": "Excludes Empty Pots",
|
||||
"randomizer.dungeon.pottery.dungeon": "Dungeon Pots",
|
||||
"randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)",
|
||||
"randomizer.dungeon.colorizepots": "Colorize Randomized Pots",
|
||||
|
||||
"randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle",
|
||||
"randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla",
|
||||
@@ -123,7 +109,7 @@
|
||||
"randomizer.enemizer.enemyshuffle.none": "None",
|
||||
"randomizer.enemizer.enemyshuffle.shuffled": "Shuffled",
|
||||
"randomizer.enemizer.enemyshuffle.random": "Random",
|
||||
"randomizer.enemizer.enemyshuffle.legacy": "Random (including Thieves)",
|
||||
"randomizer.enemizer.enemyshuffle.legacy": "Random (50/50 Thieves)",
|
||||
|
||||
"randomizer.enemizer.bossshuffle": "Boss Shuffle",
|
||||
"randomizer.enemizer.bossshuffle.none": "None",
|
||||
@@ -168,8 +154,6 @@
|
||||
|
||||
"randomizer.overworld.whirlpool": "Whirlpool Shuffle",
|
||||
|
||||
"randomizer.overworld.bonk_drops": "Bonk Drops",
|
||||
|
||||
"randomizer.overworld.overworldflute": "Flute Shuffle",
|
||||
"randomizer.overworld.overworldflute.vanilla": "Vanilla",
|
||||
"randomizer.overworld.overworldflute.balanced": "Balanced",
|
||||
@@ -200,11 +184,6 @@
|
||||
"randomizer.entrance.entranceshuffle.dungeonsfull": "Dungeons + Full",
|
||||
"randomizer.entrance.entranceshuffle.dungeonssimple": "Dungeons + Simple",
|
||||
|
||||
"randomizer.entrance.take_any": "Take Any Caves",
|
||||
"randomizer.entrance.take_any.none": "None",
|
||||
"randomizer.entrance.take_any.random": "Random",
|
||||
"randomizer.entrance.take_any.fixed": "Fixed",
|
||||
|
||||
"randomizer.gameoptions.nobgm": "Disable Music & MSU-1",
|
||||
"randomizer.gameoptions.quickswap": "L/R Quickswapping",
|
||||
"randomizer.gameoptions.reduce_flashing": "Reduce Flashing",
|
||||
@@ -253,9 +232,6 @@
|
||||
"randomizer.generation.createrom": "Create Patched ROM",
|
||||
"randomizer.generation.calcplaythrough": "Calculate Playthrough",
|
||||
"randomizer.generation.print_custom_yaml": "Print Customizer File",
|
||||
"randomizer.generation.usestartinventory": "Use Starting Inventory",
|
||||
"randomizer.generation.usecustompool": "Use Custom Item Pool",
|
||||
"randomizer.generation.race": "Generate \"Race\" ROM",
|
||||
|
||||
"randomizer.generation.saveonexit": "Save Settings on Exit",
|
||||
"randomizer.generation.saveonexit.ask": "Ask Me",
|
||||
@@ -267,10 +243,10 @@
|
||||
"randomizer.generation.rom.dialog.romfiles": "Rom Files",
|
||||
"randomizer.generation.rom.dialog.allfiles": "All Files",
|
||||
|
||||
"randomizer.item.hints": "Include Helpful Hints",
|
||||
"randomizer.item.hints": "Hints",
|
||||
"randomizer.item.race": "Generate \"Race\" ROM",
|
||||
"randomizer.item.retro": "Retro mode",
|
||||
"randomizer.item.pseudoboots": "Start with Pseudo Boots",
|
||||
"randomizer.item.bombbag": "Bombbag",
|
||||
"randomizer.item.pseudoboots": "Pseudoboots",
|
||||
|
||||
"randomizer.item.worldstate": "World State",
|
||||
"randomizer.item.worldstate.standard": "Standard",
|
||||
@@ -322,25 +298,67 @@
|
||||
"randomizer.item.weapons.swordless": "Swordless",
|
||||
"randomizer.item.weapons.vanilla": "Vanilla",
|
||||
|
||||
"randomizer.item.beemizer": "Beemizer",
|
||||
"randomizer.item.beemizer.0": "No Bee Traps",
|
||||
"randomizer.item.beemizer.1": "25% Bee Traps",
|
||||
"randomizer.item.beemizer.2": "40% Traps, 20% Refills",
|
||||
"randomizer.item.beemizer.3": "50% Traps, 50% Refills",
|
||||
"randomizer.item.beemizer.4": "100% Bee Traps",
|
||||
"randomizer.item.sortingalgo": "Item Fill",
|
||||
"randomizer.item.sortingalgo.balanced": "Balanced",
|
||||
"randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill",
|
||||
"randomizer.item.sortingalgo.major_only": "Major Location Restriction",
|
||||
"randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction",
|
||||
"randomizer.item.sortingalgo.district": "District Restriction",
|
||||
|
||||
"randomizer.item.itempool": "Item Pool",
|
||||
"randomizer.item.itempool.normal": "Normal",
|
||||
"randomizer.item.itempool.hard": "Hard",
|
||||
"randomizer.item.itempool.expert": "Expert",
|
||||
"randomizer.item.accessibility": "Accessibility",
|
||||
"randomizer.item.accessibility.items": "100% Inventory",
|
||||
"randomizer.item.accessibility.locations": "100% Locations",
|
||||
"randomizer.item.accessibility.none": "Beatable",
|
||||
|
||||
"randomizer.item.shopsanity": "Shopsanity",
|
||||
"randomizer.item.restrict_boss_items": "Forbidden Boss Items",
|
||||
"randomizer.item.restrict_boss_items.none": "None",
|
||||
"randomizer.item.restrict_boss_items.mapcompass": "Map & Compass",
|
||||
"randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys",
|
||||
|
||||
"randomizer.item.itemfunction": "Item Functionality",
|
||||
"randomizer.item.itemfunction.normal": "Normal",
|
||||
"randomizer.item.itemfunction.hard": "Hard",
|
||||
"randomizer.item.itemfunction.expert": "Expert",
|
||||
|
||||
"randomizer.item.timer": "Timer Setting",
|
||||
"randomizer.item.timer.none": "No Timer",
|
||||
"randomizer.item.timer.display": "Stopwatch",
|
||||
"randomizer.item.timer.timed": "Timed",
|
||||
"randomizer.item.timer.timed-ohko": "Timed OHKO",
|
||||
"randomizer.item.timer.ohko": "OHKO",
|
||||
"randomizer.item.timer.timed-countdown": "Timed Countdown",
|
||||
|
||||
"randomizer.item.shopsanity": "Shopsanity",
|
||||
|
||||
"randomizer.item.bonk_drops": "Bonk Drops",
|
||||
|
||||
"randomizer.item.pottery": "Pottery",
|
||||
"randomizer.item.pottery.none": "None",
|
||||
"randomizer.item.pottery.keys": "Key Pots",
|
||||
"randomizer.item.pottery.cave": "Cave Pots",
|
||||
"randomizer.item.pottery.cavekeys": "Cave+Key Pots",
|
||||
"randomizer.item.pottery.reduced": "Reduced Dungeon Pots (Dynamic)",
|
||||
"randomizer.item.pottery.clustered": "Clustered Dungeon Pots (Dynamic)",
|
||||
"randomizer.item.pottery.nonempty": "Excludes Empty Pots",
|
||||
"randomizer.item.pottery.dungeon": "Dungeon Pots",
|
||||
"randomizer.item.pottery.lottery": "Lottery (All Pots and Large Blocks)",
|
||||
|
||||
"randomizer.item.colorizepots": "Colorize Randomized Pots",
|
||||
"randomizer.item.potshuffle": "Pot Shuffle (Legacy)",
|
||||
|
||||
"randomizer.item.dropshuffle": "Shuffle Enemy Key Drops",
|
||||
"randomizer.item.keydropshuffle": "Key Drop Shuffle (Legacy)",
|
||||
|
||||
"randomizer.item.take_any": "Take Any Caves",
|
||||
"randomizer.item.take_any.none": "None",
|
||||
"randomizer.item.take_any.random": "Random",
|
||||
"randomizer.item.take_any.fixed": "Fixed",
|
||||
|
||||
"randomizer.item.itempool": "Item Pool",
|
||||
"randomizer.item.itempool.normal": "Normal",
|
||||
"randomizer.item.itempool.hard": "Hard",
|
||||
"randomizer.item.itempool.expert": "Expert",
|
||||
|
||||
"randomizer.item.flute_mode": "Flute Mode",
|
||||
"randomizer.item.flute_mode.normal": "Normal",
|
||||
"randomizer.item.flute_mode.active": "Pre-Activated",
|
||||
@@ -351,30 +369,17 @@
|
||||
"randomizer.item.bow_mode.retro": "Retro (Progressive)",
|
||||
"randomizer.item.bow_mode.retro_silvers": "Retro + Silvers",
|
||||
|
||||
"randomizer.item.timer": "Timer Setting",
|
||||
"randomizer.item.timer.none": "No Timer",
|
||||
"randomizer.item.timer.display": "Stopwatch",
|
||||
"randomizer.item.timer.timed": "Timed",
|
||||
"randomizer.item.timer.timed-ohko": "Timed OHKO",
|
||||
"randomizer.item.timer.ohko": "OHKO",
|
||||
"randomizer.item.timer.timed-countdown": "Timed Countdown",
|
||||
"randomizer.item.beemizer": "Beemizer",
|
||||
"randomizer.item.beemizer.0": "No Bee Traps",
|
||||
"randomizer.item.beemizer.1": "25% Bee Traps",
|
||||
"randomizer.item.beemizer.2": "40% Traps, 20% Refills",
|
||||
"randomizer.item.beemizer.3": "50% Traps, 50% Refills",
|
||||
"randomizer.item.beemizer.4": "100% Bee Traps",
|
||||
|
||||
"randomizer.item.accessibility": "Accessibility",
|
||||
"randomizer.item.accessibility.items": "100% Inventory",
|
||||
"randomizer.item.accessibility.locations": "100% Locations",
|
||||
"randomizer.item.accessibility.none": "Beatable",
|
||||
"randomizer.item.bombbag": "Bombbag",
|
||||
|
||||
"randomizer.item.sortingalgo": "Item Sorting",
|
||||
"randomizer.item.sortingalgo.balanced": "Balanced",
|
||||
"randomizer.item.sortingalgo.vanilla_fill": "Vanilla Fill",
|
||||
"randomizer.item.sortingalgo.major_only": "Major Location Restriction",
|
||||
"randomizer.item.sortingalgo.dungeon_only": "Dungeon Restriction",
|
||||
"randomizer.item.sortingalgo.district": "District Restriction",
|
||||
|
||||
"randomizer.item.restrict_boss_items": "Forbidden Boss Items",
|
||||
"randomizer.item.restrict_boss_items.none": "None",
|
||||
"randomizer.item.restrict_boss_items.mapcompass": "Map & Compass",
|
||||
"randomizer.item.restrict_boss_items.dungeon": "Map & Compass & Keys",
|
||||
"startinventory.usestartinventory": "Use Starting Inventory",
|
||||
"custom.usecustompool": "Use Custom Item Pool",
|
||||
|
||||
"bottom.content.worlds": "Worlds",
|
||||
"bottom.content.names": "Player names",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
{
|
||||
"keysanity": {
|
||||
"smallkeyshuffle": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"wild",
|
||||
"universal"
|
||||
]
|
||||
},
|
||||
"mapshuffle": { "type": "checkbox" },
|
||||
"compassshuffle": { "type": "checkbox" },
|
||||
"bigkeyshuffle": { "type": "checkbox" }
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
{
|
||||
"widgets": {
|
||||
"smallkeyshuffle": {
|
||||
"key_logic_algorithm": {
|
||||
"type": "selectbox",
|
||||
"default": "default",
|
||||
"options": [
|
||||
"none",
|
||||
"wild",
|
||||
"universal"
|
||||
]
|
||||
"default",
|
||||
"partial",
|
||||
"strict"
|
||||
],
|
||||
"config": {
|
||||
"padx": [20,0],
|
||||
"pady": [0,20]
|
||||
}
|
||||
},
|
||||
"dungeondoorshuffle": {
|
||||
"type": "selectbox",
|
||||
@@ -28,7 +33,8 @@
|
||||
"random"
|
||||
],
|
||||
"config": {
|
||||
"width": 45
|
||||
"width": 45,
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"door_type_mode": {
|
||||
@@ -41,7 +47,8 @@
|
||||
"chaos"
|
||||
],
|
||||
"config": {
|
||||
"width": 45
|
||||
"width": 45,
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"trap_door_mode": {
|
||||
@@ -54,41 +61,17 @@
|
||||
"oneway"
|
||||
],
|
||||
"config": {
|
||||
"width": 30
|
||||
"width": 30,
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"key_logic_algorithm": {
|
||||
"type": "selectbox",
|
||||
"default": "default",
|
||||
"options": [
|
||||
"default",
|
||||
"partial",
|
||||
"strict"
|
||||
]
|
||||
},
|
||||
"decoupledoors": { "type": "checkbox" },
|
||||
"keydropshuffle": { "type": "checkbox" },
|
||||
"pottery": {
|
||||
"type": "selectbox",
|
||||
"default": "none",
|
||||
"options": [
|
||||
"none",
|
||||
"keys",
|
||||
"cave",
|
||||
"cavekeys",
|
||||
"reduced",
|
||||
"clustered",
|
||||
"nonempty",
|
||||
"dungeon",
|
||||
"lottery"
|
||||
],
|
||||
"decoupledoors": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"width": 35
|
||||
"padx": [20,0],
|
||||
"pady": [0,20]
|
||||
}
|
||||
},
|
||||
"colorizepots": { "type": "checkbox" },
|
||||
"dropshuffle": { "type": "checkbox" },
|
||||
"potshuffle": { "type": "checkbox" },
|
||||
"experimental": { "type": "checkbox" },
|
||||
"dungeon_counters": {
|
||||
"type": "selectbox",
|
||||
|
||||
@@ -1,38 +1,5 @@
|
||||
{
|
||||
"widgets": {
|
||||
"openpyramid": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"auto",
|
||||
"yes",
|
||||
"no"
|
||||
],
|
||||
"config": {
|
||||
"width": 10
|
||||
}
|
||||
},
|
||||
"take_any": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"random",
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
"shuffleganon": { "type": "checkbox" },
|
||||
"shufflelinks": { "type": "checkbox" },
|
||||
"shuffletavern": { "type": "checkbox" },
|
||||
"overworld_map": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"default",
|
||||
"compass",
|
||||
"map"
|
||||
],
|
||||
"config": {
|
||||
"width": 45
|
||||
}
|
||||
},
|
||||
"entranceshuffle": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
@@ -47,6 +14,47 @@
|
||||
"dungeonsfull",
|
||||
"dungeonssimple"
|
||||
]
|
||||
},
|
||||
"shuffleganon": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"shufflelinks": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"shuffletavern": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [20,0]
|
||||
}
|
||||
},
|
||||
"openpyramid": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"auto",
|
||||
"yes",
|
||||
"no"
|
||||
],
|
||||
"config": {
|
||||
"width": 6,
|
||||
"pady": [20,0]
|
||||
}
|
||||
},
|
||||
"overworld_map": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"default",
|
||||
"compass",
|
||||
"map"
|
||||
],
|
||||
"config": {
|
||||
"width": 45
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
"bps": { "type": "checkbox" },
|
||||
"createspoiler": { "type": "checkbox" },
|
||||
"calcplaythrough": { "type": "checkbox" },
|
||||
"print_custom_yaml": { "type": "checkbox" },
|
||||
"usestartinventory": { "type": "checkbox" },
|
||||
"usecustompool": { "type": "checkbox" },
|
||||
"race": { "type": "checkbox" }
|
||||
"print_custom_yaml": { "type": "checkbox" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
{
|
||||
"checkboxes": {
|
||||
"retro": { "type": "checkbox" },
|
||||
"bombbag": { "type": "checkbox" },
|
||||
"shopsanity": { "type": "checkbox" },
|
||||
"hints": {
|
||||
"type": "checkbox"
|
||||
},
|
||||
"pseudoboots": { "type": "checkbox" }
|
||||
"hints": { "type": "checkbox" },
|
||||
"pseudoboots": { "type": "checkbox" },
|
||||
"race": { "type": "checkbox" }
|
||||
},
|
||||
"leftItemFrame": {
|
||||
"worldstate": {
|
||||
@@ -17,7 +13,10 @@
|
||||
"open",
|
||||
"inverted",
|
||||
"retro"
|
||||
]
|
||||
],
|
||||
"config": {
|
||||
"command": "worldstate"
|
||||
}
|
||||
},
|
||||
"logiclevel": {
|
||||
"type": "selectbox",
|
||||
@@ -63,16 +62,38 @@
|
||||
"swordless",
|
||||
"vanilla"
|
||||
]
|
||||
},
|
||||
"beemizer": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"0", "1", "2", "3", "4"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rightItemFrame": {
|
||||
"itempool": {
|
||||
"sortingalgo": {
|
||||
"type": "selectbox",
|
||||
"default": "balanced",
|
||||
"options": [
|
||||
"balanced",
|
||||
"vanilla_fill",
|
||||
"major_only",
|
||||
"dungeon_only",
|
||||
"district"
|
||||
]
|
||||
},
|
||||
"accessibility": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"items",
|
||||
"locations",
|
||||
"none"
|
||||
]
|
||||
},
|
||||
"restrict_boss_items": {
|
||||
"type": "selectbox",
|
||||
"default": "none",
|
||||
"options": [
|
||||
"none",
|
||||
"mapcompass",
|
||||
"dungeon"
|
||||
]
|
||||
},
|
||||
"itemfunction": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"normal",
|
||||
@@ -80,7 +101,78 @@
|
||||
"expert"
|
||||
]
|
||||
},
|
||||
"itemfunction": {
|
||||
"timer": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"display",
|
||||
"timed",
|
||||
"timed-ohko",
|
||||
"ohko",
|
||||
"timed-countdown"
|
||||
]
|
||||
}
|
||||
},
|
||||
"leftPoolHeader": {
|
||||
"shopsanity": {
|
||||
"type": "checkbox"
|
||||
},
|
||||
"bonk_drops": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"leftPoolFrame": {
|
||||
"pottery": {
|
||||
"type": "selectbox",
|
||||
"default": "none",
|
||||
"options": [
|
||||
"none",
|
||||
"keys",
|
||||
"cave",
|
||||
"cavekeys",
|
||||
"reduced",
|
||||
"clustered",
|
||||
"nonempty",
|
||||
"dungeon",
|
||||
"lottery"
|
||||
],
|
||||
"config": {
|
||||
"width": 35
|
||||
}
|
||||
},
|
||||
"colorizepots": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [50,0]
|
||||
}
|
||||
},
|
||||
"potshuffle": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [50,0]
|
||||
}
|
||||
},
|
||||
"dropshuffle": {
|
||||
"type": "checkbox"
|
||||
},
|
||||
"keydropshuffle": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"command": "keydropshuffle"
|
||||
}
|
||||
},
|
||||
"take_any": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"random",
|
||||
"fixed"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rightPoolFrame": {
|
||||
"itempool": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"normal",
|
||||
@@ -104,44 +196,17 @@
|
||||
"retro_silvers"
|
||||
]
|
||||
},
|
||||
"timer": {
|
||||
"beemizer": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"none",
|
||||
"display",
|
||||
"timed",
|
||||
"timed-ohko",
|
||||
"ohko",
|
||||
"timed-countdown"
|
||||
"0", "1", "2", "3", "4"
|
||||
]
|
||||
},
|
||||
"accessibility": {
|
||||
"type": "selectbox",
|
||||
"options": [
|
||||
"items",
|
||||
"locations",
|
||||
"none"
|
||||
]
|
||||
},
|
||||
"sortingalgo": {
|
||||
"type": "selectbox",
|
||||
"default": "balanced",
|
||||
"options": [
|
||||
"balanced",
|
||||
"vanilla_fill",
|
||||
"major_only",
|
||||
"dungeon_only",
|
||||
"district"
|
||||
]
|
||||
},
|
||||
"restrict_boss_items": {
|
||||
"type": "selectbox",
|
||||
"default": "none",
|
||||
"options": [
|
||||
"none",
|
||||
"mapcompass",
|
||||
"dungeon"
|
||||
]
|
||||
"bombbag": {
|
||||
"type": "checkbox",
|
||||
"config": {
|
||||
"padx": [64,0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
{
|
||||
"topOverworldFrame": {
|
||||
"bonk_drops": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"topOverworldFrame": {},
|
||||
"leftOverworldFrame": {
|
||||
"overworldshuffle": {
|
||||
"type": "selectbox",
|
||||
@@ -28,11 +23,17 @@
|
||||
},
|
||||
"mixed": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
"default": false,
|
||||
"config": {
|
||||
"padx": [79,0]
|
||||
}
|
||||
},
|
||||
"whirlpool": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
"default": false,
|
||||
"config": {
|
||||
"padx": [79,0]
|
||||
}
|
||||
},
|
||||
"overworldflute": {
|
||||
"type": "selectbox",
|
||||
@@ -41,17 +42,26 @@
|
||||
"vanilla",
|
||||
"balanced",
|
||||
"random"
|
||||
]
|
||||
],
|
||||
"config": {
|
||||
"pady": [20,0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"rightOverworldFrame": {
|
||||
"terrain": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
"default": false,
|
||||
"config": {
|
||||
"pady": [3,0]
|
||||
}
|
||||
},
|
||||
"keepsimilar": {
|
||||
"type": "checkbox",
|
||||
"default": false
|
||||
"default": false,
|
||||
"config": {
|
||||
"pady": [6,0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,25 +56,36 @@ SETTINGSTOPROCESS = {
|
||||
"randomizer": {
|
||||
"item": {
|
||||
"hints": "hints",
|
||||
"retro": "retro",
|
||||
"bombbag": "bombbag",
|
||||
"shopsanity": "shopsanity",
|
||||
"pseudoboots": "pseudoboots",
|
||||
"race": "race",
|
||||
|
||||
"worldstate": "mode",
|
||||
"logiclevel": "logic",
|
||||
"goal": "goal",
|
||||
"crystals_gt": "crystals_gt",
|
||||
"crystals_ganon": "crystals_ganon",
|
||||
"weapons": "swords",
|
||||
"itempool": "difficulty",
|
||||
|
||||
"sortingalgo": "algorithm",
|
||||
"accessibility": "accessibility",
|
||||
"restrict_boss_items": "restrict_boss_items",
|
||||
"itemfunction": "item_functionality",
|
||||
"timer": "timer",
|
||||
|
||||
"shopsanity": "shopsanity",
|
||||
"bonk_drops": "bonk_drops",
|
||||
"pottery": "pottery",
|
||||
"colorizepots": "colorizepots",
|
||||
"potshuffle": "shufflepots",
|
||||
"dropshuffle": "dropshuffle",
|
||||
"keydropshuffle": "keydropshuffle",
|
||||
"take_any": "take_any",
|
||||
|
||||
"itempool": "difficulty",
|
||||
"flute_mode": "flute_mode",
|
||||
"bow_mode": "bow_mode",
|
||||
"timer": "timer",
|
||||
"accessibility": "accessibility",
|
||||
"sortingalgo": "algorithm",
|
||||
"beemizer": "beemizer",
|
||||
"restrict_boss_items": "restrict_boss_items"
|
||||
"bombbag": "bombbag"
|
||||
},
|
||||
"overworld": {
|
||||
"overworldshuffle": "ow_shuffle",
|
||||
@@ -83,17 +94,31 @@ SETTINGSTOPROCESS = {
|
||||
"keepsimilar": "ow_keepsimilar",
|
||||
"mixed": "ow_mixed",
|
||||
"whirlpool": "ow_whirlpool",
|
||||
"bonk_drops": "bonk_drops",
|
||||
"overworldflute": "ow_fluteshuffle"
|
||||
},
|
||||
"entrance": {
|
||||
"openpyramid": "openpyramid",
|
||||
"entranceshuffle": "shuffle",
|
||||
"shuffleganon": "shuffleganon",
|
||||
"shufflelinks": "shufflelinks",
|
||||
"shuffletavern": "shuffletavern",
|
||||
"entranceshuffle": "shuffle",
|
||||
"openpyramid": "openpyramid",
|
||||
"overworld_map": "overworld_map",
|
||||
"take_any": "take_any",
|
||||
},
|
||||
"dungeon": {
|
||||
"smallkeyshuffle": "keyshuffle",
|
||||
"mapshuffle": "mapshuffle",
|
||||
"compassshuffle": "compassshuffle",
|
||||
"bigkeyshuffle": "bigkeyshuffle",
|
||||
"key_logic_algorithm": "key_logic_algorithm",
|
||||
"dungeondoorshuffle": "door_shuffle",
|
||||
"dungeonintensity": "intensity",
|
||||
"door_type_mode": "door_type_mode",
|
||||
"trap_door_mode": "trap_door_mode",
|
||||
"decoupledoors": "decoupledoors",
|
||||
"experimental": "experimental",
|
||||
"dungeon_counters": "dungeon_counters",
|
||||
"mixed_travel": "mixed_travel",
|
||||
"standardize_palettes": "standardize_palettes"
|
||||
},
|
||||
"enemizer": {
|
||||
"enemyshuffle": "shuffleenemies",
|
||||
@@ -101,27 +126,6 @@ SETTINGSTOPROCESS = {
|
||||
"enemydamage": "enemy_damage",
|
||||
"enemyhealth": "enemy_health"
|
||||
},
|
||||
"dungeon": {
|
||||
"mapshuffle": "mapshuffle",
|
||||
"compassshuffle": "compassshuffle",
|
||||
"smallkeyshuffle": "keyshuffle",
|
||||
"bigkeyshuffle": "bigkeyshuffle",
|
||||
"dungeondoorshuffle": "door_shuffle",
|
||||
"dungeonintensity": "intensity",
|
||||
"door_type_mode": "door_type_mode",
|
||||
"trap_door_mode": "trap_door_mode",
|
||||
"key_logic_algorithm": "key_logic_algorithm",
|
||||
"decoupledoors": "decoupledoors",
|
||||
"keydropshuffle": "keydropshuffle",
|
||||
"dropshuffle": "dropshuffle",
|
||||
"pottery": "pottery",
|
||||
"colorizepots": "colorizepots",
|
||||
"potshuffle": "shufflepots",
|
||||
"experimental": "experimental",
|
||||
"dungeon_counters": "dungeon_counters",
|
||||
"mixed_travel": "mixed_travel",
|
||||
"standardize_palettes": "standardize_palettes"
|
||||
},
|
||||
"gameoptions": {
|
||||
"nobgm": "disablemusic",
|
||||
"quickswap": "quickswap",
|
||||
@@ -141,12 +145,15 @@ SETTINGSTOPROCESS = {
|
||||
"createrom": "create_rom",
|
||||
"calcplaythrough": "calc_playthrough",
|
||||
"print_custom_yaml": "print_custom_yaml",
|
||||
"usestartinventory": "usestartinventory",
|
||||
"usecustompool": "custom",
|
||||
"race": "race",
|
||||
"saveonexit": "saveonexit"
|
||||
}
|
||||
},
|
||||
"startinventory": {
|
||||
"usestartinventory": "usestartinventory"
|
||||
},
|
||||
"custom": {
|
||||
"usecustompool": "custom"
|
||||
},
|
||||
"bottom": {
|
||||
"content": {
|
||||
"names": "names",
|
||||
|
||||
@@ -203,13 +203,19 @@ def create_guiargs(parent):
|
||||
|
||||
# Cycle through each page
|
||||
for mainpage in options:
|
||||
subpage = None
|
||||
_, v = next(iter(options[mainpage].items()))
|
||||
if isinstance(v, str):
|
||||
subpage = ""
|
||||
# Cycle through each subpage (in case of Item Randomizer)
|
||||
for subpage in options[mainpage]:
|
||||
for subpage in (options[mainpage] if subpage is None else [subpage]):
|
||||
# Cycle through each widget
|
||||
for widget in options[mainpage][subpage]:
|
||||
for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]):
|
||||
# Get the value and set it
|
||||
arg = options[mainpage][subpage][widget]
|
||||
setattr(guiargs, arg, parent.pages[mainpage].pages[subpage].widgets[widget].storageVar.get())
|
||||
arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget]
|
||||
page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage]
|
||||
pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets
|
||||
setattr(guiargs, arg, pagewidgets[widget].storageVar.get())
|
||||
|
||||
# Get EnemizerCLI setting
|
||||
guiargs.enemizercli = parent.pages["randomizer"].pages["enemizer"].widgets["enemizercli"].storageVar.get()
|
||||
@@ -226,7 +232,7 @@ def create_guiargs(parent):
|
||||
guiargs.customizer = customizer_value
|
||||
|
||||
# Get if we're using the Custom Item Pool
|
||||
guiargs.custom = bool(parent.pages["randomizer"].pages["generation"].widgets["usecustompool"].storageVar.get())
|
||||
guiargs.custom = bool(parent.pages["custom"].content.customWidgets["usecustompool"].storageVar.get())
|
||||
|
||||
# Get Seed ID
|
||||
guiargs.seed = None
|
||||
@@ -285,7 +291,7 @@ def create_guiargs(parent):
|
||||
guiargs.dropshuffle = 1
|
||||
guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery
|
||||
|
||||
if guiargs.retro or guiargs.mode == 'retro':
|
||||
if (hasattr(guiargs, 'retro') and guiargs.retro) or guiargs.mode == 'retro':
|
||||
if guiargs.bow_mode == 'progressive':
|
||||
guiargs.bow_mode = 'retro'
|
||||
elif guiargs.bow_mode == 'silvers':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y
|
||||
from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
@@ -11,10 +11,10 @@ def custom_page(top,parent):
|
||||
|
||||
# Create uniform list columns
|
||||
def create_list_frame(parent, framename):
|
||||
parent.frames[framename] = Frame(parent)
|
||||
parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
parent.frames[framename].thisRow = 0
|
||||
parent.frames[framename].thisCol = 0
|
||||
self.frames[framename] = Frame(parent)
|
||||
self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
self.frames[framename].thisRow = 0
|
||||
self.frames[framename].thisCol = 0
|
||||
|
||||
# Create a vertical rule to help with splitting columns visually
|
||||
def create_vertical_rule(num=1):
|
||||
@@ -34,6 +34,8 @@ def custom_page(top,parent):
|
||||
|
||||
# Custom Item Pool option sections
|
||||
self.frames = {}
|
||||
self.frames["customHeader"] = Frame(self)
|
||||
self.frames["customHeader"].pack(side=TOP, anchor=W)
|
||||
# Create 5 columns with 2 vertical rules in between each
|
||||
create_list_frame(self, "itemList1")
|
||||
create_vertical_rule(2)
|
||||
@@ -50,9 +52,14 @@ def custom_page(top,parent):
|
||||
with open(os.path.join("resources", "app", "gui", "custom", "overview", "widgets.json")) as widgetDefns:
|
||||
myDict = json.load(widgetDefns)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
if framename in self.frames:
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.customWidgets[key] = dictWidgets[key]
|
||||
if framename == "customHeader":
|
||||
packAttrs = {"anchor":W}
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
|
||||
self.customWidgets[key].pack(packAttrs)
|
||||
|
||||
# Load Custom Item Pool settings from settings file
|
||||
for key in CONST.CUSTOMITEMS:
|
||||
|
||||
@@ -23,34 +23,41 @@ def loadcliargs(gui, args, settings=None):
|
||||
|
||||
# Cycle through each page
|
||||
for mainpage in options:
|
||||
subpage = None
|
||||
_, v = next(iter(options[mainpage].items()))
|
||||
if isinstance(v, str):
|
||||
subpage = ""
|
||||
# Cycle through each subpage (in case of Item Randomizer)
|
||||
for subpage in options[mainpage]:
|
||||
for subpage in (options[mainpage] if subpage is None else [subpage]):
|
||||
# Cycle through each widget
|
||||
for widget in options[mainpage][subpage]:
|
||||
if widget in gui.pages[mainpage].pages[subpage].widgets:
|
||||
for widget in (options[mainpage][subpage] if subpage != "" else options[mainpage]):
|
||||
page = gui.pages[mainpage].pages[subpage] if subpage != "" else gui.pages[mainpage]
|
||||
pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets
|
||||
if widget in pagewidgets:
|
||||
thisType = ""
|
||||
# Get the value and set it
|
||||
arg = options[mainpage][subpage][widget]
|
||||
arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget]
|
||||
if args[arg] == None:
|
||||
args[arg] = ""
|
||||
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget)
|
||||
if hasattr(gui.pages[mainpage].pages[subpage].widgets[widget],"type"):
|
||||
thisType = gui.pages[mainpage].pages[subpage].widgets[widget].type
|
||||
label_ref = mainpage + ('.' + subpage if subpage != "" else '') + '.' + widget
|
||||
label = fish.translate("gui","gui", label_ref)
|
||||
if hasattr(pagewidgets[widget],"type"):
|
||||
thisType = pagewidgets[widget].type
|
||||
if thisType == "checkbox":
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].checkbox.configure(text=label)
|
||||
pagewidgets[widget].checkbox.configure(text=label)
|
||||
elif thisType == "selectbox":
|
||||
theseOptions = gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label)
|
||||
theseOptions = pagewidgets[widget].selectbox.options
|
||||
pagewidgets[widget].label.configure(text=label)
|
||||
i = 0
|
||||
for value in theseOptions["values"]:
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget + '.' + str(value))
|
||||
pagewidgets[widget].selectbox.options["labels"][i] = fish.translate("gui","gui", label_ref + '.' + str(value))
|
||||
i += 1
|
||||
for i in range(0, len(theseOptions["values"])):
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i])
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].selectbox.options = theseOptions
|
||||
pagewidgets[widget].selectbox["menu"].entryconfigure(i, label=theseOptions["labels"][i])
|
||||
pagewidgets[widget].selectbox.options = theseOptions
|
||||
elif thisType == "spinbox":
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].label.configure(text=label)
|
||||
gui.pages[mainpage].pages[subpage].widgets[widget].storageVar.set(args[arg])
|
||||
pagewidgets[widget].label.configure(text=label)
|
||||
pagewidgets[widget].storageVar.set(args[arg])
|
||||
# If we're on the Game Options page and it's not about Hints
|
||||
if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]:
|
||||
# Check if we've got settings
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT
|
||||
from tkinter import ttk, Frame, Label, E, W, LEFT, RIGHT, TOP
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
@@ -16,8 +16,8 @@ def dungeon_page(parent):
|
||||
self.frames["keysanity"].pack(anchor=W)
|
||||
|
||||
## Dungeon Item Shuffle
|
||||
mscbLabel = Label(self.frames["keysanity"], text="Shuffle: ")
|
||||
mscbLabel.pack(side=LEFT)
|
||||
mscbLabel = Label(self.frames["keysanity"], text="Dungeon Items: ")
|
||||
mscbLabel.pack(side=TOP, anchor=W)
|
||||
|
||||
# Load Dungeon Shuffle option widgets as defined by JSON file
|
||||
# Defns include frame name, widget type, widget options, widget placement attributes
|
||||
@@ -28,7 +28,9 @@ def dungeon_page(parent):
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["keysanity"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(side=LEFT)
|
||||
packAttrs = {"side":LEFT}
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key])
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
# These get split left & right
|
||||
self.frames["widgets"] = Frame(self)
|
||||
@@ -39,6 +41,8 @@ def dungeon_page(parent):
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["widgets"])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
self.widgets[key].pack(anchor=W)
|
||||
packAttrs = {"anchor":W}
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, myDict[key])
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
|
||||
@@ -26,9 +26,8 @@ def entrando_page(parent):
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox" or key in ["openpyramid", "take_any"]:
|
||||
packAttrs["anchor"] = W
|
||||
packAttrs = {"anchor":W}
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tkinter import ttk, Frame, E, W, LEFT, RIGHT, Label
|
||||
from tkinter import ttk, font, Frame, E, W, NW, TOP, LEFT, RIGHT, Y, Label
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
@@ -17,14 +17,40 @@ def item_page(parent):
|
||||
self.frames["checkboxes"] = Frame(self)
|
||||
self.frames["checkboxes"].pack(anchor=W)
|
||||
|
||||
various_options = Label(self.frames["checkboxes"], text="")
|
||||
various_options = Label(self.frames["checkboxes"], text="Options: ")
|
||||
various_options.pack(side=LEFT)
|
||||
|
||||
self.frames["leftItemFrame"] = Frame(self)
|
||||
self.frames["rightItemFrame"] = Frame(self)
|
||||
self.frames["mainFrame"] = Frame(self)
|
||||
self.frames["mainFrame"].pack(side=TOP, pady=(20,0))
|
||||
|
||||
self.frames["poolFrame"] = Frame(self)
|
||||
self.frames["poolFrame"].pack(fill=Y)
|
||||
|
||||
self.frames["leftItemFrame"] = Frame(self.frames["mainFrame"])
|
||||
self.frames["leftItemFrame"].pack(side=LEFT)
|
||||
self.frames["rightItemFrame"] = Frame(self.frames["mainFrame"])
|
||||
self.frames["rightItemFrame"].pack(side=RIGHT)
|
||||
|
||||
self.frames["leftPoolContainer"] = Frame(self.frames["poolFrame"])
|
||||
self.frames["leftPoolContainer"].pack(side=LEFT, padx=(0,20))
|
||||
|
||||
base_font = font.nametofont('TkTextFont').actual()
|
||||
underline_font = f'"{base_font["family"]}" {base_font["size"]} underline'
|
||||
various_options = Label(self.frames["leftPoolContainer"], text="Pool Expansions", font=underline_font)
|
||||
various_options.pack(side=TOP, pady=(20,0))
|
||||
|
||||
self.frames["leftPoolHeader"] = Frame(self.frames["leftPoolContainer"])
|
||||
self.frames["leftPoolHeader"].pack(side=TOP, anchor=W)
|
||||
|
||||
self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"])
|
||||
self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y)
|
||||
|
||||
self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"])
|
||||
self.frames["rightPoolFrame"].pack(side=RIGHT)
|
||||
|
||||
various_options = Label(self.frames["rightPoolFrame"], text="Pool Modifications", font=underline_font)
|
||||
various_options.pack(side=TOP, pady=(20,0))
|
||||
|
||||
# Load Item Randomizer option widgets as defined by JSON file
|
||||
# Defns include frame name, widget type, widget options, widget placement attributes
|
||||
# Checkboxes go West
|
||||
@@ -36,8 +62,15 @@ def item_page(parent):
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if self.widgets[key].type == "checkbox":
|
||||
if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame":
|
||||
packAttrs["anchor"] = W
|
||||
if framename == "checkboxes":
|
||||
packAttrs["side"] = LEFT
|
||||
packAttrs["padx"] = (10,0)
|
||||
elif framename == "leftPoolHeader":
|
||||
packAttrs["side"] = LEFT
|
||||
packAttrs["padx"] = (0,20)
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
|
||||
@@ -15,33 +15,24 @@ def overworld_page(parent):
|
||||
|
||||
# Load Overworld Shuffle option widgets as defined by JSON file
|
||||
# Defns include frame name, widget type, widget options, widget placement attributes
|
||||
self.frames["topOverworldFrame"] = Frame(self)
|
||||
self.frames["leftOverworldFrame"] = Frame(self)
|
||||
self.frames["rightOverworldFrame"] = Frame(self)
|
||||
|
||||
self.frames["topOverworldFrame"].pack(side=TOP, anchor=NW)
|
||||
self.frames["leftOverworldFrame"].pack(side=LEFT, anchor=NW, fill=Y)
|
||||
self.frames["rightOverworldFrame"].pack(anchor=NW, fill=Y)
|
||||
|
||||
shuffleLabel = Label(self.frames["topOverworldFrame"], text="Shuffle: ")
|
||||
shuffleLabel.pack(side=LEFT)
|
||||
|
||||
with open(os.path.join("resources","app","gui","randomize","overworld","widgets.json")) as overworldWidgets:
|
||||
myDict = json.load(overworldWidgets)
|
||||
for framename,theseWidgets in myDict.items():
|
||||
if not theseWidgets:
|
||||
continue
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.widgets[key] = dictWidgets[key]
|
||||
packAttrs = {"anchor":E}
|
||||
if key == "terrain":
|
||||
packAttrs = {"anchor":W, "pady":(3,0)}
|
||||
elif key == "keepsimilar":
|
||||
packAttrs = {"anchor":W, "pady":(6,0)}
|
||||
elif key == "overworldflute":
|
||||
packAttrs["pady"] = (20,0)
|
||||
elif key in ["mixed", "whirlpool"]:
|
||||
packAttrs = {"anchor":W, "padx":(79,0)}
|
||||
|
||||
packAttrs = {"anchor":W}
|
||||
if self.widgets[key].type != "checkbox":
|
||||
packAttrs["anchor"] = E
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
|
||||
self.widgets[key].pack(packAttrs)
|
||||
|
||||
return self
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tkinter import ttk, Frame, N, E, W, LEFT, X, VERTICAL, Y
|
||||
from tkinter import ttk, Frame, N, E, W, LEFT, TOP, X, VERTICAL, Y
|
||||
import source.gui.widgets as widgets
|
||||
import json
|
||||
import os
|
||||
@@ -11,10 +11,10 @@ def startinventory_page(top,parent):
|
||||
|
||||
# Create uniform list columns
|
||||
def create_list_frame(parent, framename):
|
||||
parent.frames[framename] = Frame(parent)
|
||||
parent.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
parent.frames[framename].thisRow = 0
|
||||
parent.frames[framename].thisCol = 0
|
||||
self.frames[framename] = Frame(parent)
|
||||
self.frames[framename].pack(side=LEFT, padx=(0,0), anchor=N)
|
||||
self.frames[framename].thisRow = 0
|
||||
self.frames[framename].thisCol = 0
|
||||
|
||||
# Create a vertical rule to help with splitting columns visually
|
||||
def create_vertical_rule(num=1):
|
||||
@@ -34,6 +34,8 @@ def startinventory_page(top,parent):
|
||||
|
||||
# Starting Inventory option sections
|
||||
self.frames = {}
|
||||
self.frames["startHeader"] = Frame(self)
|
||||
self.frames["startHeader"].pack(side=TOP, anchor=W)
|
||||
# Create 5 columns with 2 vertical rules in between each
|
||||
create_list_frame(self,"itemList1")
|
||||
create_vertical_rule(2)
|
||||
@@ -55,9 +57,14 @@ def startinventory_page(top,parent):
|
||||
if key in myDict[thisList]:
|
||||
del myDict[thisList][key]
|
||||
for framename,theseWidgets in myDict.items():
|
||||
if framename in self.frames:
|
||||
dictWidgets = widgets.make_widgets_from_dict(self, theseWidgets, self.frames[framename])
|
||||
for key in dictWidgets:
|
||||
self.startingWidgets[key] = dictWidgets[key]
|
||||
if framename == "startHeader":
|
||||
packAttrs = {"anchor":W}
|
||||
packAttrs = widgets.add_padding_from_config(packAttrs, theseWidgets[key])
|
||||
self.startingWidgets[key].pack(packAttrs)
|
||||
|
||||
# Load Custom Starting Inventory settings from settings file, ignoring ones to be excluded
|
||||
for key in CONST.CUSTOMITEMS:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from tkinter import Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X
|
||||
from tkinter import messagebox, Checkbutton, Entry, Frame, IntVar, Label, OptionMenu, Spinbox, StringVar, LEFT, RIGHT, X
|
||||
from source.classes.Empty import Empty
|
||||
|
||||
# Override Spinbox to include mousewheel support for changing value
|
||||
@@ -16,7 +16,7 @@ class mySpinbox(Spinbox):
|
||||
self.invoke('buttonup')
|
||||
|
||||
# Make a Checkbutton with a label
|
||||
def make_checkbox(self, parent, label, storageVar, manager, managerAttrs):
|
||||
def make_checkbox(self, parent, label, storageVar, manager, managerAttrs, config):
|
||||
self = Frame(parent)
|
||||
self.storageVar = storageVar
|
||||
if managerAttrs is not None and "default" in managerAttrs:
|
||||
@@ -25,7 +25,10 @@ def make_checkbox(self, parent, label, storageVar, manager, managerAttrs):
|
||||
elif managerAttrs["default"] == "false" or managerAttrs["default"] == False:
|
||||
self.storageVar.set(False)
|
||||
del managerAttrs["default"]
|
||||
self.checkbox = Checkbutton(self, text=label, variable=self.storageVar)
|
||||
options = {"text":label, "variable":self.storageVar}
|
||||
if config and "command" in config:
|
||||
options.update({"command":lambda m=config["command"]: widget_command(self, m)})
|
||||
self.checkbox = Checkbutton(self, options)
|
||||
if managerAttrs is not None:
|
||||
self.checkbox.pack(managerAttrs)
|
||||
else:
|
||||
@@ -43,6 +46,10 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt
|
||||
|
||||
self.labelVar = StringVar()
|
||||
self.storageVar = storageVar
|
||||
if config and "command" in config:
|
||||
self.command = config["command"]
|
||||
self.selectbox = OptionMenu(self, self.labelVar, *labels, command=lambda m: widget_command(self, self.command))
|
||||
else:
|
||||
self.selectbox = OptionMenu(self, self.labelVar, *labels)
|
||||
self.selectbox.options = {}
|
||||
|
||||
@@ -96,7 +103,7 @@ def make_selectbox(self, parent, label, options, storageVar, manager, managerAtt
|
||||
else:
|
||||
self.label.pack(side=LEFT)
|
||||
|
||||
self.selectbox.config(width=config['width'] if config and config['width'] else 20)
|
||||
self.selectbox.config(width=config['width'] if config and 'width' in config else 20)
|
||||
idx = 0
|
||||
default = self.selectbox.options["values"][idx]
|
||||
if managerAttrs is not None and "default" in managerAttrs:
|
||||
@@ -181,7 +188,7 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage
|
||||
if type == "checkbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = IntVar()
|
||||
widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs)
|
||||
widget = make_checkbox(self, parent, label, thisStorageVar, manager, managerAttrs, config)
|
||||
elif type == "selectbox":
|
||||
if thisStorageVar is None:
|
||||
thisStorageVar = StringVar()
|
||||
@@ -221,3 +228,51 @@ def make_widgets_from_dict(self, defns, parent):
|
||||
for key,defn in defns.items():
|
||||
widgets[key] = make_widget_from_dict(self, defn, parent)
|
||||
return widgets
|
||||
|
||||
# Add padding to widget
|
||||
def add_padding_from_config(packAttrs, defn):
|
||||
if "config" in defn:
|
||||
config = defn["config"]
|
||||
if 'padx' in config:
|
||||
packAttrs["padx"] = config['padx']
|
||||
if 'pady' in config:
|
||||
packAttrs["pady"] = config['pady']
|
||||
return packAttrs
|
||||
|
||||
# Callback when a widget issues a command
|
||||
def widget_command(widget, command=""):
|
||||
root = widget.winfo_toplevel()
|
||||
text_output = ""
|
||||
if command == "worldstate":
|
||||
if widget.storageVar.get() == 'retro':
|
||||
temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"]
|
||||
text_output += f'\n {temp_widget.label.cget("text")}'
|
||||
temp_widget.storageVar.set('universal')
|
||||
|
||||
temp_widget = root.pages["randomizer"].pages["item"].widgets["bow_mode"]
|
||||
text_output += f'\n {temp_widget.label.cget("text")}'
|
||||
if temp_widget.storageVar.get() == 'progressive':
|
||||
temp_widget.storageVar.set('retro')
|
||||
elif temp_widget.storageVar.get() == 'silvers':
|
||||
temp_widget.storageVar.set('retro_silvers')
|
||||
|
||||
temp_widget = root.pages["randomizer"].pages["item"].widgets["take_any"]
|
||||
text_output += f'\n {temp_widget.label.cget("text")}'
|
||||
if temp_widget.storageVar.get() == 'none':
|
||||
temp_widget.storageVar.set('random')
|
||||
|
||||
widget.storageVar.set('open')
|
||||
messagebox.showinfo('', f'The following settings were changed:{text_output}')
|
||||
elif command == "keydropshuffle":
|
||||
if widget.storageVar.get() > 0:
|
||||
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
|
||||
text_output += f'\n {temp_widget.label.cget("text")}'
|
||||
if temp_widget.storageVar.get() == 'none':
|
||||
temp_widget.storageVar.set('keys')
|
||||
|
||||
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
|
||||
temp_widget.storageVar.set(1)
|
||||
text_output += f'\n {temp_widget.checkbox.cget("text")}'
|
||||
|
||||
widget.storageVar.set(0)
|
||||
messagebox.showinfo('', f'The following settings were changed:{text_output}')
|
||||
|
||||
@@ -528,9 +528,14 @@ def do_links_house(entrances, exits, avail, cross_world):
|
||||
# can't have links house on eddm in restricted because Inverted Aga Tower isn't available
|
||||
# todo: inverted full may have the same problem if both links house and a mandatory connector is chosen
|
||||
# from the 3 inverted options
|
||||
if avail.world.shuffle[avail.player] in ['restricted'] and avail.world.is_tile_swapped(0x03, avail.player):
|
||||
if avail.world.shuffle[avail.player] in ['restricted', 'lite', 'lean'] and avail.world.is_tile_swapped(0x03, avail.player):
|
||||
avail.links_on_mountain = True
|
||||
forbidden.extend(['Spike Cave', 'Dark Death Mountain Fairy'])
|
||||
|
||||
if avail.world.shuffle[avail.player] in ['lite', 'lean']:
|
||||
if avail.world.is_tile_swapped(0x05, avail.player):
|
||||
avail.links_on_mountain = True
|
||||
forbidden.extend(['Cave Shop (Dark Death Mountain)'])
|
||||
else:
|
||||
avail.links_on_mountain = True
|
||||
|
||||
@@ -558,6 +563,17 @@ def do_links_house(entrances, exits, avail, cross_world):
|
||||
if links_house in dm_spots and avail.world.owShuffle[avail.player] == 'vanilla':
|
||||
if avail.links_on_mountain:
|
||||
return # connector is fine
|
||||
if avail.world.shuffle[avail.player] in ['lite', 'lean']:
|
||||
rem_exits = [e for e in avail.exits if e in Connector_Exit_Set and e not in Dungeon_Exit_Set]
|
||||
multi_exit_caves = figure_out_connectors(rem_exits)
|
||||
if cross_world:
|
||||
possible_dm_exits = [e for e in avail.entrances if e not in entrances and e in LH_DM_Connector_List]
|
||||
possible_exits = [e for e in avail.entrances if e not in entrances and e not in dm_spots]
|
||||
else:
|
||||
world_list = LW_Entrances if not avail.inverted else DW_Entrances
|
||||
possible_dm_exits = [e for e in avail.entrances if e not in entrances and e in LH_DM_Connector_List and e in world_list]
|
||||
possible_exits = [e for e in avail.entrances if e not in entrances and e not in dm_spots and e in world_list]
|
||||
else:
|
||||
multi_exit_caves = figure_out_connectors(exits)
|
||||
entrance_pool = entrances if avail.coupled else avail.decoupled_entrances
|
||||
if cross_world:
|
||||
@@ -2036,6 +2052,23 @@ Connector_Exit_Set = {
|
||||
'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)'
|
||||
}
|
||||
|
||||
Dungeon_Exit_Set = {
|
||||
'Eastern Palace Exit',
|
||||
'Tower of Hera Exit',
|
||||
'Agahnims Tower Exit',
|
||||
'Palace of Darkness Exit',
|
||||
'Swamp Palace Exit',
|
||||
'Skull Woods Final Section Exit',
|
||||
'Thieves Town Exit',
|
||||
'Ice Palace Exit',
|
||||
'Misery Mire Exit',
|
||||
'Ganons Tower Exit',
|
||||
'Skull Woods First Section Exit', 'Skull Woods Second Section Exit (East)', 'Skull Woods Second Section Exit (West)',
|
||||
'Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)',
|
||||
'Desert Palace Exit (South)', 'Desert Palace Exit (East)', 'Desert Palace Exit (West)',
|
||||
'Turtle Rock Exit (Front)', 'Turtle Rock Isolated Ledge Exit', 'Turtle Rock Ledge Exit (West)'
|
||||
}
|
||||
|
||||
# Entrances that cannot be used to access a must_exit entrance - symmetrical to allow reverse lookups
|
||||
Must_Exit_Invalid_Connections = defaultdict(set)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user