Merged DR v0.4.0.5

This commit is contained in:
codemann8
2021-06-03 11:36:24 -05:00
8 changed files with 94 additions and 28 deletions

View File

@@ -2170,6 +2170,7 @@ class Spoiler(object):
'enemy_shuffle': self.world.enemy_shuffle, 'enemy_shuffle': self.world.enemy_shuffle,
'enemy_health': self.world.enemy_health, 'enemy_health': self.world.enemy_health,
'enemy_damage': self.world.enemy_damage, 'enemy_damage': self.world.enemy_damage,
'potshuffle': self.world.potshuffle,
'players': self.world.players, 'players': self.world.players,
'teams': self.world.teams, 'teams': self.world.teams,
'experimental': self.world.experimental, 'experimental': self.world.experimental,
@@ -2249,6 +2250,7 @@ class Spoiler(object):
outfile.write('Enemy shuffle:'.ljust(line_width) + '%s\n' % self.metadata['enemy_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 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('Enemy damage:'.ljust(line_width) + '%s\n' % self.metadata['enemy_damage'][player])
outfile.write('Pot shuffle:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['potshuffle'][player] else 'No'))
outfile.write('Hints:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['hints'][player] else 'No')) outfile.write('Hints:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['hints'][player] else 'No'))
outfile.write('Experimental:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['experimental'][player] else 'No')) outfile.write('Experimental:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['experimental'][player] else 'No'))
outfile.write('Key Drops shuffled:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No')) outfile.write('Key Drops shuffled:'.ljust(line_width) + '%s\n' % ('Yes' if self.metadata['keydropshuffle'][player] else 'No'))

View File

@@ -174,7 +174,7 @@ def place_bosses(world, player):
boss_locations.remove(['Ice Palace', None]) boss_locations.remove(['Ice Palace', None])
placeable_bosses.remove('Kholdstare') placeable_bosses.remove('Kholdstare')
if world.boss_shuffle[player] == "basic": # vanilla bosses shuffled if world.boss_shuffle[player] == "simple": # vanilla bosses shuffled
bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm'] bosses = placeable_bosses + ['Armos Knights', 'Lanmolas', 'Moldorm']
else: # all bosses present, the three duplicates chosen at random else: # all bosses present, the three duplicates chosen at random
bosses = all_bosses + [random.choice(placeable_bosses) for _ in range(3)] bosses = all_bosses + [random.choice(placeable_bosses) for _ in range(3)]

View File

@@ -1308,12 +1308,28 @@ def link_entrances(world, player):
# place remaining doors # place remaining doors
connect_doors(world, doors, door_targets, player) connect_doors(world, doors, door_targets, player)
elif not invFlag and world.shuffle[player] == 'insanity_legacy': elif world.shuffle[player] == 'insanity_legacy':
world.fix_fake_world[player] = False world.fix_fake_world[player] = False
# beware ye who enter here # beware ye who enter here
entrances = LW_Entrances + LW_Dungeon_Entrances + DW_Entrances + DW_Dungeon_Entrances + Old_Man_Entrances + ['Skull Woods Second Section Door (East)', 'Skull Woods First Section Door', 'Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] if not invFlag:
entrances_must_exits = DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit + ['Skull Woods Second Section Door (West)'] entrances_must_exits = DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + LW_Dungeon_Entrances_Must_Exit + ['Skull Woods Second Section Door (West)']
doors = LW_Entrances + LW_Dungeon_Entrances + DW_Entrances + DW_Dungeon_Entrances + Old_Man_Entrances + ['Skull Woods Second Section Door (East)', 'Skull Woods First Section Door', 'Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave']
else:
entrances_must_exits = Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit
doors = Inverted_LW_Entrances + Inverted_LW_Dungeon_Entrances + Inverted_LW_Entrances_Must_Exit + Inverted_LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave', 'Hyrule Castle Secret Entrance Stairs'] + Inverted_Old_Man_Entrances +\
Inverted_DW_Entrances + Inverted_DW_Dungeon_Entrances + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] +\
Inverted_LW_Single_Cave_Doors + Inverted_DW_Single_Cave_Doors + ['Desert Palace Entrance (West)', 'Desert Palace Entrance (North)']
exit_pool = list(doors)
# randomize which desert ledge door is a must-exit
if random.randint(0, 1) == 0:
entrances_must_exits.append('Desert Palace Entrance (North)')
else:
entrances_must_exits.append('Desert Palace Entrance (West)')
doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\ doors = LW_Entrances + LW_Dungeon_Entrances + LW_Dungeon_Entrances_Must_Exit + ['Kakariko Well Cave', 'Bat Cave Cave', 'North Fairy Cave', 'Sanctuary', 'Lost Woods Hideout Stump', 'Lumberjack Tree Cave'] + Old_Man_Entrances +\
DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)'] DW_Entrances + DW_Dungeon_Entrances + DW_Entrances_Must_Exit + DW_Dungeon_Entrances_Must_Exit + ['Skull Woods First Section Door', 'Skull Woods Second Section Door (East)', 'Skull Woods Second Section Door (West)']
@@ -1333,6 +1349,9 @@ def link_entrances(world, player):
hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop', hole_targets = ['Kakariko Well (top)', 'Bat Cave (right)', 'North Fairy Cave', 'Lost Woods Hideout (top)', 'Lumberjack Tree (top)', 'Sewer Drop', 'Skull Back Drop',
'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle'] 'Skull Left Drop', 'Skull Pinball', 'Skull Pot Circle']
# tavern back door cannot be shuffled yet
connect_doors(world, ['Tavern North'], ['Tavern'], player)
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
# cannot move uncle cave # cannot move uncle cave
connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player) connect_entrance(world, 'Hyrule Castle Secret Entrance Drop', 'Hyrule Castle Secret Entrance', player)
@@ -1342,24 +1361,32 @@ def link_entrances(world, player):
hole_entrances.append('Hyrule Castle Secret Entrance Drop') hole_entrances.append('Hyrule Castle Secret Entrance Drop')
hole_targets.append('Hyrule Castle Secret Entrance') hole_targets.append('Hyrule Castle Secret Entrance')
doors.append('Hyrule Castle Secret Entrance Stairs') doors.append('Hyrule Castle Secret Entrance Stairs')
entrances.append('Hyrule Castle Secret Entrance Stairs')
caves.append('Hyrule Castle Secret Entrance Exit') caves.append('Hyrule Castle Secret Entrance Exit')
if not world.shuffle_ganon: if not world.shuffle_ganon:
connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player) connect_two_way(world, 'Ganons Tower', 'Ganons Tower Exit', player)
connect_two_way(world, 'Pyramid Entrance', 'Pyramid Exit', player) if not invFlag:
connect_entrance(world, 'Pyramid Hole', 'Pyramid', player) connect_two_way(world, 'Pyramid Entrance', 'Pyramid Exit', player)
connect_entrance(world, 'Pyramid Hole', 'Pyramid', player)
else:
connect_two_way(world, 'Inverted Pyramid Entrance', 'Pyramid Exit', player)
connect_entrance(world, 'Inverted Pyramid Hole', 'Pyramid', player)
else: else:
entrances.append('Ganons Tower')
caves.extend(['Ganons Tower Exit', 'Pyramid Exit']) caves.extend(['Ganons Tower Exit', 'Pyramid Exit'])
hole_entrances.append('Pyramid Hole')
hole_targets.append('Pyramid') hole_targets.append('Pyramid')
entrances_must_exits.append('Pyramid Entrance') if not invFlag:
doors.extend(['Ganons Tower', 'Pyramid Entrance']) hole_entrances.append('Pyramid Hole')
doors.extend(['Agahnims Tower', 'Pyramid Entrance'])
exit_pool.extend(['Agahnims Tower', 'Pyramid Entrance'])
else:
hole_entrances.append('Inverted Pyramid Hole')
doors.extend(['Agahnims Tower', 'Inverted Pyramid Entrance'])
exit_pool.extend(['Agahnims Tower', 'Inverted Pyramid Entrance'])
random.shuffle(hole_entrances) random.shuffle(hole_entrances)
random.shuffle(hole_targets) random.shuffle(hole_targets)
random.shuffle(entrances) random.shuffle(exit_pool)
# fill up holes # fill up holes
for hole in hole_entrances: for hole in hole_entrances:
@@ -1375,6 +1402,31 @@ def link_entrances(world, player):
doors.append('Hyrule Castle Entrance (South)') doors.append('Hyrule Castle Entrance (South)')
entrances.append('Hyrule Castle Entrance (South)') entrances.append('Hyrule Castle Entrance (South)')
caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)')) caves.append(('Hyrule Castle Exit (South)', 'Hyrule Castle Exit (West)', 'Hyrule Castle Exit (East)'))
if not world.shufflelinks[player]:
if not invFlag:
links_house = 'Links House'
else:
links_house = 'Big Shop Shop'
else:
if not invFlag:
links_house_doors = [i for i in doors if i not in Sanctuary_Doors + Isolated_LH_Doors]
else:
links_house_doors = [i for i in doors if i not in Inverted_Dark_Sanctuary_Doors + Isolated_LH_Doors]
links_house = random.choice(links_house_doors)
connect_two_way(world, links_house, 'Links House Exit', player)
doors.remove(links_house)
exit_pool.remove(links_house)
if not invFlag:
sanc_doors = [door for door in Sanctuary_Doors if door in exit_pool]
else:
sanc_doors = [door for door in Inverted_Dark_Sanctuary_Doors if door in exit_pool]
sanc_door = random.choice(sanc_doors)
exit_pool.remove(sanc_door)
doors.remove(sanc_door)
connect_entrance(world, sanc_door, 'Dark Sanctuary Hint', player)
world.get_entrance('Dark Sanctuary Hint Exit', player).connect(world.get_entrance(sanc_door, player).parent_region)
# now let's deal with mandatory reachable stuff # now let's deal with mandatory reachable stuff
def extract_reachable_exit(cavelist): def extract_reachable_exit(cavelist):
@@ -1393,7 +1445,7 @@ def link_entrances(world, player):
cavelist.remove(candidate) cavelist.remove(candidate)
return candidate return candidate
def connect_reachable_exit(entrance, caves, doors): def connect_reachable_exit(entrance, caves, doors, exit_pool):
cave = extract_reachable_exit(caves) cave = extract_reachable_exit(caves)
exit = cave[-1] exit = cave[-1]
@@ -1401,18 +1453,19 @@ def link_entrances(world, player):
connect_exit(world, exit, entrance, player) connect_exit(world, exit, entrance, player)
connect_entrance(world, doors.pop(), exit, player) connect_entrance(world, doors.pop(), exit, player)
# rest of cave now is forced to be in this world # rest of cave now is forced to be in this world
exit_pool.remove(entrance)
caves.append(cave) caves.append(cave)
# connect mandatory exits # connect mandatory exits
for entrance in entrances_must_exits: for entrance in entrances_must_exits:
connect_reachable_exit(entrance, caves, doors) connect_reachable_exit(entrance, caves, doors, exit_pool)
# place old man, has limited options # place old man, has limited options
# exit has to come from specific set of doors, the entrance is free to move about # exit has to come from specific set of doors, the entrance is free to move about
old_man_entrances = [entrance for entrance in old_man_entrances if entrance in entrances] old_man_entrances = [entrance for entrance in old_man_entrances if entrance in exit_pool]
random.shuffle(old_man_entrances) random.shuffle(old_man_entrances)
old_man_exit = old_man_entrances.pop() old_man_exit = old_man_entrances.pop()
entrances.remove(old_man_exit) exit_pool.remove(old_man_exit)
connect_exit(world, 'Old Man Cave Exit (East)', old_man_exit, player) connect_exit(world, 'Old Man Cave Exit (East)', old_man_exit, player)
connect_entrance(world, doors.pop(), 'Old Man Cave Exit (East)', player) connect_entrance(world, doors.pop(), 'Old Man Cave Exit (East)', player)
@@ -1438,16 +1491,24 @@ def link_entrances(world, player):
random.shuffle(blacksmith_doors) random.shuffle(blacksmith_doors)
blacksmith_hut = blacksmith_doors.pop() blacksmith_hut = blacksmith_doors.pop()
connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player) connect_entrance(world, blacksmith_hut, 'Blacksmiths Hut', player)
bomb_shop_doors.extend(blacksmith_doors) doors.remove(blacksmith_hut)
exit_pool.remove(blacksmith_hut)
# place dam and pyramid fairy, have limited options # place dam and pyramid fairy, have limited options
random.shuffle(bomb_shop_doors) random.shuffle(bomb_shop_doors)
bomb_shop = bomb_shop_doors.pop() bomb_shop = bomb_shop_doors.pop()
connect_entrance(world, bomb_shop, 'Big Bomb Shop', player) connect_entrance(world, bomb_shop, 'Big Bomb Shop', player)
single_doors.extend(bomb_shop_doors) doors.remove(bomb_shop)
exit_pool.remove(bomb_shop)
# tavern back door cannot be shuffled yet # handle remaining caves
connect_doors(world, ['Tavern North'], ['Tavern'], player) for cave in caves:
if isinstance(cave, str):
cave = (cave,)
for exit in cave:
connect_exit(world, exit, exit_pool.pop(), player)
connect_entrance(world, doors.pop(), exit, player)
# place remaining doors # place remaining doors
connect_doors(world, single_doors, door_targets, player) connect_doors(world, single_doors, door_targets, player)

View File

@@ -28,7 +28,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops
from Utils import output_path, parse_player_names from Utils import output_path, parse_player_names
__version__ = '0.4.0.4-u' __version__ = '0.4.0.5-u'
class EnemizerError(RuntimeError): class EnemizerError(RuntimeError):

View File

@@ -190,9 +190,9 @@ def roll_settings(weights):
ret.item_functionality = get_choice('item_functionality') ret.item_functionality = get_choice('item_functionality')
old_style_bosses = {'simple': 'basic', old_style_bosses = {'basic': 'simple',
'full': 'normal', 'normal': 'full',
'random': 'chaos'} 'chaos': 'random'}
boss_choice = get_choice('boss_shuffle') boss_choice = get_choice('boss_shuffle')
if boss_choice in old_style_bosses.keys(): if boss_choice in old_style_bosses.keys():
boss_choice = old_style_bosses[boss_choice] boss_choice = old_style_bosses[boss_choice]

View File

@@ -295,7 +295,7 @@ def shuffle_pots(world, player):
elif old_pot.item == PotItem.Switch: elif old_pot.item == PotItem.Switch:
available_pots = (pot for pot in new_pots if (pot.room == old_pot.room or pot.room in movable_switch_rooms[old_pot.room]) and not (pot.flags & PotFlags.NoSwitch)) available_pots = (pot for pot in new_pots if (pot.room == old_pot.room or pot.room in movable_switch_rooms[old_pot.room]) and not (pot.flags & PotFlags.NoSwitch))
elif old_pot.item == PotItem.Key: elif old_pot.item == PotItem.Key:
if world.doorShuffle[player] == 'vanilla' and not world.retro[player] and not world.keydropshuffle[player] and world.logic != 'nologic': if world.doorShuffle[player] == 'vanilla' and not world.retro[player] and not world.keydropshuffle[player] and world.logic[player] != 'nologic':
available_pots = (pot for pot in new_pots if pot.room not in invalid_key_rooms) available_pots = (pot for pot in new_pots if pot.room not in invalid_key_rooms)
else: else:
available_pots = new_pots available_pots = new_pots

View File

@@ -10,6 +10,12 @@ Thanks to qadan, cheuer, & compiling
# Bug Fixes and Notes. # Bug Fixes and Notes.
* 0.4.0.5
* Insanity - less restrictions on exiting (all modes)
* Fix for simple bosses shuffle
* Fix for boss shuffle from Mystery.py
* Minor msu fade out bug (thanks codemann8)
* Other bug fixes (thanks Catobat)
* 0.4.0.4 * 0.4.0.4
* Added --shufflelinks option * Added --shufflelinks option
* Moved spawning as a bunny indoors to experimental * Moved spawning as a bunny indoors to experimental

3
Rom.py
View File

@@ -1347,9 +1347,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if item.name != 'Piece of Heart' or equip[0x36B] == 0: if item.name != 'Piece of Heart' or equip[0x36B] == 0:
equip[0x36C] = min(equip[0x36C] + 0x08, 0xA0) equip[0x36C] = min(equip[0x36C] + 0x08, 0xA0)
equip[0x36D] = min(equip[0x36D] + 0x08, 0xA0) equip[0x36D] = min(equip[0x36D] + 0x08, 0xA0)
elif item.name == 'Pegasus Boots':
rom.write_byte(0x183015, 0x01)
ability_flags |= 0b00000100
else: else:
raise RuntimeError(f'Unsupported item in starting equipment: {item.name}') raise RuntimeError(f'Unsupported item in starting equipment: {item.name}')