Merge branch 'OverworldShuffleDev' into OverworldShuffle
This commit is contained in:
+55
-36
@@ -71,7 +71,6 @@ class World(object):
|
|||||||
self.fix_palaceofdarkness_exit = {}
|
self.fix_palaceofdarkness_exit = {}
|
||||||
self.fix_trock_exit = {}
|
self.fix_trock_exit = {}
|
||||||
self.shuffle_ganon = shuffle_ganon
|
self.shuffle_ganon = shuffle_ganon
|
||||||
self.fix_gtower_exit = self.shuffle_ganon
|
|
||||||
self.custom = custom
|
self.custom = custom
|
||||||
self.customitemarray = customitemarray
|
self.customitemarray = customitemarray
|
||||||
self.can_take_damage = True
|
self.can_take_damage = True
|
||||||
@@ -133,16 +132,17 @@ class World(object):
|
|||||||
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] or self.doorShuffle[player] not in ['vanilla'])
|
set_player_attr('fix_skullwoods_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'] or self.doorShuffle[player] not in ['vanilla'])
|
||||||
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
set_player_attr('fix_palaceofdarkness_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||||
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
set_player_attr('fix_trock_exit', self.shuffle[player] not in ['vanilla', 'simple', 'restricted', 'dungeonssimple'])
|
||||||
|
set_player_attr('fix_gtower_exit', self.shuffle_ganon[player] > 0)
|
||||||
set_player_attr('can_access_trock_eyebridge', None)
|
set_player_attr('can_access_trock_eyebridge', None)
|
||||||
set_player_attr('can_access_trock_front', None)
|
set_player_attr('can_access_trock_front', None)
|
||||||
set_player_attr('can_access_trock_big_chest', None)
|
set_player_attr('can_access_trock_big_chest', None)
|
||||||
set_player_attr('can_access_trock_middle', None)
|
set_player_attr('can_access_trock_middle', None)
|
||||||
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'hybridglitches', 'nologic']
|
set_player_attr('fix_fake_world', logic[player] not in ['owglitches', 'hybridglitches', 'nologic']
|
||||||
or shuffle[player] in ['lean', 'swapped', 'crossed', 'insanity'])
|
or shuffle[player] in ['lean', 'swapped', 'crossed', 'insanity'])
|
||||||
set_player_attr('mapshuffle', False)
|
set_player_attr('mapshuffle', 'none')
|
||||||
set_player_attr('compassshuffle', False)
|
set_player_attr('compassshuffle', 'none')
|
||||||
set_player_attr('keyshuffle', 'none')
|
set_player_attr('keyshuffle', 'none')
|
||||||
set_player_attr('bigkeyshuffle', False)
|
set_player_attr('bigkeyshuffle', 'none')
|
||||||
set_player_attr('prizeshuffle', 'none')
|
set_player_attr('prizeshuffle', 'none')
|
||||||
set_player_attr('restrict_boss_items', 'none')
|
set_player_attr('restrict_boss_items', 'none')
|
||||||
set_player_attr('bombbag', False)
|
set_player_attr('bombbag', False)
|
||||||
@@ -154,7 +154,7 @@ class World(object):
|
|||||||
set_player_attr('enemy_health', 'default')
|
set_player_attr('enemy_health', 'default')
|
||||||
set_player_attr('enemy_damage', 'default')
|
set_player_attr('enemy_damage', 'default')
|
||||||
set_player_attr('any_enemy_logic', 'allow_all')
|
set_player_attr('any_enemy_logic', 'allow_all')
|
||||||
set_player_attr('beemizer', 0)
|
set_player_attr('beemizer', '0')
|
||||||
set_player_attr('escape_assist', [])
|
set_player_attr('escape_assist', [])
|
||||||
set_player_attr('crystals_needed_for_ganon', 7)
|
set_player_attr('crystals_needed_for_ganon', 7)
|
||||||
set_player_attr('crystals_needed_for_gt', 7)
|
set_player_attr('crystals_needed_for_gt', 7)
|
||||||
@@ -477,7 +477,7 @@ class World(object):
|
|||||||
item.world = self
|
item.world = self
|
||||||
if ((item.prize and self.prizeshuffle[item.player] != 'none')
|
if ((item.prize and self.prizeshuffle[item.player] != 'none')
|
||||||
or (item.smallkey and self.keyshuffle[item.player] != 'none')
|
or (item.smallkey and self.keyshuffle[item.player] != 'none')
|
||||||
or (item.bigkey and self.bigkeyshuffle[item.player])):
|
or (item.bigkey and self.bigkeyshuffle[item.player] != 'none')):
|
||||||
item.advancement = True
|
item.advancement = True
|
||||||
self.precollected_items.append(item)
|
self.precollected_items.append(item)
|
||||||
self.state.collect(item, True)
|
self.state.collect(item, True)
|
||||||
@@ -1100,7 +1100,7 @@ class CollectionState(object):
|
|||||||
new_locations = True
|
new_locations = True
|
||||||
while new_locations:
|
while new_locations:
|
||||||
reachable_events = [location for location in locations if location.event and
|
reachable_events = [location for location in locations if location.event and
|
||||||
(not key_only or (self.world.keyshuffle[location.item.player] == 'none' and location.item.smallkey) or (not self.world.bigkeyshuffle[location.item.player] and location.item.bigkey))
|
(not key_only or (self.world.keyshuffle[location.item.player] in ['none', 'district'] and location.item.smallkey) or (self.world.bigkeyshuffle[location.item.player] in ['none', 'district'] and location.item.bigkey))
|
||||||
and location.can_reach(self)]
|
and location.can_reach(self)]
|
||||||
reachable_events = self._do_not_flood_the_keys(reachable_events)
|
reachable_events = self._do_not_flood_the_keys(reachable_events)
|
||||||
new_locations = False
|
new_locations = False
|
||||||
@@ -1577,6 +1577,7 @@ class Region(object):
|
|||||||
self.exits = []
|
self.exits = []
|
||||||
self.locations = []
|
self.locations = []
|
||||||
self.dungeon = None
|
self.dungeon = None
|
||||||
|
self.districts = []
|
||||||
self.shop = None
|
self.shop = None
|
||||||
self.world = None
|
self.world = None
|
||||||
self.is_light_world = False # will be set aftermaking connections.
|
self.is_light_world = False # will be set aftermaking connections.
|
||||||
@@ -1607,10 +1608,16 @@ class Region(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def can_fill(self, item):
|
def can_fill(self, item):
|
||||||
|
if item.is_near_dungeon_item(self.world):
|
||||||
|
item_dungeon = self.world.get_dungeon(item.dungeon, self.player) if item.dungeon else item.dungeon_object
|
||||||
|
ret = (self.dungeon and self.dungeon.is_dungeon_item(item))
|
||||||
|
ret = ret or (len(self.districts) and item_dungeon and len([d for d in self.districts if d in item_dungeon.districts]))
|
||||||
|
return ret and item.player == self.player
|
||||||
|
|
||||||
inside_dungeon_item = ((item.smallkey and self.world.keyshuffle[item.player] == 'none')
|
inside_dungeon_item = ((item.smallkey and self.world.keyshuffle[item.player] == 'none')
|
||||||
or (item.bigkey and not self.world.bigkeyshuffle[item.player])
|
or (item.bigkey and self.world.bigkeyshuffle[item.player] == 'none')
|
||||||
or (item.map and not self.world.mapshuffle[item.player])
|
or (item.map and self.world.mapshuffle[item.player] == 'none')
|
||||||
or (item.compass and not self.world.compassshuffle[item.player])
|
or (item.compass and self.world.compassshuffle[item.player] == 'none')
|
||||||
or (item.prize and self.world.prizeshuffle[item.player] == 'dungeon'))
|
or (item.prize and self.world.prizeshuffle[item.player] == 'dungeon'))
|
||||||
# not all small keys to escape must be in escape
|
# not all small keys to escape must be in escape
|
||||||
# sewer_hack = self.world.mode[item.player] == 'standard' and item.name == 'Small Key (Escape)'
|
# sewer_hack = self.world.mode[item.player] == 'standard' and item.name == 'Small Key (Escape)'
|
||||||
@@ -1859,6 +1866,7 @@ class Dungeon(object):
|
|||||||
def __init__(self, name, regions, big_key, small_keys, dungeon_items, player, dungeon_id):
|
def __init__(self, name, regions, big_key, small_keys, dungeon_items, player, dungeon_id):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.regions = regions
|
self.regions = regions
|
||||||
|
self.districts = []
|
||||||
self.prize = None
|
self.prize = None
|
||||||
self.big_key = big_key
|
self.big_key = big_key
|
||||||
self.small_keys = small_keys
|
self.small_keys = small_keys
|
||||||
@@ -1887,8 +1895,8 @@ class Dungeon(object):
|
|||||||
return self.dungeon_items + self.keys + ([self.prize] if self.prize else [])
|
return self.dungeon_items + self.keys + ([self.prize] if self.prize else [])
|
||||||
|
|
||||||
def is_dungeon_item(self, item):
|
def is_dungeon_item(self, item):
|
||||||
if item.prize:
|
if item.prize and item.dungeon is None:
|
||||||
return item.player == self.player and self.prize is None and self.name not in ['Hyrule Castle', 'Agahnims Tower', 'Ganons Tower']
|
return item.player == self.player and self.name not in ['Hyrule Castle', 'Agahnims Tower', 'Ganons Tower']
|
||||||
else:
|
else:
|
||||||
return item.player == self.player and item.name in [dungeon_item.name for dungeon_item in self.all_items]
|
return item.player == self.player and item.name in [dungeon_item.name for dungeon_item in self.all_items]
|
||||||
|
|
||||||
@@ -2757,6 +2765,7 @@ class Item(object):
|
|||||||
self.code = code
|
self.code = code
|
||||||
self.price = price
|
self.price = price
|
||||||
self.location = None
|
self.location = None
|
||||||
|
self.dungeon_object = None
|
||||||
self.world = None
|
self.world = None
|
||||||
self.player = player
|
self.player = player
|
||||||
|
|
||||||
@@ -2792,9 +2801,16 @@ class Item(object):
|
|||||||
def is_inside_dungeon_item(self, world):
|
def is_inside_dungeon_item(self, world):
|
||||||
return ((self.prize and world.prizeshuffle[self.player] in ['none', 'dungeon'])
|
return ((self.prize and world.prizeshuffle[self.player] in ['none', 'dungeon'])
|
||||||
or (self.smallkey and world.keyshuffle[self.player] == 'none')
|
or (self.smallkey and world.keyshuffle[self.player] == 'none')
|
||||||
or (self.bigkey and not world.bigkeyshuffle[self.player])
|
or (self.bigkey and world.bigkeyshuffle[self.player] == 'none')
|
||||||
or (self.compass and not world.compassshuffle[self.player])
|
or (self.compass and world.compassshuffle[self.player] == 'none')
|
||||||
or (self.map and not world.mapshuffle[self.player]))
|
or (self.map and world.mapshuffle[self.player] == 'none'))
|
||||||
|
|
||||||
|
def is_near_dungeon_item(self, world):
|
||||||
|
return ((self.prize and world.prizeshuffle[self.player] == 'district')
|
||||||
|
or (self.smallkey and world.keyshuffle[self.player] == 'district')
|
||||||
|
or (self.bigkey and world.bigkeyshuffle[self.player] == 'district')
|
||||||
|
or (self.compass and world.compassshuffle[self.player] == 'district')
|
||||||
|
or (self.map and world.mapshuffle[self.player] == 'district'))
|
||||||
|
|
||||||
def get_map_location(self):
|
def get_map_location(self):
|
||||||
if self.location:
|
if self.location:
|
||||||
@@ -2826,7 +2842,7 @@ class Item(object):
|
|||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if type(other) is str:
|
if type(other) is str:
|
||||||
return self.name == other
|
return self.name == other
|
||||||
return self.name == other.name and self.player == other.player
|
return other is not None and self.name == other.name and self.player == other.player
|
||||||
|
|
||||||
|
|
||||||
# have 6 address that need to be filled
|
# have 6 address that need to be filled
|
||||||
@@ -3266,10 +3282,10 @@ class Spoiler(object):
|
|||||||
outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player])
|
outfile.write('Pyramid Hole Pre-opened:'.ljust(line_width) + '%s\n' % self.metadata['open_pyramid'][player])
|
||||||
outfile.write('Overworld Map:'.ljust(line_width) + '%s\n' % self.metadata['overworld_map'][player])
|
outfile.write('Overworld Map:'.ljust(line_width) + '%s\n' % self.metadata['overworld_map'][player])
|
||||||
outfile.write('\n')
|
outfile.write('\n')
|
||||||
outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['mapshuffle'][player]))
|
outfile.write('Map Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['mapshuffle'][player])
|
||||||
outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['compassshuffle'][player]))
|
outfile.write('Compass Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['compassshuffle'][player])
|
||||||
outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player])
|
outfile.write('Small Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['keyshuffle'][player])
|
||||||
outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % yn(self.metadata['bigkeyshuffle'][player]))
|
outfile.write('Big Key Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['bigkeyshuffle'][player])
|
||||||
outfile.write('Prize Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['prizeshuffle'][player])
|
outfile.write('Prize Shuffle:'.ljust(line_width) + '%s\n' % self.metadata['prizeshuffle'][player])
|
||||||
outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player])
|
outfile.write('Key Logic Algorithm:'.ljust(line_width) + '%s\n' % self.metadata['key_logic'][player])
|
||||||
outfile.write('\n')
|
outfile.write('\n')
|
||||||
@@ -3627,9 +3643,11 @@ counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3}
|
|||||||
# byte 6: LCCC CPAA (shuffle links, crystals ganon, pyramid, access
|
# byte 6: LCCC CPAA (shuffle links, crystals ganon, pyramid, access
|
||||||
access_mode = {"items": 0, "locations": 1, "none": 2}
|
access_mode = {"items": 0, "locations": 1, "none": 2}
|
||||||
|
|
||||||
# byte 7: B?MC DDPP (big, ?, maps, compass, door_type, prize shuffle)
|
# byte 7: MMCC SSBB (maps, compass, small, big)
|
||||||
door_type_mode = {'original': 0, 'big': 1, 'all': 2, 'chaos': 3}
|
mapshuffle_mode = {'none': 0, 'off': 0, 'district': 2, 'wild': 3, 'on': 3}
|
||||||
prizeshuffle_mode = {'none': 0, 'dungeon': 1, 'wild': 3}
|
compassshuffle_mode = {'none': 0, 'off': 0, 'district': 2, 'wild': 3, 'on': 3}
|
||||||
|
keyshuffle_mode = {'none': 0, 'off': 0, 'universal': 1, 'district': 2, 'wild': 3, 'on': 3}
|
||||||
|
bigkeyshuffle_mode = {'none': 0, 'off': 0, 'district': 2, 'wild': 3, 'on': 3}
|
||||||
|
|
||||||
# byte 8: HHHD DPEE (enemy_health, enemy_dmg, potshuffle, enemies)
|
# byte 8: HHHD DPEE (enemy_health, enemy_dmg, potshuffle, enemies)
|
||||||
e_health = {"default": 0, "easy": 1, "normal": 2, "hard": 3, "expert": 4}
|
e_health = {"default": 0, "easy": 1, "normal": 2, "hard": 3, "expert": 4}
|
||||||
@@ -3651,11 +3669,11 @@ orcrossed_mode = {"none": 0, "polar": 1, "grouped": 2, "unrestricted": 4}
|
|||||||
# byte 12: KMB? FF?? (keep similar, mixed/tile flip, bonk drops, flute spots)
|
# byte 12: KMB? FF?? (keep similar, mixed/tile flip, bonk drops, flute spots)
|
||||||
flutespot_mode = {"vanilla": 0, "balanced": 1, "random": 2}
|
flutespot_mode = {"vanilla": 0, "balanced": 1, "random": 2}
|
||||||
|
|
||||||
# byte 13: FBBB TTSS (flute_mode, bow_mode, take_any, small_key_mode)
|
# byte 13: FBBB TTPP (flute_mode, bow_mode, take_any, prize shuffle)
|
||||||
flute_mode = {'normal': 0, 'active': 1}
|
flute_mode = {'normal': 0, 'active': 1}
|
||||||
bow_mode = {'progressive': 0, 'silvers': 1, 'retro': 2, 'retro_silvers': 3} # reserved 8 modes?
|
bow_mode = {'progressive': 0, 'silvers': 1, 'retro': 2, 'retro_silvers': 3} # reserved 8 modes?
|
||||||
take_any_mode = {'none': 0, 'random': 1, 'fixed': 2}
|
take_any_mode = {'none': 0, 'random': 1, 'fixed': 2}
|
||||||
keyshuffle_mode = {'none': 0, 'off': 0, 'wild': 1, 'on': 1, 'universal': 2}
|
prizeshuffle_mode = {'none': 0, 'dungeon': 1, 'district': 2, 'wild': 3}
|
||||||
|
|
||||||
# additions
|
# additions
|
||||||
# byte 14: POOT TKKK (pseudoboots, overworld_map, trap_door_mode, key_logic_algo)
|
# byte 14: POOT TKKK (pseudoboots, overworld_map, trap_door_mode, key_logic_algo)
|
||||||
@@ -3663,9 +3681,10 @@ overworld_map_mode = {'default': 0, 'compass': 1, 'map': 2}
|
|||||||
trap_door_mode = {'vanilla': 0, 'optional': 1, 'boss': 2, 'oneway': 3}
|
trap_door_mode = {'vanilla': 0, 'optional': 1, 'boss': 2, 'oneway': 3}
|
||||||
key_logic_algo = {'dangerous': 0, 'partial': 1, 'strict': 2}
|
key_logic_algo = {'dangerous': 0, 'partial': 1, 'strict': 2}
|
||||||
|
|
||||||
# byte 15: SSDD ???? (skullwoods, linked_drops, 4 free bytes)
|
# byte 15: SSLL ??DD (skullwoods, linked_drops, 2 free bytes, door_type)
|
||||||
skullwoods_mode = {'original': 0, 'restricted': 1, 'loose': 2, 'followlinked': 3}
|
skullwoods_mode = {'original': 0, 'restricted': 1, 'loose': 2, 'followlinked': 3}
|
||||||
linked_drops_mode = {'unset': 0, 'linked': 1, 'independent': 2}
|
linked_drops_mode = {'unset': 0, 'linked': 1, 'independent': 2}
|
||||||
|
door_type_mode = {'original': 0, 'big': 1, 'all': 2, 'chaos': 3}
|
||||||
|
|
||||||
# sfx_shuffle and other adjust items does not affect settings code
|
# sfx_shuffle and other adjust items does not affect settings code
|
||||||
|
|
||||||
@@ -3700,9 +3719,8 @@ class Settings(object):
|
|||||||
(0x80 if w.shufflelinks[p] else 0) | ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3)
|
(0x80 if w.shufflelinks[p] else 0) | ((8 if w.crystals_ganon_orig[p] == "random" else int(w.crystals_ganon_orig[p])) << 3)
|
||||||
| (0x4 if w.is_pyramid_open(p) else 0) | access_mode[w.accessibility[p]],
|
| (0x4 if w.is_pyramid_open(p) else 0) | access_mode[w.accessibility[p]],
|
||||||
|
|
||||||
(0x80 if w.bigkeyshuffle[p] else 0)
|
(mapshuffle_mode[w.mapshuffle[p]] << 6) | (compassshuffle_mode[w.compassshuffle[p]] << 4)
|
||||||
| (0x20 if w.mapshuffle[p] else 0) | (0x10 if w.compassshuffle[p] else 0)
|
| (keyshuffle_mode[w.keyshuffle[p]] << 2) | (bigkeyshuffle_mode[w.bigkeyshuffle[p]]),
|
||||||
| (door_type_mode[w.door_type_mode[p]] << 2) | prizeshuffle_mode[w.prizeshuffle[p]],
|
|
||||||
|
|
||||||
(e_health[w.enemy_health[p]] << 5) | (e_dmg[w.enemy_damage[p]] << 3)
|
(e_health[w.enemy_health[p]] << 5) | (e_dmg[w.enemy_damage[p]] << 3)
|
||||||
| (0x4 if w.potshuffle[p] else 0) | (enemy_mode[w.enemy_shuffle[p]]),
|
| (0x4 if w.potshuffle[p] else 0) | (enemy_mode[w.enemy_shuffle[p]]),
|
||||||
@@ -3718,12 +3736,13 @@ class Settings(object):
|
|||||||
| (0x20 if w.shuffle_bonk_drops[p] else 0) | (flutespot_mode[w.owFluteShuffle[p]] << 4),
|
| (0x20 if w.shuffle_bonk_drops[p] else 0) | (flutespot_mode[w.owFluteShuffle[p]] << 4),
|
||||||
|
|
||||||
(flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4
|
(flute_mode[w.flute_mode[p]] << 7 | bow_mode[w.bow_mode[p]] << 4
|
||||||
| take_any_mode[w.take_any[p]] << 2 | keyshuffle_mode[w.keyshuffle[p]]),
|
| take_any_mode[w.take_any[p]] << 2 | prizeshuffle_mode[w.prizeshuffle[p]]),
|
||||||
|
|
||||||
((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 5
|
((0x80 if w.pseudoboots[p] else 0) | overworld_map_mode[w.overworld_map[p]] << 5
|
||||||
| trap_door_mode[w.trap_door_mode[p]] << 3 | key_logic_algo[w.key_logic_algorithm[p]]),
|
| trap_door_mode[w.trap_door_mode[p]] << 3 | key_logic_algo[w.key_logic_algorithm[p]]),
|
||||||
|
|
||||||
(skullwoods_mode[w.skullwoods[p]] << 6 | linked_drops_mode[w.linked_drops[p]] << 4),
|
(skullwoods_mode[w.skullwoods[p]] << 6 | linked_drops_mode[w.linked_drops[p]] << 4
|
||||||
|
| door_type_mode[w.door_type_mode[p]]),
|
||||||
])
|
])
|
||||||
return base64.b64encode(code, "+-".encode()).decode()
|
return base64.b64encode(code, "+-".encode()).decode()
|
||||||
|
|
||||||
@@ -3776,11 +3795,10 @@ class Settings(object):
|
|||||||
args.crystals_ganon[p] = "random" if cgan == 8 else cgan
|
args.crystals_ganon[p] = "random" if cgan == 8 else cgan
|
||||||
args.openpyramid[p] = True if settings[6] & 0x4 else False
|
args.openpyramid[p] = True if settings[6] & 0x4 else False
|
||||||
|
|
||||||
args.bigkeyshuffle[p] = True if settings[7] & 0x80 else False
|
args.mapshuffle[p] = r(mapshuffle_mode)[(settings[7] & 0xC0) >> 6]
|
||||||
args.mapshuffle[p] = True if settings[7] & 0x20 else False
|
args.compassshuffle[p] = r(compassshuffle_mode)[(settings[7] & 0x30) >> 4]
|
||||||
args.compassshuffle[p] = True if settings[7] & 0x10 else False
|
args.keyshuffle[p] = r(keyshuffle_mode)[(settings[7] & 0xC) >> 2]
|
||||||
args.door_type_mode[p] = r(door_type_mode)[(settings[7] & 0xc) >> 2]
|
args.bigkeyshuffle[p] = r(bigkeyshuffle_mode)[settings[7] & 0x3]
|
||||||
args.prizeshuffle[p] = r(prizeshuffle_mode)[settings[7] & 0x3]
|
|
||||||
|
|
||||||
args.enemy_health[p] = r(e_health)[(settings[8] & 0xE0) >> 5]
|
args.enemy_health[p] = r(e_health)[(settings[8] & 0xE0) >> 5]
|
||||||
args.enemy_damage[p] = r(e_dmg)[(settings[8] & 0x18) >> 3]
|
args.enemy_damage[p] = r(e_dmg)[(settings[8] & 0x18) >> 3]
|
||||||
@@ -3806,7 +3824,7 @@ class Settings(object):
|
|||||||
args.flute_mode[p] = r(flute_mode)[(settings[13] & 0x80) >> 7]
|
args.flute_mode[p] = r(flute_mode)[(settings[13] & 0x80) >> 7]
|
||||||
args.bow_mode[p] = r(bow_mode)[(settings[13] & 0x70) >> 4]
|
args.bow_mode[p] = r(bow_mode)[(settings[13] & 0x70) >> 4]
|
||||||
args.take_any[p] = r(take_any_mode)[(settings[13] & 0xC) >> 2]
|
args.take_any[p] = r(take_any_mode)[(settings[13] & 0xC) >> 2]
|
||||||
args.keyshuffle[p] = r(keyshuffle_mode)[settings[13] & 0x3]
|
args.prizeshuffle[p] = r(prizeshuffle_mode)[settings[13] & 0x3]
|
||||||
|
|
||||||
if len(settings) > 14:
|
if len(settings) > 14:
|
||||||
args.pseudoboots[p] = True if settings[14] & 0x80 else False
|
args.pseudoboots[p] = True if settings[14] & 0x80 else False
|
||||||
@@ -3817,6 +3835,7 @@ class Settings(object):
|
|||||||
if len(settings) > 15:
|
if len(settings) > 15:
|
||||||
args.skullwoods[p] = r(skullwoods_mode)[(settings[15] & 0xc0) >> 6]
|
args.skullwoods[p] = r(skullwoods_mode)[(settings[15] & 0xc0) >> 6]
|
||||||
args.linked_drops[p] = r(linked_drops_mode)[(settings[15] & 0x30) >> 4]
|
args.linked_drops[p] = r(linked_drops_mode)[(settings[15] & 0x30) >> 4]
|
||||||
|
args.door_type_mode[p] = r(door_type_mode)[(settings[15] & 0x3)]
|
||||||
|
|
||||||
|
|
||||||
class KeyRuleType(FastEnum):
|
class KeyRuleType(FastEnum):
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.5.1.0
|
||||||
|
- New "Nearby" Dungeon Item Shuffle option
|
||||||
|
- Fixed issue with smith follower getting deleted incorrectly on s+q
|
||||||
|
- Various generation and logic fixes for HMG/NL
|
||||||
|
- \~Merged in DR v1.4.6.2~
|
||||||
|
|
||||||
## 0.5.0.6
|
## 0.5.0.6
|
||||||
- New improved Pseudoboots behavior
|
- New improved Pseudoboots behavior
|
||||||
- Fixed issue with missing Blue Potion in Dark Lake Shop in Inverted
|
- Fixed issue with missing Blue Potion in Dark Lake Shop in Inverted
|
||||||
|
|||||||
@@ -106,8 +106,7 @@ def parse_cli(argv, no_defaults=False):
|
|||||||
ret = parser.parse_args(argv)
|
ret = parser.parse_args(argv)
|
||||||
|
|
||||||
if ret.keysanity:
|
if ret.keysanity:
|
||||||
ret.mapshuffle, ret.compassshuffle, ret.bigkeyshuffle = [True] * 3
|
ret.mapshuffle, ret.compassshuffle, ret.keyshuffle, ret.bigkeyshuffle = 'wild' * 4
|
||||||
ret.keyshuffle = 'wild'
|
|
||||||
|
|
||||||
if ret.keydropshuffle:
|
if ret.keydropshuffle:
|
||||||
ret.dropshuffle = 'keys' if ret.dropshuffle == 'none' else ret.dropshuffle
|
ret.dropshuffle = 'keys' if ret.dropshuffle == 'none' else ret.dropshuffle
|
||||||
@@ -137,7 +136,7 @@ def parse_cli(argv, no_defaults=False):
|
|||||||
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
'shuffle', 'door_shuffle', 'intensity', 'crystals_ganon', 'crystals_gt', 'openpyramid',
|
||||||
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'prizeshuffle', 'startinventory',
|
'mapshuffle', 'compassshuffle', 'keyshuffle', 'bigkeyshuffle', 'prizeshuffle', 'startinventory',
|
||||||
'usestartinventory', 'bombbag', 'shuffleganon', 'overworld_map', 'restrict_boss_items',
|
'usestartinventory', 'bombbag', 'shuffleganon', 'overworld_map', 'restrict_boss_items',
|
||||||
'triforce_pool_min', 'triforce_pool_max', 'triforce_goal_min', 'triforce_goal_max', 'triforce_max_difference',
|
'triforce_max_difference', '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',
|
||||||
'skullwoods', 'linked_drops',
|
'skullwoods', 'linked_drops',
|
||||||
'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
'pseudoboots', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
|
||||||
@@ -222,10 +221,10 @@ def parse_settings():
|
|||||||
"pottery": "none",
|
"pottery": "none",
|
||||||
"colorizepots": True,
|
"colorizepots": True,
|
||||||
"shufflepots": False,
|
"shufflepots": False,
|
||||||
"mapshuffle": False,
|
"mapshuffle": "none",
|
||||||
"compassshuffle": False,
|
"compassshuffle": "none",
|
||||||
"keyshuffle": "none",
|
"keyshuffle": "none",
|
||||||
"bigkeyshuffle": False,
|
"bigkeyshuffle": "none",
|
||||||
"prizeshuffle": "none",
|
"prizeshuffle": "none",
|
||||||
"keysanity": False,
|
"keysanity": False,
|
||||||
"door_shuffle": "vanilla",
|
"door_shuffle": "vanilla",
|
||||||
@@ -285,7 +284,7 @@ def parse_settings():
|
|||||||
"seed": "",
|
"seed": "",
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"startinventory": "",
|
"startinventory": "",
|
||||||
"beemizer": 0,
|
'beemizer': '0',
|
||||||
"remote_items": False,
|
"remote_items": False,
|
||||||
"race": False,
|
"race": False,
|
||||||
"customitemarray": {
|
"customitemarray": {
|
||||||
|
|||||||
+5
-5
@@ -477,7 +477,7 @@ def choose_portals(world, player):
|
|||||||
allowed = {name: set(group[0]) for group in world.dungeon_pool[player] for name in group[0]}
|
allowed = {name: set(group[0]) for group in world.dungeon_pool[player] for name in group[0]}
|
||||||
|
|
||||||
# key drops allow the big key in the right place in Desert Tiles 2
|
# key drops allow the big key in the right place in Desert Tiles 2
|
||||||
bk_shuffle = world.bigkeyshuffle[player] or world.pottery[player] not in ['none', 'cave']
|
bk_shuffle = world.bigkeyshuffle[player] != 'none' or world.pottery[player] not in ['none', 'cave']
|
||||||
std_flag = world.mode[player] == 'standard'
|
std_flag = world.mode[player] == 'standard'
|
||||||
# roast incognito doors
|
# roast incognito doors
|
||||||
world.get_room(0x60, player).delete(5)
|
world.get_room(0x60, player).delete(5)
|
||||||
@@ -2322,7 +2322,7 @@ def validate_trap_layout(proposal, builder, start_regions, paths, world, player)
|
|||||||
if bk_special_loc:
|
if bk_special_loc:
|
||||||
if not state.found_forced_bk():
|
if not state.found_forced_bk():
|
||||||
return False
|
return False
|
||||||
if world.accessibility[player] != 'beatable':
|
if world.accessibility[player] != 'none':
|
||||||
all_locations = [l for r in builder.master_sector.region_set() for l in world.get_region(r, player).locations]
|
all_locations = [l for r in builder.master_sector.region_set() for l in world.get_region(r, player).locations]
|
||||||
if any(l not in state.found_locations for l in all_locations):
|
if any(l not in state.found_locations for l in all_locations):
|
||||||
return False
|
return False
|
||||||
@@ -2689,12 +2689,12 @@ def calc_used_dungeon_items(builder, world, player):
|
|||||||
basic_flag = world.doorShuffle[player] == 'basic'
|
basic_flag = world.doorShuffle[player] == 'basic'
|
||||||
base = 0 if basic_flag else 2 # at least 2 items per dungeon, except in basic
|
base = 0 if basic_flag else 2 # at least 2 items per dungeon, except in basic
|
||||||
base = max(count_reserved_locations(world, player, builder.location_set), base)
|
base = max(count_reserved_locations(world, player, builder.location_set), base)
|
||||||
if not world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] == 'none':
|
||||||
if builder.bk_required and not builder.bk_provided:
|
if builder.bk_required and not builder.bk_provided:
|
||||||
base += 1
|
base += 1
|
||||||
if not world.compassshuffle[player] and (builder.name not in ['Hyrule Castle', 'Agahnims Tower'] or not basic_flag):
|
if world.compassshuffle[player] == 'none' and (builder.name not in ['Hyrule Castle', 'Agahnims Tower'] or not basic_flag):
|
||||||
base += 1
|
base += 1
|
||||||
if not world.mapshuffle[player] and (builder.name != 'Agahnims Tower' or not basic_flag):
|
if world.mapshuffle[player] == 'none' and (builder.name != 'Agahnims Tower' or not basic_flag):
|
||||||
base += 1
|
base += 1
|
||||||
if world.prizeshuffle[player] == 'dungeon' and builder.name not in ['Hyrule Castle', 'Agahnims Tower', 'Ganons Tower']:
|
if world.prizeshuffle[player] == 'dungeon' and builder.name not in ['Hyrule Castle', 'Agahnims Tower', 'Ganons Tower']:
|
||||||
base += 1
|
base += 1
|
||||||
|
|||||||
+7
-7
@@ -231,7 +231,7 @@ def gen_dungeon_info(name, available_sectors, entrance_regions, all_regions, pro
|
|||||||
start = ExplorationState(dungeon=name)
|
start = ExplorationState(dungeon=name)
|
||||||
start.big_key_special = bk_special
|
start.big_key_special = bk_special
|
||||||
group_flags, door_map = find_bk_groups(name, available_sectors, proposed_map, bk_special)
|
group_flags, door_map = find_bk_groups(name, available_sectors, proposed_map, bk_special)
|
||||||
bk_flag = False if world.bigkeyshuffle[player] and not bk_special else bk_needed
|
bk_flag = False if world.bigkeyshuffle[player] != 'none' and not bk_special else bk_needed
|
||||||
|
|
||||||
def exception(d):
|
def exception(d):
|
||||||
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
|
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
|
||||||
@@ -436,7 +436,7 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a
|
|||||||
if len(dungeon.keys()) <= 1 and len(proposed_map.keys()) < len(doors_to_connect):
|
if len(dungeon.keys()) <= 1 and len(proposed_map.keys()) < len(doors_to_connect):
|
||||||
return False
|
return False
|
||||||
# origin has no more hooks, but not all doors have been proposed
|
# origin has no more hooks, but not all doors have been proposed
|
||||||
if not world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] == 'none':
|
||||||
possible_bks = len(dungeon['Origin'].possible_bk_locations)
|
possible_bks = len(dungeon['Origin'].possible_bk_locations)
|
||||||
if bk_special and check_for_special(dungeon['Origin'].visited_regions):
|
if bk_special and check_for_special(dungeon['Origin'].visited_regions):
|
||||||
possible_bks = 1
|
possible_bks = 1
|
||||||
@@ -470,7 +470,7 @@ def check_valid(name, dungeon, hangers, hooks, proposed_map, doors_to_connect, a
|
|||||||
if len(outstanding_doors[key]) > 0 and len(hangers[key]) == 0 and len(hooks[opp_key]) == 0:
|
if len(outstanding_doors[key]) > 0 and len(hangers[key]) == 0 and len(hooks[opp_key]) == 0:
|
||||||
return False
|
return False
|
||||||
all_visited = set()
|
all_visited = set()
|
||||||
bk_possible = not bk_needed or (world.bigkeyshuffle[player] and not bk_special)
|
bk_possible = not bk_needed or (world.bigkeyshuffle[player] != 'none' and not bk_special)
|
||||||
for piece in dungeon.values():
|
for piece in dungeon.values():
|
||||||
all_visited.update(piece.visited_regions)
|
all_visited.update(piece.visited_regions)
|
||||||
if ((not bk_possible and len(piece.possible_bk_locations) > 0) or
|
if ((not bk_possible and len(piece.possible_bk_locations) > 0) or
|
||||||
@@ -544,7 +544,7 @@ def valid_path(name, starting_regions, target, valid_doors, proposed_map, all_re
|
|||||||
|
|
||||||
start = ExplorationState(dungeon=name)
|
start = ExplorationState(dungeon=name)
|
||||||
start.big_key_special = bk_special
|
start.big_key_special = bk_special
|
||||||
bk_flag = False if world.bigkeyshuffle[player] and not bk_special else bk_needed
|
bk_flag = False if world.bigkeyshuffle[player] != 'none' and not bk_special else bk_needed
|
||||||
|
|
||||||
def exception(d):
|
def exception(d):
|
||||||
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
|
return name == 'Skull Woods 2' and d.name == 'Skull Pinball WS'
|
||||||
@@ -1775,11 +1775,11 @@ def requested_dungeon_items(world, player):
|
|||||||
num = 0
|
num = 0
|
||||||
if world.prizeshuffle[player] == 'dungeon':
|
if world.prizeshuffle[player] == 'dungeon':
|
||||||
num += 1
|
num += 1
|
||||||
if not world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] == 'none':
|
||||||
num += 1
|
num += 1
|
||||||
if not world.compassshuffle[player]:
|
if world.compassshuffle[player] == 'none':
|
||||||
num += 1
|
num += 1
|
||||||
if not world.mapshuffle[player]:
|
if world.mapshuffle[player] == 'none':
|
||||||
num += 1
|
num += 1
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ def fill_dungeons_restrictive(world, shuffled_locations):
|
|||||||
for item in world.get_items():
|
for item in world.get_items():
|
||||||
if ((item.prize and world.prizeshuffle[item.player] != 'none')
|
if ((item.prize and world.prizeshuffle[item.player] != 'none')
|
||||||
or (item.smallkey and world.keyshuffle[item.player] != 'none')
|
or (item.smallkey and world.keyshuffle[item.player] != 'none')
|
||||||
or (item.bigkey and world.bigkeyshuffle[item.player])):
|
or (item.bigkey and world.bigkeyshuffle[item.player] != 'none')):
|
||||||
item.advancement = True
|
item.advancement = True
|
||||||
elif (item.map and world.mapshuffle[item.player]) or (item.compass and world.compassshuffle[item.player]):
|
elif (item.map and world.mapshuffle[item.player] not in ['none', 'district']) or (item.compass and world.compassshuffle[item.player] not in ['none', 'district']):
|
||||||
item.priority = True
|
item.priority = True
|
||||||
|
|
||||||
dungeon_items = [item for item in get_dungeon_item_pool(world) if item.is_inside_dungeon_item(world)]
|
dungeon_items = [item for item in get_dungeon_item_pool(world) if item.is_inside_dungeon_item(world) or item.is_near_dungeon_item(world)]
|
||||||
bigs, smalls, prizes, others = [], [], [], []
|
bigs, smalls, prizes, others = [], [], [], []
|
||||||
for i in dungeon_items:
|
for i in dungeon_items:
|
||||||
(bigs if i.bigkey else smalls if i.smallkey else prizes if i.prize else others).append(i)
|
(bigs if i.bigkey else smalls if i.smallkey else prizes if i.prize else others).append(i)
|
||||||
@@ -76,6 +76,19 @@ def fill_dungeons_restrictive(world, shuffled_locations):
|
|||||||
prizes_copy = prizes.copy()
|
prizes_copy = prizes.copy()
|
||||||
for attempt in range(15):
|
for attempt in range(15):
|
||||||
try:
|
try:
|
||||||
|
for player in range(1, world.players + 1):
|
||||||
|
if world.prizeshuffle[player] == 'district':
|
||||||
|
dungeon_pool = []
|
||||||
|
for dungeon in world.dungeons:
|
||||||
|
from Dungeons import dungeon_table
|
||||||
|
if dungeon.player == player and dungeon_table[dungeon.name].prize:
|
||||||
|
dungeon_pool.append(dungeon)
|
||||||
|
random.shuffle(dungeon_pool)
|
||||||
|
for item in prizes:
|
||||||
|
if item.player == player:
|
||||||
|
dungeon = dungeon_pool.pop()
|
||||||
|
dungeon.prize = item
|
||||||
|
item.dungeon_object = dungeon
|
||||||
random.shuffle(prizes)
|
random.shuffle(prizes)
|
||||||
random.shuffle(shuffled_locations)
|
random.shuffle(shuffled_locations)
|
||||||
prize_state_base = all_state_base.copy()
|
prize_state_base = all_state_base.copy()
|
||||||
@@ -86,7 +99,6 @@ def fill_dungeons_restrictive(world, shuffled_locations):
|
|||||||
logging.getLogger('').info("Failed to place dungeon prizes (%s). Will retry %s more times", e, 14 - attempt)
|
logging.getLogger('').info("Failed to place dungeon prizes (%s). Will retry %s more times", e, 14 - attempt)
|
||||||
prizes = prizes_copy.copy()
|
prizes = prizes_copy.copy()
|
||||||
for dungeon in world.dungeons:
|
for dungeon in world.dungeons:
|
||||||
if world.prizeshuffle[dungeon.player] == 'dungeon':
|
|
||||||
dungeon.prize = None
|
dungeon.prize = None
|
||||||
for prize in prizes:
|
for prize in prizes:
|
||||||
if prize.location:
|
if prize.location:
|
||||||
@@ -186,7 +198,8 @@ def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_pl
|
|||||||
test_state.sweep_for_events()
|
test_state.sweep_for_events()
|
||||||
if location.can_fill(test_state, item_to_place, perform_access_check):
|
if location.can_fill(test_state, item_to_place, perform_access_check):
|
||||||
if valid_key_placement(item_to_place, location, key_pool, test_state, world):
|
if valid_key_placement(item_to_place, location, key_pool, test_state, world):
|
||||||
if item_to_place.prize or valid_dungeon_placement(item_to_place, location, world):
|
if (item_to_place.prize and world.prizeshuffle[item_to_place.player] == 'none') \
|
||||||
|
or valid_dungeon_placement(item_to_place, location, world):
|
||||||
return location
|
return location
|
||||||
if item_to_place.smallkey or item_to_place.bigkey or item_to_place.prize:
|
if item_to_place.smallkey or item_to_place.bigkey or item_to_place.prize:
|
||||||
location.item = None
|
location.item = None
|
||||||
@@ -203,6 +216,10 @@ def valid_key_placement(item, location, key_pool, collection_state, world):
|
|||||||
or world.keyshuffle[item.player] == 'universal' or world.logic[item.player] == 'nologic'):
|
or world.keyshuffle[item.player] == 'universal' or world.logic[item.player] == 'nologic'):
|
||||||
return True
|
return True
|
||||||
dungeon = location.parent_region.dungeon
|
dungeon = location.parent_region.dungeon
|
||||||
|
if not dungeon and item.is_near_dungeon_item(world):
|
||||||
|
check_dungeon = world.get_dungeon(item.dungeon, item.player) if item.dungeon else item.dungeon_object
|
||||||
|
if len([d for d in location.parent_region.districts if d in check_dungeon.districts]):
|
||||||
|
dungeon = check_dungeon
|
||||||
if dungeon:
|
if dungeon:
|
||||||
if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name):
|
if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name):
|
||||||
return True
|
return True
|
||||||
@@ -236,13 +253,22 @@ def valid_reserved_placement(item, location, world):
|
|||||||
|
|
||||||
|
|
||||||
def valid_dungeon_placement(item, location, world):
|
def valid_dungeon_placement(item, location, world):
|
||||||
if location.parent_region.dungeon:
|
dungeon = location.parent_region.dungeon
|
||||||
layout = world.dungeon_layouts[location.player][location.parent_region.dungeon.name]
|
if not dungeon and item.is_near_dungeon_item(world):
|
||||||
|
check_dungeon = world.get_dungeon(item.dungeon, item.player) if item.dungeon else item.dungeon_object
|
||||||
|
if len([d for d in location.parent_region.districts if d in check_dungeon.districts]):
|
||||||
|
dungeon = check_dungeon
|
||||||
|
if dungeon:
|
||||||
|
layout = world.dungeon_layouts[location.player][dungeon.name]
|
||||||
if not is_dungeon_item(item, world) or item.player != location.player:
|
if not is_dungeon_item(item, world) or item.player != location.player:
|
||||||
|
if item.prize and item.is_near_dungeon_item(world):
|
||||||
|
return item.dungeon_object == dungeon and layout.free_items > 0
|
||||||
return layout.free_items > 0
|
return layout.free_items > 0
|
||||||
|
elif item.prize:
|
||||||
|
return not dungeon.prize and layout.dungeon_items > 0
|
||||||
else:
|
else:
|
||||||
# the second half probably doesn't matter much - should always return true
|
# the second half probably doesn't matter much - should always return true
|
||||||
return item.dungeon == location.parent_region.dungeon.name and layout.dungeon_items > 0
|
return item.dungeon == dungeon.name and layout.dungeon_items > 0
|
||||||
return not is_dungeon_item(item, world)
|
return not is_dungeon_item(item, world)
|
||||||
|
|
||||||
|
|
||||||
@@ -267,14 +293,15 @@ def track_dungeon_items(item, location, world):
|
|||||||
layout.free_items -= 1
|
layout.free_items -= 1
|
||||||
if item.prize:
|
if item.prize:
|
||||||
location.parent_region.dungeon.prize = item
|
location.parent_region.dungeon.prize = item
|
||||||
|
item.dungeon_object = location.parent_region.dungeon
|
||||||
|
|
||||||
|
|
||||||
def is_dungeon_item(item, world):
|
def is_dungeon_item(item, world):
|
||||||
return ((item.prize and world.prizeshuffle[item.player] in ['none', 'dungeon'])
|
return ((item.prize and world.prizeshuffle[item.player] in ['none', 'dungeon'])
|
||||||
or (item.smallkey and world.keyshuffle[item.player] == 'none')
|
or (item.smallkey and world.keyshuffle[item.player] == 'none')
|
||||||
or (item.bigkey and not world.bigkeyshuffle[item.player])
|
or (item.bigkey and world.bigkeyshuffle[item.player] == 'none')
|
||||||
or (item.compass and not world.compassshuffle[item.player])
|
or (item.compass and world.compassshuffle[item.player] == 'none')
|
||||||
or (item.map and not world.mapshuffle[item.player]))
|
or (item.map and world.mapshuffle[item.player] == 'none'))
|
||||||
|
|
||||||
|
|
||||||
def recovery_placement(item_to_place, locations, world, state, base_state, itempool, perform_access_check, attempted,
|
def recovery_placement(item_to_place, locations, world, state, base_state, itempool, perform_access_check, attempted,
|
||||||
@@ -816,7 +843,8 @@ def balance_multiworld_progression(world):
|
|||||||
candidate_items = collections.defaultdict(set)
|
candidate_items = collections.defaultdict(set)
|
||||||
while True:
|
while True:
|
||||||
for location in balancing_sphere:
|
for location in balancing_sphere:
|
||||||
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) \
|
||||||
|
and (world.bigkeyshuffle[location.item.player] != 'none' or not location.item.bigkey):
|
||||||
balancing_state.collect(location.item, True, location)
|
balancing_state.collect(location.item, True, location)
|
||||||
player = location.item.player
|
player = location.item.player
|
||||||
if player in balancing_players and not location.locked and location.player != player:
|
if player in balancing_players and not location.locked and location.player != player:
|
||||||
@@ -895,7 +923,8 @@ def balance_multiworld_progression(world):
|
|||||||
sphere_locations.add(location)
|
sphere_locations.add(location)
|
||||||
|
|
||||||
for location in sphere_locations:
|
for location in sphere_locations:
|
||||||
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) and (world.bigkeyshuffle[location.item.player] or not location.item.bigkey):
|
if location.event and (world.keyshuffle[location.item.player] != 'none' or not location.item.smallkey) \
|
||||||
|
and (world.bigkeyshuffle[location.item.player] != 'none' or not location.item.bigkey):
|
||||||
state.collect(location.item, True, location)
|
state.collect(location.item, True, location)
|
||||||
checked_locations |= sphere_locations
|
checked_locations |= sphere_locations
|
||||||
|
|
||||||
|
|||||||
+15
-14
@@ -348,11 +348,11 @@ def generate_itempool(world, player):
|
|||||||
world.treasure_hunt_icon[player] = 'Triforce Piece'
|
world.treasure_hunt_icon[player] = 'Triforce Piece'
|
||||||
|
|
||||||
world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player
|
world.itempool.extend([item for item in get_dungeon_item_pool(world) if item.player == player
|
||||||
and ((item.prize and world.prizeshuffle[player] == 'wild')
|
and ((item.prize and world.prizeshuffle[player] not in ['none', 'dungeon', 'district'])
|
||||||
or (item.smallkey and world.keyshuffle[player] != 'none')
|
or (item.smallkey and world.keyshuffle[player] not in ['none', 'district'])
|
||||||
or (item.bigkey and world.bigkeyshuffle[player])
|
or (item.bigkey and world.bigkeyshuffle[player] not in ['none', 'district'])
|
||||||
or (item.map and world.mapshuffle[player])
|
or (item.map and world.mapshuffle[player] not in ['none', 'district'])
|
||||||
or (item.compass and world.compassshuffle[player]))])
|
or (item.compass and world.compassshuffle[player] not in ['none', 'district']))])
|
||||||
|
|
||||||
if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']:
|
if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']:
|
||||||
keys_to_remove = 2
|
keys_to_remove = 2
|
||||||
@@ -462,7 +462,7 @@ def generate_itempool(world, player):
|
|||||||
'3': {'trap': 50, 'bee': 50},
|
'3': {'trap': 50, 'bee': 50},
|
||||||
'4': {'trap': 100}}
|
'4': {'trap': 100}}
|
||||||
def beemizer(item):
|
def beemizer(item):
|
||||||
if world.beemizer[item.player] and not item.advancement and not item.priority and not item.type:
|
if world.beemizer[item.player] != '0' and not item.advancement and not item.priority and not item.type:
|
||||||
choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0]
|
choice = random.choices(list(beeweights[world.beemizer[item.player]].keys()), weights=list(beeweights[world.beemizer[item.player]].values()))[0]
|
||||||
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player)
|
return item if not choice else ItemFactory("Bee Trap", player) if choice == 'trap' else ItemFactory("Bee", player)
|
||||||
return item
|
return item
|
||||||
@@ -753,6 +753,7 @@ def fill_prizes(world, attempts=15):
|
|||||||
fill_restrictive(world, all_state, prize_locs, prizepool, single_player_placement=True)
|
fill_restrictive(world, all_state, prize_locs, prizepool, single_player_placement=True)
|
||||||
for prize_loc in crystal_locations:
|
for prize_loc in crystal_locations:
|
||||||
prize_loc.parent_region.dungeon.prize = prize_loc.item
|
prize_loc.parent_region.dungeon.prize = prize_loc.item
|
||||||
|
prize_loc.item.dungeon_object = prize_loc.parent_region.dungeon
|
||||||
except FillError as e:
|
except FillError as e:
|
||||||
logging.getLogger('').info("Failed to place dungeon prizes (%s). Will retry %s more times", e, attempts - attempt - 1)
|
logging.getLogger('').info("Failed to place dungeon prizes (%s). Will retry %s more times", e, attempts - attempt - 1)
|
||||||
for location in empty_crystal_locations:
|
for location in empty_crystal_locations:
|
||||||
@@ -1434,12 +1435,12 @@ def make_customizer_pool(world, player):
|
|||||||
or item_name.startswith('Crystal') or item_name.endswith('Pendant')):
|
or item_name.startswith('Crystal') or item_name.endswith('Pendant')):
|
||||||
d_item = ItemFactory(item_name, player)
|
d_item = ItemFactory(item_name, player)
|
||||||
if ((d_item.prize and world.prizeshuffle[player] in ['none', 'dungeon'])
|
if ((d_item.prize and world.prizeshuffle[player] in ['none', 'dungeon'])
|
||||||
or (d_item.bigkey and not world.bigkeyshuffle[player])
|
or (d_item.bigkey and world.bigkeyshuffle[player] == 'none')
|
||||||
or (d_item.compass and not world.compassshuffle[player])
|
or (d_item.compass and world.compassshuffle[player] == 'none')
|
||||||
or (d_item.map and not world.mapshuffle[player])):
|
or (d_item.map and world.mapshuffle[player] == 'none')):
|
||||||
d_name = d_item.dungeon
|
d_name = d_item.dungeon
|
||||||
dungeon = world.get_dungeon(d_name, player)
|
dungeon = world.get_dungeon(d_name, player)
|
||||||
current_amount = 1 if d_item == dungeon.big_key or d_item in dungeon.dungeon_items else 0
|
current_amount = 1 if dungeon.big_key and (d_item == dungeon.big_key or d_item in dungeon.dungeon_items) else 0
|
||||||
additional_amount = amount - current_amount
|
additional_amount = amount - current_amount
|
||||||
possible_fit = min(additional_amount, len(dungeon_locations[d_name])-dungeon_count[d_name])
|
possible_fit = min(additional_amount, len(dungeon_locations[d_name])-dungeon_count[d_name])
|
||||||
if possible_fit > 0:
|
if possible_fit > 0:
|
||||||
@@ -1450,7 +1451,7 @@ def make_customizer_pool(world, player):
|
|||||||
pool.extend([item_name] * amount)
|
pool.extend([item_name] * amount)
|
||||||
else:
|
else:
|
||||||
dungeon = world.get_dungeon(d_item.dungeon, player)
|
dungeon = world.get_dungeon(d_item.dungeon, player)
|
||||||
current_amount = 1 if d_item == dungeon.big_key or d_item in dungeon.dungeon_items else 0
|
current_amount = 1 if dungeon.big_key and (d_item == dungeon.big_key or d_item in dungeon.dungeon_items) else 0
|
||||||
additional_amount = amount - current_amount
|
additional_amount = amount - current_amount
|
||||||
dungeon.dungeon_items.extend([d_item] * additional_amount)
|
dungeon.dungeon_items.extend([d_item] * additional_amount)
|
||||||
else:
|
else:
|
||||||
@@ -1694,7 +1695,7 @@ def get_item_and_event_flag(item, world, player, dungeon_pool, prize_set, prize_
|
|||||||
def is_dungeon_item(item, world, player):
|
def is_dungeon_item(item, world, player):
|
||||||
return (((item.startswith('Crystal') or item.endswith('Pendant')) and world.prizeshuffle[player] in ['none', 'dungeon'])
|
return (((item.startswith('Crystal') or item.endswith('Pendant')) and world.prizeshuffle[player] in ['none', 'dungeon'])
|
||||||
or (item.startswith('Small Key') and world.keyshuffle[player] == 'none')
|
or (item.startswith('Small Key') and world.keyshuffle[player] == 'none')
|
||||||
or (item.startswith('Big Key') and not world.bigkeyshuffle[player])
|
or (item.startswith('Big Key') and world.bigkeyshuffle[player] == 'none')
|
||||||
or (item.startswith('Compass') and not world.compassshuffle[player])
|
or (item.startswith('Compass') and world.compassshuffle[player] == 'none')
|
||||||
or (item.startswith('Map') and not world.mapshuffle[player]))
|
or (item.startswith('Map') and world.mapshuffle[player] == 'none'))
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -1303,7 +1303,7 @@ def check_rules_deep(original_counter, key_layout, world, player):
|
|||||||
big_avail = counter.big_key_opened or bk_drop
|
big_avail = counter.big_key_opened or bk_drop
|
||||||
big_maybe_not_found = not counter.big_key_opened and not bk_drop # better named as big_missing?
|
big_maybe_not_found = not counter.big_key_opened and not bk_drop # better named as big_missing?
|
||||||
if not key_layout.big_key_special and not big_avail:
|
if not key_layout.big_key_special and not big_avail:
|
||||||
if world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] != 'none':
|
||||||
big_avail = True
|
big_avail = True
|
||||||
else:
|
else:
|
||||||
for location in counter.free_locations:
|
for location in counter.free_locations:
|
||||||
@@ -1430,7 +1430,7 @@ def prize_relevance_sig2(start_regions, d_name, dungeon_entrance, is_atgt_swappe
|
|||||||
|
|
||||||
def validate_bk_layout(proposal, builder, start_regions, world, player):
|
def validate_bk_layout(proposal, builder, start_regions, world, player):
|
||||||
bk_special = check_bk_special(builder.master_sector.regions, world, player)
|
bk_special = check_bk_special(builder.master_sector.regions, world, player)
|
||||||
if world.bigkeyshuffle[player] and (world.dropshuffle[player] != 'none' or not bk_special):
|
if world.bigkeyshuffle[player] != 'none' and (world.dropshuffle[player] != 'none' or not bk_special):
|
||||||
return True
|
return True
|
||||||
flat_proposal = flatten_pair_list(proposal)
|
flat_proposal = flatten_pair_list(proposal)
|
||||||
state = ExplorationState(dungeon=builder.name)
|
state = ExplorationState(dungeon=builder.name)
|
||||||
@@ -1438,7 +1438,7 @@ def validate_bk_layout(proposal, builder, start_regions, world, player):
|
|||||||
for region in start_regions:
|
for region in start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance, world.is_atgt_swapped(player))
|
prize_relevant_flag = prize_relevance_sig2(start_regions, builder.name, dungeon_entrance, world.is_atgt_swapped(player))
|
||||||
if prize_relevant_flag and world.prizeshuffle[player] == 'none':
|
if prize_relevant_flag and world.prizeshuffle[player] in ['none', 'dungeon']:
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
# key_layout.prize_relevant = prize_relevant_flag
|
# key_layout.prize_relevant = prize_relevant_flag
|
||||||
@@ -1469,7 +1469,7 @@ def validate_key_layout(key_layout, world, player):
|
|||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
||||||
if prize_relevant_flag and world.prizeshuffle[player] == 'none':
|
if prize_relevant_flag and world.prizeshuffle[player] in ['none', 'dungeon']:
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
key_layout.prize_relevant = prize_relevant_flag
|
key_layout.prize_relevant = prize_relevant_flag
|
||||||
@@ -1606,7 +1606,7 @@ def determine_prize_lock(key_layout, world, player):
|
|||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
||||||
if prize_relevant_flag and world.prizeshuffle[player] == 'none':
|
if prize_relevant_flag and world.prizeshuffle[player] in ['none', 'dungeon']:
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
key_layout.prize_relevant = prize_relevant_flag
|
key_layout.prize_relevant = prize_relevant_flag
|
||||||
@@ -1650,13 +1650,13 @@ def cnt_avail_small_locations_by_ctr(free_locations, counter, layout, world, pla
|
|||||||
|
|
||||||
|
|
||||||
def cnt_avail_big_locations(ttl_locations, state, world, player):
|
def cnt_avail_big_locations(ttl_locations, state, world, player):
|
||||||
if not world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] == 'none':
|
||||||
return max(0, ttl_locations - state.used_locations) if not state.big_key_special else 0
|
return max(0, ttl_locations - state.used_locations) if not state.big_key_special else 0
|
||||||
return 1 if not state.big_key_special else 0
|
return 1 if not state.big_key_special else 0
|
||||||
|
|
||||||
|
|
||||||
def cnt_avail_big_locations_by_ctr(ttl_locations, counter, layout, world, player):
|
def cnt_avail_big_locations_by_ctr(ttl_locations, counter, layout, world, player):
|
||||||
if not world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] == 'none':
|
||||||
bk_adj = 1 if counter.big_key_opened and not layout.big_key_special else 0
|
bk_adj = 1 if counter.big_key_opened and not layout.big_key_special else 0
|
||||||
used_locations = max(0, counter.used_keys - len(counter.key_only_locations)) + bk_adj
|
used_locations = max(0, counter.used_keys - len(counter.key_only_locations)) + bk_adj
|
||||||
return max(0, ttl_locations - used_locations) if not layout.big_key_special else 0
|
return max(0, ttl_locations - used_locations) if not layout.big_key_special else 0
|
||||||
@@ -1683,7 +1683,7 @@ def create_key_counters(key_layout, world, player):
|
|||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
prize_relevant_flag = prize_relevance(key_layout, dungeon_entrance, world.is_atgt_swapped(player))
|
||||||
if prize_relevant_flag and world.prizeshuffle[player] == 'none':
|
if prize_relevant_flag and world.prizeshuffle[player] in ['none', 'dungeon']:
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
key_layout.prize_relevant = prize_relevant_flag
|
key_layout.prize_relevant = prize_relevant_flag
|
||||||
@@ -2096,7 +2096,7 @@ def validate_key_placement(key_layout, world, player):
|
|||||||
bigkey_name = dungeon_bigs[key_layout.sector.name]
|
bigkey_name = dungeon_bigs[key_layout.sector.name]
|
||||||
if world.keyshuffle[player] != 'none':
|
if world.keyshuffle[player] != 'none':
|
||||||
keys_outside = key_layout.max_chests - sum(1 for i in max_counter.free_locations if i.item is not None and i.item.name == smallkey_name and i.item.player == player)
|
keys_outside = key_layout.max_chests - sum(1 for i in max_counter.free_locations if i.item is not None and i.item.name == smallkey_name and i.item.player == player)
|
||||||
if world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] != 'none':
|
||||||
max_counter = find_max_counter(key_layout)
|
max_counter = find_max_counter(key_layout)
|
||||||
big_key_outside = bigkey_name not in (l.item.name for l in max_counter.free_locations if l.item)
|
big_key_outside = bigkey_name not in (l.item.name for l in max_counter.free_locations if l.item)
|
||||||
for i in world.precollected_items:
|
for i in world.precollected_items:
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from Fill import distribute_items_restrictive, promote_dungeon_items, fill_dunge
|
|||||||
from Fill import dungeon_tracking
|
from Fill import dungeon_tracking
|
||||||
from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations, set_prize_drops
|
from Fill import sell_potions, sell_keys, balance_multiworld_progression, balance_money_progression, lock_shop_locations, set_prize_drops
|
||||||
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops, fill_specific_items, create_farm_locations
|
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops, fill_specific_items, create_farm_locations
|
||||||
from UnderworldGlitchRules import create_hybridmajor_connections, get_hybridmajor_connection_entrances
|
from UnderworldGlitchRules import connect_hmg_entrances_regions, create_hmg_entrances_regions
|
||||||
from Utils import output_path, parse_player_names
|
from Utils import output_path, parse_player_names
|
||||||
|
|
||||||
from source.item.District import init_districts
|
from source.item.District import init_districts
|
||||||
@@ -40,7 +40,7 @@ from source.enemizer.DamageTables import DamageTable
|
|||||||
from source.enemizer.Enemizer import randomize_enemies
|
from source.enemizer.Enemizer import randomize_enemies
|
||||||
from source.rom.DataTables import init_data_tables
|
from source.rom.DataTables import init_data_tables
|
||||||
|
|
||||||
version_number = '1.4.6'
|
version_number = '1.4.7.2'
|
||||||
version_branch = '-u'
|
version_branch = '-u'
|
||||||
__version__ = f'{version_number}{version_branch}'
|
__version__ = f'{version_number}{version_branch}'
|
||||||
|
|
||||||
@@ -224,7 +224,8 @@ def main(args, seed=None, fish=None):
|
|||||||
|
|
||||||
for player in range(1, world.players + 1):
|
for player in range(1, world.players + 1):
|
||||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||||
create_hybridmajor_connections(world, player)
|
create_hmg_entrances_regions(world, player)
|
||||||
|
connect_hmg_entrances_regions(world, player)
|
||||||
generate_itempool(world, player)
|
generate_itempool(world, player)
|
||||||
|
|
||||||
verify_item_pool_config(world)
|
verify_item_pool_config(world)
|
||||||
@@ -479,7 +480,7 @@ def init_world(args, fish):
|
|||||||
world.enemy_health = args.enemy_health.copy()
|
world.enemy_health = args.enemy_health.copy()
|
||||||
world.enemy_damage = args.enemy_damage.copy()
|
world.enemy_damage = args.enemy_damage.copy()
|
||||||
world.any_enemy_logic = args.any_enemy_logic.copy()
|
world.any_enemy_logic = args.any_enemy_logic.copy()
|
||||||
world.beemizer = args.beemizer.copy()
|
world.beemizer = {player: str(args.beemizer[player]) for player in range(1, world.players + 1)}
|
||||||
world.intensity = {player: 'random' if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)}
|
world.intensity = {player: 'random' if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)}
|
||||||
world.door_type_mode = args.door_type_mode.copy()
|
world.door_type_mode = args.door_type_mode.copy()
|
||||||
world.trap_door_mode = args.trap_door_mode.copy()
|
world.trap_door_mode = args.trap_door_mode.copy()
|
||||||
@@ -643,6 +644,10 @@ def copy_world(world):
|
|||||||
connection = Entrance(player, 'Uncle S&Q', parent)
|
connection = Entrance(player, 'Uncle S&Q', parent)
|
||||||
parent.exits.append(connection)
|
parent.exits.append(connection)
|
||||||
connection.connect(target)
|
connection.connect(target)
|
||||||
|
# This makes the regions for HMG only
|
||||||
|
# we'll connect them later after all other connections are made (OW <=> UW, Portals)
|
||||||
|
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||||
|
create_hmg_entrances_regions(ret, player)
|
||||||
|
|
||||||
# copy bosses
|
# copy bosses
|
||||||
for dungeon in world.dungeons:
|
for dungeon in world.dungeons:
|
||||||
@@ -659,7 +664,6 @@ def copy_world(world):
|
|||||||
|
|
||||||
# We have to skip these for now. They require both the rest of the entrances _and_ the dungeon portals to be copied first
|
# We have to skip these for now. They require both the rest of the entrances _and_ the dungeon portals to be copied first
|
||||||
# We will connect them later
|
# We will connect them later
|
||||||
hmg_entrances = get_hybridmajor_connection_entrances()
|
|
||||||
|
|
||||||
for region in world.regions:
|
for region in world.regions:
|
||||||
copied_region = ret.get_region(region.name, region.player)
|
copied_region = ret.get_region(region.name, region.player)
|
||||||
@@ -670,8 +674,6 @@ def copy_world(world):
|
|||||||
for location in copied_region.locations:
|
for location in copied_region.locations:
|
||||||
location.parent_region = copied_region
|
location.parent_region = copied_region
|
||||||
for entrance in region.entrances:
|
for entrance in region.entrances:
|
||||||
if entrance.name in hmg_entrances:
|
|
||||||
continue
|
|
||||||
ret.get_entrance(entrance.name, entrance.player).connect(copied_region)
|
ret.get_entrance(entrance.name, entrance.player).connect(copied_region)
|
||||||
for exit in region.exits:
|
for exit in region.exits:
|
||||||
if exit.connected_region:
|
if exit.connected_region:
|
||||||
@@ -739,14 +741,14 @@ def copy_world(world):
|
|||||||
categorize_world_regions(ret, player)
|
categorize_world_regions(ret, player)
|
||||||
create_farm_locations(ret, player)
|
create_farm_locations(ret, player)
|
||||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
if world.logic[player] in ('nologic', 'hybridglitches'):
|
||||||
create_hybridmajor_connections(ret, player)
|
connect_hmg_entrances_regions(ret, player)
|
||||||
|
|
||||||
for region in world.regions:
|
for region in world.regions:
|
||||||
copied_region = ret.get_region(region.name, region.player)
|
copied_region = ret.get_region(region.name, region.player)
|
||||||
for entrance in region.entrances:
|
for entrance in region.entrances:
|
||||||
if entrance.name not in hmg_entrances:
|
ent = ret.get_entrance(entrance.name, entrance.player)
|
||||||
continue
|
if (ent.connected_region != copied_region):
|
||||||
ret.get_entrance(entrance.name, entrance.player).connect(copied_region)
|
ent.connect(copied_region)
|
||||||
|
|
||||||
for player in range(1, world.players + 1):
|
for player in range(1, world.players + 1):
|
||||||
set_rules(ret, player)
|
set_rules(ret, player)
|
||||||
@@ -899,9 +901,6 @@ def copy_world_premature(world, player):
|
|||||||
for portal in world.dungeon_portals[player]:
|
for portal in world.dungeon_portals[player]:
|
||||||
connect_portal(portal, ret, player)
|
connect_portal(portal, ret, player)
|
||||||
|
|
||||||
if world.logic[player] in ('nologic', 'hybridglitches'):
|
|
||||||
create_hybridmajor_connections(ret, player)
|
|
||||||
|
|
||||||
set_rules(ret, player)
|
set_rules(ret, player)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
+4
-1
@@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
|
|||||||
from OverworldGlitchRules import create_owg_connections
|
from OverworldGlitchRules import create_owg_connections
|
||||||
from Utils import bidict
|
from Utils import bidict
|
||||||
|
|
||||||
version_number = '0.5.0.6'
|
version_number = '0.5.1.0'
|
||||||
# branch indicator is intentionally different across branches
|
# branch indicator is intentionally different across branches
|
||||||
version_branch = ''
|
version_branch = ''
|
||||||
|
|
||||||
@@ -1404,6 +1404,9 @@ def can_reach_smith(world, player):
|
|||||||
if world.logic[player] in ['noglitches', 'minorglitches'] and not world.is_tile_swapped(0x29, player):
|
if world.logic[player] in ['noglitches', 'minorglitches'] and not world.is_tile_swapped(0x29, player):
|
||||||
blank_state.collect(ItemFactory('Titans Mitts', player), True)
|
blank_state.collect(ItemFactory('Titans Mitts', player), True)
|
||||||
blank_state.collect(ItemFactory('Moon Pearl', player), True)
|
blank_state.collect(ItemFactory('Moon Pearl', player), True)
|
||||||
|
if not world.bombbag[player]:
|
||||||
|
blank_state.collect(ItemFactory('Farmable Bombs', player), True)
|
||||||
|
blank_state.collect(ItemFactory('Farmable Rupees', player), True)
|
||||||
|
|
||||||
found = False
|
found = False
|
||||||
explored_regions = list()
|
explored_regions = list()
|
||||||
|
|||||||
@@ -268,6 +268,10 @@ As far as map trackers, Bonk Locations are supported on `CodeTracker` when the B
|
|||||||
- 1 8x Bomb Pack
|
- 1 8x Bomb Pack
|
||||||
- 1 Good Bee
|
- 1 Good Bee
|
||||||
|
|
||||||
|
## Nearby Dungeon Items
|
||||||
|
|
||||||
|
This is a new option in addition to the traditional wild vs non-wild (keysanity/non-keysanity) options for all the dungeon item types (maps, compasses, small keys, big keys, prizes). This new option shuffles dungeon items into locations somewhere either within the dungeon that it is assigned to or within the surrounding district of that dungeon.
|
||||||
|
|
||||||
## Prize Shuffle
|
## Prize Shuffle
|
||||||
|
|
||||||
A new option has been added to shuffle the 10 dungeon prizes in ways that they haven't been shuffled before. This means that dungeon prizes can be found in other item locations, such as chests or free-standing item locations. This also means that bosses are able to drop a 2nd item in place of the shuffled prize.
|
A new option has been added to shuffle the 10 dungeon prizes in ways that they haven't been shuffled before. This means that dungeon prizes can be found in other item locations, such as chests or free-standing item locations. This also means that bosses are able to drop a 2nd item in place of the shuffled prize.
|
||||||
@@ -280,6 +284,10 @@ This is the normal prize behavior that has been a part of rando up until now. Th
|
|||||||
|
|
||||||
This option shuffles the prize into a location somewhere within the dungeon that it is assigned to.
|
This option shuffles the prize into a location somewhere within the dungeon that it is assigned to.
|
||||||
|
|
||||||
|
### Nearby
|
||||||
|
|
||||||
|
This option shuffles the prize into a location somewhere either within the dungeon that it is assigned to or within the surrounding district of that dungeon.
|
||||||
|
|
||||||
### Randomized
|
### Randomized
|
||||||
|
|
||||||
This option freely shuffles the prizes throughout the world. While the dungeon prizes can end up anywhere, they still are assigned to a specific dungeon. When you defeat the boss of a certain dungeon, checking the map on the overworld will reveal the location WHERE you can find the prize, an example shown [here](https://zelda.codemann8.com/images/shared/prizemap-all.gif). Finding the map will still reveal WHAT the prize is. If you defeated a boss but haven't collected the map for that dungeon, the prize will be indicated by a red X, example shown [here](https://zelda.codemann8.com/images/shared/prizemap-boss.gif). If you collected a map but haven't defeated the boss yet, the icon indicator on the map will be shown on the top edge (for LW dungeons) or the bottom edge (for DW dungeons), but it will show you WHAT the prize is for that dungeon, an example of that is shown [here](https://zelda.codemann8.com/images/shared/prizemap-map.gif).
|
This option freely shuffles the prizes throughout the world. While the dungeon prizes can end up anywhere, they still are assigned to a specific dungeon. When you defeat the boss of a certain dungeon, checking the map on the overworld will reveal the location WHERE you can find the prize, an example shown [here](https://zelda.codemann8.com/images/shared/prizemap-all.gif). Finding the map will still reveal WHAT the prize is. If you defeated a boss but haven't collected the map for that dungeon, the prize will be indicated by a red X, example shown [here](https://zelda.codemann8.com/images/shared/prizemap-boss.gif). If you collected a map but haven't defeated the boss yet, the icon indicator on the map will be shown on the top edge (for LW dungeons) or the bottom edge (for DW dungeons), but it will show you WHAT the prize is for that dungeon, an example of that is shown [here](https://zelda.codemann8.com/images/shared/prizemap-map.gif).
|
||||||
|
|||||||
+17
-9
@@ -141,12 +141,20 @@ These are now independent of retro mode and have three options: None, Random, an
|
|||||||
|
|
||||||
# Patch Notes
|
# Patch Notes
|
||||||
|
|
||||||
1.4.6
|
* 1.4.7.2
|
||||||
|
- Fixed an issue with shuffle_ganon/fix_gtower_exit causing a generation failure
|
||||||
- Restores original Sanc & Quit behavior, if Aga1 is not dead, then no quick pyramid warp
|
- More HMG fixes by Muffins
|
||||||
- Fixed problem with Lite/Lean shuffling some fairy caves unnecessarily
|
* 1.4.7.1
|
||||||
- The 300 Rupees item is now marked as priority, so it will not be used as GT junk fill (this matches a change in the VT randomizer)
|
- Fixed an issue with the repaired "beemizer" setting not being backwards compatible
|
||||||
- Murahdahla is now logically accessible in inverted mode as a bunny. May affect some beatable-only TFH seeds by allowing Moon Pearl to be inaccessible.
|
* 1.4.7
|
||||||
- Fixed an issue around PreferredLocationGroups in customizer which would not work with pre-activated Ocraina or priority items.
|
- Fixed generation error with Big Key in starting inventory (thanks Cody!)
|
||||||
- Minor fix on triforce text
|
- HMG/NL logic fixes by Muffins
|
||||||
- Enemy bans for poor placements
|
- Enemizer: Disabled Walking Zora in the UW due to crash with Swamola (they ignore a lot of collison anyway)
|
||||||
|
- Enemizer: Fixed an issue with enemizer bush sprites
|
||||||
|
- Enemizer: Banned new Mimics from being the randomized bush sprite due to crash
|
||||||
|
- "Beatable" or "accessibility: none" can now use randomized trap doors to seal off entire parts of dungeons (was intended, bug prevented the logic skip)
|
||||||
|
- Logic error with enemizer and standard should use new enemy logic rules
|
||||||
|
- Fixed a bug with the inconsistent treatment of the beemizer setting
|
||||||
|
- Fixed an issue with returning Blacksmith in Simple shuffle (when blacksmith is at Link's House)
|
||||||
|
- Fixed an issue with dark sanctuary spawn at tavern north door (thanks Codemann!)
|
||||||
|
- Various enemy bans for the last few months
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
|
|||||||
|
|
||||||
|
|
||||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||||
RANDOMIZERBASEHASH = 'a51679f0e31ee29f59247545d705992a'
|
RANDOMIZERBASEHASH = '1fde4fa24bc9d3efe450c3bc30e4cf2c'
|
||||||
|
|
||||||
|
|
||||||
class JsonRom(object):
|
class JsonRom(object):
|
||||||
@@ -480,14 +480,14 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
rom.write_byte(address, value)
|
rom.write_byte(address, value)
|
||||||
|
|
||||||
# patch music
|
# patch music
|
||||||
if world.mapshuffle[player]:
|
if world.mapshuffle[player] != 'none':
|
||||||
music = random.choice([0x11, 0x16])
|
music = random.choice([0x11, 0x16])
|
||||||
else:
|
else:
|
||||||
music = 0x11 if 'Pendant' in dungeon.prize.name else 0x16
|
music = 0x11 if 'Pendant' in dungeon.prize.name else 0x16
|
||||||
for music_address in dungeon_music_addresses[dungeon.name]:
|
for music_address in dungeon_music_addresses[dungeon.name]:
|
||||||
rom.write_byte(music_address, music)
|
rom.write_byte(music_address, music)
|
||||||
|
|
||||||
if world.mapshuffle[player]:
|
if world.mapshuffle[player] != 'none':
|
||||||
rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle
|
rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle
|
||||||
|
|
||||||
if world.doorShuffle[player] != 'vanilla':
|
if world.doorShuffle[player] != 'vanilla':
|
||||||
@@ -1131,7 +1131,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
ERtimeincrease = 10
|
ERtimeincrease = 10
|
||||||
else:
|
else:
|
||||||
ERtimeincrease = 20
|
ERtimeincrease = 20
|
||||||
if world.keyshuffle[player] != 'none' or world.bigkeyshuffle[player] or world.mapshuffle[player]:
|
if world.keyshuffle[player] != 'none' or world.bigkeyshuffle[player] != 'none' or world.mapshuffle[player] != 'none':
|
||||||
ERtimeincrease = ERtimeincrease + 15
|
ERtimeincrease = ERtimeincrease + 15
|
||||||
if world.clock_mode == 'none':
|
if world.clock_mode == 'none':
|
||||||
rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode
|
rom.write_bytes(0x180190, [0x00, 0x00, 0x00]) # turn off clock mode
|
||||||
@@ -1268,34 +1268,36 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
|
|
||||||
# Bitfield - enable text box to show with free roaming items
|
# Bitfield - enable text box to show with free roaming items
|
||||||
#
|
#
|
||||||
# --po bmcs
|
# -tpo bmcs
|
||||||
|
# t - suppress "this dungeon" textboxes (temporary fix)
|
||||||
# p - enabled for non-prize crystals
|
# p - enabled for non-prize crystals
|
||||||
# o - enabled for outside dungeon items
|
# o - enabled for outside dungeon items (unused currently?)
|
||||||
# b - enabled for inside big keys
|
# b - enabled for inside big keys
|
||||||
# m - enabled for inside maps
|
# m - enabled for inside maps
|
||||||
# c - enabled for inside compasses
|
# c - enabled for inside compasses
|
||||||
# s - enabled for inside small keys
|
# s - enabled for inside small keys
|
||||||
rom.write_byte(0x18016A, 0x10 | ((0x20 if world.prizeshuffle[player] == 'wild' else 0x00)
|
free_item_text = 0x40 if 'district' in [world.mapshuffle[player], world.compassshuffle[player], world.keyshuffle[player], world.bigkeyshuffle[player]] else 0x00
|
||||||
| (0x01 if world.keyshuffle[player] == 'wild' else 0x00)
|
rom.write_byte(0x18016A, free_item_text | 0x10 | ((0x20 if world.prizeshuffle[player] not in ['none', 'dungeon'] else 0x00)
|
||||||
| (0x02 if world.compassshuffle[player] else 0x00)
|
| (0x01 if world.keyshuffle[player] not in ['none', 'universal'] else 0x00)
|
||||||
| (0x04 if world.mapshuffle[player] else 0x00)
|
| (0x02 if world.compassshuffle[player] != 'none' else 0x00)
|
||||||
| (0x08 if world.bigkeyshuffle[player] else 0x00))) # free roaming item text boxes
|
| (0x04 if world.mapshuffle[player] != 'none' else 0x00)
|
||||||
rom.write_byte(0x18003B, 0x01 if world.mapshuffle[player] else 0x00) # maps showing crystals on overworld
|
| (0x08 if world.bigkeyshuffle[player] != 'none' else 0x00))) # free roaming item text boxes
|
||||||
|
rom.write_byte(0x18003B, 0x01 if world.mapshuffle[player] not in ['none', 'district'] else 0x00) # maps showing crystals on overworld
|
||||||
|
|
||||||
# compasses showing dungeon count
|
# compasses showing dungeon count
|
||||||
compass_mode = 0x80 if world.compassshuffle[player] else 0x00
|
compass_mode = 0x80 if world.compassshuffle[player] not in ['none', 'district'] else 0x00
|
||||||
if world.clock_mode != 'none' or world.dungeon_counters[player] == 'off':
|
if world.clock_mode != 'none' or world.dungeon_counters[player] == 'off':
|
||||||
pass
|
pass
|
||||||
elif world.dungeon_counters[player] == 'on':
|
elif world.dungeon_counters[player] == 'on':
|
||||||
compass_mode |= 0x02 # always on
|
compass_mode |= 0x02 # always on
|
||||||
elif (world.compassshuffle[player] or world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none'
|
elif (world.compassshuffle[player] not in ['none', 'district'] or world.doorShuffle[player] != 'vanilla' or world.dropshuffle[player] != 'none'
|
||||||
or world.dungeon_counters[player] == 'pickup' or world.pottery[player] not in ['none', 'cave']):
|
or world.dungeon_counters[player] == 'pickup' or world.pottery[player] not in ['none', 'cave']):
|
||||||
compass_mode |= 0x01 # show on pickup
|
compass_mode |= 0x01 # show on pickup
|
||||||
if world.overworld_map[player] == 'map':
|
if world.overworld_map[player] == 'map':
|
||||||
compass_mode |= 0x10 # show icon if map is collected
|
compass_mode |= 0x10 # show icon if map is collected
|
||||||
elif world.overworld_map[player] == 'compass':
|
elif world.overworld_map[player] == 'compass':
|
||||||
compass_mode |= 0x20 # show icon if compass is collected
|
compass_mode |= 0x20 # show icon if compass is collected
|
||||||
if world.prizeshuffle[player] == 'wild':
|
if world.prizeshuffle[player] not in ['none', 'dungeon', 'district']:
|
||||||
compass_mode |= 0x40 # show icon if boss is defeated, hide if collected
|
compass_mode |= 0x40 # show icon if boss is defeated, hide if collected
|
||||||
rom.write_byte(0x18003C, compass_mode)
|
rom.write_byte(0x18003C, compass_mode)
|
||||||
|
|
||||||
@@ -1331,7 +1333,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
map_index = max(0, dungeon_index - 2)
|
map_index = max(0, dungeon_index - 2)
|
||||||
|
|
||||||
# write out dislocated coords
|
# write out dislocated coords
|
||||||
if map_index >= 0x02 and map_index < 0x18 and (world.overworld_map[player] != 'default' or world.prizeshuffle[player] == 'wild'):
|
if map_index >= 0x02 and map_index < 0x18 and (world.overworld_map[player] != 'default' or world.prizeshuffle[player] not in ['none', 'dungeon', 'district']):
|
||||||
owid_map = [0x1E, 0x30, 0xFF, 0x7B, 0x5E, 0x70, 0x40, 0x75, 0x03, 0x58, 0x47]
|
owid_map = [0x1E, 0x30, 0xFF, 0x7B, 0x5E, 0x70, 0x40, 0x75, 0x03, 0x58, 0x47]
|
||||||
x_map_position_generic = [0x03c0, 0x0740, 0xff00, 0x03c0, 0x01c0, 0x0bc0, 0x05c0, 0x09c0, 0x0ac0, 0x07c0, 0x0dc0]
|
x_map_position_generic = [0x03c0, 0x0740, 0xff00, 0x03c0, 0x01c0, 0x0bc0, 0x05c0, 0x09c0, 0x0ac0, 0x07c0, 0x0dc0]
|
||||||
y_map_position_generic = [0xff00, 0xff00, 0xff00, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0xff00, 0x0fc0, 0x0fc0]
|
y_map_position_generic = [0xff00, 0xff00, 0xff00, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0x0fc0, 0xff00, 0x0fc0, 0x0fc0]
|
||||||
@@ -1345,7 +1347,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
write_int16(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+6, y_map_position_generic[idx])
|
write_int16(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+6, y_map_position_generic[idx])
|
||||||
|
|
||||||
# write out icon coord data
|
# write out icon coord data
|
||||||
if world.prizeshuffle[player] == 'wild' and dungeon_table[dungeon].prize:
|
if world.prizeshuffle[player] not in ['none', 'dungeon', 'district'] and dungeon_table[dungeon].prize:
|
||||||
dungeon_obj = world.get_dungeon(dungeon, player)
|
dungeon_obj = world.get_dungeon(dungeon, player)
|
||||||
entrance = dungeon_obj.prize.get_map_location()
|
entrance = dungeon_obj.prize.get_map_location()
|
||||||
coords = get_entrance_coords(entrance)
|
coords = get_entrance_coords(entrance)
|
||||||
@@ -1385,7 +1387,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
|
|
||||||
# figure out compass entrances and what world (light/dark)
|
# figure out compass entrances and what world (light/dark)
|
||||||
write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6), coords)
|
write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6), coords)
|
||||||
if world.prizeshuffle[player] != 'wild' and dungeon_table[dungeon].prize:
|
if world.prizeshuffle[player] in ['none', 'dungeon', 'district'] and dungeon_table[dungeon].prize:
|
||||||
# prize location
|
# prize location
|
||||||
write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+8, coords)
|
write_int16s(rom, snes_to_pc(0x0ABE2E)+(map_index*6)+8, coords)
|
||||||
|
|
||||||
@@ -1424,11 +1426,11 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
# b - Big Key
|
# b - Big Key
|
||||||
# a - Small Key
|
# a - Small Key
|
||||||
#
|
#
|
||||||
enable_menu_map_check = (world.overworld_map[player] != 'default' and world.shuffle[player] != 'vanilla') or world.prizeshuffle[player] == 'wild'
|
enable_menu_map_check = (world.overworld_map[player] != 'default' and world.shuffle[player] != 'vanilla') or world.prizeshuffle[player] not in ['none', 'dungeon', 'district']
|
||||||
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] == 'wild' else 0x00)
|
rom.write_byte(0x180045, ((0x01 if world.keyshuffle[player] not in ['none', 'universal'] else 0x00)
|
||||||
| (0x02 if world.bigkeyshuffle[player] else 0x00)
|
| (0x02 if world.bigkeyshuffle[player] != 'none' else 0x00)
|
||||||
| (0x04 if world.mapshuffle[player] or enable_menu_map_check else 0x00)
|
| (0x04 if world.mapshuffle[player] != 'none' or enable_menu_map_check else 0x00)
|
||||||
| (0x08 if world.compassshuffle[player] else 0x00) # free roaming items in menu
|
| (0x08 if world.compassshuffle[player] != 'none' else 0x00) # free roaming items in menu
|
||||||
| (0x10 if world.logic[player] == 'nologic' else 0))) # boss icon
|
| (0x10 if world.logic[player] == 'nologic' else 0))) # boss icon
|
||||||
|
|
||||||
def get_reveal_bytes(itemName):
|
def get_reveal_bytes(itemName):
|
||||||
@@ -1528,7 +1530,7 @@ def patch_rom(world, rom, player, team, is_mystery=False):
|
|||||||
# rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water
|
# rom.write_byte(snes_to_pc(0x0DB730), 0x08) # allows chickens to travel across water
|
||||||
|
|
||||||
# allow smith into multi-entrance caves in appropriate shuffles
|
# allow smith into multi-entrance caves in appropriate shuffles
|
||||||
if world.shuffle[player] in ['restricted', 'full', 'lite', 'lean', 'district', 'swapped', 'crossed', 'insanity'] or (world.shuffle[player] == 'simple' and world.mode[player] == 'inverted'):
|
if world.shuffle[player] in ['restricted', 'simple', 'full', 'lite', 'lean', 'district', 'swapped', 'crossed', 'insanity']:
|
||||||
rom.write_byte(0x18004C, 0x01)
|
rom.write_byte(0x18004C, 0x01)
|
||||||
|
|
||||||
# set correct flag for hera basement item
|
# set correct flag for hera basement item
|
||||||
@@ -2203,11 +2205,11 @@ def write_strings(rom, world, player, team):
|
|||||||
this_hint = this_hint[0].upper() + this_hint[1:]
|
this_hint = this_hint[0].upper() + this_hint[1:]
|
||||||
tt[hint_locations.pop(0)] = this_hint
|
tt[hint_locations.pop(0)] = this_hint
|
||||||
items_to_hint.remove(flute_item)
|
items_to_hint.remove(flute_item)
|
||||||
if world.keyshuffle[player] == 'wild':
|
if world.keyshuffle[player] not in ['none', 'universal']:
|
||||||
items_to_hint.extend(SmallKeys)
|
items_to_hint.extend(SmallKeys)
|
||||||
if world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] != 'none':
|
||||||
items_to_hint.extend(BigKeys)
|
items_to_hint.extend(BigKeys)
|
||||||
if world.prizeshuffle[player] == 'wild':
|
if world.prizeshuffle[player] not in ['none', 'dungeon']:
|
||||||
items_to_hint.extend(Prizes)
|
items_to_hint.extend(Prizes)
|
||||||
random.shuffle(items_to_hint)
|
random.shuffle(items_to_hint)
|
||||||
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'district', 'swapped'] else 8
|
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'district', 'swapped'] else 8
|
||||||
@@ -2323,10 +2325,14 @@ def write_strings(rom, world, player, team):
|
|||||||
crystal5 = world.find_items('Crystal 5', player)[0]
|
crystal5 = world.find_items('Crystal 5', player)[0]
|
||||||
crystal6 = world.find_items('Crystal 6', player)[0]
|
crystal6 = world.find_items('Crystal 6', player)[0]
|
||||||
greenpendant = world.find_items('Green Pendant', player)[0]
|
greenpendant = world.find_items('Green Pendant', player)[0]
|
||||||
if world.prizeshuffle[player] == 'none':
|
if world.prizeshuffle[player] in ['none', 'dungeon']:
|
||||||
(crystal5, crystal6, greenpendant) = tuple([x.parent_region.dungeon.name for x in [crystal5, crystal6, greenpendant]])
|
(crystal5, crystal6, greenpendant) = tuple([x.parent_region.dungeon.name for x in [crystal5, crystal6, greenpendant]])
|
||||||
tt['bomb_shop'] = 'Big Bomb?\nMy supply is blocked until you clear %s and %s.' % (crystal5, crystal6)
|
tt['bomb_shop'] = 'Big Bomb?\nMy supply is blocked until you clear %s and %s.' % (crystal5, crystal6)
|
||||||
tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant
|
tt['sahasrahla_bring_courage'] = 'I lost my family heirloom in %s' % greenpendant
|
||||||
|
elif world.prizeshuffle[player] == 'district':
|
||||||
|
(crystal5, crystal6, greenpendant) = tuple([x.item.dungeon_object.name for x in [crystal5, crystal6, greenpendant]])
|
||||||
|
tt['bomb_shop'] = 'Big Bomb?\nThe crystals can be found near %s and %s.' % (crystal5, crystal6)
|
||||||
|
tt['sahasrahla_bring_courage'] = 'I lost my family heirloom near %s' % greenpendant
|
||||||
else:
|
else:
|
||||||
tt['bomb_shop'] = 'Big Bomb?\nThe crystals can be found %s and %s.' % (crystal5.hint_text, crystal6.hint_text)
|
tt['bomb_shop'] = 'Big Bomb?\nThe crystals can be found %s and %s.' % (crystal5.hint_text, crystal6.hint_text)
|
||||||
tt['sahasrahla_bring_courage'] = 'My family heirloom can be found %s' % greenpendant.hint_text
|
tt['sahasrahla_bring_courage'] = 'My family heirloom can be found %s' % greenpendant.hint_text
|
||||||
|
|||||||
@@ -1614,16 +1614,28 @@ def standard_rules(world, player):
|
|||||||
add_rule(world.get_location('Secret Passage', player), lambda state: standard_escape_rule(state))
|
add_rule(world.get_location('Secret Passage', player), lambda state: standard_escape_rule(state))
|
||||||
|
|
||||||
escape_builder = world.dungeon_layouts[player]['Hyrule Castle']
|
escape_builder = world.dungeon_layouts[player]['Hyrule Castle']
|
||||||
|
room_map = world.data_tables[player].uw_enemy_table.room_map
|
||||||
|
stats = world.data_tables[player].enemy_stats
|
||||||
for region in escape_builder.master_sector.regions:
|
for region in escape_builder.master_sector.regions:
|
||||||
for loc in region.locations:
|
|
||||||
add_rule(loc, lambda state: standard_escape_rule(state))
|
|
||||||
if region.name in std_kill_rooms:
|
if region.name in std_kill_rooms:
|
||||||
for ent in std_kill_rooms[region.name][0]:
|
entrances, trap_ables, room_id, enemy_list = std_kill_rooms[region.name]
|
||||||
add_rule(world.get_entrance(ent, player), lambda state: standard_escape_rule(state))
|
rule = get_challenge_rule(world, player, room_map, stats, room_id, enemy_list, region)
|
||||||
for ent in std_kill_rooms[region.name][1]:
|
for ent in entrances:
|
||||||
entrance = world.get_entrance(ent, player)
|
entrance = world.get_entrance(ent, player)
|
||||||
if entrance.door.trapped:
|
if not entrance.door or not entrance.door.entranceFlag:
|
||||||
add_rule(entrance, lambda state: standard_escape_rule(state))
|
add_rule_new(entrance, rule)
|
||||||
|
for ent in trap_ables:
|
||||||
|
entrance = world.get_entrance(ent, player)
|
||||||
|
if entrance.door.trapped and not entrance.door.entranceFlag:
|
||||||
|
add_rule_new(entrance, rule)
|
||||||
|
else:
|
||||||
|
for loc in region.locations:
|
||||||
|
if loc.name in kill_chests:
|
||||||
|
locations, room_id, enemy_list = kill_chests[loc.name]
|
||||||
|
rule = get_challenge_rule(world, player, room_map, stats, room_id, enemy_list, region)
|
||||||
|
add_rule_new(world.get_location(loc, player), rule)
|
||||||
|
else:
|
||||||
|
add_rule(loc, lambda state: standard_escape_rule(state))
|
||||||
|
|
||||||
set_rule(world.get_location('Zelda Pickup', player), lambda state: state.has('Big Key (Escape)', player))
|
set_rule(world.get_location('Zelda Pickup', player), lambda state: state.has('Big Key (Escape)', player))
|
||||||
set_rule(world.get_entrance('Hyrule Castle Tapestry Backwards', player), lambda state: state.has('Zelda Herself', player))
|
set_rule(world.get_entrance('Hyrule Castle Tapestry Backwards', player), lambda state: state.has('Zelda Herself', player))
|
||||||
@@ -2017,7 +2029,7 @@ def add_hmg_key_logic_rules(world, player):
|
|||||||
def add_key_logic_rules(world, player):
|
def add_key_logic_rules(world, player):
|
||||||
key_logic = world.key_logic[player]
|
key_logic = world.key_logic[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] not in ['none', 'universal']:
|
||||||
eval_func = eval_small_key_door_strict
|
eval_func = eval_small_key_door_strict
|
||||||
elif world.key_logic_algorithm[player] != 'dangerous':
|
elif world.key_logic_algorithm[player] != 'dangerous':
|
||||||
eval_func = eval_small_key_door_partial
|
eval_func = eval_small_key_door_partial
|
||||||
|
|||||||
+33
-30
@@ -1,9 +1,7 @@
|
|||||||
import functools
|
import functools
|
||||||
from BaseClasses import Entrance, DoorType
|
from BaseClasses import Entrance, DoorType, Door
|
||||||
from DoorShuffle import connect_simple_door
|
from DoorShuffle import connect_simple_door
|
||||||
import Rules
|
import Rules
|
||||||
from OverworldGlitchRules import create_no_logic_connections
|
|
||||||
from Doors import create_door
|
|
||||||
|
|
||||||
kikiskip_spots = [
|
kikiskip_spots = [
|
||||||
("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Portal")
|
("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Portal")
|
||||||
@@ -13,7 +11,7 @@ mirehera_spots = [("Mire to Hera Clip", "Mire Torches Top", "Hera Portal")]
|
|||||||
|
|
||||||
heraswamp_spots = [("Hera to Swamp Clip", "Mire Torches Top", "Swamp Portal")]
|
heraswamp_spots = [("Hera to Swamp Clip", "Mire Torches Top", "Swamp Portal")]
|
||||||
|
|
||||||
icepalace_spots = [("Ice Lobby Clip", "Ice Portal", "Ice Bomb Drop - Top")]
|
icepalace_spots = [("Ice Lobby Clip", "Ice Lobby", "Ice Bomb Drop - Top")]
|
||||||
|
|
||||||
thievesdesert_spots = [
|
thievesdesert_spots = [
|
||||||
("Thieves to Desert West Clip", "Thieves Attic", "Desert West Portal"),
|
("Thieves to Desert West Clip", "Thieves Attic", "Desert West Portal"),
|
||||||
@@ -29,10 +27,7 @@ paradox_spots = [
|
|||||||
("Paradox Front Teleport", "Paradox Cave Front", "Paradox Cave Chest Area")
|
("Paradox Front Teleport", "Paradox Cave Front", "Paradox Cave Chest Area")
|
||||||
]
|
]
|
||||||
|
|
||||||
# Create connections between dungeons/locations
|
def create_hmg_entrances_regions(world, player):
|
||||||
def create_hybridmajor_connections(world, player):
|
|
||||||
fix_fake_worlds = world.fix_fake_world[player]
|
|
||||||
|
|
||||||
for spots in [
|
for spots in [
|
||||||
kikiskip_spots,
|
kikiskip_spots,
|
||||||
mirehera_spots,
|
mirehera_spots,
|
||||||
@@ -42,35 +37,43 @@ def create_hybridmajor_connections(world, player):
|
|||||||
specrock_spots,
|
specrock_spots,
|
||||||
paradox_spots,
|
paradox_spots,
|
||||||
]:
|
]:
|
||||||
create_no_logic_connections(player, world, spots, connect_external=fix_fake_worlds)
|
for entrance, parent_region, _, *_ in spots:
|
||||||
|
parent = world.get_region(parent_region, player)
|
||||||
|
connection = Entrance(player, entrance, parent)
|
||||||
|
connection.spot_type = 'HMG'
|
||||||
|
if connection not in parent.exits:
|
||||||
|
parent.exits.append(connection)
|
||||||
|
|
||||||
|
ip_bomb_top_reg = world.get_region("Ice Bomb Drop - Top", player)
|
||||||
|
ip_clip_entrance = Entrance(player, "Ice Bomb Drop Clip", ip_bomb_top_reg)
|
||||||
|
ip_bomb_top_reg.exits.append(ip_clip_entrance)
|
||||||
|
|
||||||
|
def connect_hmg_entrances_regions(world, player):
|
||||||
|
for spots in [
|
||||||
|
kikiskip_spots,
|
||||||
|
mirehera_spots,
|
||||||
|
heraswamp_spots,
|
||||||
|
icepalace_spots,
|
||||||
|
thievesdesert_spots,
|
||||||
|
specrock_spots,
|
||||||
|
paradox_spots,
|
||||||
|
]:
|
||||||
|
for entrance, _, target_region, *_ in spots:
|
||||||
|
connection = world.get_entrance(entrance, player)
|
||||||
|
if world.fix_fake_world[player] and target_region.endswith(" Portal"):
|
||||||
|
target = world.get_portal(target_region[:-7], player).find_portal_entrance().parent_region
|
||||||
|
else:
|
||||||
|
target = world.get_region(target_region, player)
|
||||||
|
connection.connect(target)
|
||||||
|
|
||||||
# Add the new Ice path (back of bomb drop to front) to the world and model it properly
|
# Add the new Ice path (back of bomb drop to front) to the world and model it properly
|
||||||
clip_door = create_door(player, "Ice Bomb Drop Clip", DoorType.Logical)
|
ip_clip_entrance = world.get_entrance('Ice Bomb Drop Clip', 1)
|
||||||
|
clip_door = Door(player, "Ice Bomb Drop Clip", DoorType.Logical, ip_clip_entrance)
|
||||||
world.doors += [clip_door]
|
world.doors += [clip_door]
|
||||||
world.initialize_doors([clip_door])
|
world.initialize_doors([clip_door])
|
||||||
|
|
||||||
ice_bomb_top_reg = world.get_region("Ice Bomb Drop - Top", player)
|
|
||||||
ice_bomb_top_reg.exits.append(
|
|
||||||
Entrance(player, "Ice Bomb Drop Clip", ice_bomb_top_reg)
|
|
||||||
)
|
|
||||||
connect_simple_door(world, "Ice Bomb Drop Clip", "Ice Bomb Drop", player)
|
connect_simple_door(world, "Ice Bomb Drop Clip", "Ice Bomb Drop", player)
|
||||||
|
|
||||||
def get_hybridmajor_connection_entrances():
|
|
||||||
connections = []
|
|
||||||
for connector in (
|
|
||||||
kikiskip_spots
|
|
||||||
+ mirehera_spots
|
|
||||||
+ heraswamp_spots
|
|
||||||
+ icepalace_spots
|
|
||||||
+ thievesdesert_spots
|
|
||||||
+ specrock_spots
|
|
||||||
+ paradox_spots
|
|
||||||
):
|
|
||||||
connections.append(connector[0])
|
|
||||||
connections.append('Ice Bomb Drop Clip')
|
|
||||||
return set(connections)
|
|
||||||
|
|
||||||
|
|
||||||
# For some entrances, we need to fake having pearl, because we're in fake DW/LW.
|
# For some entrances, we need to fake having pearl, because we're in fake DW/LW.
|
||||||
# This creates a copy of the input state that has Moon Pearl.
|
# This creates a copy of the input state that has Moon Pearl.
|
||||||
def fake_pearl_state(state, player):
|
def fake_pearl_state(state, player):
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,24 @@
|
|||||||
|
meta:
|
||||||
|
bps: on
|
||||||
|
user_notes: An attempt to replicate the Avianart Pots and Bones settings
|
||||||
|
settings:
|
||||||
|
1:
|
||||||
|
goal: triforcehunt
|
||||||
|
mode: standard
|
||||||
|
swords: assured
|
||||||
|
hints: on
|
||||||
|
shuffle: crossed
|
||||||
|
keysanity: on
|
||||||
|
|
||||||
|
pottery: lottery
|
||||||
|
dropshuffle: underworld
|
||||||
|
|
||||||
|
triforce_goal: 216
|
||||||
|
triforce_pool: 469
|
||||||
|
|
||||||
|
beemizer: 0
|
||||||
|
start_inventory:
|
||||||
|
1:
|
||||||
|
- Pegasus Boots
|
||||||
|
- Lamp
|
||||||
|
- Red Boomerang
|
||||||
+11
-6
@@ -151,6 +151,7 @@
|
|||||||
prize_shuffle:
|
prize_shuffle:
|
||||||
none: 1
|
none: 1
|
||||||
dungeon: 1
|
dungeon: 1
|
||||||
|
district: 1
|
||||||
wild: 1
|
wild: 1
|
||||||
dungeon_items:
|
dungeon_items:
|
||||||
standard: 10
|
standard: 10
|
||||||
@@ -160,18 +161,22 @@
|
|||||||
mcu: 1 # map, compass, universal smalls
|
mcu: 1 # map, compass, universal smalls
|
||||||
# for use when you aren't using the dungeon_items above
|
# for use when you aren't using the dungeon_items above
|
||||||
# map_shuffle:
|
# map_shuffle:
|
||||||
# on: 1
|
# none: 1
|
||||||
# off: 1
|
# district: 1
|
||||||
|
# wild: 1
|
||||||
# compass_shuffle:
|
# compass_shuffle:
|
||||||
# on: 1
|
# none: 1
|
||||||
# off: 1
|
# district: 1
|
||||||
|
# wild: 1
|
||||||
# smallkey_shuffle:
|
# smallkey_shuffle:
|
||||||
# none: 5
|
# none: 5
|
||||||
|
# district: 1
|
||||||
# wild: 1
|
# wild: 1
|
||||||
# universal: 1
|
# universal: 1
|
||||||
# bigkey_shuffle:
|
# bigkey_shuffle:
|
||||||
# on: 1
|
# none: 1
|
||||||
# off: 1
|
# district: 1
|
||||||
|
# wild: 1
|
||||||
dungeon_counters:
|
dungeon_counters:
|
||||||
on: 5
|
on: 5
|
||||||
off: 0
|
off: 0
|
||||||
|
|||||||
@@ -369,12 +369,18 @@
|
|||||||
"type": "bool"
|
"type": "bool"
|
||||||
},
|
},
|
||||||
"mapshuffle": {
|
"mapshuffle": {
|
||||||
"action": "store_true",
|
"choices": [
|
||||||
"type": "bool"
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"compassshuffle": {
|
"compassshuffle": {
|
||||||
"action": "store_true",
|
"choices": [
|
||||||
"type": "bool"
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"keyshuffle": {
|
"keyshuffle": {
|
||||||
"choices": [
|
"choices": [
|
||||||
@@ -384,13 +390,17 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"bigkeyshuffle": {
|
"bigkeyshuffle": {
|
||||||
"action": "store_true",
|
"choices": [
|
||||||
"type": "bool"
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"prizeshuffle": {
|
"prizeshuffle": {
|
||||||
"choices": [
|
"choices": [
|
||||||
"none",
|
"none",
|
||||||
"dungeon",
|
"dungeon",
|
||||||
|
"district",
|
||||||
"wild"
|
"wild"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -53,15 +53,26 @@
|
|||||||
|
|
||||||
"randomizer.dungeon.keysanity": "Shuffle: ",
|
"randomizer.dungeon.keysanity": "Shuffle: ",
|
||||||
"randomizer.dungeon.mapshuffle": "Maps",
|
"randomizer.dungeon.mapshuffle": "Maps",
|
||||||
|
"randomizer.dungeon.mapshuffle.none": "In Dungeon",
|
||||||
|
"randomizer.dungeon.mapshuffle.district": "Nearby",
|
||||||
|
"randomizer.dungeon.mapshuffle.wild": "Randomized",
|
||||||
"randomizer.dungeon.compassshuffle": "Compasses",
|
"randomizer.dungeon.compassshuffle": "Compasses",
|
||||||
|
"randomizer.dungeon.compassshuffle.none": "In Dungeon",
|
||||||
|
"randomizer.dungeon.compassshuffle.district": "Nearby",
|
||||||
|
"randomizer.dungeon.compassshuffle.wild": "Randomized",
|
||||||
"randomizer.dungeon.smallkeyshuffle": "Small Keys",
|
"randomizer.dungeon.smallkeyshuffle": "Small Keys",
|
||||||
"randomizer.dungeon.smallkeyshuffle.none": "In Dungeon",
|
"randomizer.dungeon.smallkeyshuffle.none": "In Dungeon",
|
||||||
|
"randomizer.dungeon.smallkeyshuffle.district": "Nearby",
|
||||||
"randomizer.dungeon.smallkeyshuffle.wild": "Randomized",
|
"randomizer.dungeon.smallkeyshuffle.wild": "Randomized",
|
||||||
"randomizer.dungeon.smallkeyshuffle.universal": "Universal",
|
"randomizer.dungeon.smallkeyshuffle.universal": "Universal",
|
||||||
"randomizer.dungeon.bigkeyshuffle": "Big Keys",
|
"randomizer.dungeon.bigkeyshuffle": "Big Keys",
|
||||||
|
"randomizer.dungeon.bigkeyshuffle.none": "In Dungeon",
|
||||||
|
"randomizer.dungeon.bigkeyshuffle.district": "Nearby",
|
||||||
|
"randomizer.dungeon.bigkeyshuffle.wild": "Randomized",
|
||||||
"randomizer.dungeon.prizeshuffle": "Prizes",
|
"randomizer.dungeon.prizeshuffle": "Prizes",
|
||||||
"randomizer.dungeon.prizeshuffle.none": "On Boss",
|
"randomizer.dungeon.prizeshuffle.none": "On Boss",
|
||||||
"randomizer.dungeon.prizeshuffle.dungeon": "In Dungeon",
|
"randomizer.dungeon.prizeshuffle.dungeon": "In Dungeon",
|
||||||
|
"randomizer.dungeon.prizeshuffle.district": "Nearby",
|
||||||
"randomizer.dungeon.prizeshuffle.wild": "Randomized",
|
"randomizer.dungeon.prizeshuffle.wild": "Randomized",
|
||||||
"randomizer.dungeon.decoupledoors": "Decouple Doors",
|
"randomizer.dungeon.decoupledoors": "Decouple Doors",
|
||||||
"randomizer.dungeon.door_self_loops": "Allow Self-Looping Spiral Stairs",
|
"randomizer.dungeon.door_self_loops": "Allow Self-Looping Spiral Stairs",
|
||||||
|
|||||||
@@ -1,9 +1,32 @@
|
|||||||
{
|
{
|
||||||
"keysanity": {
|
"keysanity": {
|
||||||
|
"mapshuffle": {
|
||||||
|
"type": "selectbox",
|
||||||
|
"options": [
|
||||||
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"padx": [20,0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compassshuffle": {
|
||||||
|
"type": "selectbox",
|
||||||
|
"options": [
|
||||||
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"padx": [20,0]
|
||||||
|
}
|
||||||
|
},
|
||||||
"smallkeyshuffle": {
|
"smallkeyshuffle": {
|
||||||
"type": "selectbox",
|
"type": "selectbox",
|
||||||
"options": [
|
"options": [
|
||||||
"none",
|
"none",
|
||||||
|
"district",
|
||||||
"wild",
|
"wild",
|
||||||
"universal"
|
"universal"
|
||||||
],
|
],
|
||||||
@@ -11,8 +34,16 @@
|
|||||||
"padx": [20,0]
|
"padx": [20,0]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mapshuffle": { "type": "checkbox" },
|
"bigkeyshuffle": {
|
||||||
"compassshuffle": { "type": "checkbox" },
|
"type": "selectbox",
|
||||||
"bigkeyshuffle": { "type": "checkbox" }
|
"options": [
|
||||||
|
"none",
|
||||||
|
"district",
|
||||||
|
"wild"
|
||||||
|
],
|
||||||
|
"config": {
|
||||||
|
"padx": [20,0]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"options": [
|
"options": [
|
||||||
"none",
|
"none",
|
||||||
"dungeon",
|
"dungeon",
|
||||||
|
"district",
|
||||||
"wild"
|
"wild"
|
||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ class CustomSettings(object):
|
|||||||
args.outputname = get_setting(meta['name'], args.outputname)
|
args.outputname = get_setting(meta['name'], args.outputname)
|
||||||
args.bps = get_setting(meta['bps'], args.bps)
|
args.bps = get_setting(meta['bps'], args.bps)
|
||||||
args.suppress_rom = get_setting(meta['suppress_rom'], args.suppress_rom)
|
args.suppress_rom = get_setting(meta['suppress_rom'], args.suppress_rom)
|
||||||
|
args.skip_playthrough = get_setting(meta['skip_playthrough'], args.skip_playthrough)
|
||||||
|
args.spoiler = get_setting(meta['spoiler'], args.spoiler)
|
||||||
args.names = get_setting(meta['names'], args.names)
|
args.names = get_setting(meta['names'], args.names)
|
||||||
args.race = get_setting(meta['race'], args.race)
|
args.race = get_setting(meta['race'], args.race)
|
||||||
args.notes = get_setting(meta['user_notes'], args.notes)
|
args.notes = get_setting(meta['user_notes'], args.notes)
|
||||||
@@ -145,11 +147,14 @@ class CustomSettings(object):
|
|||||||
args.compassshuffle[p] = get_setting(settings['compassshuffle'], args.compassshuffle[p])
|
args.compassshuffle[p] = get_setting(settings['compassshuffle'], args.compassshuffle[p])
|
||||||
|
|
||||||
if get_setting(settings['keysanity'], args.keysanity):
|
if get_setting(settings['keysanity'], args.keysanity):
|
||||||
args.bigkeyshuffle[p] = True
|
if args.bigkeyshuffle[p] == 'none':
|
||||||
|
args.bigkeyshuffle[p] = 'wild'
|
||||||
if args.keyshuffle[p] == 'none':
|
if args.keyshuffle[p] == 'none':
|
||||||
args.keyshuffle[p] = 'wild'
|
args.keyshuffle[p] = 'wild'
|
||||||
args.mapshuffle[p] = True
|
if args.mapshuffle[p] == 'none':
|
||||||
args.compassshuffle[p] = True
|
args.mapshuffle[p] = 'wild'
|
||||||
|
if args.compassshuffle[p] == 'none':
|
||||||
|
args.compassshuffle[p] = 'wild'
|
||||||
|
|
||||||
args.shufflebosses[p] = get_setting(settings['boss_shuffle'], get_setting(settings['shufflebosses'], args.shufflebosses[p]))
|
args.shufflebosses[p] = get_setting(settings['boss_shuffle'], get_setting(settings['shufflebosses'], args.shufflebosses[p]))
|
||||||
args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], get_setting(settings['shuffleenemies'], args.shuffleenemies[p]))
|
args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], get_setting(settings['shuffleenemies'], args.shuffleenemies[p]))
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ def modify_proposal(proposed_map, explored_state, doors_to_connect, hash_code_se
|
|||||||
|
|
||||||
def explore_proposal(name, entrance_regions, all_regions, proposed_map, valid_doors, bk_special, world, player):
|
def explore_proposal(name, entrance_regions, all_regions, proposed_map, valid_doors, bk_special, world, player):
|
||||||
start = ExplorationState(dungeon=name)
|
start = ExplorationState(dungeon=name)
|
||||||
bk_relevant = (world.door_type_mode[player] == 'original' and not world.bigkeyshuffle[player]) or bk_special
|
bk_relevant = (world.door_type_mode[player] == 'original' and world.bigkeyshuffle[player] == 'none') or bk_special
|
||||||
start.big_key_special = bk_special
|
start.big_key_special = bk_special
|
||||||
original_state = extend_reachable_state_lenient(entrance_regions, start, proposed_map,
|
original_state = extend_reachable_state_lenient(entrance_regions, start, proposed_map,
|
||||||
all_regions, valid_doors, bk_relevant, world, player)
|
all_regions, valid_doors, bk_relevant, world, player)
|
||||||
@@ -302,7 +302,7 @@ def valid_path(name, starting_regions, target, valid_doors, proposed_map, all_re
|
|||||||
target_regions.add(region)
|
target_regions.add(region)
|
||||||
|
|
||||||
start = ExplorationState(dungeon=name)
|
start = ExplorationState(dungeon=name)
|
||||||
bk_relevant = (world.door_type_mode[player] == 'original' and not world.bigkeyshuffle[player]) or bk_special
|
bk_relevant = (world.door_type_mode[player] == 'original' and world.bigkeyshuffle[player] == 'none') or bk_special
|
||||||
start.big_key_special = bk_special
|
start.big_key_special = bk_special
|
||||||
original_state = extend_reachable_state_lenient(starting_regions, start, proposed_map, all_regions,
|
original_state = extend_reachable_state_lenient(starting_regions, start, proposed_map, all_regions,
|
||||||
valid_doors, bk_relevant, world, player)
|
valid_doors, bk_relevant, world, player)
|
||||||
|
|||||||
@@ -408,8 +408,9 @@ def randomize_overworld_enemies(data_tables, custom_ow):
|
|||||||
chosen = random.choices(candidate_sprites, weight, k=1)[0]
|
chosen = random.choices(candidate_sprites, weight, k=1)[0]
|
||||||
sprite.kind = chosen.sprite
|
sprite.kind = chosen.sprite
|
||||||
# randomize the bush sprite per area
|
# randomize the bush sprite per area
|
||||||
weight = [data_tables.ow_weights[r.sprite] for r in candidate_sprites]
|
bush_candidates = [x for x in candidate_sprites if x.bush_valid]
|
||||||
bush_sprite_choice = random.choices(candidate_sprites, weight, k=1)[0]
|
weight = [data_tables.ow_weights[r.sprite] for r in bush_candidates]
|
||||||
|
bush_sprite_choice = random.choices(bush_candidates, weight, k=1)[0]
|
||||||
data_tables.bush_sprite_table[area_id] = bush_sprite_choice
|
data_tables.bush_sprite_table[area_id] = bush_sprite_choice
|
||||||
|
|
||||||
|
|
||||||
@@ -532,5 +533,5 @@ def write_enemy_shuffle_settings(world, player, rom):
|
|||||||
for idx, pair in enumerate(tile_pattern):
|
for idx, pair in enumerate(tile_pattern):
|
||||||
rom.write_byte(snes_to_pc(0x09BA2A + idx), (pair[0] + 3) * 16)
|
rom.write_byte(snes_to_pc(0x09BA2A + idx), (pair[0] + 3) * 16)
|
||||||
rom.write_byte(snes_to_pc(0x09BA40 + idx), (pair[1] + 4) * 16)
|
rom.write_byte(snes_to_pc(0x09BA40 + idx), (pair[1] + 4) * 16)
|
||||||
if world.enemy_shuffle[player] == 'random':
|
if world.enemy_shuffle[player] == 'shuffled':
|
||||||
rom.write_byte(snes_to_pc(0x368100), 1) # randomize bushes
|
rom.write_byte(snes_to_pc(0x368100), 1) # randomize bushes
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class SpriteRequirement:
|
|||||||
self.uw_valid = True
|
self.uw_valid = True
|
||||||
self.can_randomize = True
|
self.can_randomize = True
|
||||||
self.water_phobic = False
|
self.water_phobic = False
|
||||||
|
self.bush_valid = True
|
||||||
|
|
||||||
self.groups = []
|
self.groups = []
|
||||||
self.sub_groups = defaultdict(list)
|
self.sub_groups = defaultdict(list)
|
||||||
@@ -94,6 +95,10 @@ class SpriteRequirement:
|
|||||||
self.uw_valid = False
|
self.uw_valid = False
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def no_bush(self):
|
||||||
|
self.bush_valid = False
|
||||||
|
return self
|
||||||
|
|
||||||
def good_for_uw_water(self):
|
def good_for_uw_water(self):
|
||||||
return self.water_only and not self.static and not self.dont_use and self.uw_valid
|
return self.water_only and not self.static and not self.dont_use and self.uw_valid
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ def init_sprite_requirements():
|
|||||||
SpriteRequirement(EnemySprite.ArmosKnight).exalt().sub_group(3, 0x1d),
|
SpriteRequirement(EnemySprite.ArmosKnight).exalt().sub_group(3, 0x1d),
|
||||||
SpriteRequirement(EnemySprite.Lanmolas).exalt().sub_group(3, 0x31),
|
SpriteRequirement(EnemySprite.Lanmolas).exalt().sub_group(3, 0x31),
|
||||||
SpriteRequirement(EnemySprite.FireballZora).immerse().no_drop().sub_group(2, [0xc, 0x18]), # .uw_skip() test
|
SpriteRequirement(EnemySprite.FireballZora).immerse().no_drop().sub_group(2, [0xc, 0x18]), # .uw_skip() test
|
||||||
SpriteRequirement(EnemySprite.Zora).sub_group(2, 0xc).sub_group(3, 0x44), # .uw_skip() test
|
SpriteRequirement(EnemySprite.Zora).sub_group(2, 0xc).sub_group(3, 0x44).uw_skip(),
|
||||||
SpriteRequirement(EnemySprite.DesertStatue).affix().sub_group(2, 0x12),
|
SpriteRequirement(EnemySprite.DesertStatue).affix().sub_group(2, 0x12),
|
||||||
SpriteRequirement(EnemySprite.Crab).sub_group(2, 0xc),
|
SpriteRequirement(EnemySprite.Crab).sub_group(2, 0xc),
|
||||||
SpriteRequirement(EnemySprite.LostWoodsBird).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
SpriteRequirement(EnemySprite.LostWoodsBird).affix().sub_group(2, 0x37).sub_group(3, 0x36),
|
||||||
@@ -366,8 +371,8 @@ def init_sprite_requirements():
|
|||||||
SpriteRequirement(EnemySprite.MagicShopAssistant).affix().sub_group(0, 0x4b).sub_group(3, 0x5a),
|
SpriteRequirement(EnemySprite.MagicShopAssistant).affix().sub_group(0, 0x4b).sub_group(3, 0x5a),
|
||||||
SpriteRequirement(EnemySprite.SomariaPlatform).affix().sub_group(2, 0x27),
|
SpriteRequirement(EnemySprite.SomariaPlatform).affix().sub_group(2, 0x27),
|
||||||
SpriteRequirement(EnemySprite.CastleMantle).affix().sub_group(0, 0x5d),
|
SpriteRequirement(EnemySprite.CastleMantle).affix().sub_group(0, 0x5d),
|
||||||
SpriteRequirement(EnemySprite.GreenMimic).sub_group(1, 0x2c),
|
SpriteRequirement(EnemySprite.GreenMimic).sub_group(1, 0x2c).no_bush(),
|
||||||
SpriteRequirement(EnemySprite.RedMimic).sub_group(1, 0x2c),
|
SpriteRequirement(EnemySprite.RedMimic).sub_group(1, 0x2c).no_bush(),
|
||||||
SpriteRequirement(EnemySprite.MedallionTablet).affix().sub_group(2, 0x12),
|
SpriteRequirement(EnemySprite.MedallionTablet).affix().sub_group(2, 0x12),
|
||||||
|
|
||||||
# overlord requirements - encapsulated mostly in the required sheets
|
# overlord requirements - encapsulated mostly in the required sheets
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ UwGeneralDeny:
|
|||||||
- [ 0x000e, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Entrance - Freezor"
|
- [ 0x000e, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Entrance - Freezor"
|
||||||
- [ 0x000e, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Top Bari"
|
- [ 0x000e, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Top Bari"
|
||||||
- [ 0x000e, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Middle Bari"
|
- [ 0x000e, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Middle Bari"
|
||||||
- [ 0x0016, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit"] ] #"Swamp Palace - Pool - Zol 1"
|
- [ 0x0016, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit", "Deadrock"] ] #"Swamp Palace - Pool - Zol 1"
|
||||||
- [ 0x0016, 1, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Zol 2"
|
- [ 0x0016, 1, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit", "Deadrock" ] ] #"Swamp Palace - Pool - Zol 2"
|
||||||
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit" ] ] #"Swamp Palace - Pool - Blue Bari"
|
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "GreenMimic", "RedMimic", "Pikit", "Deadrock" ] ] #"Swamp Palace - Pool - Blue Bari"
|
||||||
- [ 0x0016, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 3"
|
- [ 0x0016, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 3"
|
||||||
- [ 0x0017, 5, [ "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower of Hera - Bumper Room - Fire Bar (Clockwise)"
|
- [ 0x0017, 5, [ "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower of Hera - Bumper Room - Fire Bar (Clockwise)"
|
||||||
- [ 0x0019, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Dark Maze - Kodongo 1"
|
- [ 0x0019, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Dark Maze - Kodongo 1"
|
||||||
@@ -43,7 +43,7 @@ UwGeneralDeny:
|
|||||||
- [ 0x0024, 6, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
|
- [ 0x0024, 6, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
|
||||||
- [ 0x0026, 1, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Statue" ] ] #"Swamp Palace - Big Spoon - Red Bari 1"
|
- [ 0x0026, 1, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Statue" ] ] #"Swamp Palace - Big Spoon - Red Bari 1"
|
||||||
- [ 0x0026, 8, [ "AntiFairyCircle", "Bumper", "Statue" ] ] #"Swamp Palace - Big Spoon - Red Bari 3"
|
- [ 0x0026, 8, [ "AntiFairyCircle", "Bumper", "Statue" ] ] #"Swamp Palace - Big Spoon - Red Bari 3"
|
||||||
- [ 0x0026, 9, [ "RollerHorizontalRight", "Statue" ] ] #"Swamp Palace - Big Spoon - Kyameron"
|
- [0x0026, 9, ["RollerHorizontalRight", "Statue", "BigSpike"]] #"Swamp Palace - Big Spoon - Kyameron"
|
||||||
- [ 0x0026, 10, [ "Statue" ] ] # multiple push statues in this room can cause issues
|
- [ 0x0026, 10, [ "Statue" ] ] # multiple push statues in this room can cause issues
|
||||||
- [ 0x0026, 11, [ "Statue" ] ] # multiple push statues in this room can cause issues
|
- [ 0x0026, 11, [ "Statue" ] ] # multiple push statues in this room can cause issues
|
||||||
- [ 0x0027, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalLeft", "FirebarCW" ] ] #"Tower of Hera - Petting Zoo - Mini Moldorm 1"
|
- [ 0x0027, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalLeft", "FirebarCW" ] ] #"Tower of Hera - Petting Zoo - Mini Moldorm 1"
|
||||||
@@ -84,6 +84,7 @@ UwGeneralDeny:
|
|||||||
- [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1"
|
- [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1"
|
||||||
- [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper"]] #"Skull Woods - Play Pen - Hardhat Beetle"
|
- [0x0039, 5, ["RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Bumper"]] #"Skull Woods - Play Pen - Hardhat Beetle"
|
||||||
- [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2"
|
- [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2"
|
||||||
|
- [0x003a, 1, ["RollerVerticalUp"]]
|
||||||
- [ 0x003b, 1, [ "Bumper" ]]
|
- [ 0x003b, 1, [ "Bumper" ]]
|
||||||
- [ 0x003b, 4, ["RollerVerticalUp", "RollerVerticalDown"]]
|
- [ 0x003b, 4, ["RollerVerticalUp", "RollerVerticalDown"]]
|
||||||
- [ 0x003c, 0, ["BigSpike"]]
|
- [ 0x003c, 0, ["BigSpike"]]
|
||||||
@@ -92,7 +93,7 @@ UwGeneralDeny:
|
|||||||
- [ 0x003d, 9, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Spark (Counterclockwise)"
|
- [ 0x003d, 9, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Spark (Counterclockwise)"
|
||||||
- [ 0x003d, 10, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Spark (Clockwise) 1"
|
- [ 0x003d, 10, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Spark (Clockwise) 1"
|
||||||
- [ 0x003d, 12, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Bunny Beam"
|
- [ 0x003d, 12, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Bunny Beam"
|
||||||
- [ 0x003d, 13, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Antifairy"
|
- [0x003d, 13, ["AntiFairyCircle", "Bumper", "RollerHorizontalLeft", "RollerHorizontalRight"]] #"Ganon's Tower - Torches 2 - Antifairy"
|
||||||
- [0x003e, 8, ["Wizzrobe"]]
|
- [0x003e, 8, ["Wizzrobe"]]
|
||||||
- [0x003e, 9, ["Wizzrobe", "GreenMimic", "RedMimic", "RedEyegoreMimic", "GreenEyegoreMimic"]] # drops a key by default
|
- [0x003e, 9, ["Wizzrobe", "GreenMimic", "RedMimic", "RedEyegoreMimic", "GreenEyegoreMimic"]] # drops a key by default
|
||||||
- [0x003e, 10, ["Wizzrobe"]]
|
- [0x003e, 10, ["Wizzrobe"]]
|
||||||
@@ -171,7 +172,7 @@ UwGeneralDeny:
|
|||||||
- [0x0059, 5, ["RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
|
- [0x0059, 5, ["RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
|
||||||
- [ 0x0059, 9, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Gibdo 1"
|
- [ 0x0059, 9, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Gibdo 1"
|
||||||
- [ 0x005e, 3, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Pit Trap - Big Spike Trap"
|
- [ 0x005e, 3, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Pit Trap - Big Spike Trap"
|
||||||
- [ 0x005e, 4, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ice Palace - Pit Trap - Fire Bar (Clockwise)"
|
- [0x005e, 4, ["RollerVerticalUp", "RollerVerticalDown", "SpikeBlock"]] #"Ice Palace - Pit Trap - Fire Bar (Clockwise)"
|
||||||
- [ 0x005f, 0, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari University - Blue Bari 1"
|
- [ 0x005f, 0, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari University - Blue Bari 1"
|
||||||
- [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2"
|
- [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2"
|
||||||
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Beamos", "SpikeBlock" ] ] #"Hyrule Castle - West - Blue Guard"
|
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Beamos", "SpikeBlock" ] ] #"Hyrule Castle - West - Blue Guard"
|
||||||
@@ -198,6 +199,7 @@ UwGeneralDeny:
|
|||||||
- [ 0x006a, 5, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 4"
|
- [ 0x006a, 5, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 4"
|
||||||
- [ 0x006b, 7, [ "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Mimics 1 - Spike Trap 1"
|
- [ 0x006b, 7, [ "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Mimics 1 - Spike Trap 1"
|
||||||
- [ 0x0071, 0, [ "RollerHorizontalLeft" ] ] #"Hyrule Castle - Basement Trap - Green Guard"
|
- [ 0x0071, 0, [ "RollerHorizontalLeft" ] ] #"Hyrule Castle - Basement Trap - Green Guard"
|
||||||
|
- [0x0072, 1, ["RollerHorizontalLeft", "RollerHorizontalRight"]]
|
||||||
- [ 0x0074, 0, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - North Hallway - Red Devalant 1"
|
- [ 0x0074, 0, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - North Hallway - Red Devalant 1"
|
||||||
- [ 0x0074, 1, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - North Hallway - Red Devalant 2"
|
- [ 0x0074, 1, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - North Hallway - Red Devalant 2"
|
||||||
- [ 0x0074, 4, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - North Hallway - Leever 1"
|
- [ 0x0074, 4, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - North Hallway - Leever 1"
|
||||||
@@ -275,6 +277,7 @@ UwGeneralDeny:
|
|||||||
- [ 0x009c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 3"
|
- [ 0x009c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 3"
|
||||||
- [ 0x009c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 4"
|
- [ 0x009c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 4"
|
||||||
- [ 0x009c, 5, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 5"
|
- [ 0x009c, 5, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 5"
|
||||||
|
- [0x009c, 6, ["AntiFairyCircle", "Bumper"]]
|
||||||
- [0x009d, 2, ["AntiFairyCircle"]]
|
- [0x009d, 2, ["AntiFairyCircle"]]
|
||||||
- [ 0x009d, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Compass Room - Gibdo 2"
|
- [ 0x009d, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Compass Room - Gibdo 2"
|
||||||
- [ 0x009d, 6, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Ganon's Tower - Compass Room - Blue Bari 1"
|
- [ 0x009d, 6, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Ganon's Tower - Compass Room - Blue Bari 1"
|
||||||
@@ -414,13 +417,17 @@ UwGeneralDeny:
|
|||||||
- [ 0x00f1, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 5"
|
- [ 0x00f1, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 5"
|
||||||
- [ 0x00f1, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 6"
|
- [ 0x00f1, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 6"
|
||||||
- [0x00fd, 0, ["Bumper", "AntiFairyCircle"]]
|
- [0x00fd, 0, ["Bumper", "AntiFairyCircle"]]
|
||||||
- [ 0x0107, 1, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
|
- [0x0107, 1, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
|
||||||
- [ 0x0107, 2, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
|
- [0x0107, 2, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
|
||||||
- [0x010b, 6, ["RollerHorizontalRight"]]
|
- [0x010b, 6, ["RollerHorizontalRight"]]
|
||||||
- [0x010c, 4, ["AntiFairyCircle"]]
|
- [0x010c, 4, ["AntiFairyCircle"]]
|
||||||
- [0x010c, 5, ["AntiFairyCircle"]]
|
- [0x010c, 5, ["AntiFairyCircle"]]
|
||||||
- [0x010c, 6, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
|
- [0x010c, 6, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
|
||||||
- [0x010c, 7, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
|
- [0x010c, 7, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
|
||||||
|
- [0x011e, 0, ["RollerVerticalDown"]]
|
||||||
|
- [0x011e, 1, ["RollerVerticalDown"]]
|
||||||
|
- [0x011e, 2, ["RollerVerticalDown"]]
|
||||||
|
- [0x011e, 3, ["RollerVerticalDown"]]
|
||||||
OwGeneralDeny:
|
OwGeneralDeny:
|
||||||
- [0x03, 2, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 2, ["Gibo"]] # OldMan eating Gibo
|
||||||
- [0x03, 4, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 4, ["Gibo"]] # OldMan eating Gibo
|
||||||
@@ -428,12 +435,14 @@ OwGeneralDeny:
|
|||||||
- [0x03, 6, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 6, ["Gibo"]] # OldMan eating Gibo
|
||||||
- [0x03, 8, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 8, ["Gibo"]] # OldMan eating Gibo
|
||||||
- [0x03, 9, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 9, ["Gibo"]] # OldMan eating Gibo
|
||||||
- [0x03, 10, ["Gibo"]] # OldMan eating Gibo
|
- [0x03, 10, ["Gibo", "Beamos"]] # OldMan eating Gibo
|
||||||
- [0x05, 10, ["Bumper", "AntiFairyCircle"]] # Blocks path
|
- [0x05, 10, ["Bumper", "AntiFairyCircle"]] # Blocks path
|
||||||
- [0x05, 11, ["Bumper", "AntiFairyCircle"]] # Blocks path to portal
|
- [0x05, 11, ["Bumper", "AntiFairyCircle"]] # Blocks path to portal
|
||||||
- [0x07, 3, ["Bumper", "AntiFairyCircle"]] # Blocks path to ladder
|
- [0x07, 3, ["Bumper", "AntiFairyCircle", "RollerHorizontalRight", "RollerHorizontalLeft"]] # Blocks path to ladder
|
||||||
|
- [0x07, 4, ["RollerHorizontalLeft"]] # Blocks path to ladder
|
||||||
- [0x1e, 3, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]] # forbid a beamos here
|
- [0x1e, 3, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]] # forbid a beamos here
|
||||||
- [0x35, 8, ["RollerVerticalUp", "RollerVerticalDown"]] # blocks the dock
|
- [0x35, 8, ["RollerVerticalUp", "RollerVerticalDown"]] # blocks the dock
|
||||||
|
- [0x37, 5, ["RollerVerticalUp"]] # combines with a roller above to make the way impassable
|
||||||
- [0x40, 0, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
- [0x40, 0, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
||||||
- [0x40, 7, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
- [0x40, 7, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
||||||
- [0x40, 13, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
- [0x40, 13, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ def dungeon_page(parent):
|
|||||||
self.frames = {}
|
self.frames = {}
|
||||||
self.frames["keysanity"] = Frame(self)
|
self.frames["keysanity"] = Frame(self)
|
||||||
self.frames["keysanity"].pack(anchor=W)
|
self.frames["keysanity"].pack(anchor=W)
|
||||||
|
self.frames["keysanity2"] = Frame(self)
|
||||||
|
self.frames["keysanity2"].pack(anchor=W)
|
||||||
|
|
||||||
## Dungeon Item Shuffle
|
## Dungeon Item Shuffle
|
||||||
mscbLabel = Label(self.frames["keysanity"], text="Dungeon Items: ")
|
mscbLabel = Label(self.frames["keysanity"], text="Dungeon Items: ")
|
||||||
@@ -23,9 +25,15 @@ def dungeon_page(parent):
|
|||||||
# Defns include frame name, widget type, widget options, widget placement attributes
|
# Defns include frame name, widget type, widget options, widget placement attributes
|
||||||
# This first set goes in the Keysanity frame
|
# This first set goes in the Keysanity frame
|
||||||
with open(os.path.join("resources","app","gui","randomize","dungeon","keysanity.json")) as keysanityItems:
|
with open(os.path.join("resources","app","gui","randomize","dungeon","keysanity.json")) as keysanityItems:
|
||||||
myDict = json.load(keysanityItems)
|
myDictFile = json.load(keysanityItems)
|
||||||
myDict = myDict["keysanity"]
|
myDict = myDictFile["keysanity"]
|
||||||
dictWidgets = widgets.make_widgets_from_dict(self, myDict, self.frames["keysanity"])
|
myDict1, myDict2 = dict(), dict()
|
||||||
|
count = 2
|
||||||
|
for key in myDict.keys():
|
||||||
|
(myDict1 if count > 0 else myDict2)[key] = myDict[key]
|
||||||
|
count -= 1
|
||||||
|
dictWidgets = {**widgets.make_widgets_from_dict(self, myDict1, self.frames["keysanity"]), \
|
||||||
|
**widgets.make_widgets_from_dict(self, myDict2, self.frames["keysanity2"])}
|
||||||
for key in dictWidgets:
|
for key in dictWidgets:
|
||||||
self.widgets[key] = dictWidgets[key]
|
self.widgets[key] = dictWidgets[key]
|
||||||
packAttrs = {"side":LEFT}
|
packAttrs = {"side":LEFT}
|
||||||
|
|||||||
@@ -96,12 +96,15 @@ def resolve_districts(world):
|
|||||||
|
|
||||||
for name, district in world.districts[player].items():
|
for name, district in world.districts[player].items():
|
||||||
if district.dungeon:
|
if district.dungeon:
|
||||||
|
dungeon = world.get_dungeon(district.dungeon, player)
|
||||||
|
dungeon.districts = [district] + dungeon.districts
|
||||||
layout = world.dungeon_layouts[player][district.dungeon]
|
layout = world.dungeon_layouts[player][district.dungeon]
|
||||||
district.locations.update([l.name for r in layout.master_sector.regions
|
district.locations.update([l.name for r in layout.master_sector.regions
|
||||||
for l in r.locations if not l.item and l.real])
|
for l in r.locations if not l.item and l.real])
|
||||||
else:
|
else:
|
||||||
for region_name in district.regions:
|
for region_name in district.regions:
|
||||||
region = world.get_region(region_name, player)
|
region = world.get_region(region_name, player)
|
||||||
|
region.districts.append(district)
|
||||||
for location in region.locations:
|
for location in region.locations:
|
||||||
if not location.item and location.real:
|
if not location.item and location.real:
|
||||||
district.locations.add(location.name)
|
district.locations.add(location.name)
|
||||||
@@ -115,6 +118,7 @@ def resolve_districts(world):
|
|||||||
RuntimeError(f'No region connected to entrance: {ent.name} Likely a missing entry in OWExitTypes')
|
RuntimeError(f'No region connected to entrance: {ent.name} Likely a missing entry in OWExitTypes')
|
||||||
visited.add(region)
|
visited.add(region)
|
||||||
if region.type == RegionType.Cave:
|
if region.type == RegionType.Cave:
|
||||||
|
region.districts.append(district)
|
||||||
for location in region.locations:
|
for location in region.locations:
|
||||||
if not location.item and location.real:
|
if not location.item and location.real:
|
||||||
district.locations.add(location.name)
|
district.locations.add(location.name)
|
||||||
@@ -123,6 +127,8 @@ def resolve_districts(world):
|
|||||||
queue.appendleft(ext.connected_region)
|
queue.appendleft(ext.connected_region)
|
||||||
elif region.type == RegionType.Dungeon and region.dungeon:
|
elif region.type == RegionType.Dungeon and region.dungeon:
|
||||||
district.dungeons.add(region.dungeon.name)
|
district.dungeons.add(region.dungeon.name)
|
||||||
|
if district not in region.dungeon.districts:
|
||||||
|
region.dungeon.districts.append(district)
|
||||||
elif region.name in inaccessible:
|
elif region.name in inaccessible:
|
||||||
district.access_points.add(region)
|
district.access_points.add(region)
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -134,7 +134,7 @@ def create_item_pool_config(world):
|
|||||||
groups = LocationGroup('Major').locs(init_set)
|
groups = LocationGroup('Major').locs(init_set)
|
||||||
if world.prizeshuffle[player] != 'none':
|
if world.prizeshuffle[player] != 'none':
|
||||||
groups.locations.extend(mode_grouping['Prizes'])
|
groups.locations.extend(mode_grouping['Prizes'])
|
||||||
if world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] != 'none':
|
||||||
groups.locations.extend(mode_grouping['Big Keys'])
|
groups.locations.extend(mode_grouping['Big Keys'])
|
||||||
if world.dropshuffle[player] != 'none':
|
if world.dropshuffle[player] != 'none':
|
||||||
groups.locations.extend(mode_grouping['Big Key Drops'])
|
groups.locations.extend(mode_grouping['Big Key Drops'])
|
||||||
@@ -144,9 +144,9 @@ def create_item_pool_config(world):
|
|||||||
groups.locations.extend(mode_grouping['Key Drops'])
|
groups.locations.extend(mode_grouping['Key Drops'])
|
||||||
if world.pottery[player] not in ['none', 'cave']:
|
if world.pottery[player] not in ['none', 'cave']:
|
||||||
groups.locations.extend(mode_grouping['Pot Keys'])
|
groups.locations.extend(mode_grouping['Pot Keys'])
|
||||||
if world.compassshuffle[player]:
|
if world.compassshuffle[player] != 'none':
|
||||||
groups.locations.extend(mode_grouping['Compasses'])
|
groups.locations.extend(mode_grouping['Compasses'])
|
||||||
if world.mapshuffle[player]:
|
if world.mapshuffle[player] != 'none':
|
||||||
groups.locations.extend(mode_grouping['Maps'])
|
groups.locations.extend(mode_grouping['Maps'])
|
||||||
if world.shopsanity[player]:
|
if world.shopsanity[player]:
|
||||||
groups.locations.append('Capacity Upgrade - Left')
|
groups.locations.append('Capacity Upgrade - Left')
|
||||||
@@ -259,12 +259,12 @@ def location_prefilled(location, world, player):
|
|||||||
|
|
||||||
def previously_reserved(location, world, player):
|
def previously_reserved(location, world, player):
|
||||||
if '- Boss' in location.name or '- Prize' in location.name:
|
if '- Boss' in location.name or '- Prize' in location.name:
|
||||||
if world.restrict_boss_items[player] == 'mapcompass' and (not world.compassshuffle[player]
|
if world.restrict_boss_items[player] == 'mapcompass' and (world.compassshuffle[player] == 'none'
|
||||||
or not world.mapshuffle[player]):
|
or world.mapshuffle[player] == 'none'):
|
||||||
return True
|
return True
|
||||||
if world.restrict_boss_items[player] == 'dungeon' and (not world.compassshuffle[player]
|
if world.restrict_boss_items[player] == 'dungeon' and (world.compassshuffle[player] == 'none'
|
||||||
or not world.mapshuffle[player]
|
or world.mapshuffle[player] == 'none'
|
||||||
or not world.bigkeyshuffle[player]
|
or world.bigkeyshuffle[player] == 'none'
|
||||||
or world.keyshuffle[player] == 'none'
|
or world.keyshuffle[player] == 'none'
|
||||||
or world.prizeshuffle[player] in ['none', 'dungeon']):
|
or world.prizeshuffle[player] in ['none', 'dungeon']):
|
||||||
return True
|
return True
|
||||||
@@ -303,6 +303,7 @@ def massage_item_pool(world):
|
|||||||
if item.prize:
|
if item.prize:
|
||||||
dungeon = dungeon_pool[item.player].pop()
|
dungeon = dungeon_pool[item.player].pop()
|
||||||
dungeon.prize = item
|
dungeon.prize = item
|
||||||
|
item.dungeon_object = dungeon
|
||||||
player_pool[item.player].append(item)
|
player_pool[item.player].append(item)
|
||||||
for dungeon in world.dungeons:
|
for dungeon in world.dungeons:
|
||||||
for item in dungeon.all_items:
|
for item in dungeon.all_items:
|
||||||
@@ -381,13 +382,13 @@ def determine_major_items(world, player):
|
|||||||
pass # now what?
|
pass # now what?
|
||||||
if world.prizeshuffle[player] not in ['none', 'dungeon']:
|
if world.prizeshuffle[player] not in ['none', 'dungeon']:
|
||||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Prize'})
|
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Prize'})
|
||||||
if world.bigkeyshuffle[player]:
|
if world.bigkeyshuffle[player] != 'none':
|
||||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'BigKey'})
|
major_item_set.update({x for x, y in item_table.items() if y[2] == 'BigKey'})
|
||||||
if world.keyshuffle[player] != 'none':
|
if world.keyshuffle[player] != 'none':
|
||||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'SmallKey'})
|
major_item_set.update({x for x, y in item_table.items() if y[2] == 'SmallKey'})
|
||||||
if world.compassshuffle[player]:
|
if world.compassshuffle[player] != 'none':
|
||||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Compass'})
|
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Compass'})
|
||||||
if world.mapshuffle[player]:
|
if world.mapshuffle[player] != 'none':
|
||||||
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Map'})
|
major_item_set.update({x for x, y in item_table.items() if y[2] == 'Map'})
|
||||||
if world.shopsanity[player]:
|
if world.shopsanity[player]:
|
||||||
major_item_set.add('Bomb Upgrade (+5)')
|
major_item_set.add('Bomb Upgrade (+5)')
|
||||||
|
|||||||
@@ -504,7 +504,7 @@ def remove_from_list(t_list, removals):
|
|||||||
def do_holes_and_linked_drops(entrances, exits, avail, cross_world):
|
def do_holes_and_linked_drops(entrances, exits, avail, cross_world):
|
||||||
holes_to_shuffle = [x for x in entrances if x in drop_map]
|
holes_to_shuffle = [x for x in entrances if x in drop_map]
|
||||||
|
|
||||||
if not avail.world.shuffle_ganon:
|
if not avail.world.shuffle_ganon[avail.player]:
|
||||||
if avail.world.is_tile_swapped(0x1b, avail.player) and 'Inverted Pyramid Hole' in holes_to_shuffle:
|
if avail.world.is_tile_swapped(0x1b, avail.player) and 'Inverted Pyramid Hole' in holes_to_shuffle:
|
||||||
connect_entrance('Inverted Pyramid Hole', 'Pyramid', avail)
|
connect_entrance('Inverted Pyramid Hole', 'Pyramid', avail)
|
||||||
connect_two_way('Pyramid Entrance', 'Pyramid Exit', avail)
|
connect_two_way('Pyramid Entrance', 'Pyramid Exit', avail)
|
||||||
|
|||||||
@@ -96,8 +96,14 @@ def roll_settings(weights):
|
|||||||
dungeon_items = get_choice('dungeon_items')
|
dungeon_items = get_choice('dungeon_items')
|
||||||
dungeon_items = '' if dungeon_items == 'standard' or dungeon_items is None else dungeon_items
|
dungeon_items = '' if dungeon_items == 'standard' or dungeon_items is None else dungeon_items
|
||||||
dungeon_items = 'mcsb' if dungeon_items == 'full' else dungeon_items
|
dungeon_items = 'mcsb' if dungeon_items == 'full' else dungeon_items
|
||||||
ret.mapshuffle = get_choice_bool('map_shuffle') if 'map_shuffle' in weights else 'm' in dungeon_items
|
if 'map_shuffle' in weights:
|
||||||
ret.compassshuffle = get_choice_bool('compass_shuffle') if 'compass_shuffle' in weights else 'c' in dungeon_items
|
ret.mapshuffle = get_choice('map_shuffle')
|
||||||
|
elif 'm' in dungeon_items:
|
||||||
|
ret.mapshuffle = 'wild'
|
||||||
|
if 'compass_shuffle' in weights:
|
||||||
|
ret.compassshuffle = get_choice('compass_shuffle')
|
||||||
|
elif 'c' in dungeon_items:
|
||||||
|
ret.compassshuffle = 'wild'
|
||||||
if 'smallkey_shuffle' in weights:
|
if 'smallkey_shuffle' in weights:
|
||||||
ret.keyshuffle = get_choice('smallkey_shuffle')
|
ret.keyshuffle = get_choice('smallkey_shuffle')
|
||||||
else:
|
else:
|
||||||
@@ -105,7 +111,10 @@ def roll_settings(weights):
|
|||||||
ret.keyshuffle = 'wild'
|
ret.keyshuffle = 'wild'
|
||||||
if 'u' in dungeon_items:
|
if 'u' in dungeon_items:
|
||||||
ret.keyshuffle = 'universal'
|
ret.keyshuffle = 'universal'
|
||||||
ret.bigkeyshuffle = get_choice_bool('bigkey_shuffle') if 'bigkey_shuffle' in weights else 'b' in dungeon_items
|
if 'bigkey_shuffle' in weights:
|
||||||
|
ret.bigkeyshuffle = get_choice('bigkey_shuffle')
|
||||||
|
elif 'b' in dungeon_items:
|
||||||
|
ret.bigkeyshuffle = 'wild'
|
||||||
ret.prizeshuffle = get_choice('prize_shuffle')
|
ret.prizeshuffle = get_choice('prize_shuffle')
|
||||||
|
|
||||||
ret.accessibility = get_choice('accessibility')
|
ret.accessibility = get_choice('accessibility')
|
||||||
@@ -140,7 +149,7 @@ def roll_settings(weights):
|
|||||||
|
|
||||||
ret.dungeon_counters = get_choice_non_bool('dungeon_counters') if 'dungeon_counters' in weights else 'default'
|
ret.dungeon_counters = get_choice_non_bool('dungeon_counters') if 'dungeon_counters' in weights else 'default'
|
||||||
if ret.dungeon_counters == 'default':
|
if ret.dungeon_counters == 'default':
|
||||||
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle == 'on' else 'off'
|
ret.dungeon_counters = 'pickup' if ret.door_shuffle != 'vanilla' or ret.compassshuffle != 'none' else 'off'
|
||||||
|
|
||||||
ret.pseudoboots = get_choice_bool('pseudoboots')
|
ret.pseudoboots = get_choice_bool('pseudoboots')
|
||||||
ret.shopsanity = get_choice_bool('shopsanity')
|
ret.shopsanity = get_choice_bool('shopsanity')
|
||||||
|
|||||||
Reference in New Issue
Block a user