Spoiler log improvements
Fix multi-entrance checks Tower lobby door pairing fixed
This commit is contained in:
@@ -123,6 +123,8 @@ class World(object):
|
||||
set_player_attr('escape_assist', [])
|
||||
set_player_attr('crystals_needed_for_ganon', 7)
|
||||
set_player_attr('crystals_needed_for_gt', 7)
|
||||
set_player_attr('crystals_ganon_orig', {})
|
||||
set_player_attr('crystals_gt_orig', {})
|
||||
set_player_attr('open_pyramid', False)
|
||||
set_player_attr('treasure_hunt_icon', 'Triforce Piece')
|
||||
set_player_attr('treasure_hunt_count', 0)
|
||||
@@ -1654,6 +1656,15 @@ class Location(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
def gen_name(self):
|
||||
name = self.name
|
||||
world = self.parent_region.world if self.parent_region and self.parent_region.world else None
|
||||
if self.parent_region.dungeon and world and world.doorShuffle[self.player] == 'crossed':
|
||||
name += f' @ {self.parent_region.dungeon.name}'
|
||||
if world and world.players > 1:
|
||||
name += f' ({world.get_player_names(self.player)})'
|
||||
return name
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__unicode__())
|
||||
|
||||
@@ -1833,25 +1844,25 @@ class Spoiler(object):
|
||||
listed_locations = set()
|
||||
|
||||
lw_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.type == RegionType.LightWorld]
|
||||
self.locations['Light World'] = OrderedDict([(str(location), str(location.item) if location.item is not None else 'Nothing') for location in lw_locations])
|
||||
self.locations['Light World'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in lw_locations])
|
||||
listed_locations.update(lw_locations)
|
||||
|
||||
dw_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.type == RegionType.DarkWorld]
|
||||
self.locations['Dark World'] = OrderedDict([(str(location), str(location.item) if location.item is not None else 'Nothing') for location in dw_locations])
|
||||
self.locations['Dark World'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in dw_locations])
|
||||
listed_locations.update(dw_locations)
|
||||
|
||||
cave_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.type == RegionType.Cave]
|
||||
self.locations['Caves'] = OrderedDict([(str(location), str(location.item) if location.item is not None else 'Nothing') for location in cave_locations])
|
||||
self.locations['Caves'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in cave_locations])
|
||||
listed_locations.update(cave_locations)
|
||||
|
||||
for dungeon in self.world.dungeons:
|
||||
dungeon_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations and loc.parent_region and loc.parent_region.dungeon == dungeon]
|
||||
self.locations[str(dungeon)] = OrderedDict([(str(location), str(location.item) if location.item is not None else 'Nothing') for location in dungeon_locations])
|
||||
self.locations[str(dungeon)] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in dungeon_locations])
|
||||
listed_locations.update(dungeon_locations)
|
||||
|
||||
other_locations = [loc for loc in self.world.get_locations() if loc not in listed_locations]
|
||||
if other_locations:
|
||||
self.locations['Other Locations'] = OrderedDict([(str(location), str(location.item) if location.item is not None else 'Nothing') for location in other_locations])
|
||||
self.locations['Other Locations'] = OrderedDict([(location.gen_name(), str(location.item) if location.item is not None else 'Nothing') for location in other_locations])
|
||||
listed_locations.update(other_locations)
|
||||
|
||||
self.shops = []
|
||||
@@ -1970,8 +1981,10 @@ class Spoiler(object):
|
||||
outfile.write('Entrance Shuffle: %s\n' % self.metadata['shuffle'][player])
|
||||
outfile.write('Door Shuffle: %s\n' % self.metadata['door_shuffle'][player])
|
||||
outfile.write('Intensity: %s\n' % self.metadata['intensity'][player])
|
||||
outfile.write('Crystals required for GT: %s\n' % self.metadata['gt_crystals'][player])
|
||||
outfile.write('Crystals required for Ganon: %s\n' % self.metadata['ganon_crystals'][player])
|
||||
addition = ' (Random)' if self.world.crystals_gt_orig[player] == 'random' else ''
|
||||
outfile.write('Crystals required for GT: %s\n' % (str(self.metadata['gt_crystals'][player]) + addition))
|
||||
addition = ' (Random)' if self.world.crystals_ganon_orig[player] == 'random' else ''
|
||||
outfile.write('Crystals required for Ganon: %s\n' % (str(self.metadata['ganon_crystals'][player]) + addition))
|
||||
outfile.write('Pyramid hole pre-opened: %s\n' % ('Yes' if self.metadata['open_pyramid'][player] else 'No'))
|
||||
outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player])
|
||||
outfile.write('Map shuffle: %s\n' % ('Yes' if self.metadata['mapshuffle'][player] else 'No'))
|
||||
@@ -2019,7 +2032,7 @@ class Spoiler(object):
|
||||
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
|
||||
# items: Item names
|
||||
outfile.write('\n\nLocations:\n\n')
|
||||
outfile.write('\n'.join(['%s: %s' % (self.world.fish.translate("meta","locations",location), self.world.fish.translate("meta","items",item)) for grouping in self.locations.values() for (location, item) in grouping.items()]))
|
||||
outfile.write('\n'.join(['%s: %s' % (self.world.fish.translate("meta", "locations", location), self.world.fish.translate("meta", "items", item)) for grouping in self.locations.values() for (location, item) in grouping.items()]))
|
||||
|
||||
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
|
||||
# items: Item names
|
||||
|
||||
@@ -1063,7 +1063,7 @@ def check_entrance_fixes(world, player):
|
||||
dungeon = entrance.connected_region.dungeon
|
||||
if dungeon:
|
||||
layout = world.dungeon_layouts[player][dungeon.name]
|
||||
if 'Sanctuary' in layout.master_sector.region_set():
|
||||
if 'Sanctuary' in layout.master_sector.region_set() or dungeon.name in ['Hyrule Castle', 'Desert Palace', 'Skull Woods', 'Turtle Rock']:
|
||||
portal = None
|
||||
for portal_name in dungeon_portals[dungeon.name]:
|
||||
test_portal = world.get_portal(portal_name, player)
|
||||
@@ -1071,8 +1071,6 @@ def check_entrance_fixes(world, player):
|
||||
portal = test_portal
|
||||
break
|
||||
world.force_fix[player][key] = portal
|
||||
elif dungeon.name in ['Hyrule Castle', 'Desert Palace', 'Skull Woods', 'Turtle Rock']:
|
||||
world.force_fix[player][key] = portal
|
||||
|
||||
|
||||
def palette_assignment(world, player):
|
||||
|
||||
14
Main.py
14
Main.py
@@ -24,7 +24,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes, fill_specific_items
|
||||
from Utils import output_path, parse_player_names
|
||||
|
||||
__version__ = '0.2.0.14u'
|
||||
__version__ = '0.2.0.15u'
|
||||
|
||||
class EnemizerError(RuntimeError):
|
||||
pass
|
||||
@@ -56,6 +56,8 @@ def main(args, seed=None, fish=None):
|
||||
world.bigkeyshuffle = args.bigkeyshuffle.copy()
|
||||
world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)}
|
||||
world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)}
|
||||
world.crystals_ganon_orig = args.crystals_ganon.copy()
|
||||
world.crystals_gt_orig = args.crystals_gt.copy()
|
||||
world.open_pyramid = args.openpyramid.copy()
|
||||
world.boss_shuffle = args.shufflebosses.copy()
|
||||
world.enemy_shuffle = args.shuffleenemies.copy()
|
||||
@@ -374,6 +376,8 @@ def copy_world(world):
|
||||
ret.bigkeyshuffle = world.bigkeyshuffle.copy()
|
||||
ret.crystals_needed_for_ganon = world.crystals_needed_for_ganon.copy()
|
||||
ret.crystals_needed_for_gt = world.crystals_needed_for_gt.copy()
|
||||
ret.crystals_ganon_orig = world.crystals_ganon_orig.copy()
|
||||
ret.crystals_gt_orig = world.crystals_gt_orig.copy()
|
||||
ret.open_pyramid = world.open_pyramid.copy()
|
||||
ret.boss_shuffle = world.boss_shuffle.copy()
|
||||
ret.enemy_shuffle = world.enemy_shuffle.copy()
|
||||
@@ -419,6 +423,10 @@ def copy_world(world):
|
||||
copied_region = ret.get_region(region.name, region.player)
|
||||
copied_region.is_light_world = region.is_light_world
|
||||
copied_region.is_dark_world = region.is_dark_world
|
||||
copied_region.dungeon = region.dungeon
|
||||
copied_region.locations = [copy.copy(location) for location in region.locations]
|
||||
for location in copied_region.locations:
|
||||
location.parent_region = copied_region
|
||||
for entrance in region.entrances:
|
||||
ret.get_entrance(entrance.name, entrance.player).connect(copied_region)
|
||||
|
||||
@@ -598,7 +606,7 @@ def create_playthrough(world):
|
||||
|
||||
old_world.spoiler.paths = dict()
|
||||
for player in range(1, world.players + 1):
|
||||
old_world.spoiler.paths.update({ str(location) : get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player})
|
||||
old_world.spoiler.paths.update({location.gen_name(): get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player})
|
||||
for _, path in dict(old_world.spoiler.paths).items():
|
||||
if any(exit == 'Pyramid Fairy' for (_, exit) in path):
|
||||
if world.mode[player] != 'inverted':
|
||||
@@ -609,4 +617,4 @@ def create_playthrough(world):
|
||||
# we can finally output our playthrough
|
||||
old_world.spoiler.playthrough = OrderedDict([("0", [str(item) for item in world.precollected_items if item.advancement])])
|
||||
for i, sphere in enumerate(collection_spheres):
|
||||
old_world.spoiler.playthrough[str(i + 1)] = {str(location): str(location.item) for location in sphere}
|
||||
old_world.spoiler.playthrough[str(i + 1)] = {location.gen_name(): str(location.item) for location in sphere}
|
||||
|
||||
@@ -68,6 +68,18 @@ Redesign of Keysanity Menu complete for crossed dungeon and moved out of experim
|
||||
* 1st Column: indicate if you have foudn the map of not for that dungeon
|
||||
* 2nd and 3rd Column: You must have the compass to see these columns. A two-digit display that show you how
|
||||
many chests are left in the dungeon. If -keydropshuffle is off, this does not count key drop. If on, it does.
|
||||
|
||||
## Potshuffle by compiling
|
||||
|
||||
Same flag as before but uses python logic written by compiling instead of the enemizer logic-less version. Needs some
|
||||
testing to verify logic is all good.
|
||||
|
||||
## Other features
|
||||
|
||||
### Spoiler log improvements
|
||||
|
||||
* In crossed mode, the new dungeon is listed along with the location designated by a '@' sign
|
||||
* Random gt crystals and ganon crystal are noted in the settings for better reproduction of seeds
|
||||
|
||||
### Experimental features
|
||||
|
||||
@@ -80,6 +92,9 @@ Redesign of Keysanity Menu complete for crossed dungeon and moved out of experim
|
||||
|
||||
# Bug Fixes
|
||||
|
||||
* 2.0.15u
|
||||
* Allow Aga Tower lobby door as a a paired keydoor (typo)
|
||||
* Fix portal check for multi-entrance dungeons
|
||||
* 2.0.14u
|
||||
* Removal of key doors no longer messes up certain lobbies
|
||||
* Fixed ER entrances when Desert Back is a connector
|
||||
|
||||
2
Rom.py
2
Rom.py
@@ -713,8 +713,6 @@ def patch_rom(world, rom, player, team, enemized):
|
||||
if portal.boss_exit_idx > -1:
|
||||
rom.write_byte(0x7939 + portal.boss_exit_idx, portal.current_room())
|
||||
|
||||
world.force_fix[player]['sw'] |= world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla'
|
||||
|
||||
# fix exits, if not fixed during exit patching
|
||||
if world.fix_skullwoods_exit[player] and world.shuffle[player] == 'vanilla':
|
||||
write_int16(rom, 0x15DB5 + 2 * exit_ids['Skull Woods Final Section Exit'][1], 0x00F8)
|
||||
|
||||
@@ -62,7 +62,7 @@ door_pair_offset_table = {
|
||||
0xb8: 0x01a4, 0xb9: 0x01a6, 0xba: 0x01aa, 0xbb: 0x01ad, 0xbc: 0x01b3, 0xbe: 0x01bb, 0xbf: 0x01be, 0xc0: 0x01bf,
|
||||
0xc1: 0x01c2, 0xc2: 0x01ca, 0xc3: 0x01d2, 0xc4: 0x01d9, 0xc5: 0x01da, 0xc6: 0x01dd, 0xc7: 0x01e3, 0xc8: 0x01e6,
|
||||
0xc9: 0x01e7, 0xcb: 0x01ec, 0xcc: 0x01ed, 0xce: 0x01f0, 0xd0: 0x01f1, 0xd1: 0x01f3, 0xd2: 0x01f7, 0xd5: 0x01f8,
|
||||
0xd6: 0x01fa, 0xd8: 0x01fd, 0xd9: 0x0200, 0xda: 0x0203, 0xdb: 0x0204, 0xdc: 0x0206, 0xe0: 0x020
|
||||
0xd6: 0x01fa, 0xd8: 0x01fd, 0xd9: 0x0200, 0xda: 0x0203, 0xdb: 0x0204, 0xdc: 0x0206, 0xe0: 0x0207
|
||||
}
|
||||
|
||||
# Note: 0-7 correspond to 1,2,3,4,5,6,a,14 respectively, see doortables.asm : MultDivInfo
|
||||
|
||||
Reference in New Issue
Block a user