Merge branch 'DoorDevUnstable' into DoorDevVolatile

# Conflicts:
#	Main.py
#	MultiClient.py
#	Rom.py
#	data/base2current.bps
#	resources/app/gui/lang/en.json
#	resources/app/gui/randomize/item/widgets.json
#	source/gui/bottom.py
#	source/gui/widgets.py
This commit is contained in:
aerinon
2023-08-04 11:33:31 -06:00
31 changed files with 289 additions and 155 deletions
+3 -1
View File
@@ -289,7 +289,7 @@ class World(object):
else: else:
if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']: if self.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull']:
return False return False
elif self.goal[player] in ['crystals', 'trinity']: elif self.goal[player] in ['crystals', 'trinity', 'ganonhunt']:
return True return True
else: else:
return False return False
@@ -2513,6 +2513,7 @@ class Spoiler(object):
'pseudoboots': self.world.pseudoboots, 'pseudoboots': self.world.pseudoboots,
'triforcegoal': self.world.treasure_hunt_count, 'triforcegoal': self.world.treasure_hunt_count,
'triforcepool': self.world.treasure_hunt_total, 'triforcepool': self.world.treasure_hunt_total,
'race': self.world.settings.world_rep['meta']['race'],
'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)} 'code': {p: Settings.make_code(self.world, p) for p in range(1, self.world.players + 1)}
} }
@@ -2615,6 +2616,7 @@ class Spoiler(object):
self.set_lobby(portal.name, portal.door.name, player) self.set_lobby(portal.name, portal.door.name, player)
def to_json(self): def to_json(self):
self.parse_meta()
self.parse_data() self.parse_data()
out = OrderedDict() out = OrderedDict()
out['Entrances'] = list(self.entrances.values()) out['Entrances'] = list(self.entrances.values())
+3 -2
View File
@@ -132,7 +132,7 @@ def parse_cli(argv, no_defaults=False):
'flute_mode', 'bow_mode', 'take_any', 'boots_hint', 'flute_mode', 'bow_mode', 'take_any', 'boots_hint',
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid', 'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory', 'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'startinventory',
'usestartinventory', 'bombbag', 'overworld_map', 'restrict_boss_items', 'usestartinventory', 'bombbag', 'overworld_map', 'restrict_boss_items', 'triforce_max_difference',
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max',
'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'shuffletavern', 'triforce_min_difference', 'triforce_goal', 'triforce_pool', 'shufflelinks', 'shuffletavern',
'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', 'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
@@ -229,7 +229,8 @@ def parse_settings():
"triforce_pool_max": 0, "triforce_pool_max": 0,
"triforce_goal_min": 0, "triforce_goal_min": 0,
"triforce_goal_max": 0, "triforce_goal_max": 0,
"triforce_min_difference": 10, "triforce_min_difference": 0,
"triforce_max_difference": 10000,
"code": "", "code": "",
"multi": 1, "multi": 1,
+16 -14
View File
@@ -1962,7 +1962,7 @@ def shuffle_big_key_doors(door_type_pools, used_doors, start_regions_map, all_cu
if flex_map[dungeon] > 0: if flex_map[dungeon] > 0:
queue.append(dungeon) queue.append(dungeon)
# time to re-assign # time to re-assign
reassign_big_key_doors(bk_map, world, player) reassign_big_key_doors(bk_map, used_doors, world, player)
for name, big_list in bk_map.items(): for name, big_list in bk_map.items():
used_doors.update(flatten_pair_list(big_list)) used_doors.update(flatten_pair_list(big_list))
return used_doors return used_doors
@@ -2047,7 +2047,7 @@ def shuffle_small_key_doors(door_type_pools, used_doors, start_regions_map, all_
else: else:
builder.key_doors_num -= 1 builder.key_doors_num -= 1
# time to re-assign # time to re-assign
reassign_key_doors(small_map, world, player) reassign_key_doors(small_map, used_doors, world, player)
for dungeon_name in pool: for dungeon_name in pool:
if world.keyshuffle[player] != 'universal': if world.keyshuffle[player] != 'universal':
builder = world.dungeon_layouts[player][dungeon_name] builder = world.dungeon_layouts[player][dungeon_name]
@@ -2129,7 +2129,7 @@ def shuffle_bomb_dash_doors(door_type_pools, used_doors, start_regions_map, all_
suggestion_map[dungeon] = pair suggestion_map[dungeon] = pair
queue.append(dungeon) queue.append(dungeon)
# time to re-assign # time to re-assign
reassign_bd_doors(bd_map, world, player) reassign_bd_doors(bd_map, used_doors, world, player)
for name, pair in bd_map.items(): for name, pair in bd_map.items():
used_doors.update(flatten_pair_list(pair[0])) used_doors.update(flatten_pair_list(pair[0]))
used_doors.update(flatten_pair_list(pair[1])) used_doors.update(flatten_pair_list(pair[1]))
@@ -2539,7 +2539,7 @@ def find_current_bk_doors(builder):
return current_doors return current_doors
def reassign_big_key_doors(bk_map, world, player): def reassign_big_key_doors(bk_map, used_doors, world, player):
logger = logging.getLogger('') logger = logging.getLogger('')
for name, big_doors in bk_map.items(): for name, big_doors in bk_map.items():
flat_proposal = flatten_pair_list(big_doors) flat_proposal = flatten_pair_list(big_doors)
@@ -2548,11 +2548,11 @@ def reassign_big_key_doors(bk_map, world, player):
while len(queue) > 0: while len(queue) > 0:
d = queue.pop() d = queue.pop()
if d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: if d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal:
if not d.entranceFlag: if not d.entranceFlag and d not in used_doors and d.dest not in used_doors:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
d.bigKey = False d.bigKey = False
elif d.type is DoorType.Normal and d not in flat_proposal : elif d.type is DoorType.Normal and d not in flat_proposal :
if not d.entranceFlag: if not d.entranceFlag and d not in used_doors:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
d.bigKey = False d.bigKey = False
for obj in big_doors: for obj in big_doors:
@@ -2795,7 +2795,7 @@ def find_valid_bd_combination(builder, suggested, world, player):
return bomb_proposal, dash_proposal, ttl_needed return bomb_proposal, dash_proposal, ttl_needed
def reassign_bd_doors(bd_map, world, player): def reassign_bd_doors(bd_map, used_doors, world, player):
for name, pair in bd_map.items(): for name, pair in bd_map.items():
flat_bomb_proposal = flatten_pair_list(pair[0]) flat_bomb_proposal = flatten_pair_list(pair[0])
flat_dash_proposal = flatten_pair_list(pair[1]) flat_dash_proposal = flatten_pair_list(pair[1])
@@ -2808,10 +2808,10 @@ def reassign_bd_doors(bd_map, world, player):
queue = deque(find_current_bd_doors(builder, world)) queue = deque(find_current_bd_doors(builder, world))
while len(queue) > 0: while len(queue) > 0:
d = queue.pop() d = queue.pop()
if d.type is DoorType.Interior and not_in_proposal(d): if d.type is DoorType.Interior and not_in_proposal(d) and d not in used_doors and d.dest not in used_doors:
if not d.entranceFlag: if not d.entranceFlag:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
elif d.type is DoorType.Normal and not_in_proposal(d): elif d.type is DoorType.Normal and not_in_proposal(d) and d not in used_doors:
if not d.entranceFlag: if not d.entranceFlag:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
do_bombable_dashable(pair[0], DoorKind.Bombable, world, player) do_bombable_dashable(pair[0], DoorKind.Bombable, world, player)
@@ -3003,7 +3003,7 @@ def valid_key_door_pair(door1, door2):
return len(door1.entrance.parent_region.exits) <= 1 or len(door2.entrance.parent_region.exits) <= 1 return len(door1.entrance.parent_region.exits) <= 1 or len(door2.entrance.parent_region.exits) <= 1
def reassign_key_doors(small_map, world, player): def reassign_key_doors(small_map, used_doors, world, player):
logger = logging.getLogger('') logger = logging.getLogger('')
for name, small_doors in small_map.items(): for name, small_doors in small_map.items():
logger.debug(f'Key doors for {name}') logger.debug(f'Key doors for {name}')
@@ -3024,13 +3024,13 @@ def reassign_key_doors(small_map, world, player):
room.delete(d.doorListPos) room.delete(d.doorListPos)
d.smallKey = False d.smallKey = False
elif d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal: elif d.type is DoorType.Interior and d not in flat_proposal and d.dest not in flat_proposal:
if not d.entranceFlag: if not d.entranceFlag and d not in used_doors and d.dest not in used_doors:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
d.smallKey = False d.smallKey = False
d.dest.smallKey = False d.dest.smallKey = False
queue.remove(d.dest) queue.remove(d.dest)
elif d.type is DoorType.Normal and d not in flat_proposal: elif d.type is DoorType.Normal and d not in flat_proposal:
if not d.entranceFlag: if not d.entranceFlag and d not in used_doors:
world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal) world.get_room(d.roomIndex, player).change(d.doorListPos, DoorKind.Normal)
d.smallKey = False d.smallKey = False
for dp in world.paired_doors[player]: for dp in world.paired_doors[player]:
@@ -3295,7 +3295,7 @@ def find_inaccessible_regions(world, player):
while len(queue) > 0: while len(queue) > 0:
next_region = queue.popleft() next_region = queue.popleft()
visited_regions.add(next_region) visited_regions.add(next_region)
if next_region.name == 'Dark Sanctuary Hint': # special spawn point in cave if world.mode[player] == 'inverted' and next_region.name == 'Dark Sanctuary Hint': # special spawn point in cave
for ent in next_region.entrances: for ent in next_region.entrances:
parent = ent.parent_region parent = ent.parent_region
if parent and parent.type is not RegionType.Dungeon and parent not in queue and parent not in visited_regions: if parent and parent.type is not RegionType.Dungeon and parent not in queue and parent not in visited_regions:
@@ -3811,6 +3811,8 @@ logical_connections = [
('GT Blocked Stairs Block Path', 'GT Big Chest'), ('GT Blocked Stairs Block Path', 'GT Big Chest'),
('GT Speed Torch South Path', 'GT Speed Torch'), ('GT Speed Torch South Path', 'GT Speed Torch'),
('GT Speed Torch North Path', 'GT Speed Torch Upper'), ('GT Speed Torch North Path', 'GT Speed Torch Upper'),
('GT Conveyor Cross Hammer Path', 'GT Conveyor Cross Across Pits'),
('GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross'),
('GT Hookshot East-Mid Path', 'GT Hookshot Mid Platform'), ('GT Hookshot East-Mid Path', 'GT Hookshot Mid Platform'),
('GT Hookshot Mid-East Path', 'GT Hookshot East Platform'), ('GT Hookshot Mid-East Path', 'GT Hookshot East Platform'),
('GT Hookshot North-Mid Path', 'GT Hookshot Mid Platform'), ('GT Hookshot North-Mid Path', 'GT Hookshot Mid Platform'),
@@ -4159,7 +4161,7 @@ interior_doors = [
('Mire Neglected Room SE', 'Mire Chest View NE'), ('Mire Neglected Room SE', 'Mire Chest View NE'),
('Mire BK Chest Ledge WS', 'Mire Warping Pool ES'), # technically one-way ('Mire BK Chest Ledge WS', 'Mire Warping Pool ES'), # technically one-way
('Mire Torches Top SW', 'Mire Torches Bottom NW'), ('Mire Torches Top SW', 'Mire Torches Bottom NW'),
('Mire Torches Bottom WS', 'Mire Attic Hint ES'), ('Mire Torches Bottom ES', 'Mire Attic Hint WS'),
('Mire Dark Shooters SE', 'Mire Key Rupees NE'), ('Mire Dark Shooters SE', 'Mire Key Rupees NE'),
('Mire Dark Shooters SW', 'Mire Block X NW'), ('Mire Dark Shooters SW', 'Mire Block X NW'),
('Mire Tall Dark and Roomy WS', 'Mire Crystal Right ES'), ('Mire Tall Dark and Roomy WS', 'Mire Crystal Right ES'),
+4 -2
View File
@@ -929,9 +929,9 @@ def create_doors(world, player):
create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1), create_door(player, 'Mire Torches Top SW', Intr).dir(So, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom Holes', Hole), create_door(player, 'Mire Torches Bottom Holes', Hole),
create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1), create_door(player, 'Mire Torches Bottom NW', Intr).dir(No, 0x97, Left, High).pos(1),
create_door(player, 'Mire Torches Bottom WS', Intr).dir(We, 0x97, Bot, High).pos(0), create_door(player, 'Mire Torches Bottom ES', Intr).dir(Ea, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Torches Top Holes', Hole), create_door(player, 'Mire Torches Top Holes', Hole),
create_door(player, 'Mire Attic Hint ES', Intr).dir(Ea, 0x97, Bot, High).pos(0), create_door(player, 'Mire Attic Hint WS', Intr).dir(We, 0x97, Bot, High).pos(0),
create_door(player, 'Mire Attic Hint Hole', Hole), create_door(player, 'Mire Attic Hint Hole', Hole),
create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec), create_door(player, 'Mire Dark Shooters Up Stairs', Sprl).dir(Up, 0x93, 0, LTH).ss(A, 0x32, 0xec),
create_door(player, 'Mire Dark Shooters SW', Intr).dir(So, 0x93, Left, High).pos(0), create_door(player, 'Mire Dark Shooters SW', Intr).dir(So, 0x93, Left, High).pos(0),
@@ -1120,6 +1120,8 @@ def create_doors(world, player):
create_door(player, 'GT Invisible Catwalk NE', Nrml).dir(No, 0x9c, Right, High).pos(2), create_door(player, 'GT Invisible Catwalk NE', Nrml).dir(No, 0x9c, Right, High).pos(2),
create_door(player, 'GT Conveyor Cross EN', Nrml).dir(Ea, 0x8b, Top, High).pos(2), create_door(player, 'GT Conveyor Cross EN', Nrml).dir(Ea, 0x8b, Top, High).pos(2),
create_door(player, 'GT Conveyor Cross WN', Intr).dir(We, 0x8b, Top, High).pos(0), create_door(player, 'GT Conveyor Cross WN', Intr).dir(We, 0x8b, Top, High).pos(0),
create_door(player, 'GT Conveyor Cross Hammer Path', Lgcl),
create_door(player, 'GT Conveyor Cross Hookshot Path', Lgcl),
create_door(player, 'GT Hookshot EN', Intr).dir(Ea, 0x8b, Top, High).pos(0), create_door(player, 'GT Hookshot EN', Intr).dir(Ea, 0x8b, Top, High).pos(0),
create_door(player, 'GT Hookshot East-Mid Path', Lgcl), create_door(player, 'GT Hookshot East-Mid Path', Lgcl),
create_door(player, 'GT Hookshot Mid-East Path', Lgcl), create_door(player, 'GT Hookshot Mid-East Path', Lgcl),
+8 -6
View File
@@ -191,10 +191,11 @@ gt_regions = [
'GT Tile Room', 'GT Speed Torch', 'GT Speed Torch Upper', 'GT Pots n Blocks', 'GT Crystal Conveyor', 'GT Tile Room', 'GT Speed Torch', 'GT Speed Torch Upper', 'GT Pots n Blocks', 'GT Crystal Conveyor',
'GT Crystal Conveyor Corner', 'GT Crystal Conveyor Left', 'GT Crystal Conveyor - Ranged Crystal', 'GT Crystal Conveyor Corner', 'GT Crystal Conveyor Left', 'GT Crystal Conveyor - Ranged Crystal',
'GT Crystal Conveyor Corner - Ranged Crystal', 'GT Compass Room', 'GT Invisible Bridges', 'GT Invisible Catwalk', 'GT Crystal Conveyor Corner - Ranged Crystal', 'GT Compass Room', 'GT Invisible Bridges', 'GT Invisible Catwalk',
'GT Conveyor Cross', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform', 'GT Hookshot North Platform', 'GT Conveyor Cross', 'GT Conveyor Cross Across Pits', 'GT Hookshot East Platform', 'GT Hookshot Mid Platform',
'GT Hookshot South Platform', 'GT Hookshot South Entry', 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', 'GT Hookshot North Platform', 'GT Hookshot South Platform', 'GT Hookshot South Entry',
'GT Double Switch Entry', 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', 'GT Hookshot South Entry - Ranged Crystal', 'GT Map Room', 'GT Double Switch Entry',
'GT Double Switch Left', 'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches', 'GT Double Switch Pot Corners - Ranged Switches', 'GT Double Switch Pot Corners', 'GT Double Switch Left',
'GT Double Switch Left - Crystal', 'GT Double Switch Entry - Ranged Switches',
'GT Double Switch Exit', 'GT Spike Crystal Left', 'GT Double Switch Exit', 'GT Spike Crystal Left',
'GT Spike Crystal Right', 'GT Warp Maze - Left Section', 'GT Warp Maze - Mid Section', 'GT Spike Crystal Right', 'GT Warp Maze - Left Section', 'GT Warp Maze - Mid Section',
'GT Warp Maze - Right Section', 'GT Warp Maze - Pit Section', 'GT Warp Maze - Pit Exit Warp Spot', 'GT Warp Maze - Right Section', 'GT Warp Maze - Pit Section', 'GT Warp Maze - Pit Exit Warp Spot',
@@ -205,8 +206,9 @@ gt_regions = [
'GT Dash Hall', 'GT Hidden Spikes', 'GT Cannonball Bridge', 'GT Refill', 'GT Gauntlet 1', 'GT Gauntlet 2', 'GT Dash Hall', 'GT Hidden Spikes', 'GT Cannonball Bridge', 'GT Refill', 'GT Gauntlet 1', 'GT Gauntlet 2',
'GT Gauntlet 3', 'GT Gauntlet 4', 'GT Gauntlet 5', 'GT Beam Dash', 'GT Lanmolas 2', 'GT Quad Pot', 'GT Wizzrobes 1', 'GT Gauntlet 3', 'GT Gauntlet 4', 'GT Gauntlet 5', 'GT Beam Dash', 'GT Lanmolas 2', 'GT Quad Pot', 'GT Wizzrobes 1',
'GT Dashing Bridge', 'GT Wizzrobes 2', 'GT Conveyor Bridge', 'GT Torch Cross', 'GT Staredown', 'GT Falling Torches', 'GT Dashing Bridge', 'GT Wizzrobes 2', 'GT Conveyor Bridge', 'GT Torch Cross', 'GT Staredown', 'GT Falling Torches',
'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle', 'GT Crystal Circles - Ranged Crystal', 'GT Mini Helmasaur Room', 'GT Bomb Conveyor', 'GT Crystal Circles', 'GT Crystal Inner Circle',
'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm', 'GT Moldorm Pit', 'GT Validation', 'GT Validation Door', 'GT Crystal Circles - Ranged Crystal', 'GT Left Moldorm Ledge', 'GT Right Moldorm Ledge', 'GT Moldorm',
'GT Moldorm Pit', 'GT Validation', 'GT Validation Door',
'GT Frozen Over', 'GT Brightly Lit Hall', 'GT Agahnim 2', 'Ganons Tower Portal' 'GT Frozen Over', 'GT Brightly Lit Hall', 'GT Agahnim 2', 'Ganons Tower Portal'
] ]
+2
View File
@@ -2171,6 +2171,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'),
('West Dark World Gap', 'West Dark World'), ('West Dark World Gap', 'West Dark World'),
('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'),
('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'),
('Dark Graveyard Bush (South)', 'Dark Graveyard North'),
('Dark Graveyard Bush (North)', 'West Dark World'),
('Peg Area Rocks (Left)', 'Hammer Peg Area'), ('Peg Area Rocks (Left)', 'Hammer Peg Area'),
('Peg Area Rocks (Right)', 'West Dark World'), ('Peg Area Rocks (Right)', 'West Dark World'),
('Village of Outcasts Heavy Rock', 'West Dark World'), ('Village of Outcasts Heavy Rock', 'West Dark World'),
+5 -1
View File
@@ -279,6 +279,10 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp
if spot_to_fill: if spot_to_fill:
return spot_to_fill return spot_to_fill
return None return None
# explicitly fail these cases
elif world.algorithm in ['dungeon_only', 'major_only']:
raise FillError(f'Rare placement for {world.algorithm} detected. {item_to_place} unable to be placed.'
f' Try a different seed')
else: else:
other_locations = [x for x in locations if x not in attempted] other_locations = [x for x in locations if x not in attempted]
for location in other_locations: for location in other_locations:
@@ -402,7 +406,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
else: else:
max_trash = gt_count max_trash = gt_count
scaled_trash = math.floor(max_trash * scale_factor) scaled_trash = math.floor(max_trash * scale_factor)
if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt']: if world.goal[player] in ['triforcehunt', 'trinity', 'ganonhunt'] or world.algorithm == 'dungeon_only':
gftower_trash_count = random.randint(scaled_trash, max_trash) gftower_trash_count = random.randint(scaled_trash, max_trash)
else: else:
gftower_trash_count = random.randint(0, scaled_trash) gftower_trash_count = random.randint(0, scaled_trash)
+12 -4
View File
@@ -1294,6 +1294,7 @@ def make_customizer_pool(world, player):
bow_found = next((i for i in pool if i in {'Bow', 'Progressive Bow'}), None) bow_found = next((i for i in pool if i in {'Bow', 'Progressive Bow'}), None)
if not bow_found: if not bow_found:
missing_items.append('Progressive Bow') missing_items.append('Progressive Bow')
if missing_items:
logging.getLogger('').warning(f'The following items are not in the custom item pool {", ".join(missing_items)}') logging.getLogger('').warning(f'The following items are not in the custom item pool {", ".join(missing_items)}')
g, t = set_default_triforce(world.goal[player], world.treasure_hunt_count[player], g, t = set_default_triforce(world.goal[player], world.treasure_hunt_count[player],
@@ -1303,13 +1304,16 @@ def make_customizer_pool(world, player):
if pieces < t: if pieces < t:
pool.extend(['Triforce Piece'] * (t - pieces)) pool.extend(['Triforce Piece'] * (t - pieces))
if not world.customizer.get_start_inventory(): sphere_0 = world.customizer.get_start_inventory()
if world.logic[player] in ['owglitches', 'nologic']: no_start_inventory = not sphere_0 or not sphere_0[player]
init_equip = [] if no_start_inventory else sphere_0[player]
if (world.logic[player] in ['owglitches', 'nologic']
and (no_start_inventory or all(x != 'Pegasus Boots' for x in init_equip))):
precollected_items.append('Pegasus Boots') precollected_items.append('Pegasus Boots')
if 'Pegasus Boots' in pool: if 'Pegasus Boots' in pool:
pool.remove('Pegasus Boots') pool.remove('Pegasus Boots')
pool.append('Rupees (20)') pool.append('Rupees (20)')
if world.swords[player] == 'assured': if world.swords[player] == 'assured' and (no_start_inventory or all(' Sword' not in x for x in init_equip)):
precollected_items.append('Progressive Sword') precollected_items.append('Progressive Sword')
if 'Progressive Sword' in pool: if 'Progressive Sword' in pool:
pool.remove('Progressive Sword') pool.remove('Progressive Sword')
@@ -1399,10 +1403,13 @@ def fill_specific_items(world):
dungeon_pool, prize_set, prize_pool) dungeon_pool, prize_set, prize_pool)
if item_to_place: if item_to_place:
world.push_item(loc, item_to_place, False) world.push_item(loc, item_to_place, False)
loc.locked = True
track_outside_keys(item_to_place, loc, world) track_outside_keys(item_to_place, loc, world)
track_dungeon_items(item_to_place, loc, world) track_dungeon_items(item_to_place, loc, world)
loc.event = (event_flag or item_to_place.advancement loc.event = (event_flag or item_to_place.advancement
or item_to_place.bigkey or item_to_place.smallkey) or item_to_place.bigkey or item_to_place.smallkey)
else:
raise Exception(f'Did not find "{item}" in item pool to place at "{location}"')
advanced_placements = world.customizer.get_advanced_placements() advanced_placements = world.customizer.get_advanced_placements()
if advanced_placements: if advanced_placements:
for player, placement_list in advanced_placements.items(): for player, placement_list in advanced_placements.items():
@@ -1412,7 +1419,7 @@ def fill_specific_items(world):
item_to_place, event_flag = get_item_and_event_flag(item, world, player, item_to_place, event_flag = get_item_and_event_flag(item, world, player,
dungeon_pool, prize_set, prize_pool) dungeon_pool, prize_set, prize_pool)
if not item_to_place: if not item_to_place:
continue raise Exception(f'Did not find "{item}" in item pool to place for a LocationGroup"')
locations = placement['locations'] locations = placement['locations']
handled = False handled = False
while not handled: while not handled:
@@ -1432,6 +1439,7 @@ def fill_specific_items(world):
if loc.item: if loc.item:
continue continue
world.push_item(loc, item_to_place, False) world.push_item(loc, item_to_place, False)
loc.locked = True
track_outside_keys(item_to_place, loc, world) track_outside_keys(item_to_place, loc, world)
track_dungeon_items(item_to_place, loc, world) track_dungeon_items(item_to_place, loc, world)
loc.event = (event_flag or item_to_place.advancement loc.event = (event_flag or item_to_place.advancement
+23 -3
View File
@@ -128,8 +128,6 @@ def main(args, seed=None, fish=None):
world.potshuffle = args.shufflepots.copy() world.potshuffle = args.shufflepots.copy()
world.mixed_travel = args.mixed_travel.copy() world.mixed_travel = args.mixed_travel.copy()
world.standardize_palettes = args.standardize_palettes.copy() world.standardize_palettes = args.standardize_palettes.copy()
world.treasure_hunt_count = {k: int(v) for k, v in args.triforce_goal.items()}
world.treasure_hunt_total = {k: int(v) for k, v in args.triforce_pool.items()}
world.shufflelinks = args.shufflelinks.copy() world.shufflelinks = args.shufflelinks.copy()
world.shuffletavern = args.shuffletavern.copy() world.shuffletavern = args.shuffletavern.copy()
world.pseudoboots = args.pseudoboots.copy() world.pseudoboots = args.pseudoboots.copy()
@@ -139,6 +137,26 @@ def main(args, seed=None, fish=None):
world.collection_rate = args.collection_rate.copy() world.collection_rate = args.collection_rate.copy()
world.colorizepots = args.colorizepots.copy() world.colorizepots = args.colorizepots.copy()
world.treasure_hunt_count = {}
world.treasure_hunt_total = {}
for p in args.triforce_goal:
if int(args.triforce_goal[p]) != 0 or int(args.triforce_pool[p]) != 0 or int(args.triforce_goal_min[p]) != 0 or int(args.triforce_goal_max[p]) != 0 or int(args.triforce_pool_min[p]) != 0 or int(args.triforce_pool_max[p]) != 0:
if int(args.triforce_goal[p]) != 0:
world.treasure_hunt_count[p] = int(args.triforce_goal[p])
elif int(args.triforce_goal_min[p]) != 0 and int(args.triforce_goal_max[p]) != 0:
world.treasure_hunt_count[p] = random.randint(int(args.triforce_goal_min[p]), int(args.triforce_goal_max[p]))
else:
world.treasure_hunt_count[p] = 8 if world.goal[p] == 'trinity' else 20
if int(args.triforce_pool[p]) != 0:
world.treasure_hunt_total[p] = int(args.triforce_pool[p])
elif int(args.triforce_pool_min[p]) != 0 and int(args.triforce_pool_max[p]) != 0:
world.treasure_hunt_total[p] = random.randint(max(int(args.triforce_pool_min[p]), world.treasure_hunt_count[p] + int(args.triforce_min_difference[p])), min(int(args.triforce_pool_max[p]), world.treasure_hunt_count[p] + int(args.triforce_max_difference[p])))
else:
world.treasure_hunt_total[p] = 10 if world.goal[p] == 'trinity' else 30
else:
# this will be handled in ItemList.py and custom item pool is used to determine the numbers
world.treasure_hunt_count[p], world.treasure_hunt_total[p] = 0, 0
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
world.finish_init() world.finish_init()
@@ -620,7 +638,9 @@ def create_playthrough(world):
logging.getLogger('').debug(world.fish.translate("cli", "cli", "building.calculating.spheres"), len(collection_spheres), len(sphere), len(prog_locations)) logging.getLogger('').debug(world.fish.translate("cli", "cli", "building.calculating.spheres"), len(collection_spheres), len(sphere), len(prog_locations))
if not sphere: if not sphere:
logging.getLogger('').error(world.fish.translate("cli", "cli", "cannot.reach.items"), [world.fish.translate("cli","cli","cannot.reach.item") % (location.item.name, location.item.player, location.name, location.player) for location in sphere_candidates]) if world.accessibility[location.item.player] != 'none':
logging.getLogger('').error(world.fish.translate("cli", "cli", "cannot.reach.items"),
[world.fish.translate("cli","cli","cannot.reach.item") % (location.item.name, location.item.player, location.name, location.player) for location in sphere_candidates])
if any([location.name not in optional_locations and world.accessibility[location.item.player] != 'none' for location in sphere_candidates]): if any([location.name not in optional_locations and world.accessibility[location.item.player] != 'none' for location in sphere_candidates]):
raise RuntimeError(world.fish.translate("cli", "cli", "cannot.reach.progression")) raise RuntimeError(world.fish.translate("cli", "cli", "cannot.reach.progression"))
else: else:
+1 -1
View File
@@ -48,7 +48,7 @@ mirror_connections = {
'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'], 'East Dark Death Mountain (Bushes)': ['Fairy Ascension Plateau'],
'East Dark Death Mountain (Bottom)': ['East Death Mountain (Bottom)'], 'East Dark Death Mountain (Bottom)': ['East Death Mountain (Bottom)'],
'West Dark World': ['Graveyard Ledge', 'Kings Grave Area'], 'Dark Graveyard North': ['Graveyard Ledge', 'Kings Grave Area'],
'Bumper Cave Ledge': ['Death Mountain Return Ledge'], 'Bumper Cave Ledge': ['Death Mountain Return Ledge'],
'Bumper Cave Entrance': ['Death Mountain Entrance'], 'Bumper Cave Entrance': ['Death Mountain Entrance'],
+3 -2
View File
@@ -404,7 +404,7 @@ CLI: `--logic owglitches`
New supported goals: New supported goals:
* Trinity: Find one of 3 triforces to win. One is at pedestal. One is with Ganon. One is with Murahdahla who wants you to find 8 of 10 triforce pieces to complete. * Trinity: Find one of 3 triforces to win. One is at pedestal. One is with Ganon. One is with Murahdahla who wants you to find 8 of 10 triforce pieces to complete.
* Triforce Hunt + Ganon: Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI * Ganonhunt: Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI
* Completionist: All dungeons not enough for you? You have to obtain every item in the game too. This option turns on the collection rate counter and forces accessibility to be 100% locations. Finish by defeating Ganon. * Completionist: All dungeons not enough for you? You have to obtain every item in the game too. This option turns on the collection rate counter and forces accessibility to be 100% locations. Finish by defeating Ganon.
@@ -573,13 +573,14 @@ Create bps patch(es) instead of generating rom(s) for distribution. `--bps`
### Triforce Hunt Settings ### Triforce Hunt Settings
A collection of settings to control the triforce piece pool for the CLI/Mystery A collection of settings to control the triforce piece pool if not specified through --triforce_goal and --triforce_pool
* --triforce_goal_min: Minimum number of pieces to collect to win * --triforce_goal_min: Minimum number of pieces to collect to win
* --triforce_goal_max: Maximum number of pieces to collect to win * --triforce_goal_max: Maximum number of pieces to collect to win
* --triforce_pool_min: Minimum number of pieces in item pool * --triforce_pool_min: Minimum number of pieces in item pool
* --triforce_pool_max: Maximum number of pieces in item pool * --triforce_pool_max: Maximum number of pieces in item pool
* --triforce_min_difference: Minimum difference between pool and goal to win * --triforce_min_difference: Minimum difference between pool and goal to win
* --triforce_max_difference: Maximum difference between pool and goal to win
### Seed ### Seed
+29 -1
View File
@@ -57,7 +57,7 @@ Please see [Customizer documentation](docs/Customizer.md) on how to create custo
## New Goals ## New Goals
### Triforce Hunt + Ganon ### Ganonhunt
Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI Collect the requisite triforce pieces, then defeat Ganon. (Aga2 not required). Use `ganonhunt` on CLI
### Completionist ### Completionist
@@ -109,8 +109,35 @@ These are now independent of retro mode and have three options: None, Random, an
# Bug Fixes and Notes # Bug Fixes and Notes
* 1.2.0.19u
* Added min/max for triforce pool, goal, and difference for CLI and Customizer. (Thanks Catobat)
* Fixed a bug with dungeon generation
* Multiworld: Fixed /missing command to not list all the pots
* Changed the "Ganonhunt" goal to use open pyramid on the Auto setting
* Customizer: Fixed the example yaml for shopsanity
* 1.2.0.18u
* Fixed an issue with pyramid hole being in logic when it is not opened.
* Crystal cutscene at GT use new symmetrical layouts (thanks Codemann)
* Fix for Hera Boss music (thanks Codemann)
* Fixed an issue where certain vanilla door types would not allow other types to be placed.
* Customizer: fixed an issue where last ditch placements would move customized items. Those are now locked and the generation will fail instead if no alternatives are found.
* Customizer: fixed an issue with assured sword and start_inventory
* Customizer: warns when trying to specifically place an item that's not in the item pool
* Fixed "accessibility: none" displaying a spoiling message
* Fixed warning message about custom item pool when it is fine
* 1.2.0.17u
* Fixed logic bug that allowed Pearl to be behind Graveyard Cave or King's Tomb entrances with only Mirror and West Dark World access (cross world shuffles only)
* Removed backup locations for Dungeon Only and Major Only algorithms. If item cannot be placed in the appropriate location, the seed will fail to generate instead
* Fix for Non-ER Inverted Experimental (Aga and GT weren't logically swapped)
* Fix for customizer setting crystals to 0 for either GT/Ganon
* 1.2.0.16u
* Fix for partial key logic on vanilla Mire
* Fix for Kholdstare Shell collision when at Lanmo 2
* Fix for Mire Attic Hint door (direction was swapped)
* Dungeon at Chest Game displays correctly on OW map option
* 1.2.0.15u * 1.2.0.15u
* GUI reorganization * GUI reorganization
* Logic fix for pots in GT conveyor cross
* Auto option for pyramid open (trinity or ER + crystals goal) * Auto option for pyramid open (trinity or ER + crystals goal)
* World model refactor (combining inverted and normal world models) * World model refactor (combining inverted and normal world models)
* Partitioned fix for lamp logic and links house * Partitioned fix for lamp logic and links house
@@ -118,6 +145,7 @@ These are now independent of retro mode and have three options: None, Random, an
* Reduced universal keys in pool slightly for non-vanilla dungeons * Reduced universal keys in pool slightly for non-vanilla dungeons
* Fake world fix finally * Fake world fix finally
* Some extra restrictions on links house placement for lite/lean * Some extra restrictions on links house placement for lite/lean
* Collection_rate works in customizer files
* 1.2.0.14u * 1.2.0.14u
* Small fix for key logic validation (got rid of a false negative) * Small fix for key logic validation (got rid of a false negative)
* Customized doors in ice cross work properly now * Customized doors in ice cross work properly now
+6 -4
View File
@@ -87,7 +87,8 @@ def create_regions(world, player):
create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town', create_dw_region(player, 'West Dark World', ['Frog'], ['Dark Lumberjack Shop', 'Fortune Teller (Dark)', 'Dark Sanctuary Hint', 'Chest Game', 'Thieves Town',
'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock', 'C-Shaped House', 'Brewery', 'Red Shield Shop', 'Skull Woods Forest', 'Bumper Cave Entrance Rock',
'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop', 'West Dark World Water Drop', 'Grassy Lawn Pegs (Bottom)', 'Peg Area Rocks (Left)', 'Village of Outcasts Drop',
'West Dark World Teleporter', 'WDW Flute']), 'West Dark World Teleporter', 'WDW Flute', 'Dark Graveyard Bush (South)']),
create_dw_region(player, 'Dark Graveyard North', None, ['Dark Graveyard Bush (North)']),
create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)', create_dw_region(player, 'Skull Woods Forest', None, ['Skull Woods First Section Hole (East)', 'Skull Woods First Section Hole (West)', 'Skull Woods First Section Hole (North)',
'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']), 'Skull Woods First Section Door', 'Skull Woods Second Section Door (East)']),
create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'), create_dw_region(player, 'Skull Woods Forest (West)', None, ['Skull Woods Second Section Hole', 'Skull Woods Second Section Door (West)', 'Skull Woods Final Section'], 'a deep, dark forest'),
@@ -697,8 +698,8 @@ def create_dungeon_regions(world, player):
create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']), create_dungeon_region(player, 'Mire BK Chest Ledge', 'Misery Mire', ['Misery Mire - Big Key Chest'], ['Mire BK Chest Ledge WS']),
create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']), create_dungeon_region(player, 'Mire Warping Pool', 'Misery Mire', None, ['Mire Warping Pool ES', 'Mire Warping Pool Warp']),
create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']), create_dungeon_region(player, 'Mire Torches Top', 'Misery Mire', None, ['Mire Torches Top Down Stairs', 'Mire Torches Top SW', 'Mire Torches Top Holes']),
create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom WS', 'Mire Torches Bottom Holes']), create_dungeon_region(player, 'Mire Torches Bottom', 'Misery Mire', None, ['Mire Torches Bottom NW', 'Mire Torches Bottom ES', 'Mire Torches Bottom Holes']),
create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint ES', 'Mire Attic Hint Hole']), create_dungeon_region(player, 'Mire Attic Hint', 'Misery Mire', None, ['Mire Attic Hint WS', 'Mire Attic Hint Hole']),
create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']), create_dungeon_region(player, 'Mire Dark Shooters', 'Misery Mire', None, ['Mire Dark Shooters Up Stairs', 'Mire Dark Shooters SW', 'Mire Dark Shooters SE']),
create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']), create_dungeon_region(player, 'Mire Key Rupees', 'Misery Mire', None, ['Mire Key Rupees NE']),
create_dungeon_region(player, 'Mire Block X', 'Misery Mire', None, ['Mire Block X NW', 'Mire Block X WS']), create_dungeon_region(player, 'Mire Block X', 'Misery Mire', None, ['Mire Block X NW', 'Mire Block X WS']),
@@ -792,7 +793,8 @@ def create_dungeon_regions(world, player):
['GT Compass Room EN', 'GT Compass Room Warp']), ['GT Compass Room EN', 'GT Compass Room Warp']),
create_dungeon_region(player, 'GT Invisible Bridges', 'Ganon\'s Tower', None, ['GT Invisible Bridges WS']), create_dungeon_region(player, 'GT Invisible Bridges', 'Ganon\'s Tower', None, ['GT Invisible Bridges WS']),
create_dungeon_region(player, 'GT Invisible Catwalk', 'Ganon\'s Tower', None, ['GT Invisible Catwalk ES', 'GT Invisible Catwalk WS', 'GT Invisible Catwalk NW', 'GT Invisible Catwalk NE']), create_dungeon_region(player, 'GT Invisible Catwalk', 'Ganon\'s Tower', None, ['GT Invisible Catwalk ES', 'GT Invisible Catwalk WS', 'GT Invisible Catwalk NW', 'GT Invisible Catwalk NE']),
create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross WN']), create_dungeon_region(player, 'GT Conveyor Cross', 'Ganon\'s Tower', ['Ganons Tower - Conveyor Cross Pot Key'], ['GT Conveyor Cross EN', 'GT Conveyor Cross Hammer Path']),
create_dungeon_region(player, 'GT Conveyor Cross Across Pits', 'Ganon\'s Tower', None, ['GT Conveyor Cross Hookshot Path', 'GT Conveyor Cross WN']),
create_dungeon_region(player, 'GT Hookshot East Platform', 'Ganon\'s Tower', None, ['GT Hookshot EN', 'GT Hookshot East-Mid Path']), create_dungeon_region(player, 'GT Hookshot East Platform', 'Ganon\'s Tower', None, ['GT Hookshot EN', 'GT Hookshot East-Mid Path']),
create_dungeon_region(player, 'GT Hookshot Mid Platform', 'Ganon\'s Tower', None, ['GT Hookshot Mid-East Path', 'GT Hookshot Mid-South Path', 'GT Hookshot Mid-North Path']), create_dungeon_region(player, 'GT Hookshot Mid Platform', 'Ganon\'s Tower', None, ['GT Hookshot Mid-East Path', 'GT Hookshot Mid-South Path', 'GT Hookshot Mid-North Path']),
create_dungeon_region(player, 'GT Hookshot North Platform', 'Ganon\'s Tower', None, ['GT Hookshot NW', 'GT Hookshot North-Mid Path']), create_dungeon_region(player, 'GT Hookshot North Platform', 'Ganon\'s Tower', None, ['GT Hookshot NW', 'GT Hookshot North-Mid Path']),
+1 -1
View File
@@ -40,7 +40,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '563fe28515c5dd9f64270ca475d1c2d3' RANDOMIZERBASEHASH = 'e5f3f7dd5be54dce0f490529803dafc3'
class JsonRom(object): class JsonRom(object):
+41 -4
View File
@@ -209,7 +209,6 @@ def global_rules(world, player):
set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest set_rule(world.get_location('Purple Chest', player), lambda state: state.has('Pick Up Purple Chest', player)) # Can S&Q with chest
# underworld rules # underworld rules
set_rule(world.get_entrance('Old Man Cave Exit (West)', player), lambda state: False) # drop cannot be climbed up
set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player)) set_rule(world.get_location('Mimic Cave', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: state.has_Mirror(player)) # can erase block - overridden in noglitches
set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player)) set_rule(world.get_location('Potion Shop', player), lambda state: state.has('Mushroom', player) and state.can_reach('Potion Shop Area', 'Region', player))
@@ -479,8 +478,8 @@ def global_rules(world, player):
set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player)) set_rule(world.get_location('Ganons Tower - Bob\'s Torch', player), lambda state: state.has_Boots(player))
set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('GT Hope Room EN', player), lambda state: state.has('Cane of Somaria', player))
set_rule(world.get_entrance('GT Conveyor Cross WN', player), lambda state: state.has('Hammer', player)) set_rule(world.get_entrance('GT Conveyor Cross Hammer Path', player), lambda state: state.has('Hammer', player))
set_rule(world.get_entrance('GT Conveyor Cross EN', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Conveyor Cross Hookshot Path', player), lambda state: state.has('Hookshot', player))
if not world.get_door('GT Speed Torch SE', player).entranceFlag: if not world.get_door('GT Speed Torch SE', player).entranceFlag:
set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player)) set_rule(world.get_entrance('GT Speed Torch SE', player), lambda state: state.has('Fire Rod', player))
set_rule(world.get_entrance('GT Hookshot South-Mid Path', player), lambda state: state.has('Hookshot', player)) set_rule(world.get_entrance('GT Hookshot South-Mid Path', player), lambda state: state.has('Hookshot', player))
@@ -887,7 +886,7 @@ def ow_inverted_rules(world, player):
set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player))
set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player)) set_rule(world.get_entrance('Hyrule Castle Main Gate (North)', player), lambda state: state.has_Mirror(player))
set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player)) set_rule(world.get_location('Frog', player), lambda state: state.can_lift_heavy_rocks(player) and state.has_Pearl(player))
set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.open_pyramid[player] or world.goal[player] == 'trinity' or state.has('Beat Agahnim 2', player)) set_rule(world.get_entrance('Pyramid Hole', player), lambda state: world.is_pyramid_open(player) or state.has('Beat Agahnim 2', player))
else: else:
set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Top)', player), lambda state: state.can_lift_heavy_rocks(player) and state.has('Hammer', player) and state.has_Pearl(player)) # bunny cannot use hammer
set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Bottom)', player), lambda state: state.can_lift_heavy_rocks(player)) set_rule(world.get_entrance('East Dark Death Mountain Teleporter (Bottom)', player), lambda state: state.can_lift_heavy_rocks(player))
@@ -965,6 +964,8 @@ def ow_bunny_rules(world, player):
add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player) add_bunny_rule(world.get_entrance('East Dark Death Mountain Bushes', player), player)
add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player) add_bunny_rule(world.get_entrance('Bumper Cave Entrance Rock', player), player)
add_bunny_rule(world.get_entrance('Dark Graveyard Bush (South)', player), player)
add_bunny_rule(world.get_entrance('Dark Graveyard Bush (North)', player), player)
add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (North)', player), player)
add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player) add_bunny_rule(world.get_entrance('Dark Witch Rock (South)', player), player)
add_bunny_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), player) add_bunny_rule(world.get_entrance('Grassy Lawn Pegs (Bottom)', player), player)
@@ -2057,6 +2058,8 @@ def add_key_logic_rules(world, player):
eval_func = eval_small_key_door eval_func = eval_small_key_door
if world.key_logic_algorithm[player] == 'strict' and world.keyshuffle[player] == 'wild': if world.key_logic_algorithm[player] == 'strict' and world.keyshuffle[player] == 'wild':
eval_func = eval_small_key_door_strict eval_func = eval_small_key_door_strict
elif world.key_logic_algorithm[player] != 'default':
eval_func = eval_small_key_door_partial
for d_name, d_logic in key_logic.items(): for d_name, d_logic in key_logic.items():
for door_name, rule in d_logic.door_rules.items(): for door_name, rule in d_logic.door_rules.items():
door_entrance = world.get_entrance(door_name, player) door_entrance = world.get_entrance(door_name, player)
@@ -2112,6 +2115,36 @@ def eval_small_key_door_main(state, door_name, dungeon, player):
return door_openable return door_openable
def eval_small_key_door_partial_main(state, door_name, dungeon, player):
if state.is_door_open(door_name, player):
return True
key_logic = state.world.key_logic[player][dungeon]
if door_name not in key_logic.door_rules:
return False
door_rule = key_logic.door_rules[door_name]
door_openable = False
for ruleType, number in door_rule.new_rules.items():
if door_openable:
return True
if ruleType == KeyRuleType.WorstCase:
number = min(number, door_rule.small_key_num)
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
elif ruleType == KeyRuleType.AllowSmall:
small_loc_item = door_rule.small_location.item
if small_loc_item and small_loc_item.name == key_logic.small_key_name and small_loc_item.player == player:
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
elif isinstance(ruleType, tuple):
lock, lock_item = ruleType
# this doesn't track logical locks yet, i.e. hammer locks the item and hammer is there, but the item isn't
for loc in door_rule.alternate_big_key_loc:
spot = state.world.get_location(loc, player)
if spot.item and spot.item.name == lock_item:
number = min(number, door_rule.alternate_small_key)
door_openable |= state.has_sm_key(key_logic.small_key_name, player, number)
break
return door_openable
def eval_small_key_door_strict_main(state, door_name, dungeon, player): def eval_small_key_door_strict_main(state, door_name, dungeon, player):
if state.is_door_open(door_name, player): if state.is_door_open(door_name, player):
return True return True
@@ -2126,6 +2159,10 @@ def eval_small_key_door(door_name, dungeon, player):
return lambda state: eval_small_key_door_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_main(state, door_name, dungeon, player)
def eval_small_key_door_partial(door_name, dungeon, player):
return lambda state: eval_small_key_door_partial_main(state, door_name, dungeon, player)
def eval_small_key_door_strict(door_name, dungeon, player): def eval_small_key_door_strict(door_name, dungeon, player):
return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player) return lambda state: eval_small_key_door_strict_main(state, door_name, dungeon, player)
Binary file not shown.
+4 -1
View File
@@ -1,7 +1,7 @@
meta: meta:
algorithm: balanced algorithm: balanced
players: 1 players: 1
seed: 42 seed: 41 # note to self: seed 42 had an interesting Swamp Palace problem
names: Lonk names: Lonk
settings: settings:
1: 1:
@@ -56,6 +56,9 @@ item_pool:
Sanctuary Heart Container: 3 Sanctuary Heart Container: 3
Shovel: 3 Shovel: 3
Single Arrow: 1 Single Arrow: 1
Green Potion: 1
Blue Potion: 1
Red Potion: 1
placements: placements:
1: 1:
Palace of Darkness - Big Chest: Hammer Palace of Darkness - Big Chest: Hammer
+1
View File
@@ -108,6 +108,7 @@
triforce_pool_min: 20 triforce_pool_min: 20
triforce_pool_max: 40 triforce_pool_max: 40
triforce_min_difference: 10 triforce_min_difference: 10
triforce_max_difference: 15
dungeon_items: dungeon_items:
standard: 10 standard: 10
mc: 3 mc: 3
+1
View File
@@ -84,6 +84,7 @@ triforce_goal_max: 30
triforce_pool_min: 30 triforce_pool_min: 30
triforce_pool_max: 40 triforce_pool_max: 40
triforce_min_difference: 10 triforce_min_difference: 10
triforce_max_difference: 12
map_shuffle: map_shuffle:
on: 1 on: 1
off: 1 off: 1
+1
View File
@@ -342,6 +342,7 @@
"triforce_goal_min": {}, "triforce_goal_min": {},
"triforce_goal_max": {}, "triforce_goal_max": {},
"triforce_min_difference": {}, "triforce_min_difference": {},
"triforce_max_difference": {},
"custom": { "custom": {
"type": "bool", "type": "bool",
"help": "suppress" "help": "suppress"
+3 -2
View File
@@ -228,6 +228,7 @@
"randomizer.item.worldstate.open": "Open", "randomizer.item.worldstate.open": "Open",
"randomizer.item.worldstate.inverted": "Inverted", "randomizer.item.worldstate.inverted": "Inverted",
"randomizer.item.worldstate.retro": "Retro", "randomizer.item.worldstate.retro": "Retro",
"randomizer.item.retro": "Enable Retro",
"randomizer.item.logiclevel": "Logic Level", "randomizer.item.logiclevel": "Logic Level",
"randomizer.item.logiclevel.noglitches": "No Glitches", "randomizer.item.logiclevel.noglitches": "No Glitches",
@@ -242,7 +243,7 @@
"randomizer.item.goal.triforcehunt": "Triforce Hunt", "randomizer.item.goal.triforcehunt": "Triforce Hunt",
"randomizer.item.goal.trinity": "Trinity", "randomizer.item.goal.trinity": "Trinity",
"randomizer.item.goal.crystals": "Crystals", "randomizer.item.goal.crystals": "Crystals",
"randomizer.item.goal.ganonhunt": "Triforce Hunt + Ganon", "randomizer.item.goal.ganonhunt": "Ganonhunt",
"randomizer.item.goal.completionist": "Completionist", "randomizer.item.goal.completionist": "Completionist",
"randomizer.item.crystals_gt": "Crystals to open GT", "randomizer.item.crystals_gt": "Crystals to open GT",
@@ -325,7 +326,7 @@
"randomizer.item.dropshuffle.none": "None", "randomizer.item.dropshuffle.none": "None",
"randomizer.item.dropshuffle.keys": "Small Key Enemies", "randomizer.item.dropshuffle.keys": "Small Key Enemies",
"randomizer.item.dropshuffle.underworld": "Underworld Enemies", "randomizer.item.dropshuffle.underworld": "Underworld Enemies",
"randomizer.item.keydropshuffle": "Key Drop Shuffle (Legacy)", "randomizer.item.keydropshuffle": "Enable Key Drop Shuffle (Legacy)",
"randomizer.item.take_any": "Take Any Caves", "randomizer.item.take_any": "Take Any Caves",
"randomizer.item.take_any.none": "None", "randomizer.item.take_any.none": "None",
+19 -9
View File
@@ -11,12 +11,8 @@
"options": [ "options": [
"standard", "standard",
"open", "open",
"inverted", "inverted"
"retro" ]
],
"config": {
"command": "worldstate"
}
}, },
"logiclevel": { "logiclevel": {
"type": "selectbox", "type": "selectbox",
@@ -65,6 +61,12 @@
} }
}, },
"rightItemFrame": { "rightItemFrame": {
"retro": {
"type": "button",
"config": {
"command": "retro"
}
},
"sortingalgo": { "sortingalgo": {
"type": "selectbox", "type": "selectbox",
"default": "balanced", "default": "balanced",
@@ -140,13 +142,19 @@
"colorizepots": { "colorizepots": {
"type": "checkbox", "type": "checkbox",
"config": { "config": {
"padx": [50,0] "padx": [
50,
0
]
} }
}, },
"potshuffle": { "potshuffle": {
"type": "checkbox", "type": "checkbox",
"config": { "config": {
"padx": [50,0] "padx": [
50,
0
]
} }
}, },
"dropshuffle": { "dropshuffle": {
@@ -156,7 +164,9 @@
"none", "none",
"keys", "keys",
"underworld" "underworld"
]}, ]}
},
"leftPoolFrame2": {
"keydropshuffle": { "keydropshuffle": {
"type": "checkbox", "type": "checkbox",
"config": { "config": {
+11 -2
View File
@@ -2,6 +2,7 @@ import os
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import yaml import yaml
from typing import Any
from yaml.representer import Representer from yaml.representer import Representer
from collections import defaultdict from collections import defaultdict
from pathlib import Path from pathlib import Path
@@ -46,8 +47,8 @@ class CustomSettings(object):
return meta['players'] return meta['players']
def adjust_args(self, args): def adjust_args(self, args):
def get_setting(value, default): def get_setting(value: Any, default):
if value: if value or value == 0:
if isinstance(value, dict): if isinstance(value, dict):
return random.choices(list(value.keys()), list(value.values()), k=1)[0] return random.choices(list(value.keys()), list(value.values()), k=1)[0]
else: else:
@@ -117,6 +118,7 @@ class CustomSettings(object):
args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p]) args.crystals_gt[p] = get_setting(settings['crystals_gt'], args.crystals_gt[p])
args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p]) args.crystals_ganon[p] = get_setting(settings['crystals_ganon'], args.crystals_ganon[p])
args.experimental[p] = get_setting(settings['experimental'], args.experimental[p]) args.experimental[p] = get_setting(settings['experimental'], args.experimental[p])
args.collection_rate[p] = get_setting(settings['collection_rate'], args.collection_rate[p])
args.openpyramid[p] = get_setting(settings['openpyramid'], args.openpyramid[p]) args.openpyramid[p] = get_setting(settings['openpyramid'], args.openpyramid[p])
args.bigkeyshuffle[p] = get_setting(settings['bigkeyshuffle'], args.bigkeyshuffle[p]) args.bigkeyshuffle[p] = get_setting(settings['bigkeyshuffle'], args.bigkeyshuffle[p])
args.keyshuffle[p] = get_setting(settings['keyshuffle'], args.keyshuffle[p]) args.keyshuffle[p] = get_setting(settings['keyshuffle'], args.keyshuffle[p])
@@ -144,6 +146,12 @@ class CustomSettings(object):
args.pseudoboots[p] = get_setting(settings['pseudoboots'], args.pseudoboots[p]) args.pseudoboots[p] = get_setting(settings['pseudoboots'], args.pseudoboots[p])
args.triforce_goal[p] = get_setting(settings['triforce_goal'], args.triforce_goal[p]) args.triforce_goal[p] = get_setting(settings['triforce_goal'], args.triforce_goal[p])
args.triforce_pool[p] = get_setting(settings['triforce_pool'], args.triforce_pool[p]) args.triforce_pool[p] = get_setting(settings['triforce_pool'], args.triforce_pool[p])
args.triforce_goal_min[p] = get_setting(settings['triforce_goal_min'], args.triforce_goal_min[p])
args.triforce_goal_max[p] = get_setting(settings['triforce_goal_max'], args.triforce_goal_max[p])
args.triforce_pool_min[p] = get_setting(settings['triforce_pool_min'], args.triforce_pool_min[p])
args.triforce_pool_max[p] = get_setting(settings['triforce_pool_max'], args.triforce_pool_max[p])
args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p])
args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p])
args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p]) args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p])
# mystery usage # mystery usage
@@ -251,6 +259,7 @@ class CustomSettings(object):
settings_dict[p]['crystals_gt'] = world.crystals_gt_orig[p] settings_dict[p]['crystals_gt'] = world.crystals_gt_orig[p]
settings_dict[p]['crystals_ganon'] = world.crystals_ganon_orig[p] settings_dict[p]['crystals_ganon'] = world.crystals_ganon_orig[p]
settings_dict[p]['experimental'] = world.experimental[p] settings_dict[p]['experimental'] = world.experimental[p]
settings_dict[p]['collection_rate'] = world.collection_rate[p]
settings_dict[p]['openpyramid'] = world.open_pyramid[p] settings_dict[p]['openpyramid'] = world.open_pyramid[p]
settings_dict[p]['bigkeyshuffle'] = world.bigkeyshuffle[p] settings_dict[p]['bigkeyshuffle'] = world.bigkeyshuffle[p]
settings_dict[p]['keyshuffle'] = world.keyshuffle[p] settings_dict[p]['keyshuffle'] = world.keyshuffle[p]
+1
View File
@@ -66,6 +66,7 @@ SETTINGSTOPROCESS = {
"crystals_ganon": "crystals_ganon", "crystals_ganon": "crystals_ganon",
"weapons": "swords", "weapons": "swords",
"retro": "retro",
"sortingalgo": "algorithm", "sortingalgo": "algorithm",
"accessibility": "accessibility", "accessibility": "accessibility",
"restrict_boss_items": "restrict_boss_items", "restrict_boss_items": "restrict_boss_items",
+1 -13
View File
@@ -214,6 +214,7 @@ def create_guiargs(parent):
arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget] arg = options[mainpage][subpage][widget] if subpage != "" else options[mainpage][widget]
page = parent.pages[mainpage].pages[subpage] if subpage != "" else parent.pages[mainpage] 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 pagewidgets = page.content.customWidgets if mainpage == "custom" else page.content.startingWidgets if mainpage == "startinventory" else page.widgets
if hasattr(pagewidgets[widget], 'storageVar'):
setattr(guiargs, arg, pagewidgets[widget].storageVar.get()) setattr(guiargs, arg, pagewidgets[widget].storageVar.get())
# Get Multiworld Worlds count # Get Multiworld Worlds count
@@ -282,17 +283,4 @@ def create_guiargs(parent):
guiargs = update_deprecated_args(guiargs) guiargs = update_deprecated_args(guiargs)
# Key drop shuffle stuff
if guiargs.keydropshuffle:
guiargs.dropshuffle = 'keys' if guiargs.dropshuffle == 'none' else guiargs.dropshuffle
guiargs.pottery = 'keys' if guiargs.pottery == 'none' else guiargs.pottery
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':
guiargs.bow_mode = 'retro_silvers'
guiargs.take_any = 'random' if guiargs.take_any == 'none' else guiargs.take_any
guiargs.keyshuffle = 'universal'
return guiargs return guiargs
+3
View File
@@ -57,6 +57,9 @@ def loadcliargs(gui, args, settings=None):
pagewidgets[widget].selectbox.options = theseOptions pagewidgets[widget].selectbox.options = theseOptions
elif thisType == "spinbox": elif thisType == "spinbox":
pagewidgets[widget].label.configure(text=label) pagewidgets[widget].label.configure(text=label)
elif thisType == 'button':
pagewidgets[widget].button.configure(text=label)
if hasattr(pagewidgets[widget], 'storageVar'):
pagewidgets[widget].storageVar.set(args[arg]) pagewidgets[widget].storageVar.set(args[arg])
# If we're on the Game Options page and it's not about Hints # If we're on the Game Options page and it's not about Hints
if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]: if subpage == "gameoptions" and widget not in ["hints", "collection_rate"]:
+7 -2
View File
@@ -43,7 +43,10 @@ def item_page(parent):
self.frames["leftPoolHeader"].pack(side=TOP, anchor=W) self.frames["leftPoolHeader"].pack(side=TOP, anchor=W)
self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"]) self.frames["leftPoolFrame"] = Frame(self.frames["leftPoolContainer"])
self.frames["leftPoolFrame"].pack(side=LEFT, fill=Y) self.frames["leftPoolFrame"].pack(side=TOP, fill=Y)
self.frames["leftPoolFrame2"] = Frame(self.frames["leftPoolContainer"])
self.frames["leftPoolFrame2"].pack(side=LEFT, fill=Y)
self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"]) self.frames["rightPoolFrame"] = Frame(self.frames["poolFrame"])
self.frames["rightPoolFrame"].pack(side=RIGHT) self.frames["rightPoolFrame"].pack(side=RIGHT)
@@ -62,7 +65,9 @@ def item_page(parent):
for key in dictWidgets: for key in dictWidgets:
self.widgets[key] = dictWidgets[key] self.widgets[key] = dictWidgets[key]
packAttrs = {"anchor":E} packAttrs = {"anchor":E}
if self.widgets[key].type == "checkbox" or framename == "leftPoolFrame": if key == "retro":
packAttrs["side"] = RIGHT
if self.widgets[key].type == "checkbox" or framename.startswith("leftPoolFrame"):
packAttrs["anchor"] = W packAttrs["anchor"] = W
if framename == "checkboxes": if framename == "checkboxes":
packAttrs["side"] = LEFT packAttrs["side"] = LEFT
+26 -17
View File
@@ -1,4 +1,6 @@
from tkinter import messagebox, 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 tkinter import Button
from source.classes.Empty import Empty from source.classes.Empty import Empty
# Override Spinbox to include mousewheel support for changing value # Override Spinbox to include mousewheel support for changing value
@@ -172,6 +174,22 @@ def make_textbox(self, parent, label, storageVar, manager, managerAttrs):
widget.textbox.pack(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None) widget.textbox.pack(managerAttrs["textbox"] if managerAttrs is not None and "textbox" in managerAttrs else None)
return widget return widget
def make_button(self, parent, label, manager, managerAttrs, config):
self = Frame(parent)
if config and "command" in config:
self.command = config["command"]
else:
self.command = lambda: None
self.button = Button(parent, text=label, command=lambda: widget_command(self, self.command))
if managerAttrs is not None:
self.button.pack(managerAttrs)
else:
self.button.pack(anchor='w')
return self
# Make a generic widget # Make a generic widget
def make_widget(self, type, parent, label, storageVar=None, manager=None, managerAttrs=dict(), def make_widget(self, type, parent, label, storageVar=None, manager=None, managerAttrs=dict(),
options=None, config=None): options=None, config=None):
@@ -201,6 +219,8 @@ def make_widget(self, type, parent, label, storageVar=None, manager=None, manage
if thisStorageVar is None: if thisStorageVar is None:
thisStorageVar = StringVar() thisStorageVar = StringVar()
widget = make_textbox(self, parent, label, thisStorageVar, manager, managerAttrs) widget = make_textbox(self, parent, label, thisStorageVar, manager, managerAttrs)
elif type == 'button':
widget = make_button(self, parent, label, manager, managerAttrs, config)
widget.type = type widget.type = type
return widget return widget
@@ -243,8 +263,7 @@ def add_padding_from_config(packAttrs, defn):
def widget_command(widget, command=""): def widget_command(widget, command=""):
root = widget.winfo_toplevel() root = widget.winfo_toplevel()
text_output = "" text_output = ""
if command == "worldstate": if command == "retro":
if widget.storageVar.get() == 'retro':
temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"] temp_widget = root.pages["randomizer"].pages["dungeon"].widgets["smallkeyshuffle"]
text_output += f'\n {temp_widget.label.cget("text")}' text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('universal') temp_widget.storageVar.set('universal')
@@ -261,29 +280,19 @@ def widget_command(widget, command=""):
if temp_widget.storageVar.get() == 'none': if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('random') temp_widget.storageVar.set('random')
widget.storageVar.set('open')
messagebox.showinfo('', f'The following settings were changed:{text_output}') messagebox.showinfo('', f'The following settings were changed:{text_output}')
elif command == "keydropshuffle": elif command == "keydropshuffle":
if widget.storageVar.get() > 0:
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"] temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
if temp_widget.storageVar.get() == 'none':
text_output += f'\n {temp_widget.label.cget("text")}' text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys') temp_widget.storageVar.set('keys')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"] temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
text_output += f'\n {temp_widget.label.cget("text")}'
if temp_widget.storageVar.get() == 'none': if temp_widget.storageVar.get() == 'none':
temp_widget.storageVar.set('keys') temp_widget.storageVar.set('keys')
text_output += f'\n {temp_widget.label.cget("text")}'
if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}')
else:
temp_widget = root.pages["randomizer"].pages["item"].widgets["pottery"]
if temp_widget.storageVar.get() == 'keys':
text_output += f'\n {temp_widget.label.cget("text")}'
temp_widget.storageVar.set('none')
temp_widget = root.pages["randomizer"].pages["item"].widgets["dropshuffle"]
if temp_widget.storageVar.get() == 'keys':
temp_widget.storageVar.set('none')
text_output += f'\n {temp_widget.label.cget("text")}'
if text_output: if text_output:
messagebox.showinfo('', f'The following settings were changed:{text_output}') messagebox.showinfo('', f'The following settings were changed:{text_output}')
+1 -11
View File
@@ -151,9 +151,6 @@ def create_item_pool_config(world):
config.item_pool[player] = determine_major_items(world, player) config.item_pool[player] = determine_major_items(world, player)
config.location_groups[0].locations = set(groups.locations) config.location_groups[0].locations = set(groups.locations)
config.reserved_locations[player].update(groups.locations) config.reserved_locations[player].update(groups.locations)
backup = (mode_grouping['Heart Pieces'] + mode_grouping['Dungeon Trash'] + mode_grouping['Shops']
+ mode_grouping['Overworld Trash'] + mode_grouping['GT Trash'] + mode_grouping['RetroShops'])
config.location_groups[1].locations = set(backup)
elif world.algorithm == 'dungeon_only': elif world.algorithm == 'dungeon_only':
config.location_groups = [ config.location_groups = [
LocationGroup('Dungeons'), LocationGroup('Dungeons'),
@@ -171,9 +168,6 @@ def create_item_pool_config(world):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
config.item_pool[player] = determine_major_items(world, player) config.item_pool[player] = determine_major_items(world, player)
config.location_groups[0].locations = set(dungeon_set) config.location_groups[0].locations = set(dungeon_set)
backup = (mode_grouping['Heart Pieces'] + mode_grouping['Overworld Major']
+ mode_grouping['Overworld Trash'] + mode_grouping['Shops'] + mode_grouping['RetroShops'])
config.location_groups[1].locations = set(backup)
def district_item_pool_config(world): def district_item_pool_config(world):
@@ -419,11 +413,7 @@ def filter_locations(item_to_place, locations, world, vanilla_skip=False, potion
if item_to_place.name in config.item_pool[item_to_place.player]: if item_to_place.name in config.item_pool[item_to_place.player]:
restricted = config.location_groups[0].locations restricted = config.location_groups[0].locations
filtered = [l for l in locations if l.name in restricted] filtered = [l for l in locations if l.name in restricted]
if len(filtered) == 0: return filtered
restricted = config.location_groups[1].locations
filtered = [l for l in locations if l.name in restricted]
# bias toward certain location in overflow? (thinking about this for major_bias)
return filtered if len(filtered) > 0 else locations
if world.algorithm == 'district': if world.algorithm == 'district':
config = world.item_pool_config config = world.item_pool_config
if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder') if ((isinstance(item_to_place,str) and item_to_place == 'Placeholder')
+5 -3
View File
@@ -56,6 +56,8 @@ def link_entrances_new(world, player):
one_way_map.update(drop_map) one_way_map.update(drop_map)
one_way_map.update(single_entrance_map) one_way_map.update(single_entrance_map)
if avail_pool.inverted: if avail_pool.inverted:
default_map['Ganons Tower'] = 'Agahnims Tower Exit'
default_map['Agahnims Tower'] = 'Ganons Tower Exit'
default_map['Old Man Cave (West)'] = 'Bumper Cave Exit (Bottom)' default_map['Old Man Cave (West)'] = 'Bumper Cave Exit (Bottom)'
default_map['Death Mountain Return Cave (West)'] = 'Bumper Cave Exit (Top)' default_map['Death Mountain Return Cave (West)'] = 'Bumper Cave Exit (Top)'
default_map['Bumper Cave (Bottom)'] = 'Old Man Cave Exit (West)' default_map['Bumper Cave (Bottom)'] = 'Old Man Cave Exit (West)'
@@ -64,8 +66,6 @@ def link_entrances_new(world, player):
default_map['Old Man Cave (East)'] = 'Death Mountain Return Cave Exit (West)' default_map['Old Man Cave (East)'] = 'Death Mountain Return Cave Exit (West)'
one_way_map['Bumper Cave (Top)'] = 'Dark Death Mountain Healer Fairy' one_way_map['Bumper Cave (Top)'] = 'Dark Death Mountain Healer Fairy'
del default_map['Bumper Cave (Top)'] del default_map['Bumper Cave (Top)']
del one_way_map['Big Bomb Shop']
one_way_map['Inverted Big Bomb Shop'] = 'Inverted Big Bomb Shop'
avail_pool.default_map = default_map avail_pool.default_map = default_map
avail_pool.one_way_map = one_way_map avail_pool.one_way_map = one_way_map
@@ -1964,6 +1964,8 @@ mandatory_connections = [('Links House S&Q', 'Links House'),
('Grassy Lawn Pegs (Top)', 'West Dark World'), ('Grassy Lawn Pegs (Top)', 'West Dark World'),
('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'), ('Grassy Lawn Pegs (Bottom)', 'Dark Grassy Lawn'),
('West Dark World Gap', 'West Dark World'), ('West Dark World Gap', 'West Dark World'),
('Dark Graveyard Bush (South)', 'Dark Graveyard North'),
('Dark Graveyard Bush (North)', 'West Dark World'),
('Broken Bridge Pass (Top)', 'East Dark World'), ('Broken Bridge Pass (Top)', 'East Dark World'),
('Broken Bridge Pass (Bottom)', 'Northeast Dark World'), ('Broken Bridge Pass (Bottom)', 'Northeast Dark World'),
('Peg Area Rocks (Left)', 'Hammer Peg Area'), ('Peg Area Rocks (Left)', 'Hammer Peg Area'),
@@ -2746,7 +2748,7 @@ ow_prize_table = {'Links House': (0x8b1, 0xb2d),
'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00), 'Dark Lake Hylia Ledge Hint': (0xec0, 0xc00),
'Hype Cave': (0x940, 0xc80), 'Hype Cave': (0x940, 0xc80),
'Bonk Fairy (Dark)': (0x740, 0xa80), 'Bonk Fairy (Dark)': (0x740, 0xa80),
'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x800, 0x7a0), 'Brewery': (0x170, 0x980), 'C-Shaped House': (0x310, 0x7a0), 'Chest Game': (0x080, 0x7a0),
'Hammer Peg Cave': (0x4c0, 0x940), 'Hammer Peg Cave': (0x4c0, 0x940),
'Red Shield Shop': (0x500, 0x680), 'Red Shield Shop': (0x500, 0x680),
'Dark Sanctuary Hint': (0x720, 0x4a0), 'Dark Sanctuary Hint': (0x720, 0x4a0),
+8 -9
View File
@@ -126,15 +126,14 @@ def roll_settings(weights):
ret.crystals_ganon = get_choice('ganon_open') ret.crystals_ganon = get_choice('ganon_open')
from ItemList import set_default_triforce ret.triforce_pool = get_choice_default('triforce_pool', default=0)
default_tf_goal, default_tf_pool = set_default_triforce(ret.goal, 0, 0) ret.triforce_goal = get_choice_default('triforce_goal', default=0)
goal_min = get_choice_default('triforce_goal_min', default=default_tf_goal) ret.triforce_pool_min = get_choice_default('triforce_pool_min', default=0)
goal_max = get_choice_default('triforce_goal_max', default=default_tf_goal) ret.triforce_pool_max = get_choice_default('triforce_pool_max', default=0)
pool_min = get_choice_default('triforce_pool_min', default=default_tf_pool) ret.triforce_goal_min = get_choice_default('triforce_goal_min', default=0)
pool_max = get_choice_default('triforce_pool_max', default=default_tf_pool) ret.triforce_goal_max = get_choice_default('triforce_goal_max', default=0)
ret.triforce_goal = random.randint(int(goal_min), int(goal_max)) ret.triforce_min_difference = get_choice_default('triforce_min_difference', default=0)
min_diff = get_choice_default('triforce_min_difference', default=default_tf_pool-default_tf_goal) ret.triforce_max_difference = get_choice_default('triforce_max_difference', default=10000)
ret.triforce_pool = random.randint(max(int(pool_min), ret.triforce_goal + int(min_diff)), int(pool_max))
ret.mode = get_choice('world_state') ret.mode = get_choice('world_state')
if ret.mode == 'retro': if ret.mode == 'retro':