Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2024-01-05 13:09:20 -06:00
53 changed files with 2624 additions and 582 deletions
-7
View File
@@ -10,7 +10,6 @@ except ImportError:
from Utils import output_path from Utils import output_path
from Rom import LocalRom, apply_rom_settings from Rom import LocalRom, apply_rom_settings
from source.classes.SFX import output_song_data
from source.tools.BPS import bps_read_vlv from source.tools.BPS import bps_read_vlv
@@ -39,9 +38,6 @@ def adjust(args):
output_path.cached_path = args.outputpath output_path.cached_path = args.outputpath
rom.write_to_file(output_path('%s.sfc' % outfilebase)) rom.write_to_file(output_path('%s.sfc' % outfilebase))
if args.shuffle_songinstruments:
output_song_data(rom, output_path('OR_SPCInstruments.txt'), outfilebase)
logger.info('Done. Enjoy.') logger.info('Done. Enjoy.')
logger.debug('Total Time: %s', time.process_time() - start) logger.debug('Total Time: %s', time.process_time() - start)
@@ -77,9 +73,6 @@ def patch(args):
output_path.cached_path = args.outputpath output_path.cached_path = args.outputpath
rom.write_to_file(output_path('%s.sfc' % outfile_base)) rom.write_to_file(output_path('%s.sfc' % outfile_base))
if args.shuffle_songinstruments:
output_song_data(rom, output_path('OR_SPCInstruments.txt'), outfile_base)
logger.info('Done. Enjoy.') logger.info('Done. Enjoy.')
logger.debug('Total Time: %s', time.process_time() - start) logger.debug('Total Time: %s', time.process_time() - start)
+61 -11
View File
@@ -64,7 +64,6 @@ class World(object):
self.dark_world_light_cone = False self.dark_world_light_cone = False
self.clock_mode = 'none' self.clock_mode = 'none'
self.rupoor_cost = 10 self.rupoor_cost = 10
self.aga_randomness = True
self.lock_aga_door_in_escape = False self.lock_aga_door_in_escape = False
self.save_and_quit_from_boss = True self.save_and_quit_from_boss = True
self.override_bomb_check = False self.override_bomb_check = False
@@ -134,7 +133,7 @@ class World(object):
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', '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', False)
set_player_attr('compassshuffle', False) set_player_attr('compassshuffle', False)
@@ -170,7 +169,8 @@ class World(object):
set_player_attr('door_self_loops', False) set_player_attr('door_self_loops', False)
set_player_attr('door_type_mode', 'original') set_player_attr('door_type_mode', 'original')
set_player_attr('trap_door_mode', 'optional') set_player_attr('trap_door_mode', 'optional')
set_player_attr('key_logic_algorithm', 'default') set_player_attr('key_logic_algorithm', 'partial')
set_player_attr('aga_randomness', True)
set_player_attr('shopsanity', False) set_player_attr('shopsanity', False)
set_player_attr('mixed_travel', 'prevent') set_player_attr('mixed_travel', 'prevent')
@@ -565,7 +565,7 @@ class World(object):
if not sphere: if not sphere:
# ran out of places and did not finish yet, quit # ran out of places and did not finish yet, quit
if log_error: if log_error:
missing_locations = ", ".join([x.name for x in prog_locations]) missing_locations = ", ".join([f'{x.name} (#{x.player})' for x in prog_locations])
logging.getLogger('').error(f'Cannot reach the following locations: {missing_locations}') logging.getLogger('').error(f'Cannot reach the following locations: {missing_locations}')
return False return False
@@ -600,9 +600,45 @@ class CollectionState(object):
self.opened_doors = {player: set() for player in range(1, parent.players + 1)} self.opened_doors = {player: set() for player in range(1, parent.players + 1)}
self.dungeons_to_check = {player: defaultdict(dict) for player in range(1, parent.players + 1)} self.dungeons_to_check = {player: defaultdict(dict) for player in range(1, parent.players + 1)}
self.dungeon_limits = None self.dungeon_limits = None
self.placing_item = None self.placing_items = None
# self.trace = None # self.trace = None
def can_reach_from(self, spot, start, player=None):
old_state = self.copy()
# old_state.path = {old_state.world.get_region(start, player)}
old_state.stale[player] = False
old_state.reachable_regions[player] = dict()
old_state.blocked_connections[player] = dict()
rrp = old_state.reachable_regions[player]
bc = old_state.blocked_connections[player]
# init on first call - this can't be done on construction since the regions don't exist yet
start = self.world.get_region(start, player)
if start in self.reachable_regions[player]:
rrp[start] = self.reachable_regions[player][start]
for conn in start.exits:
bc[conn] = self.blocked_connections[player][conn]
else:
rrp[start] = CrystalBarrier.Orange
for conn in start.exits:
bc[conn] = CrystalBarrier.Orange
queue = deque(old_state.blocked_connections[player].items())
old_state.traverse_world(queue, rrp, bc, player)
if old_state.world.key_logic_algorithm[player] == 'default':
unresolved_events = [x for y in old_state.reachable_regions[player] for x in y.locations
if x.event and x.item and (x.item.smallkey or x.item.bigkey or x.item.advancement)
and x not in old_state.locations_checked and x.can_reach(old_state)]
unresolved_events = old_state._do_not_flood_the_keys(unresolved_events)
if len(unresolved_events) == 0:
old_state.check_key_doors_in_dungeons(rrp, player)
if self.world.get_region(spot, player) in rrp:
return True
else:
return False
def update_reachable_regions(self, player): def update_reachable_regions(self, player):
self.stale[player] = False self.stale[player] = False
rrp = self.reachable_regions[player] rrp = self.reachable_regions[player]
@@ -878,7 +914,7 @@ class CollectionState(object):
return door_candidates return door_candidates
door_candidates, skip = [], set() door_candidates, skip = [], set()
if (state.world.accessibility[player] != 'locations' and remaining_keys == 0 and dungeon_name != 'Universal' if (state.world.accessibility[player] != 'locations' and remaining_keys == 0 and dungeon_name != 'Universal'
and state.placing_item and state.placing_item.name == small_key_name): and state.placing_items and any(i.name == small_key_name and i.player == player for i in state.placing_items)):
key_logic = state.world.key_logic[player][dungeon_name] key_logic = state.world.key_logic[player][dungeon_name]
for door, paired in key_logic.sm_doors.items(): for door, paired in key_logic.sm_doors.items():
if door.name in key_logic.door_rules: if door.name in key_logic.door_rules:
@@ -923,7 +959,7 @@ class CollectionState(object):
player: defaultdict(dict, {name: copy.copy(checklist) player: defaultdict(dict, {name: copy.copy(checklist)
for name, checklist in self.dungeons_to_check[player].items()}) for name, checklist in self.dungeons_to_check[player].items()})
for player in range(1, self.world.players + 1)} for player in range(1, self.world.players + 1)}
ret.placing_item = self.placing_item ret.placing_items = self.placing_items
return ret return ret
def apply_dungeon_exploration(self, rrp, player, dungeon_name, checklist): def apply_dungeon_exploration(self, rrp, player, dungeon_name, checklist):
@@ -1020,7 +1056,7 @@ class CollectionState(object):
# try to resolve a name # try to resolve a name
if resolution_hint == 'Location': if resolution_hint == 'Location':
spot = self.world.get_location(spot, player) spot = self.world.get_location(spot, player)
elif resolution_hint in ['Entrance', 'OWEdge', 'OWTerrain', 'Ledge', 'Portal', 'Whirlpool', 'Mirror', 'Flute']: elif resolution_hint in ['Entrance', 'OWEdge', 'OWTerrain', 'OpenTerrain', 'Ledge', 'OWG', 'Portal', 'Whirlpool', 'Mirror', 'Flute']:
spot = self.world.get_entrance(spot, player) spot = self.world.get_entrance(spot, player)
else: else:
# default to Region # default to Region
@@ -1169,6 +1205,12 @@ class CollectionState(object):
def can_lift_rocks(self, player): def can_lift_rocks(self, player):
return self.has('Power Glove', player) or self.has('Titans Mitts', player) return self.has('Power Glove', player) or self.has('Titans Mitts', player)
def can_bomb_clip(self, region, player: int) -> bool:
return self.is_not_bunny(region, player) and self.has('Pegasus Boots', player) and self.can_use_bombs(player)
def can_dash_clip(self, region, player: int) -> bool:
return self.is_not_bunny(region, player) and self.has('Pegasus Boots', player)
def has_bottle(self, player): def has_bottle(self, player):
return self.bottle_count(player) > 0 return self.bottle_count(player) > 0
@@ -1300,7 +1342,9 @@ class CollectionState(object):
return self.has('Fire Rod', player) or (self.has('Bombos', player) and self.has_sword(player)) return self.has('Fire Rod', player) or (self.has('Bombos', player) and self.has_sword(player))
def can_avoid_lasers(self, player): def can_avoid_lasers(self, player):
return self.has('Mirror Shield', player) or self.has('Cane of Byrna', player) or self.has('Cape', player) return (self.has('Mirror Shield', player) or
self.has('Cape', player) or
(self.has('Cane of Byrna', player) and self.world.difficulty_adjustments[player] not in ['hard', 'expert']))
def is_not_bunny(self, region, player): def is_not_bunny(self, region, player):
return self.has_Pearl(player) or not region.can_cause_bunny(player) return self.has_Pearl(player) or not region.can_cause_bunny(player)
@@ -1346,6 +1390,9 @@ class CollectionState(object):
def can_superbunny_mirror_with_sword(self, player): def can_superbunny_mirror_with_sword(self, player):
return self.has_Mirror(player) and self.has_sword(player) return self.has_Mirror(player) and self.has_sword(player)
def can_bunny_pocket(self, player):
return self.has_Boots(player) and (self.has_Mirror(player) or self.has_bottle(player))
def collect(self, item, event=False, location=None): def collect(self, item, event=False, location=None):
if location: if location:
self.locations_checked.add(location) self.locations_checked.add(location)
@@ -1555,6 +1602,9 @@ class Region(object):
return self.is_dark_world if self.world.mode[player] != 'inverted' else self.is_light_world return self.is_dark_world if self.world.mode[player] != 'inverted' else self.is_light_world
def is_outdoors(self):
return self.type in {RegionType.LightWorld, RegionType.DarkWorld}
def __str__(self): def __str__(self):
return str(self.__unicode__()) return str(self.__unicode__())
@@ -1626,7 +1676,7 @@ class Entrance(object):
if region not in explored_regions: if region not in explored_regions:
explored_regions[region] = path explored_regions[region] = path
for exit in region.exits: for exit in region.exits:
if exit.connected_region and (not ignore_ledges or exit.spot_type != 'Ledge') \ if exit.connected_region and (not ignore_ledges or exit.spot_type not in ['Ledge', 'OWG']) \
and exit.name not in ['Dig Game To Ledge Drop'] \ and exit.name not in ['Dig Game To Ledge Drop'] \
and exit.access_rule(state): and exit.access_rule(state):
if exit.connected_region == destination: if exit.connected_region == destination:
@@ -3417,7 +3467,7 @@ er_mode = {"vanilla": 0, "simple": 1, "restricted": 2, "full": 3, "crossed": 4,
'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6, "swapped": 10} 'lean': 9, "dungeonsfull": 7, "dungeonssimple": 6, "swapped": 10}
# byte 1: LLLW WSS? (logic, mode, sword) # byte 1: LLLW WSS? (logic, mode, sword)
logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4} logic_mode = {"noglitches": 0, "minorglitches": 1, "nologic": 2, "owglitches": 3, "majorglitches": 4, "hybridglitches": 5}
world_mode = {"open": 0, "standard": 1, "inverted": 2} world_mode = {"open": 0, "standard": 1, "inverted": 2}
sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3} sword_mode = {"random": 0, "assured": 1, "swordless": 2, "vanilla": 3}
+18
View File
@@ -1,5 +1,23 @@
# Changelog # Changelog
## 0.3.4.0
- \~Merged in some things from DR v1.4.0.0-v~
- Improved bunny-walking algorithm
- Improved multiworld balancing
- Implemented Hyrid Major Glitches logic (thanks Muffins/Espeon)
- Added sparkles to Bonk Drop locations for better visibility
- Some tweaks/improvements to Shuffle Song Instruments
- Replaced Save Settings on Exit with Settings on Load
- Added new button in GUI to export a Yaml file based on current settings
- Allow starting Aga-Defeated and Old-Man-Rescued in inventory
## 0.3.3.2
- \~Merged in DR v1.2.0.22~
- Added Shuffle Song Instruments as post-gen option
- Allow user to change and save output directory within the GUI
- Fixed issue with Smith not deleting on S+Q when no path is possible
- Fixed various MSU inaccuracies
## 0.3.3.1 ## 0.3.3.1
- \~Merged in DR v1.2.0.21~ - \~Merged in DR v1.2.0.21~
- Fixed issue with Old Man death spawning on Pyramid/Castle - Fixed issue with Old Man death spawning on Pyramid/Castle
+14 -4
View File
@@ -34,7 +34,9 @@ def parse_cli(argv, no_defaults=False):
parser.add_argument('--settingsfile', help="input json file of settings", type=str) parser.add_argument('--settingsfile', help="input json file of settings", type=str)
parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--multi', default=defval(settings["multi"]), type=lambda value: min(max(int(value), 1), 255))
parser.add_argument('--customizer', help='input yaml file for customizations', type=str) parser.add_argument('--customizer', help='input yaml file for customizations', type=str)
parser.add_argument('--print_custom_yaml', help='print example yaml for current settings', parser.add_argument('--print_template_yaml', help='print example yaml for current settings',
default=False, action="store_true")
parser.add_argument('--print_custom_yaml', help='print example plando yaml for current settings and placements',
default=False, action="store_true") default=False, action="store_true")
parser.add_argument('--mystery', dest="mystery", default=False, action="store_true") parser.add_argument('--mystery', dest="mystery", default=False, action="store_true")
@@ -94,6 +96,7 @@ def parse_cli(argv, no_defaults=False):
parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1)) parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1))
parser.add_argument('--settingsfile', dest="filename", help="input json file of settings", type=str) parser.add_argument('--settingsfile', dest="filename", help="input json file of settings", type=str)
parser.add_argument('--customizer', dest="customizer", help='input yaml file for customizations', type=str) parser.add_argument('--customizer', dest="customizer", help='input yaml file for customizations', type=str)
parser.add_argument('--print_template_yaml', dest="print_template_yaml", default=False, action="store_true")
parser.add_argument('--print_custom_yaml', dest="print_custom_yaml", default=False, action="store_true") parser.add_argument('--print_custom_yaml', dest="print_custom_yaml", default=False, action="store_true")
if player_num: if player_num:
@@ -142,7 +145,7 @@ def parse_cli(argv, no_defaults=False):
'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle', 'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle',
'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'shuffle_songinstruments', 'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'shuffle_songinstruments',
'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode', 'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode',
'bonk_drops', 'trap_door_mode', 'key_logic_algorithm', 'door_self_loops']: 'bonk_drops', 'trap_door_mode', 'key_logic_algorithm', 'door_self_loops', 'aga_randomness']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
if player == 1: if player == 1:
setattr(ret, name, {1: value}) setattr(ret, name, {1: value})
@@ -225,13 +228,14 @@ def parse_settings():
"intensity": 3, "intensity": 3,
"door_type_mode": "original", "door_type_mode": "original",
"trap_door_mode": "optional", "trap_door_mode": "optional",
"key_logic_algorithm": "default", "key_logic_algorithm": "partial",
"decoupledoors": False, "decoupledoors": False,
"door_self_loops": False, "door_self_loops": False,
"experimental": False, "experimental": False,
"dungeon_counters": "default", "dungeon_counters": "default",
"mixed_travel": "prevent", "mixed_travel": "prevent",
"standardize_palettes": "standardize", "standardize_palettes": "standardize",
'aga_randomness': True,
"triforce_pool": 0, "triforce_pool": 0,
"triforce_goal": 0, "triforce_goal": 0,
@@ -355,7 +359,7 @@ def parse_settings():
}, },
"randomSprite": False, "randomSprite": False,
"outputpath": os.path.join("."), "outputpath": os.path.join("."),
"saveonexit": "ask", "settingsonload": "saved",
"outputname": "", "outputname": "",
"startinventoryarray": {}, "startinventoryarray": {},
"notes": "" "notes": ""
@@ -367,6 +371,12 @@ def parse_settings():
# read saved settings file if it exists and set these # read saved settings file if it exists and set these
settings_path = os.path.join(".", "resources", "user", "settings.json") settings_path = os.path.join(".", "resources", "user", "settings.json")
settings = apply_settings_file(settings, settings_path) settings = apply_settings_file(settings, settings_path)
if settings["settingsonload"] == "saved":
settings_path = os.path.join(".", "resources", "user", "saved.json")
settings = apply_settings_file(settings, settings_path)
elif settings["settingsonload"] == "lastused":
settings_path = os.path.join(".", "resources", "user", "last.json")
settings = apply_settings_file(settings, settings_path)
return settings return settings
# Priority fallback is: # Priority fallback is:
+19 -3
View File
@@ -7,7 +7,7 @@ from typing import DefaultDict, Dict, List
from itertools import chain from itertools import chain
from BaseClasses import RegionType, Region, Door, DoorType, Sector, CrystalBarrier, DungeonInfo, dungeon_keys from BaseClasses import RegionType, Region, Door, DoorType, Sector, CrystalBarrier, DungeonInfo, dungeon_keys
from BaseClasses import PotFlags, LocationType, Direction from BaseClasses import PotFlags, LocationType, Direction, KeyRuleType
from Doors import reset_portals from Doors import reset_portals
from Dungeons import dungeon_regions, region_starts, standard_starts, split_region_starts from Dungeons import dungeon_regions, region_starts, standard_starts, split_region_starts
from Dungeons import dungeon_bigs, dungeon_hints from Dungeons import dungeon_bigs, dungeon_hints
@@ -261,8 +261,24 @@ def vanilla_key_logic(world, player):
world.key_logic[player][builder.name] = key_layout.key_logic world.key_logic[player][builder.name] = key_layout.key_logic
world.key_layout[player][builder.name] = key_layout world.key_layout[player][builder.name] = key_layout
log_key_logic(builder.name, key_layout.key_logic) log_key_logic(builder.name, key_layout.key_logic)
# if world.shuffle[player] == 'vanilla' and world.accessibility[player] == 'items' and not world.retro[player] and not world.keydropshuffle[player]: # special adjustments for vanilla
# validate_vanilla_key_logic(world, player) if world.mode[player] != 'standard' and world.dropshuffle[player] == 'none':
# adjust hc doors
def adjust_hc_door(door_rule):
if door_rule.new_rules[KeyRuleType.WorstCase] == 3:
door_rule.new_rules[KeyRuleType.WorstCase] = 2
door_rule.small_key_num = 2
rules = world.key_logic[player]['Hyrule Castle'].door_rules
adjust_hc_door(rules['Sewers Secret Room Key Door S'])
adjust_hc_door(rules['Hyrule Dungeon Map Room Key Door S'])
adjust_hc_door(rules['Sewers Dark Cross Key Door N'])
# adjust pod front door
pod_front = world.key_logic[player]['Palace of Darkness'].door_rules['PoD Middle Cage N']
if pod_front.new_rules[KeyRuleType.WorstCase] == 6:
pod_front.new_rules[KeyRuleType.WorstCase] = 1
pod_front.small_key_num = 1
# gt logic? I'm unsure it needs adjusting
def validate_vanilla_reservation(dungeon, world, player): def validate_vanilla_reservation(dungeon, world, player):
+1 -1
View File
@@ -814,7 +814,7 @@ def connect_mandatory_exits(world, entrances, caves, must_be_exits, player, must
# Keeps track of entrances that cannot be used to access each exit / cave # Keeps track of entrances that cannot be used to access each exit / cave
invalid_cave_connections = defaultdict(set) invalid_cave_connections = defaultdict(set)
# if world.logic[player] in ['owglitches', 'nologic']: # if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
# import OverworldGlitchRules # import OverworldGlitchRules
# for entrance in OverworldGlitchRules.get_non_mandatory_exits(world, player): # for entrance in OverworldGlitchRules.get_non_mandatory_exits(world, player):
# if entrance in must_be_exits: # if entrance in must_be_exits:
+41 -11
View File
@@ -3,6 +3,7 @@ import collections
import itertools import itertools
import logging import logging
import math import math
from collections import Counter
from contextlib import suppress from contextlib import suppress
from BaseClasses import CollectionState, FillError, LocationType from BaseClasses import CollectionState, FillError, LocationType
@@ -71,13 +72,13 @@ def fill_dungeons_restrictive(world, shuffled_locations):
def fill_restrictive(world, base_state, locations, itempool, key_pool=None, single_player_placement=False, def fill_restrictive(world, base_state, locations, itempool, key_pool=None, single_player_placement=False,
vanilla=False): vanilla=False):
def sweep_from_pool(placing_item=None): def sweep_from_pool(placing_items=None):
new_state = base_state.copy() new_state = base_state.copy()
for item in itempool: for item in itempool:
new_state.collect(item, True) new_state.collect(item, True)
new_state.placing_item = placing_item new_state.placing_items = placing_items
new_state.sweep_for_events() new_state.sweep_for_events()
new_state.placing_item = None new_state.placing_items = None
return new_state return new_state
unplaced_items = [] unplaced_items = []
@@ -94,7 +95,7 @@ def fill_restrictive(world, base_state, locations, itempool, key_pool=None, sing
while any(player_items.values()) and locations: while any(player_items.values()) and locations:
items_to_place = [[itempool.remove(items[-1]), items.pop()][-1] for items in player_items.values() if items] items_to_place = [[itempool.remove(items[-1]), items.pop()][-1] for items in player_items.values() if items]
maximum_exploration_state = sweep_from_pool(placing_item=items_to_place[0]) maximum_exploration_state = sweep_from_pool(placing_items=items_to_place)
has_beaten_game = world.has_beaten_game(maximum_exploration_state) has_beaten_game = world.has_beaten_game(maximum_exploration_state)
for item_to_place in items_to_place: for item_to_place in items_to_place:
@@ -174,6 +175,9 @@ def valid_key_placement(item, location, key_pool, collection_state, world):
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
# Small key and big key in Swamp and Hera are placed without logic
if world.logic[item.player] == 'hybridglitches' and dungeon.name in ['Tower of Hera', 'Swamp Palace'] and dungeon.name in item.name:
return True
key_logic = world.key_logic[item.player][dungeon.name] key_logic = world.key_logic[item.player][dungeon.name]
unplaced_keys = len([x for x in key_pool if x.name == key_logic.small_key_name and x.player == item.player]) unplaced_keys = len([x for x in key_pool if x.name == key_logic.small_key_name and x.player == item.player])
prize_loc = None prize_loc = None
@@ -419,7 +423,7 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
# fill in gtower locations with trash first # fill in gtower locations with trash first
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
if (not gftower_trash or not world.ganonstower_vanilla[player] if (not gftower_trash or not world.ganonstower_vanilla[player]
or world.logic[player] in ['owglitches', 'nologic']): or world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']):
continue continue
gt_count, total_count = calc_trash_locations(world, player) gt_count, total_count = calc_trash_locations(world, player)
scale_factor = .75 * (world.crystals_needed_for_gt[player] / 7) scale_factor = .75 * (world.crystals_needed_for_gt[player] / 7)
@@ -734,24 +738,44 @@ def balance_multiworld_progression(world):
checked_locations = set() checked_locations = set()
unchecked_locations = set(world.get_locations()) unchecked_locations = set(world.get_locations())
total_locations_count = Counter(location.player for location in world.get_locations() if not location.locked and not location.forced_item)
reachable_locations_count = {} reachable_locations_count = {}
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
reachable_locations_count[player] = 0 reachable_locations_count[player] = 0
sphere_num = 1
moved_item_count = 0
def get_sphere_locations(sphere_state, locations): def get_sphere_locations(sphere_state, locations):
sphere_state.sweep_for_events(key_only=True, locations=locations) sphere_state.sweep_for_events(key_only=True, locations=locations)
return {loc for loc in locations if sphere_state.can_reach(loc) and sphere_state.not_flooding_a_key(sphere_state.world, loc)} return {loc for loc in locations if sphere_state.can_reach(loc) and sphere_state.not_flooding_a_key(sphere_state.world, loc)}
def item_percentage(player, num):
return num / total_locations_count[player]
while True: while True:
sphere_locations = get_sphere_locations(state, unchecked_locations) sphere_locations = get_sphere_locations(state, unchecked_locations)
for location in sphere_locations: for location in sphere_locations:
unchecked_locations.remove(location) unchecked_locations.remove(location)
if not location.locked and not location.forced_item:
reachable_locations_count[location.player] += 1 reachable_locations_count[location.player] += 1
if checked_locations: logging.debug(f'Sphere {sphere_num}')
threshold = max(reachable_locations_count.values()) - 20 logging.debug(f'Reachable locations: {reachable_locations_count}')
debug_percentages = {
player: round(item_percentage(player, num), 2)
for player, num in reachable_locations_count.items()
}
logging.debug(f'Reachable percentages: {debug_percentages}\n')
sphere_num += 1
balancing_players = {player for player, reachables in reachable_locations_count.items() if reachables < threshold} if checked_locations:
max_percentage = max(map(lambda p: item_percentage(p, reachable_locations_count[p]), reachable_locations_count))
threshold_percentages = {player: max_percentage * .8 for player in range(1, world.players + 1)}
logging.debug(f'Thresholds: {threshold_percentages}')
balancing_players = {player for player, reachables in reachable_locations_count.items()
if item_percentage(player, reachables) < threshold_percentages[player]}
if balancing_players: if balancing_players:
balancing_state = state.copy() balancing_state = state.copy()
balancing_unchecked_locations = unchecked_locations.copy() balancing_unchecked_locations = unchecked_locations.copy()
@@ -769,7 +793,8 @@ def balance_multiworld_progression(world):
for location in balancing_sphere: for location in balancing_sphere:
balancing_unchecked_locations.remove(location) balancing_unchecked_locations.remove(location)
balancing_reachables[location.player] += 1 balancing_reachables[location.player] += 1
if world.has_beaten_game(balancing_state) or all(reachables >= threshold for reachables in balancing_reachables.values()): if world.has_beaten_game(balancing_state) or all(item_percentage(player, reachables) >= threshold_percentages[player]
for player, reachables in balancing_reachables.items()):
break break
elif not balancing_sphere: elif not balancing_sphere:
raise RuntimeError('Not all required items reachable. Something went terribly wrong here.') raise RuntimeError('Not all required items reachable. Something went terribly wrong here.')
@@ -796,7 +821,8 @@ def balance_multiworld_progression(world):
items_to_replace.append(testing) items_to_replace.append(testing)
else: else:
reduced_sphere = get_sphere_locations(reducing_state, locations_to_test) reduced_sphere = get_sphere_locations(reducing_state, locations_to_test)
if reachable_locations_count[player] + len(reduced_sphere) < threshold: p = item_percentage(player, reachable_locations_count[player] + len(reduced_sphere))
if p < threshold_percentages[player]:
items_to_replace.append(testing) items_to_replace.append(testing)
replaced_items = False replaced_items = False
@@ -821,6 +847,7 @@ def balance_multiworld_progression(world):
new_location.event, old_location.event = True, False new_location.event, old_location.event = True, False
logging.debug(f"Progression balancing moved {new_location.item} to {new_location}, " logging.debug(f"Progression balancing moved {new_location.item} to {new_location}, "
f"displacing {old_location.item} into {old_location}") f"displacing {old_location.item} into {old_location}")
moved_item_count += 1
state.collect(new_location.item, True, new_location) state.collect(new_location.item, True, new_location)
replaced_items = True replaced_items = True
break break
@@ -828,6 +855,7 @@ def balance_multiworld_progression(world):
logging.warning(f"Could not Progression Balance {old_location.item}") logging.warning(f"Could not Progression Balance {old_location.item}")
if replaced_items: if replaced_items:
logging.debug(f'Moved {moved_item_count} items so far\n')
unlocked = {fresh for player in balancing_players for fresh in unlocked_locations[player]} unlocked = {fresh for player in balancing_players for fresh in unlocked_locations[player]}
for location in get_sphere_locations(state, unlocked): for location in get_sphere_locations(state, unlocked):
unchecked_locations.remove(location) unchecked_locations.remove(location)
@@ -842,7 +870,8 @@ def balance_multiworld_progression(world):
if world.has_beaten_game(state): if world.has_beaten_game(state):
break break
elif not sphere_locations: elif not sphere_locations:
raise RuntimeError('Not all required items reachable. Something went terribly wrong here.') logging.warning('Progression Balancing ran out of paths.')
break
def check_shop_swap(l, make_item_free=False): def check_shop_swap(l, make_item_free=False):
@@ -1007,6 +1036,7 @@ def balance_money_progression(world):
logger.debug(f'Money balancing needed: Player {target_player} short {difference}') logger.debug(f'Money balancing needed: Player {target_player} short {difference}')
else: else:
difference = 0 difference = 0
target_player = next(p for p in solvent)
while difference > 0: while difference > 0:
swap_targets = [x for x in unchecked_locations if x not in sphere_locations and x.item.name.startswith('Rupees') and x.item.player == target_player] swap_targets = [x for x in unchecked_locations if x not in sphere_locations and x.item.name.startswith('Rupees') and x.item.player == target_player]
if len(swap_targets) == 0: if len(swap_targets) == 0:
+24 -21
View File
@@ -34,22 +34,34 @@ def check_python_version(fish):
import sys import sys
version = sys.version_info version = sys.version_info
if version.major < 3 or version.minor < 7: if version.major < 3 or version.minor < 7:
messagebox.showinfo("Door Shuffle " + ESVersion, fish.translate("cli","cli","old.python.version") % sys.version) messagebox.showinfo("Overworld Shuffle %s (DR %s)" % (ORVersion, ESVersion), fish.translate("cli","cli","old.python.version") % sys.version)
def guiMain(args=None):
# Save settings to file # Save settings to file
def save_settings(args): def save_settings(gui, args, filename):
user_resources_path = os.path.join(".", "resources", "user") user_resources_path = os.path.join(".", "resources", "user")
settings_path = os.path.join(user_resources_path) settings_path = os.path.join(user_resources_path)
if not os.path.exists(settings_path): if not os.path.exists(settings_path):
os.makedirs(settings_path) os.makedirs(settings_path)
for widget in self.pages["adjust"].content.widgets: output_args = {}
args["adjust." + widget] = self.pages["adjust"].content.widgets[widget].storageVar.get() settings = ["create_rom", "suppress_rom", "bps", "create_spoiler", "suppress_spoiler",
with open(os.path.join(settings_path, "settings.json"), "w+") as f: "calc_playthrough", "skip_playthrough", "print_custom_yaml",
f.write(json.dumps(args, indent=2)) "settingsonload", "rom", "enemizercli", "outputpath"]
os.chmod(os.path.join(settings_path, "settings.json"),0o755) if filename == "settings.json":
for s in settings:
output_args[s] = args[s]
for widget in gui.pages["adjust"].content.widgets:
output_args["adjust." + widget] = gui.pages["adjust"].content.widgets[widget].storageVar.get()
else:
for k, v in args.items():
if k not in settings and not k.startswith("adjust."):
output_args[k] = v
with open(os.path.join(settings_path, filename), "w+") as f:
f.write(json.dumps(output_args, indent=2))
os.chmod(os.path.join(settings_path, filename),0o755)
def guiMain(args=None):
# Save settings from GUI # Save settings from GUI
def save_settings_from_gui(confirm): def save_settings_from_gui(confirm):
gui_args = vars(create_guiargs(self)) gui_args = vars(create_guiargs(self))
@@ -57,22 +69,13 @@ def guiMain(args=None):
gui_args['sprite'] = 'random' gui_args['sprite'] = 'random'
elif gui_args['sprite']: elif gui_args['sprite']:
gui_args['sprite'] = gui_args['sprite'].name gui_args['sprite'] = gui_args['sprite'].name
save_settings(gui_args) save_settings(self, gui_args, "saved.json")
save_settings(self, gui_args, "settings.json")
if confirm: if confirm:
messagebox.showinfo("Overworld Shuffle " + ORVersion, "Settings saved from GUI.") messagebox.showinfo("Overworld Shuffle " + ORVersion, "Settings saved from GUI.")
# routine for exiting the app # routine for exiting the app
def guiExit(): def guiExit():
skip_exit = False
if self.settings['saveonexit'] == 'ask':
dosave = messagebox.askyesnocancel("Overworld Shuffle " + ORVersion, "Save settings before exit?")
if dosave:
save_settings_from_gui(True)
if dosave is None:
skip_exit = True
elif self.settings['saveonexit'] == 'always':
save_settings_from_gui(False)
if not skip_exit:
sys.exit(0) sys.exit(0)
# make main window # make main window
@@ -172,8 +175,8 @@ def guiMain(args=None):
self.pages["bottom"].pages = {} self.pages["bottom"].pages = {}
self.pages["bottom"].pages["content"] = bottom_frame(self, self, None) self.pages["bottom"].pages["content"] = bottom_frame(self, self, None)
## Save Settings Button ## Save Settings Button
savesettingsButton = Button(self.pages["bottom"].pages["content"], text='Save Settings to File', command=lambda: save_settings_from_gui(True)) savesettingsButton = self.pages["bottom"].pages["content"].widgets["savesettings"].pieces["button"]
savesettingsButton.pack(side=RIGHT) savesettingsButton.configure(command=lambda: save_settings_from_gui(True))
# set bottom frame to main window # set bottom frame to main window
self.pages["bottom"].pages["content"].pack(side=BOTTOM, fill=X, padx=5, pady=5) self.pages["bottom"].pages["content"].pack(side=BOTTOM, fill=X, padx=5, pady=5)
+12 -1
View File
@@ -114,6 +114,16 @@ class InitialSram:
equip[0x37B] = 1 equip[0x37B] = 1
equip[0x36E] = 0x80 equip[0x36E] = 0x80
if startingstate.has('Return Old Man', player):
self._initial_sram_bytes[0x410] |= 0x01
if startingstate.has('Beat Agahnim 1', player):
self.pre_open_lumberjack()
if world.mode[player] == 'standard':
self.set_progress_indicator(0x80)
else:
self.set_progress_indicator(0x03)
for item in world.precollected_items: for item in world.precollected_items:
if item.player != player: if item.player != player:
continue continue
@@ -123,7 +133,8 @@ class InitialSram:
'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword', 'Golden Sword', 'Tempered Sword', 'Master Sword', 'Fighter Sword', 'Progressive Sword',
'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield', 'Mirror Shield', 'Red Shield', 'Blue Shield', 'Progressive Shield',
'Red Mail', 'Blue Mail', 'Progressive Armor', 'Red Mail', 'Blue Mail', 'Progressive Armor',
'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)']: 'Magic Upgrade (1/4)', 'Magic Upgrade (1/2)',
'Return Old Man', 'Beat Agahnim 1']:
continue continue
set_table = {'Book of Mudora': (0x34E, 1), 'Hammer': (0x34B, 1), 'Bug Catching Net': (0x34D, 1), 'Hookshot': (0x342, 1), 'Magic Mirror': (0x353, 2), set_table = {'Book of Mudora': (0x34E, 1), 'Hammer': (0x34B, 1), 'Bug Catching Net': (0x34D, 1), 'Hookshot': (0x342, 1), 'Magic Mirror': (0x353, 2),
+26 -5
View File
@@ -227,6 +227,12 @@ def generate_itempool(world, player):
loc.locked = True loc.locked = True
loc.forced_item = loc.item loc.forced_item = loc.item
if 'Return Old Man' in list(map(str, [i for i in world.precollected_items if i.player == player])):
old_man = world.get_location('Old Man', player)
world.push_item(old_man, ItemFactory('Nothing', player), False)
old_man.forced_item = old_man.item
old_man.skip = True
world.get_location('Ganon', player).event = True world.get_location('Ganon', player).event = True
world.get_location('Ganon', player).locked = True world.get_location('Ganon', player).locked = True
world.push_item(world.get_location('Agahnim 1', player), ItemFactory('Beat Agahnim 1', player), False) world.push_item(world.get_location('Agahnim 1', player), ItemFactory('Beat Agahnim 1', player), False)
@@ -321,6 +327,11 @@ def generate_itempool(world, player):
for _ in range(0, amt): for _ in range(0, amt):
pool.append('Rupees (20)') pool.append('Rupees (20)')
if world.logic[player] == 'hybridglitches' and world.pottery[player] not in ['none', 'cave']:
# In HMG force swamp smalls in pots to allow getting out of swamp palace
placed_items['Swamp Palace - Trench 1 Pot Key'] = 'Small Key (Swamp Palace)'
placed_items['Swamp Palace - Pot Row Pot Key'] = 'Small Key (Swamp Palace)'
start_inventory = list(world.precollected_items) start_inventory = list(world.precollected_items)
for item in precollected_items: for item in precollected_items:
world.push_precollected(ItemFactory(item, player)) world.push_precollected(ItemFactory(item, player))
@@ -335,6 +346,8 @@ def generate_itempool(world, player):
if not found_sword and world.swords[player] != 'swordless': if not found_sword and world.swords[player] != 'swordless':
found_sword = True found_sword = True
possible_weapons.append(item) possible_weapons.append(item)
if world.algorithm == 'vanilla_fill': # skip other possibilities
continue
if (item in ['Progressive Bow', 'Bow'] and not found_bow if (item in ['Progressive Bow', 'Bow'] and not found_bow
and not world.bow_mode[player].startswith('retro')): and not world.bow_mode[player].startswith('retro')):
found_bow = True found_bow = True
@@ -428,8 +441,14 @@ def generate_itempool(world, player):
if tr_medallion == 'Random': if tr_medallion == 'Random':
tr_medallion = None tr_medallion = None
if not mm_medallion: if not mm_medallion:
if world.algorithm == 'vanilla_fill':
mm_medallion = 'Ether'
else:
mm_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] mm_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
if not tr_medallion: if not tr_medallion:
if world.algorithm == 'vanilla_fill':
tr_medallion = 'Quake'
else:
tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)] tr_medallion = ['Ether', 'Quake', 'Bombos'][random.randint(0, 2)]
world.required_medallions[player] = (mm_medallion, tr_medallion) world.required_medallions[player] = (mm_medallion, tr_medallion)
@@ -552,7 +571,9 @@ def set_up_take_anys(world, player, skip_adjustments=False):
world.dynamic_regions.append(take_any) world.dynamic_regions.append(take_any)
target, room_id = random.choice([(0x58, 0x0112), (0x60, 0x010F), (0x46, 0x011F)]) target, room_id = random.choice([(0x58, 0x0112), (0x60, 0x010F), (0x46, 0x011F)])
reg = regions.pop() reg = regions.pop()
entrance = world.get_region(reg, player).entrances[0] entrance = next((ent for ent in world.get_region(reg, player).entrances if ent.parent_region.is_outdoors()), None)
if entrance is None:
raise Exception(f'No outside entrance found for {reg}')
connect_entrance(world, entrance, take_any, player) connect_entrance(world, entrance, take_any, player)
entrance.target = target entrance.target = target
take_any.shop = Shop(take_any, room_id, take_any_type, 0xE3, True, not world.shopsanity[player], 33 + num*2) take_any.shop = Shop(take_any, room_id, take_any_type, 0xE3, True, not world.shopsanity[player], 33 + num*2)
@@ -1040,7 +1061,7 @@ def get_pool_core(world, player, progressive, shuffle, difficulty, treasure_hunt
return random.choice([True, False]) if progressive == 'random' else progressive == 'on' return random.choice([True, False]) if progressive == 'random' else progressive == 'on'
# provide boots to boots glitch dependent modes # provide boots to boots glitch dependent modes
if logic in ['owglitches', 'nologic']: if logic in ['owglitches', 'hybridglitches', 'nologic']:
precollected_items.append('Pegasus Boots') precollected_items.append('Pegasus Boots')
pool.remove('Pegasus Boots') pool.remove('Pegasus Boots')
pool.extend(['Rupees (20)']) pool.extend(['Rupees (20)'])
@@ -1346,12 +1367,12 @@ def make_custom_item_pool(world, player, progressive, shuffle, difficulty, timer
start_inventory = [x for x in world.precollected_items if x.player == player] start_inventory = [x for x in world.precollected_items if x.player == player]
if not start_inventory: if not start_inventory:
if world.logic[player] in ['owglitches', 'nologic']: if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic'] and all(x.name != 'Pegasus Boots' for x in start_inventory):
precollected_items.append('Pegasus Boots') precollected_items.append('Pegasus Boots')
if 'Pegasus Boots' in pool: if 'Pegasus Boots' in pool:
pool.remove('Pegasus Boots') pool.remove('Pegasus Boots')
pool.append('Rupees (20)') pool.append('Rupees (20)')
if world.swords[player] == 'assured': if world.swords[player] == 'assured' and all(' Sword' not in x.name for x in start_inventory):
precollected_items.append('Progressive Sword') precollected_items.append('Progressive Sword')
if 'Progressive Sword' in pool: if 'Progressive Sword' in pool:
pool.remove('Progressive Sword') pool.remove('Progressive Sword')
@@ -1487,7 +1508,7 @@ def make_customizer_pool(world, player):
sphere_0 = world.customizer.get_start_inventory() sphere_0 = world.customizer.get_start_inventory()
no_start_inventory = not sphere_0 or not sphere_0[player] no_start_inventory = not sphere_0 or not sphere_0[player]
init_equip = [] if no_start_inventory else sphere_0[player] init_equip = [] if no_start_inventory else sphere_0[player]
if (world.logic[player] in ['owglitches', 'nologic'] if (world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']
and (no_start_inventory or all(x != 'Pegasus Boots' for x in init_equip))): and (no_start_inventory or all(x != 'Pegasus Boots' for x in init_equip))):
precollected_items.append('Pegasus Boots') precollected_items.append('Pegasus Boots')
if 'Pegasus Boots' in pool: if 'Pegasus Boots' in pool:
+16
View File
@@ -2106,6 +2106,22 @@ def validate_key_placement(key_layout, world, player):
if i.player == player and i.name == smallkey_name: if i.player == player and i.name == smallkey_name:
keys_outside += 1 keys_outside += 1
if world.logic[player] == 'hybridglitches':
# Swamp keylogic
if smallkey_name.endswith('(Swamp Palace)'):
swamp_entrance = world.get_location('Swamp Palace - Entrance', player)
# Swamp small not vanilla
if swamp_entrance.item is None or (swamp_entrance.item.name != smallkey_name or swamp_entrance.item.player != player):
mire_keylayout = world.key_layout[player]['Misery Mire']
mire_smallkey_name = dungeon_keys[mire_keylayout.sector.name]
# Check if any mire keys are in swamp (excluding entrance), if none then add one to keys_outside
mire_keys_in_swamp = sum([1 if x.item.name == mire_smallkey_name else 0 for x in key_layout.item_locations if x.item is not None and x != swamp_entrance])
if mire_keys_in_swamp == 0:
keys_outside +=1
# Mire keylogic
if smallkey_name.endswith('(Tower of Hera)'):
# TODO: Make sure that mire medallion isn't in hera basement, or if it is, the small key is available downstairs
big_key_outside = True
for code, counter in key_layout.key_counters.items(): for code, counter in key_layout.key_counters.items():
if len(counter.child_doors) == 0: if len(counter.child_doors) == 0:
continue continue
+182 -93
View File
@@ -28,6 +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, create_hybridmajor_connectors
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
@@ -35,7 +36,6 @@ from source.item.FillUtil import create_item_pool_config, massage_item_pool, dis
from source.overworld.EntranceShuffle2 import link_entrances_new from source.overworld.EntranceShuffle2 import link_entrances_new
from source.tools.BPS import create_bps_from_data from source.tools.BPS import create_bps_from_data
from source.classes.CustomSettings import CustomSettings from source.classes.CustomSettings import CustomSettings
from source.classes.SFX import output_song_data
version_number = '1.2.0.22' version_number = '1.2.0.22'
version_branch = '-u' version_branch = '-u'
@@ -57,32 +57,33 @@ def check_python_version():
def main(args, seed=None, fish=None): def main(args, seed=None, fish=None):
check_python_version() check_python_version()
if args.print_template_yaml:
return export_yaml(args, fish)
if args.outputpath: if args.outputpath:
os.makedirs(args.outputpath, exist_ok=True) os.makedirs(args.outputpath, exist_ok=True)
output_path.cached_path = args.outputpath output_path.cached_path = args.outputpath
start = time.perf_counter() start = time.perf_counter()
world = init_world(args, fish)
logger = logging.getLogger('')
if args.securerandom: if args.securerandom:
random.use_secure() random.use_secure()
seeded = False seeded = False
# initialize the world if world.customizer:
if args.code: seed = world.customizer.determine_seed(seed)
for player, code in args.code.items():
if code:
Settings.adjust_args_from_code(code, player, args)
customized = None
if args.customizer:
customized = CustomSettings()
customized.load_yaml(args.customizer)
seed = customized.determine_seed(seed)
seeded = True seeded = True
customized.adjust_args(args) world.customizer.adjust_args(args)
world = World(args.multi, args.ow_shuffle, args.ow_crossed, args.ow_mixed, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords, world = init_world(args, fish)
args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm,
args.accessibility, args.shuffleganon, args.custom, args.customitemarray, args.hints) for i in zip(args.logic.values(), args.door_shuffle.values()):
world.customizer = customized if customized else None if i[0] == 'hybridglitches' and i[1] != 'vanilla':
logger = logging.getLogger('') raise RuntimeError(BabelFish().translate("cli","cli","hybridglitches.door.shuffle"))
if seed is None: if seed is None:
random.seed(None) random.seed(None)
world.seed = random.randint(0, 999999999) world.seed = random.randint(0, 999999999)
@@ -94,53 +95,9 @@ def main(args, seed=None, fish=None):
if args.securerandom: if args.securerandom:
world.seed = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(9)) world.seed = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(9))
world.boots_hint = args.boots_hint.copy()
world.remote_items = args.remote_items.copy()
world.mapshuffle = args.mapshuffle.copy()
world.compassshuffle = args.compassshuffle.copy()
world.keyshuffle = args.keyshuffle.copy()
world.bigkeyshuffle = args.bigkeyshuffle.copy()
world.bombbag = args.bombbag.copy()
world.flute_mode = args.flute_mode.copy()
world.bow_mode = args.bow_mode.copy()
world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_ganon = {player: random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(args.crystals_ganon[player]) for player in range(1, world.players + 1)}
world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)} world.crystals_needed_for_gt = {player: random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player]) for player in range(1, world.players + 1)}
world.crystals_ganon_orig = args.crystals_ganon.copy()
world.crystals_gt_orig = args.crystals_gt.copy()
world.owTerrain = args.ow_terrain.copy()
world.owKeepSimilar = args.ow_keepsimilar.copy()
world.owWhirlpoolShuffle = args.ow_whirlpool.copy()
world.owFluteShuffle = args.ow_fluteshuffle.copy()
world.shuffle_bonk_drops = args.bonk_drops.copy()
world.open_pyramid = args.openpyramid.copy()
world.boss_shuffle = args.shufflebosses.copy()
world.enemy_shuffle = args.shuffleenemies.copy()
world.enemy_health = args.enemy_health.copy()
world.enemy_damage = args.enemy_damage.copy()
world.beemizer = args.beemizer.copy()
world.intensity = {player: random.randint(1, 3) if args.intensity[player] == 'random' else int(args.intensity[player]) for player in range(1, world.players + 1)} world.intensity = {player: random.randint(1, 3) 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.trap_door_mode = args.trap_door_mode.copy()
world.key_logic_algorithm = args.key_logic_algorithm.copy()
world.decoupledoors = args.decoupledoors.copy()
world.door_self_loops = args.door_self_loops.copy()
world.experimental = args.experimental.copy()
world.dungeon_counters = args.dungeon_counters.copy()
world.fish = fish
world.shopsanity = args.shopsanity.copy()
world.dropshuffle = args.dropshuffle.copy()
world.pottery = args.pottery.copy()
world.potshuffle = args.shufflepots.copy()
world.mixed_travel = args.mixed_travel.copy()
world.standardize_palettes = args.standardize_palettes.copy()
world.shufflelinks = args.shufflelinks.copy()
world.shuffletavern = args.shuffletavern.copy()
world.pseudoboots = args.pseudoboots.copy()
world.overworld_map = args.overworld_map.copy()
world.take_any = args.take_any.copy()
world.restrict_boss_items = args.restrict_boss_items.copy()
world.collection_rate = args.collection_rate.copy()
world.colorizepots = args.colorizepots.copy()
world.treasure_hunt_count = {} world.treasure_hunt_count = {}
world.treasure_hunt_total = {} world.treasure_hunt_total = {}
@@ -184,8 +141,6 @@ def main(args, seed=None, fish=None):
for player, name in enumerate(team, 1): for player, name in enumerate(team, 1):
world.player_names[player].append(name) world.player_names[player].append(name)
logger.info('') logger.info('')
world.settings = CustomSettings()
world.settings.create_from_world(world, args)
outfilebase = f'OR_{args.outputname if args.outputname else world.seed}' outfilebase = f'OR_{args.outputname if args.outputname else world.seed}'
@@ -196,13 +151,10 @@ def main(args, seed=None, fish=None):
if hasattr(world,"escape_assist") and player in world.escape_assist: if hasattr(world,"escape_assist") and player in world.escape_assist:
world.escape_assist[player].append('bombs') # enemized escape assumes infinite bombs available and will likely be unbeatable without it world.escape_assist[player].append('bombs') # enemized escape assumes infinite bombs available and will likely be unbeatable without it
if args.usestartinventory[player]: set_starting_inventory(world, args)
for tok in filter(None, args.startinventory[player].split(',')):
name = tok.strip() world.settings = CustomSettings()
name = name if name != 'Ocarina' or world.flute_mode[player] != 'active' else 'Ocarina (Activated)' world.settings.create_from_world(world, args)
item = ItemFactory(name, player)
if item:
world.push_precollected(item)
if args.create_spoiler and not args.jsonout: if args.create_spoiler and not args.jsonout:
logger.info(world.fish.translate("cli", "cli", "create.meta")) logger.info(world.fish.translate("cli", "cli", "create.meta"))
@@ -220,15 +172,8 @@ def main(args, seed=None, fish=None):
create_dungeons(world, player) create_dungeons(world, player)
adjust_locations(world, player) adjust_locations(world, player)
place_bosses(world, player) place_bosses(world, player)
if world.logic[player] in ('nologic', 'hybridglitches'):
if world.customizer and world.customizer.get_start_inventory(): create_hybridmajor_connections(world, player)
for p, inv_list in world.customizer.get_start_inventory().items():
for inv_item in inv_list:
item = ItemFactory(inv_item.strip(), p)
if item:
world.push_precollected(item)
if args.print_custom_yaml:
world.settings.record_info(world)
if any(world.potshuffle.values()): if any(world.potshuffle.values()):
logger.info(world.fish.translate("cli", "cli", "shuffling.pots")) logger.info(world.fish.translate("cli", "cli", "shuffling.pots"))
@@ -247,8 +192,6 @@ def main(args, seed=None, fish=None):
update_world_regions(world, player) update_world_regions(world, player)
mark_light_dark_world_regions(world, player) mark_light_dark_world_regions(world, player)
create_dynamic_exits(world, player) create_dynamic_exits(world, player)
if args.print_custom_yaml:
world.settings.record_overworld(world)
init_districts(world) init_districts(world)
@@ -256,14 +199,14 @@ def main(args, seed=None, fish=None):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
link_entrances_new(world, player) link_entrances_new(world, player)
if world.logic[player] in ('nologic', 'hybridglitches'):
create_hybridmajor_connectors(world, player)
logger.info(world.fish.translate("cli", "cli", "shuffling.prep")) logger.info(world.fish.translate("cli", "cli", "shuffling.prep"))
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
link_doors_prep(world, player) link_doors_prep(world, player)
if args.print_custom_yaml:
world.settings.record_entrances(world)
create_item_pool_config(world) create_item_pool_config(world)
logger.info(world.fish.translate("cli", "cli", "shuffling.dungeons")) logger.info(world.fish.translate("cli", "cli", "shuffling.dungeons"))
@@ -271,8 +214,6 @@ def main(args, seed=None, fish=None):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
link_doors(world, player) link_doors(world, player)
mark_light_dark_world_regions(world, player) mark_light_dark_world_regions(world, player)
if args.print_custom_yaml:
world.settings.record_doors(world)
logger.info(world.fish.translate("cli", "cli", "generating.itempool")) logger.info(world.fish.translate("cli", "cli", "generating.itempool"))
@@ -300,8 +241,6 @@ def main(args, seed=None, fish=None):
lock_shop_locations(world, player) lock_shop_locations(world, player)
massage_item_pool(world) massage_item_pool(world)
if args.print_custom_yaml:
world.settings.record_item_pool(world)
logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes")) logger.info(world.fish.translate("cli", "cli", "placing.dungeon.prizes"))
fill_prizes(world) fill_prizes(world)
@@ -351,6 +290,11 @@ def main(args, seed=None, fish=None):
ensure_good_pots(world, True) ensure_good_pots(world, True)
if args.print_custom_yaml: if args.print_custom_yaml:
world.settings.record_info(world)
world.settings.record_overworld(world)
world.settings.record_entrances(world)
world.settings.record_doors(world)
world.settings.record_item_pool(world)
world.settings.record_item_placements(world) world.settings.record_item_placements(world)
world.settings.write_to_file(output_path(f'{outfilebase}_custom.yaml')) world.settings.write_to_file(output_path(f'{outfilebase}_custom.yaml'))
@@ -405,8 +349,6 @@ def main(args, seed=None, fish=None):
if world.players > 1 or world.teams > 1: if world.players > 1 or world.teams > 1:
outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][team] != 'Player %d' % player else '' outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][team] != 'Player %d' % player else ''
outfilesuffix = f'_{Settings.make_code(world, player)}' if not args.outputname else '' outfilesuffix = f'_{Settings.make_code(world, player)}' if not args.outputname else ''
if args.shuffle_songinstruments:
output_song_data(rom, output_path('OR_SPCInstruments.txt'), outfilebase)
if args.bps: if args.bps:
patchfile = output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.bps') patchfile = output_path(f'{outfilebase}{outfilepname}{outfilesuffix}.bps')
patch = create_bps_from_data(LocalRom(args.rom, patch=False).buffer, rom.buffer) patch = create_bps_from_data(LocalRom(args.rom, patch=False).buffer, rom.buffer)
@@ -470,6 +412,124 @@ def main(args, seed=None, fish=None):
return world return world
def export_yaml(args, fish):
if args.outputpath:
os.makedirs(args.outputpath, exist_ok=True)
output_path.cached_path = args.outputpath
outfilebase = f'{args.outputname if args.outputname else "export"}'
logger = logging.getLogger('')
world = init_world(args, fish)
from OverworldShuffle import __version__ as ORVersion
logger.info(
world.fish.translate("cli","cli","app.title") + "\n",
ORVersion,
"(%s)" % outfilebase,
Settings.make_code(world, 1) if world.players == 1 else ''
)
for k,v in {"DR":__version__,"OR":ORVersion}.items():
logger.info((k + ' Version:').ljust(16) + '%s' % v)
set_starting_inventory(world, args)
world.settings = CustomSettings()
world.settings.create_from_world(world, args)
world.settings.record_item_pool(world, True)
world.settings.write_to_file(output_path(f'{outfilebase}.yaml'))
return world
def init_world(args, fish):
if args.code:
for player, code in args.code.items():
if code:
Settings.adjust_args_from_code(code, player, args)
customized = None
if args.customizer:
customized = CustomSettings()
customized.load_yaml(args.customizer)
customized.adjust_args(args, False)
world = World(args.multi, args.ow_shuffle, args.ow_crossed, args.ow_mixed, args.shuffle, args.door_shuffle, args.logic, args.mode, args.swords,
args.difficulty, args.item_functionality, args.timer, args.progressive, args.goal, args.algorithm,
args.accessibility, args.shuffleganon, args.custom, args.customitemarray, args.hints)
world.customizer = customized
world.boots_hint = args.boots_hint.copy()
world.remote_items = args.remote_items.copy()
world.mapshuffle = args.mapshuffle.copy()
world.compassshuffle = args.compassshuffle.copy()
world.keyshuffle = args.keyshuffle.copy()
world.bigkeyshuffle = args.bigkeyshuffle.copy()
world.bombbag = args.bombbag.copy()
world.flute_mode = args.flute_mode.copy()
world.bow_mode = args.bow_mode.copy()
world.crystals_ganon_orig = args.crystals_ganon.copy()
world.crystals_gt_orig = args.crystals_gt.copy()
world.owTerrain = args.ow_terrain.copy()
world.owKeepSimilar = args.ow_keepsimilar.copy()
world.owWhirlpoolShuffle = args.ow_whirlpool.copy()
world.owFluteShuffle = args.ow_fluteshuffle.copy()
world.shuffle_bonk_drops = args.bonk_drops.copy()
world.open_pyramid = args.openpyramid.copy()
world.boss_shuffle = args.shufflebosses.copy()
world.enemy_shuffle = args.shuffleenemies.copy()
world.enemy_health = args.enemy_health.copy()
world.enemy_damage = args.enemy_damage.copy()
world.beemizer = args.beemizer.copy()
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.trap_door_mode = args.trap_door_mode.copy()
world.key_logic_algorithm = args.key_logic_algorithm.copy()
world.decoupledoors = args.decoupledoors.copy()
world.door_self_loops = args.door_self_loops.copy()
world.experimental = args.experimental.copy()
world.dungeon_counters = args.dungeon_counters.copy()
world.fish = fish
world.shopsanity = args.shopsanity.copy()
world.dropshuffle = args.dropshuffle.copy()
world.pottery = args.pottery.copy()
world.potshuffle = args.shufflepots.copy()
world.mixed_travel = args.mixed_travel.copy()
world.standardize_palettes = args.standardize_palettes.copy()
world.shufflelinks = args.shufflelinks.copy()
world.shuffletavern = args.shuffletavern.copy()
world.pseudoboots = args.pseudoboots.copy()
world.overworld_map = args.overworld_map.copy()
world.take_any = args.take_any.copy()
world.restrict_boss_items = args.restrict_boss_items.copy()
world.collection_rate = args.collection_rate.copy()
world.colorizepots = args.colorizepots.copy()
world.aga_randomness = args.aga_randomness.copy()
return world
def set_starting_inventory(world, args):
for player in range(1, world.players + 1):
if args.usestartinventory[player]:
for tok in filter(None, args.startinventory[player].split(',')):
name = tok.strip()
name = name if name != 'Ocarina' or world.flute_mode[player] != 'active' else 'Ocarina (Activated)'
item = ItemFactory(name, player)
if item:
world.push_precollected(item)
if world.customizer and world.customizer.get_start_inventory():
for p, inv_list in world.customizer.get_start_inventory().items():
for inv_item in inv_list:
item = ItemFactory(inv_item.strip(), p)
if item:
world.push_precollected(item)
def copy_world(world): def copy_world(world):
# ToDo: Not good yet # ToDo: Not good yet
ret = World(world.players, world.owShuffle, world.owCrossed, world.owMixed, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords, ret = World(world.players, world.owShuffle, world.owCrossed, world.owMixed, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords,
@@ -524,6 +584,10 @@ def copy_world(world):
ret.intensity = world.intensity.copy() ret.intensity = world.intensity.copy()
ret.decoupledoors = world.decoupledoors.copy() ret.decoupledoors = world.decoupledoors.copy()
ret.door_self_loops = world.door_self_loops.copy() ret.door_self_loops = world.door_self_loops.copy()
ret.door_type_mode = world.door_type_mode.copy()
ret.trap_door_mode = world.trap_door_mode.copy()
ret.key_logic_algorithm = world.key_logic_algorithm.copy()
ret.aga_randomness = world.aga_randomness.copy()
ret.experimental = world.experimental.copy() ret.experimental = world.experimental.copy()
ret.shopsanity = world.shopsanity.copy() ret.shopsanity = world.shopsanity.copy()
ret.dropshuffle = world.dropshuffle.copy() ret.dropshuffle = world.dropshuffle.copy()
@@ -540,8 +604,10 @@ def copy_world(world):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
create_regions(ret, player) create_regions(ret, player)
update_world_regions(ret, player) update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player) create_owg_connections(ret, player)
if world.logic[player] in ('nologic', 'hybridglitches'):
create_hybridmajor_connections(ret, player)
create_dynamic_exits(ret, player) create_dynamic_exits(ret, player)
create_dungeon_regions(ret, player) create_dungeon_regions(ret, player)
create_owedges(ret, player) create_owedges(ret, player)
@@ -587,7 +653,12 @@ def copy_world(world):
for exit in region.exits: for exit in region.exits:
if exit.connected_region: if exit.connected_region:
dest_region = ret.get_region(exit.connected_region.name, region.player) dest_region = ret.get_region(exit.connected_region.name, region.player)
ret.get_entrance(exit.name, exit.player).connect(dest_region) src_exit = ret.get_entrance(exit.name, exit.player)
if exit.name not in [e.name for e in dest_region.entrances if e.connected_region is not None]:
if exit.name in [e.name for e in dest_region.entrances]:
src_exit.connected_region = dest_region
else:
src_exit.connect(dest_region)
# fill locations # fill locations
for location in world.get_locations(): for location in world.get_locations():
@@ -644,6 +715,8 @@ def copy_world(world):
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
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'):
create_hybridmajor_connectors(ret, player)
set_rules(ret, player) set_rules(ret, player)
return ret return ret
@@ -700,6 +773,12 @@ def copy_world_premature(world, player):
ret.enemy_damage = world.enemy_damage.copy() ret.enemy_damage = world.enemy_damage.copy()
ret.beemizer = world.beemizer.copy() ret.beemizer = world.beemizer.copy()
ret.intensity = world.intensity.copy() ret.intensity = world.intensity.copy()
ret.decoupledoors = world.decoupledoors.copy()
ret.door_self_loops = world.door_self_loops.copy()
ret.door_type_mode = world.door_type_mode.copy()
ret.trap_door_mode = world.trap_door_mode.copy()
ret.key_logic_algorithm = world.key_logic_algorithm.copy()
ret.aga_randomness = world.aga_randomness.copy()
ret.experimental = world.experimental.copy() ret.experimental = world.experimental.copy()
ret.shopsanity = world.shopsanity.copy() ret.shopsanity = world.shopsanity.copy()
ret.dropshuffle = world.dropshuffle.copy() ret.dropshuffle = world.dropshuffle.copy()
@@ -717,8 +796,10 @@ def copy_world_premature(world, player):
create_regions(ret, player) create_regions(ret, player)
update_world_regions(ret, player) update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player) create_owg_connections(ret, player)
if world.logic[player] in ('nologic', 'hybridglitches'):
create_hybridmajor_connections(ret, player)
create_dynamic_exits(ret, player) create_dynamic_exits(ret, player)
create_dungeon_regions(ret, player) create_dungeon_regions(ret, player)
create_owedges(ret, player) create_owedges(ret, player)
@@ -749,7 +830,12 @@ def copy_world_premature(world, player):
for exit in region.exits: for exit in region.exits:
if exit.connected_region: if exit.connected_region:
dest_region = ret.get_region(exit.connected_region.name, region.player) dest_region = ret.get_region(exit.connected_region.name, region.player)
ret.get_entrance(exit.name, exit.player).connect(dest_region) src_exit = ret.get_entrance(exit.name, exit.player)
if exit.name not in [e.name for e in dest_region.entrances if e.connected_region is not None]:
if exit.name in [e.name for e in dest_region.entrances]:
src_exit.connected_region = dest_region
else:
src_exit.connect(dest_region)
from OverworldShuffle import categorize_world_regions from OverworldShuffle import categorize_world_regions
categorize_world_regions(ret, player) categorize_world_regions(ret, player)
@@ -774,6 +860,9 @@ 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_connectors(ret, player)
set_rules(ret, player) set_rules(ret, player)
return ret return ret
+27 -24
View File
@@ -1558,23 +1558,39 @@ OWExitTypes = {
'Ice Lake Southeast Water Drop', 'Ice Lake Southeast Water Drop',
'Bomber Corner Waterfall Water Drop' 'Bomber Corner Waterfall Water Drop'
], ],
'OWTerrain': ['Lost Woods Bush (West)', 'OpenTerrain': ['Old Man Drop Off',
'Lost Woods Bush (East)',
'Old Man Drop Off',
'Spectacle Rock Approach', 'Spectacle Rock Approach',
'Spectacle Rock Leave', 'Spectacle Rock Leave',
'DM Hammer Bridge (West)',
'DM Hammer Bridge (East)',
'Floating Island Bridge (East)', 'Floating Island Bridge (East)',
'Fairy Ascension Rocks (Inner)',
'DM Broken Bridge (West)',
'DM Broken Bridge (East)',
'Spiral Mimic Bridge (West)', 'Spiral Mimic Bridge (West)',
'Spiral Mimic Bridge (East)', 'Spiral Mimic Bridge (East)',
'Spiral Ledge Approach', 'Spiral Ledge Approach',
'Mimic Ledge Approach', 'Mimic Ledge Approach',
'Fairy Ascension Rocks (Outer)',
'Floating Island Bridge (West)', 'Floating Island Bridge (West)',
'Graveyard Ladder (Bottom)',
'Graveyard Ladder (Top)',
'Hyrule Castle Main Gate (South)',
'Hyrule Castle Main Gate (North)',
'Stone Bridge (Northbound)',
'Stone Bridge (Southbound)',
'Checkerboard Ledge Approach',
'Checkerboard Ledge Leave',
'Cave 45 Approach',
'Cave 45 Leave',
'Middle Aged Man',
'Desert Pass Ladder (South)',
'Desert Pass Ladder (North)',
'GT Approach',
'GT Leave',
],
'OWTerrain': ['Lost Woods Bush (West)',
'Lost Woods Bush (East)',
'DM Hammer Bridge (West)',
'DM Hammer Bridge (East)',
'Fairy Ascension Rocks (Inner)',
'DM Broken Bridge (West)',
'DM Broken Bridge (East)',
'Fairy Ascension Rocks (Outer)',
'TR Pegs Ledge Entry', 'TR Pegs Ledge Entry',
'TR Pegs Ledge Leave', 'TR Pegs Ledge Leave',
'Mountain Pass Rock (Outer)', 'Mountain Pass Rock (Outer)',
@@ -1587,8 +1603,6 @@ OWExitTypes = {
'Lost Woods Pass Rock (North)', 'Lost Woods Pass Rock (North)',
'Lost Woods Pass Rock (South)', 'Lost Woods Pass Rock (South)',
'Kings Grave Rocks (Outer)', 'Kings Grave Rocks (Outer)',
'Graveyard Ladder (Bottom)',
'Graveyard Ladder (Top)',
'Kings Grave Rocks (Inner)', 'Kings Grave Rocks (Inner)',
'River Bend Water Drop', 'River Bend Water Drop',
'River Bend West Pier', 'River Bend West Pier',
@@ -1602,12 +1616,10 @@ OWExitTypes = {
'Kakariko Yard Bush (South)', 'Kakariko Yard Bush (South)',
'Kakariko Southwest Bush (South)', 'Kakariko Southwest Bush (South)',
'Kakariko Yard Bush (North)', 'Kakariko Yard Bush (North)',
'Hyrule Castle Main Gate (South)',
'Hyrule Castle East Rock (Inner)', 'Hyrule Castle East Rock (Inner)',
'Hyrule Castle Southwest Bush (North)', 'Hyrule Castle Southwest Bush (North)',
'Hyrule Castle Southwest Bush (South)', 'Hyrule Castle Southwest Bush (South)',
'Hyrule Castle Courtyard Bush (South)', 'Hyrule Castle Courtyard Bush (South)',
'Hyrule Castle Main Gate (North)',
'Hyrule Castle Courtyard Bush (North)', 'Hyrule Castle Courtyard Bush (North)',
'Hyrule Castle East Rock (Outer)', 'Hyrule Castle East Rock (Outer)',
'Wooden Bridge Bush (South)', 'Wooden Bridge Bush (South)',
@@ -1615,17 +1627,11 @@ OWExitTypes = {
'Blacksmith Ledge Peg (West)', 'Blacksmith Ledge Peg (West)',
'Blacksmith Ledge Peg (East)', 'Blacksmith Ledge Peg (East)',
'Maze Race Game', 'Maze Race Game',
'Stone Bridge (Northbound)',
'Stone Bridge (Southbound)',
'Desert Statue Move', 'Desert Statue Move',
'Checkerboard Ledge Approach',
'Desert Ledge Rocks (Outer)', 'Desert Ledge Rocks (Outer)',
'Desert Ledge Rocks (Inner)', 'Desert Ledge Rocks (Inner)',
'Checkerboard Ledge Leave',
'Flute Boy Bush (South)', 'Flute Boy Bush (South)',
'Cave 45 Approach',
'Flute Boy Bush (North)', 'Flute Boy Bush (North)',
'Cave 45 Leave',
'C Whirlpool Rock (Bottom)', 'C Whirlpool Rock (Bottom)',
'C Whirlpool Rock (Top)', 'C Whirlpool Rock (Top)',
'C Whirlpool Pegs (Outer)', 'C Whirlpool Pegs (Outer)',
@@ -1643,19 +1649,15 @@ OWExitTypes = {
'Lake Hylia East Pier', 'Lake Hylia East Pier',
'Lake Hylia Water D Approach', 'Lake Hylia Water D Approach',
'Lake Hylia Water D Leave', 'Lake Hylia Water D Leave',
'Desert Pass Ladder (South)', 'Ice Cave Pier',
'Desert Pass Rocks (North)', 'Desert Pass Rocks (North)',
'Desert Pass Rocks (South)', 'Desert Pass Rocks (South)',
'Desert Pass Ladder (North)',
'Middle Aged Man',
'Octoballoon Water Drop', 'Octoballoon Water Drop',
'Octoballoon Pier', 'Octoballoon Pier',
'Skull Woods Rock (East)', 'Skull Woods Rock (East)',
'Skull Woods Rock (West)', 'Skull Woods Rock (West)',
'Skull Woods Forgotten Bush (West)', 'Skull Woods Forgotten Bush (West)',
'Skull Woods Forgotten Bush (East)', 'Skull Woods Forgotten Bush (East)',
'GT Approach',
'GT Leave',
'East Dark Death Mountain Bushes', 'East Dark Death Mountain Bushes',
'Bumper Cave Rock (Outer)', 'Bumper Cave Rock (Outer)',
'Bumper Cave Rock (Inner)', 'Bumper Cave Rock (Inner)',
@@ -1702,6 +1704,7 @@ OWExitTypes = {
'Ice Lake Northeast Pier', 'Ice Lake Northeast Pier',
'Ice Lake Northeast Pier Hop', 'Ice Lake Northeast Pier Hop',
'Ice Lake Iceberg Water Entry', 'Ice Lake Iceberg Water Entry',
'Shopping Mall Pier',
'Bomber Corner Water Drop', 'Bomber Corner Water Drop',
'Bomber Corner Pier' 'Bomber Corner Pier'
], ],
+89 -90
View File
@@ -5,102 +5,86 @@ Helper functions to deliver entrance/exit/region sets to OWG rules.
from BaseClasses import Entrance from BaseClasses import Entrance
from OWEdges import OWTileRegions from OWEdges import OWTileRegions
# Cave regions that superbunny can get through - but only with a sword.
sword_required_superbunny_mirror_regions = ["Spiral Cave (Top)"]
def get_sword_required_superbunny_mirror_regions(): # Cave regions that superbunny can get through - but only with boots.
""" boots_required_superbunny_mirror_regions = ["Two Brothers House"]
Cave regions that superbunny can get through - but only with a sword.
"""
yield 'Spiral Cave (Top)'
def get_boots_required_superbunny_mirror_regions(): # Cave locations that superbunny can access - but only with boots.
""" boots_required_superbunny_mirror_locations = [
Cave regions that superbunny can get through - but only with boots. "Sahasrahla's Hut - Left",
""" "Sahasrahla's Hut - Middle",
yield 'Two Brothers House' "Sahasrahla's Hut - Right",
]
def get_boots_required_superbunny_mirror_locations(): # Entrances that can't be superbunny-mirrored into.
""" invalid_mirror_bunny_entrances = [
Cave locations that superbunny can access - but only with boots. "Hype Cave",
""" "Bonk Fairy (Dark)",
yield 'Sahasrahla\'s Hut - Left' "Thieves Town",
yield 'Sahasrahla\'s Hut - Middle' "Hammer Peg Cave",
yield 'Sahasrahla\'s Hut - Right' "Brewery",
"Hookshot Cave",
"Dark Lake Hylia Ledge Fairy",
"Dark Lake Hylia Ledge Spike Cave",
"Palace of Darkness",
"Misery Mire",
"Turtle Rock",
"Bonk Rock Cave",
"Bonk Fairy (Light)",
"50 Rupee Cave",
"20 Rupee Cave",
"Checkerboard Cave",
"Light Hype Fairy",
"Waterfall of Wishing",
"Light World Bomb Hut",
"Mini Moldorm Cave",
"Ice Rod Cave",
"Sanctuary Grave",
"Kings Grave",
"Sanctuary Grave",
"Hyrule Castle Secret Entrance Drop",
"Skull Woods Second Section Hole",
"Skull Woods First Section Hole (North)",
]
# Interior locations that can be accessed with superbunny state.
superbunny_accessible_locations = [
"Waterfall of Wishing - Left",
"Waterfall of Wishing - Right",
"King's Tomb",
"Floodgate",
"Floodgate Chest",
"Cave 45",
"Bonk Rock Cave",
"Brewery",
"C-Shaped House",
"Chest Game",
"Mire Shed - Left",
"Mire Shed - Right",
"Secret Passage",
"Ice Rod Cave",
"Pyramid Fairy - Left",
"Pyramid Fairy - Right",
"Superbunny Cave - Top",
"Superbunny Cave - Bottom",
"Blind's Hideout - Left",
"Blind's Hideout - Right",
"Blind's Hideout - Far Left",
"Blind's Hideout - Far Right",
"Kakariko Well - Left",
"Kakariko Well - Middle",
"Kakariko Well - Right",
"Kakariko Well - Bottom",
"Kakariko Tavern",
"Library",
"Spiral Cave",
] + boots_required_superbunny_mirror_locations
# TODO: Add pottery locations # TODO: Add pottery locations
def get_invalid_mirror_bunny_entrances():
"""
Entrances that can't be superbunny-mirrored into.
"""
yield 'Skull Woods Final Section'
yield 'Hype Cave'
yield 'Bonk Fairy (Dark)'
yield 'Thieves Town'
yield 'Hammer Peg Cave'
yield 'Brewery'
yield 'Hookshot Cave'
yield 'Dark Lake Hylia Ledge Fairy'
yield 'Dark Lake Hylia Ledge Spike Cave'
yield 'Palace of Darkness'
yield 'Misery Mire'
yield 'Turtle Rock'
yield 'Bonk Rock Cave'
yield 'Bonk Fairy (Light)'
yield '50 Rupee Cave'
yield '20 Rupee Cave'
yield 'Checkerboard Cave'
yield 'Light Hype Fairy'
yield 'Waterfall of Wishing'
yield 'Light World Bomb Hut'
yield 'Mini Moldorm Cave'
yield 'Ice Rod Cave'
yield 'Sanctuary Grave'
yield 'Kings Grave'
yield 'Sanctuary Grave'
yield 'Hyrule Castle Secret Entrance Drop'
yield 'Skull Woods Second Section Hole'
yield 'Skull Woods First Section Hole (North)'
def get_superbunny_accessible_locations():
"""
Interior locations that can be accessed with superbunny state.
"""
yield 'Waterfall of Wishing - Left'
yield 'Waterfall of Wishing - Right'
yield 'King\'s Tomb'
yield 'Floodgate'
yield 'Floodgate Chest'
yield 'Cave 45'
yield 'Bonk Rock Cave'
yield 'Brewery'
yield 'C-Shaped House'
yield 'Chest Game'
yield 'Mire Shed - Left'
yield 'Mire Shed - Right'
yield 'Secret Passage'
yield 'Ice Rod Cave'
yield 'Pyramid Fairy - Left'
yield 'Pyramid Fairy - Right'
yield 'Superbunny Cave - Top'
yield 'Superbunny Cave - Bottom'
yield 'Blind\'s Hideout - Left'
yield 'Blind\'s Hideout - Right'
yield 'Blind\'s Hideout - Far Left'
yield 'Blind\'s Hideout - Far Right'
yield 'Kakariko Well - Left'
yield 'Kakariko Well - Middle'
yield 'Kakariko Well - Right'
yield 'Kakariko Well - Bottom'
yield 'Kakariko Tavern'
yield 'Library'
yield 'Spiral Cave'
for location in get_boots_required_superbunny_mirror_locations():
yield location
def get_non_mandatory_exits(world, player): def get_non_mandatory_exits(world, player):
""" """
Entrances that can be reached with full equipment using overworld glitches and don't need to be an exit. Entrances that can be reached with full equipment using overworld glitches and don't need to be an exit.
@@ -295,6 +279,7 @@ def overworld_glitches_rules(world, player):
#set_owg_rules(player, world, get_glitched_speed_drops_dw(world, player), lambda state: state.can_get_glitched_speed_dw(player)) #set_owg_rules(player, world, get_glitched_speed_drops_dw(world, player), lambda state: state.can_get_glitched_speed_dw(player))
# Mirror clip spots. # Mirror clip spots.
# TODO: Should this also require can_boots_clip
set_owg_rules(player, world, get_mirror_clip_spots(world, player), lambda state: state.has_Mirror(player)) set_owg_rules(player, world, get_mirror_clip_spots(world, player), lambda state: state.has_Mirror(player))
# Mirror offset spots. # Mirror offset spots.
@@ -319,6 +304,18 @@ def overworld_glitches_rules(world, player):
add_additional_rule(world.get_entrance('Tree Line Water Clip', player), lambda state: state.has('Flippers', player)) add_additional_rule(world.get_entrance('Tree Line Water Clip', player), lambda state: state.has('Flippers', player))
add_additional_rule(world.get_entrance('Dark Tree Line Water Clip', player), lambda state: state.has('Flippers', player)) add_additional_rule(world.get_entrance('Dark Tree Line Water Clip', player), lambda state: state.has('Flippers', player))
# Bunny pocket
if not world.is_tile_swapped(0x00, player):
add_alternate_rule(world.get_entrance("Skull Woods Final Section", player), lambda state: state.can_bunny_pocket(player) and state.has("Fire Rod", player))
if world.is_tile_swapped(0x05, player):
add_alternate_rule(world.get_entrance("DM Hammer Bridge (West)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
add_alternate_rule(world.get_entrance("DM Hammer Bridge (East)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
if not world.is_tile_swapped(0x18, player):
add_alternate_rule(world.get_entrance("Bush Yard Pegs (Inner)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
add_alternate_rule(world.get_entrance("Bush Yard Pegs (Outer)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
if world.is_tile_swapped(0x22, player):
add_alternate_rule(world.get_entrance("Blacksmith Ledge Peg (West)", player), lambda state: state.can_bunny_pocket(player) and state.has("Hammer", player))
def add_alternate_rule(entrance, rule): def add_alternate_rule(entrance, rule):
old_rule = entrance.access_rule old_rule = entrance.access_rule
@@ -335,7 +332,7 @@ def create_no_logic_connections(player, world, connections):
parent = world.get_region(parent_region, player) parent = world.get_region(parent_region, player)
target = world.get_region(target_region, player) target = world.get_region(target_region, player)
connection = Entrance(player, entrance, parent) connection = Entrance(player, entrance, parent)
connection.spot_type = 'Ledge' connection.spot_type = 'OWG'
parent.exits.append(connection) parent.exits.append(connection)
connection.connect(target) connection.connect(target)
@@ -387,6 +384,8 @@ boots_clips_local = [ # (name, from_region, to_region)
('Maze Race Item Get Ledge Clip', 'Maze Race Area', 'Maze Race Prize'), ('Maze Race Item Get Ledge Clip', 'Maze Race Area', 'Maze Race Prize'),
#('Hobo Water Clip', 'Stone Bridge South Area', 'Stone Bridge Water'), # TODO: Doesn't work with OW Free Terrain
('Tree Line Water Clip', 'Tree Line Area', 'Tree Line Water'), #requires flippers ('Tree Line Water Clip', 'Tree Line Area', 'Tree Line Water'), #requires flippers
('Dark Tree Line Water Clip', 'Dark Tree Line Area', 'Dark Tree Line Water'), #requires flippers ('Dark Tree Line Water Clip', 'Dark Tree Line Area', 'Dark Tree Line Water'), #requires flippers
+3 -3
View File
@@ -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.3.3.2' version_number = '0.3.4.0'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''
@@ -200,7 +200,7 @@ def link_overworld(world, player):
categorize_world_regions(world, player) categorize_world_regions(world, player)
if world.logic[player] in ('owglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(world, player) create_owg_connections(world, player)
# crossed shuffle # crossed shuffle
@@ -1486,7 +1486,7 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F
elif exit.connected_region.name not in explored_regions \ elif exit.connected_region.name not in explored_regions \
and (exit.connected_region.type == region.type and (exit.connected_region.type == region.type
or exit.name in OWExitTypes['OWEdge'] or (cross_world and exit.name in (OWExitTypes['Portal'] + OWExitTypes['Mirror']))) \ or exit.name in OWExitTypes['OWEdge'] or (cross_world and exit.name in (OWExitTypes['Portal'] + OWExitTypes['Mirror']))) \
and (not region_rules or exit.access_rule(blank_state)) and (not ignore_ledges or exit.name not in OWExitTypes['Ledge']): and (not region_rules or exit.access_rule(blank_state)) and (not ignore_ledges or exit.name not in OWExitTypes['Ledge', 'OWG']):
explore_region(exit.connected_region.name, exit.connected_region) explore_region(exit.connected_region.name, exit.connected_region)
if build_copy_world: if build_copy_world:
+15 -1
View File
@@ -109,7 +109,21 @@ These are now independent of retro mode and have three options: None, Random, an
# Bug Fixes and Notes # Bug Fixes and Notes
* 1.2.0.22u * 1.4.0.1v
* Key logic: Vanilla key logic fixes. Statically set some HC logic and PoD front door
* 1.4.0.0v
* Generation: fix for bunny walk logic taking up too much memory
* Key Logic: Partial is now the new default
* 1.3.0.9v
* Ganonhunt: playthrough no longer collects crystals
* Vanilla Fill: Uncle weapon is always a sword, medallions for Mire/TR will be vanilla
* Customizer: support shufflebosses/shuffleenemies as well as boss_shuffle/enemy_shuffle
* 1.3.0.8v
* No Logic Standard ER: Rain doors aren't blocked if no logic is enabled.
* MW Progression Balancing: Change to be percentage based instead of raw count. (80% threshold)
* Take anys: Good Bee cave chosen as take any should no longer prevent generation
* Money balancing: Fixed generation issue
1.2.0.22u
* Flute can't be activated in rain state (except glitched modes) (Thanks codemann!) * Flute can't be activated in rain state (except glitched modes) (Thanks codemann!)
* ER: Minor fix for Link's House on DM in Insanity (escape cave should not be re-used) * ER: Minor fix for Link's House on DM in Insanity (escape cave should not be re-used)
* Logic issues: * Logic issues:
+26 -26
View File
@@ -1287,32 +1287,32 @@ bonk_prize_table = {
'Forgotten Forest Southwest Tree': (0x0e, 0x10, False, '', 'Forgotten Forest Area', 'in a tree'), 'Forgotten Forest Southwest Tree': (0x0e, 0x10, False, '', 'Forgotten Forest Area', 'in a tree'),
'Forgotten Forest Central Tree': (0x0f, 0x08, False, '', 'Forgotten Forest Area', 'in a tree'), 'Forgotten Forest Central Tree': (0x0f, 0x08, False, '', 'Forgotten Forest Area', 'in a tree'),
#'Forgotten Forest Southeast Tree': (0x10, 0x04, False, '', 'Forgotten Forest Area', 'in a tree'), #'Forgotten Forest Southeast Tree': (0x10, 0x04, False, '', 'Forgotten Forest Area', 'in a tree'),
'Hyrule Castle Tree': (0x11, 0x10, False, '', 'Hyrule Castle Courtyard', 'in a tree'), 'Hyrule Castle Tree': (0x10, 0x10, False, '', 'Hyrule Castle Courtyard', 'in a tree'),
'Wooden Bridge Tree': (0x12, 0x10, False, '', 'Wooden Bridge Area', 'in a tree'), 'Wooden Bridge Tree': (0x11, 0x10, False, '', 'Wooden Bridge Area', 'in a tree'),
'Eastern Palace Tree': (0x13, 0x10, True, '', 'Eastern Palace Area', 'in a tree'), 'Eastern Palace Tree': (0x12, 0x10, True, '', 'Eastern Palace Area', 'in a tree'),
'Flute Boy South Tree': (0x14, 0x10, True, '', 'Flute Boy Area', 'in a tree'), 'Flute Boy South Tree': (0x13, 0x10, True, '', 'Flute Boy Area', 'in a tree'),
'Flute Boy East Tree': (0x15, 0x08, True, '', 'Flute Boy Area', 'in a tree'), 'Flute Boy East Tree': (0x14, 0x08, True, '', 'Flute Boy Area', 'in a tree'),
'Central Bonk Rocks Tree': (0x16, 0x10, False, '', 'Central Bonk Rocks Area', 'in a tree'), 'Central Bonk Rocks Tree': (0x15, 0x10, False, '', 'Central Bonk Rocks Area', 'in a tree'),
'Tree Line Tree 2': (0x17, 0x10, True, '', 'Tree Line Area', 'in a tree'), 'Tree Line Tree 2': (0x16, 0x10, True, '', 'Tree Line Area', 'in a tree'),
'Tree Line Tree 4': (0x18, 0x08, True, '', 'Tree Line Area', 'in a tree'), 'Tree Line Tree 4': (0x17, 0x08, True, '', 'Tree Line Area', 'in a tree'),
'Flute Boy Approach South Tree': (0x19, 0x10, False, '', 'Flute Boy Approach Area', 'in a tree'), 'Flute Boy Approach South Tree': (0x18, 0x10, False, '', 'Flute Boy Approach Area', 'in a tree'),
'Flute Boy Approach North Tree': (0x1a, 0x08, False, '', 'Flute Boy Approach Area', 'in a tree'), 'Flute Boy Approach North Tree': (0x19, 0x08, False, '', 'Flute Boy Approach Area', 'in a tree'),
'Dark Lumberjack Tree': (0x1b, 0x10, False, '', 'Dark Lumberjack Area', 'in a tree'), 'Dark Lumberjack Tree': (0x1a, 0x10, False, '', 'Dark Lumberjack Area', 'in a tree'),
'Dark Fortune Bonk Rocks (Drop 1)': (0x1c, 0x10, False, '', 'Dark Fortune Area', 'encased in stone'), 'Dark Fortune Bonk Rocks (Drop 1)': (0x1b, 0x10, False, '', 'Dark Fortune Area', 'encased in stone'),
'Dark Fortune Bonk Rocks (Drop 2)': (0x1d, 0x08, False, '', 'Dark Fortune Area', 'encased in stone'), 'Dark Fortune Bonk Rocks (Drop 2)': (0x1c, 0x08, False, '', 'Dark Fortune Area', 'encased in stone'),
'Dark Graveyard West Bonk Rocks': (0x1e, 0x10, False, '', 'Dark Graveyard Area', 'encased in stone'), 'Dark Graveyard West Bonk Rocks': (0x1d, 0x10, False, '', 'Dark Graveyard Area', 'encased in stone'),
'Dark Graveyard North Bonk Rocks': (0x1f, 0x08, False, '', 'Dark Graveyard North', 'encased in stone'), 'Dark Graveyard North Bonk Rocks': (0x1e, 0x08, False, '', 'Dark Graveyard North', 'encased in stone'),
'Dark Graveyard Tomb Bonk Rocks': (0x20, 0x04, False, '', 'Dark Graveyard North', 'encased in stone'), 'Dark Graveyard Tomb Bonk Rocks': (0x1f, 0x04, False, '', 'Dark Graveyard North', 'encased in stone'),
'Qirn Jump West Tree': (0x21, 0x10, False, '', 'Qirn Jump Area', 'in a tree'), 'Qirn Jump West Tree': (0x20, 0x10, False, '', 'Qirn Jump Area', 'in a tree'),
'Qirn Jump East Tree': (0x22, 0x08, False, '', 'Qirn Jump East Bank', 'in a tree'), 'Qirn Jump East Tree': (0x21, 0x08, False, '', 'Qirn Jump East Bank', 'in a tree'),
'Dark Witch Tree': (0x23, 0x10, False, '', 'Dark Witch Area', 'in a tree'), 'Dark Witch Tree': (0x22, 0x10, False, '', 'Dark Witch Area', 'in a tree'),
'Pyramid Tree': (0x24, 0x10, False, '', 'Pyramid Area', 'in a tree'), 'Pyramid Tree': (0x23, 0x10, False, '', 'Pyramid Area', 'in a tree'),
'Palace of Darkness Tree': (0x25, 0x10, False, '', 'Palace of Darkness Area', 'in a tree'), 'Palace of Darkness Tree': (0x24, 0x10, False, '', 'Palace of Darkness Area', 'in a tree'),
'Dark Tree Line Tree 2': (0x26, 0x10, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 2': (0x25, 0x10, False, '', 'Dark Tree Line Area', 'in a tree'),
'Dark Tree Line Tree 3': (0x27, 0x08, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 3': (0x26, 0x08, False, '', 'Dark Tree Line Area', 'in a tree'),
'Dark Tree Line Tree 4': (0x28, 0x04, False, '', 'Dark Tree Line Area', 'in a tree'), 'Dark Tree Line Tree 4': (0x27, 0x04, False, '', 'Dark Tree Line Area', 'in a tree'),
'Hype Cave Statue': (0x29, 0x10, False, '', 'Hype Cave Area', 'encased in stone'), 'Hype Cave Statue': (0x28, 0x10, False, '', 'Hype Cave Area', 'encased in stone'),
'Cold Fairy Statue': (0x2a, 0x02, False, '', 'Good Bee Cave', 'encased in stone') 'Cold Fairy Statue': (0x29, 0x02, False, '', 'Good Bee Cave', 'encased in stone')
} }
bonk_table_by_location_id = {0x2ABB00+(data[0]*6)+3: name for name, data in bonk_prize_table.items()} bonk_table_by_location_id = {0x2ABB00+(data[0]*6)+3: name for name, data in bonk_prize_table.items()}
+11 -10
View File
@@ -38,7 +38,7 @@ from source.dungeon.RoomList import Room0127
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = 'fe9e7870071daa40829c1072829bf30b' RANDOMIZERBASEHASH = '3f08ebba5a2c79b373dbd0c9151ade9b'
class JsonRom(object): class JsonRom(object):
@@ -802,10 +802,10 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
# setting spriteID to D8, a placeholder sprite we use to inform ROM to spawn a dynamic item # setting spriteID to D8, a placeholder sprite we use to inform ROM to spawn a dynamic item
#for address in bonk_addresses: #for address in bonk_addresses:
for address in [b for b in bonk_addresses if b != 0x4D0AE]: # temp fix for screen 1A murahdahla sprite replacement for address in [b for b in bonk_addresses if b != 0x4D0AE]: # temp fix for screen 1A murahdahla sprite replacement
rom.write_byte(address, 0xD8) rom.write_byte(address, 0xD9)
# temporary fix for screen 1A # temporary fix for screen 1A
rom.write_byte(snes_to_pc(0x09AE32), 0xD8) rom.write_byte(snes_to_pc(0x09AE32), 0xD9)
rom.write_byte(snes_to_pc(0x09AE35), 0xD8) rom.write_byte(snes_to_pc(0x09AE35), 0xD9)
rom.write_byte(snes_to_pc(0x06918E), 0x80) # skip good bee bottle check rom.write_byte(snes_to_pc(0x06918E), 0x80) # skip good bee bottle check
@@ -1365,9 +1365,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(0x180211, gametype) # Game type rom.write_byte(0x180211, gametype) # Game type
warningflags = 0x00 # none warningflags = 0x00 # none
if world.logic[player] in ['owglitches', 'nologic']: if world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']:
warningflags |= 0x20 warningflags |= 0x20
if world.logic[player] in ['minorglitches', 'owglitches', 'nologic']: if world.logic[player] in ['minorglitches', 'owglitches', 'hybridglitches', 'nologic']:
warningflags |= 0x40 warningflags |= 0x40
rom.write_byte(0x180212, warningflags) # Warning flags rom.write_byte(0x180212, warningflags) # Warning flags
@@ -1391,7 +1391,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(0x18008F, 0x01 if world.is_atgt_swapped(player) else 0x00) # AT/GT swapped rom.write_byte(0x18008F, 0x01 if world.is_atgt_swapped(player) else 0x00) # AT/GT swapped
rom.write_byte(0xF5D73, 0xF0) # bees are catchable rom.write_byte(0xF5D73, 0xF0) # bees are catchable
rom.write_byte(0xF5F10, 0xF0) # bees are catchable rom.write_byte(0xF5F10, 0xF0) # bees are catchable
rom.write_byte(0x180086, 0x00 if world.aga_randomness else 0x01) # set blue ball and ganon warp randomness rom.write_byte(0x180086, 0x00 if world.aga_randomness[player] else 0x01) # set blue ball and ganon warp randomness
rom.write_byte(0x1800A0, 0x01) # return to light world on s+q without mirror rom.write_byte(0x1800A0, 0x01) # return to light world on s+q without mirror
rom.write_byte(0x1800A1, 0x01) # enable overworld screen transition draining for water level inside swamp rom.write_byte(0x1800A1, 0x01) # enable overworld screen transition draining for water level inside swamp
rom.write_byte(0x180174, 0x01 if world.fix_fake_world[player] else 0x00) rom.write_byte(0x180174, 0x01 if world.fix_fake_world[player] else 0x00)
@@ -1434,10 +1434,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(0x18005F, world.crystals_needed_for_ganon[player]) rom.write_byte(0x18005F, world.crystals_needed_for_ganon[player])
# block HC upstairs doors in rain state in standard mode # block HC upstairs doors in rain state in standard mode
prevent_rain = world.mode[player] == "standard" and world.shuffle[player] != 'vanilla' prevent_rain = world.mode[player] == 'standard' and world.shuffle[player] != 'vanilla' and world.logic[player] != 'nologic'
rom.write_byte(0x18008A, 0x01 if prevent_rain else 0x00) rom.write_byte(0x18008A, 0x01 if prevent_rain else 0x00)
# block sanc door in rain state and the dungeon is not vanilla # block sanc door in rain state and the dungeon is not vanilla
rom.write_byte(0x13f0fa, 0x01 if world.mode[player] == "standard" and world.doorShuffle[player] != 'vanilla' else 0x00) block_sanc = world.mode[player] == 'standard' and world.doorShuffle[player] != 'vanilla' and world.logic[player] != 'nologic'
rom.write_byte(0x13f0fa, 0x01 if block_sanc else 0x00)
if prevent_rain: if prevent_rain:
portals = [world.get_portal('Hyrule Castle East', player), world.get_portal('Hyrule Castle West', player)] portals = [world.get_portal('Hyrule Castle East', player), world.get_portal('Hyrule Castle West', player)]
@@ -1598,7 +1599,7 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills rom.write_byte(0x1800A3, 0x01) # enable correct world setting behaviour after agahnim kills
rom.write_byte(0x1800A4, 0x01 if world.logic[player] != 'nologic' else 0x00) # enable POD EG fix rom.write_byte(0x1800A4, 0x01 if world.logic[player] != 'nologic' else 0x00) # enable POD EG fix
rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill rom.write_byte(0x180042, 0x01 if world.save_and_quit_from_boss else 0x00) # Allow Save and Quit after boss kill
rom.write_byte(0x180358, 0x01 if (world.logic[player] in ['owglitches', 'nologic']) else 0x00) rom.write_byte(0x180358, 0x01 if (world.logic[player] in ['owglitches', 'hybridglitches', 'nologic']) else 0x00)
# remove shield from uncle # remove shield from uncle
rom.write_bytes(0x6D253, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E]) rom.write_bytes(0x6D253, [0x00, 0x00, 0xf6, 0xff, 0x00, 0x0E])
+76 -24
View File
@@ -9,6 +9,7 @@ from Dungeons import dungeon_table
from RoomData import DoorKind from RoomData import DoorKind
from OWEdges import OWExitTypes from OWEdges import OWExitTypes
from OverworldGlitchRules import overworld_glitches_rules from OverworldGlitchRules import overworld_glitches_rules
from UnderworldGlitchRules import underworld_glitches_rules
def set_rules(world, player): def set_rules(world, player):
@@ -32,7 +33,7 @@ def set_rules(world, player):
logging.getLogger('').info('Minor Glitches may be buggy still. No guarantee for proper logic checks.') logging.getLogger('').info('Minor Glitches may be buggy still. No guarantee for proper logic checks.')
no_glitches_rules(world, player) no_glitches_rules(world, player)
fake_flipper_rules(world, player) fake_flipper_rules(world, player)
elif world.logic[player] == 'owglitches': elif world.logic[player] in ['owglitches', 'hybridglitches']:
logging.getLogger('').info('There is a chance OWG has bugged edge case rulesets, especially in inverted. Definitely file a report on GitHub if you see anything strange.') logging.getLogger('').info('There is a chance OWG has bugged edge case rulesets, especially in inverted. Definitely file a report on GitHub if you see anything strange.')
# Initially setting no_glitches_rules to set the baseline rules for some # Initially setting no_glitches_rules to set the baseline rules for some
# entrances. The overworld_glitches_rules set is primarily additive. # entrances. The overworld_glitches_rules set is primarily additive.
@@ -84,6 +85,9 @@ def set_rules(world, player):
if not world.is_copied_world: if not world.is_copied_world:
set_bunny_rules(world, player, world.mode[player] == 'inverted') set_bunny_rules(world, player, world.mode[player] == 'inverted')
# These rules go here because they overwrite/add to some of the above rules
if world.logic[player] == 'hybridglitches':
underworld_glitches_rules(world, player)
def mirrorless_path_to_location(world, startName, targetName, player): def mirrorless_path_to_location(world, startName, targetName, player):
# If Agahnim is defeated then the courtyard needs to be accessible without using the mirror for the mirror offset glitch. # If Agahnim is defeated then the courtyard needs to be accessible without using the mirror for the mirror offset glitch.
@@ -604,10 +608,10 @@ def global_rules(world, player):
set_rule(location, lambda state: state.has('Cane of Somaria', player)) set_rule(location, lambda state: state.has('Cane of Somaria', player))
set_rule(world.get_entrance('TR Final Abyss Balcony Path', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('TR Final Abyss Balcony Path', player), lambda state: state.has('Cane of Somaria', player))
set_rule(world.get_entrance('TR Final Abyss Ledge Path', player), lambda state: state.has('Cane of Somaria', player)) set_rule(world.get_entrance('TR Final Abyss Ledge Path', player), lambda state: state.has('Cane of Somaria', player))
set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player), lambda state: state.has('Cane of Byrna', player) or state.has('Cape', player) or state.has('Mirror Shield', player)) set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Left', player), lambda state: state.can_avoid_lasers(player))
set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player), lambda state: state.has('Cane of Byrna', player) or state.has('Cape', player) or state.has('Mirror Shield', player)) set_rule(world.get_location('Turtle Rock - Eye Bridge - Bottom Right', player), lambda state: state.can_avoid_lasers(player))
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left', player), lambda state: state.has('Cane of Byrna', player) or state.has('Cape', player) or state.has('Mirror Shield', player)) set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Left', player), lambda state: state.can_avoid_lasers(player))
set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right', player), lambda state: state.has('Cane of Byrna', player) or state.has('Cape', player) or state.has('Mirror Shield', player)) set_rule(world.get_location('Turtle Rock - Eye Bridge - Top Right', player), lambda state: state.can_avoid_lasers(player))
set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Boss', player)) set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Boss', player))
set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Prize', player)) set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Prize', player))
@@ -845,6 +849,9 @@ def global_rules(world, player):
set_rule(world.get_entrance('GT Crystal Circles to Ranged Crystal', player), lambda state: state.can_hit_crystal_through_barrier(player) or state.has_blunt_weapon(player) or state.has('Cane of Byrna', player)) # or state.has_beam_sword(player) set_rule(world.get_entrance('GT Crystal Circles to Ranged Crystal', player), lambda state: state.can_hit_crystal_through_barrier(player) or state.has_blunt_weapon(player) or state.has('Cane of Byrna', player)) # or state.has_beam_sword(player)
add_key_logic_rules(world, player) add_key_logic_rules(world, player)
if world.logic[player] == 'hybridglitches':
add_hmg_key_logic_rules(world, player)
# End of door rando rules. # End of door rando rules.
if world.restrict_boss_items[player] != 'none': if world.restrict_boss_items[player] != 'none':
@@ -864,8 +871,11 @@ def global_rules(world, player):
add_mc_rule('Agahnim 1') add_mc_rule('Agahnim 1')
add_mc_rule('Agahnim 2') add_mc_rule('Agahnim 2')
set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player) set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player)
and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Arrows', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12))) # need to light torch a sufficient amount of times
if world.goal[player] != 'ganonhunt':
add_rule(world.get_location('Ganon', player), lambda state: state.has_crystals(world.crystals_needed_for_ganon[player], player))
set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player)) # need to damage ganon to get tiles to drop
@@ -1541,6 +1551,7 @@ def standard_rules(world, player):
world.get_entrance('Uncle S&Q', player).hide_path = True world.get_entrance('Uncle S&Q', player).hide_path = True
set_rule(world.get_entrance('Links House S&Q', player), lambda state: state.has('Zelda Delivered', player)) set_rule(world.get_entrance('Links House S&Q', player), lambda state: state.has('Zelda Delivered', player))
set_rule(world.get_entrance('Sanctuary S&Q', player), lambda state: state.has('Zelda Delivered', player)) set_rule(world.get_entrance('Sanctuary S&Q', player), lambda state: state.has('Zelda Delivered', player))
add_rule(world.get_entrance('Old Man S&Q', player), lambda state: state.has('Zelda Delivered', player))
# these are because of rails # these are because of rails
if world.shuffle[player] != 'vanilla': if world.shuffle[player] != 'vanilla':
# where ever these happen to be # where ever these happen to be
@@ -1640,6 +1651,8 @@ def find_rules_for_zelda_delivery(world, player):
def set_bunny_rules(world, player, inverted): def set_bunny_rules(world, player, inverted):
# regions for the exits of multi-entrace caves/drops that bunny cannot pass # regions for the exits of multi-entrace caves/drops that bunny cannot pass
# Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing. # Note spiral cave may be technically passible, but it would be too absurd to require since OHKO mode is a thing.
all_single_exit_dungeons = ['Eastern Palace', 'Tower of Hera', 'Castle Tower', 'Palace of Darkness', 'Swamp Palace', 'Thieves Town', 'Ice Palace', 'Misery Mire', 'Ganons Tower']
hmg_single_exit_dungeons = [d for d in all_single_exit_dungeons if d not in ['Tower of Hera', 'Misery Mire', 'Thieves Town']]
bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House', bunny_impassable_caves = ['Bumper Cave (top)', 'Bumper Cave (bottom)', 'Two Brothers House',
'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)'] 'Hookshot Cave (Middle)', 'Pyramid', 'Spiral Cave (Top)', 'Fairy Ascension Cave (Drop)']
bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree', bunny_accessible_locations = ['Link\'s Uncle', 'Sahasrahla', 'Sick Kid', 'Lost Woods Hideout', 'Lumberjack Tree',
@@ -1664,6 +1677,9 @@ def set_bunny_rules(world, player, inverted):
'Take - Any # 3 Item 1', 'Take - Any # 3 Item 2', 'Take - Any # 3 Item 1', 'Take - Any # 3 Item 2',
'Take - Any # 4 Item 1', 'Take - Any # 4 Item 2', 'Take - Any # 4 Item 1', 'Take - Any # 4 Item 2',
] ]
bunny_pocket_entrances = ['Skull Woods Final Section', 'Bush Yard Pegs (Inner)', 'Bush Yard Pegs (Outer)',
'DM Hammer Bridge (West)', 'DM Hammer Bridge (East)', 'Blacksmith Ledge Peg (West)'
]
def path_to_access_rule(path, entrance): def path_to_access_rule(path, entrance):
return lambda state: state.can_reach(entrance) and all(rule_func(state) for rule_func in path) return lambda state: state.can_reach(entrance) and all(rule_func(state) for rule_func in path)
@@ -1684,12 +1700,31 @@ def set_bunny_rules(world, player, inverted):
else: else:
return region.is_light_world return region.is_light_world
# Is it possible to do bunny pocket here
def can_bunny_pocket_to(world, entrance_name, player):
def can_activate_bunny_pocket(region):
explored_regions.append(region.name)
for ent in region.entrances:
if (is_link(ent.parent_region) or
(ent.parent_region.type == RegionType.Dungeon and ent.parent_region.name in bunny_revivable_entrances)):
return True
for ent in region.entrances:
if ent.spot_type in ['OWEdge', 'Ledge', 'OpenTerrain'] and ent.parent_region.name not in explored_regions:
if can_activate_bunny_pocket(ent.parent_region):
return True
return False
entrance = world.get_entrance(entrance_name, player)
explored_regions = []
return can_activate_bunny_pocket(entrance.parent_region)
def get_rule_to_add(region, location=None, connecting_entrance=None): def get_rule_to_add(region, location=None, connecting_entrance=None):
# In OWG, a location can potentially be superbunny-mirror accessible or # In OWG, a location can potentially be superbunny-mirror accessible or
# bunny revival accessible. # bunny revival accessible.
if world.logic[player] == 'owglitches': if world.logic[player] in ['owglitches', 'hybridglitches']:
if region.type != RegionType.Dungeon \ if region.type != RegionType.Dungeon \
and (location is None or location.name not in OverworldGlitchRules.get_superbunny_accessible_locations()) \ and (location is None or location.name not in OverworldGlitchRules.superbunny_accessible_locations) \
and not is_link(region): and not is_link(region):
return lambda state: state.has_Pearl(player) return lambda state: state.has_Pearl(player)
else: else:
@@ -1707,25 +1742,30 @@ def set_bunny_rules(world, player, inverted):
# for each such entrance a new option is added that consist of: # for each such entrance a new option is added that consist of:
# a) being able to reach it, and # a) being able to reach it, and
# b) being able to access all entrances from there to `region` # b) being able to access all entrances from there to `region`
seen = {region} queue = deque([(region, [], {region})])
queue = deque([(region, [])]) seen_sets = set([frozenset({region})])
while queue: while queue:
(current, path) = queue.popleft() (current, path, seen) = queue.popleft()
for entrance in current.entrances: for entrance in current.entrances:
new_region = entrance.parent_region new_region = entrance.parent_region
if new_region.type in (RegionType.Cave, RegionType.Dungeon) and new_region in seen: new_seen = seen.union({new_region})
if new_region.type in (RegionType.Cave, RegionType.Dungeon) and new_seen in seen_sets:
continue continue
new_path = path + [entrance.access_rule] new_path = path + [entrance.access_rule]
seen.add(new_region) seen_sets.add(frozenset(new_seen))
if not is_link(new_region): if not is_link(new_region):
if world.logic[player] == 'owglitches': if world.logic[player] in ['owglitches', 'hybridglitches']:
# Is this a bunny pocketable entrance?
if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon: if region.type == RegionType.Dungeon and new_region.type != RegionType.Dungeon:
if entrance.name in OverworldGlitchRules.get_invalid_mirror_bunny_entrances(): if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances:
continue
if entrance.name in bunny_pocket_entrances and not can_bunny_pocket_to(world, entrance.name, player):
continue continue
if entrance.name in drop_dungeon_entrances: if entrance.name in drop_dungeon_entrances:
lobby = entrance.connected_region lobby = entrance.connected_region
else: else:
lobby = next(exit.connected_region for exit in current.exits if exit.connected_region.type == RegionType.Dungeon) portal_regions = [world.get_region(reg, player) for reg in region.dungeon.regions if reg.endswith('Portal')]
lobby = next(reg.connected_region for portal_reg in portal_regions for reg in portal_reg.exits if reg.name.startswith('Enter '))
if lobby.name in bunny_revivable_entrances: if lobby.name in bunny_revivable_entrances:
possible_options.append(path_to_access_rule(new_path, entrance)) possible_options.append(path_to_access_rule(new_path, entrance))
elif lobby.name in superbunny_revivable_entrances: elif lobby.name in superbunny_revivable_entrances:
@@ -1734,26 +1774,29 @@ def set_bunny_rules(world, player, inverted):
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance)) possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance))
continue continue
elif region.type == RegionType.Cave and new_region.type != RegionType.Cave: elif region.type == RegionType.Cave and new_region.type != RegionType.Cave:
if entrance.name in OverworldGlitchRules.get_invalid_mirror_bunny_entrances(): if entrance.name in OverworldGlitchRules.invalid_mirror_bunny_entrances:
continue continue
if region.name in OverworldGlitchRules.get_sword_required_superbunny_mirror_regions(): if entrance.name in bunny_pocket_entrances and not can_bunny_pocket_to(world, entrance.name, player):
continue
if region.name in OverworldGlitchRules.sword_required_superbunny_mirror_regions:
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance)) possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_sword(player)], entrance))
elif region.name in OverworldGlitchRules.get_boots_required_superbunny_mirror_regions(): elif region.name in OverworldGlitchRules.boots_required_superbunny_mirror_regions:
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance)) possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance))
elif location and location.name in OverworldGlitchRules.get_superbunny_accessible_locations(): elif location and location.name in OverworldGlitchRules.superbunny_accessible_locations:
if location.name in OverworldGlitchRules.get_boots_required_superbunny_mirror_locations(): if location.name in OverworldGlitchRules.boots_required_superbunny_mirror_locations:
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance)) possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player) and state.has_Boots(player)], entrance))
elif region.name == 'Kakariko Well (top)': elif region.name == 'Kakariko Well (top)':
possible_options.append(path_to_access_rule(new_path, entrance)) possible_options.append(path_to_access_rule(new_path, entrance))
else: else:
possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player)], entrance)) possible_options.append(path_to_access_rule(new_path + [lambda state: state.has_Mirror(player)], entrance))
continue continue
elif region.name == 'Superbunny Cave (Top)' and new_region.name == 'Superbunny Cave (Bottom)' and location and location.name in OverworldGlitchRules.get_superbunny_accessible_locations(): elif region.name == 'Superbunny Cave (Top)' and new_region.name == 'Superbunny Cave (Bottom)' and location and location.name in OverworldGlitchRules.superbunny_accessible_locations:
possible_options.append(path_to_access_rule(new_path, entrance)) possible_options.append(path_to_access_rule(new_path, entrance))
else: else:
continue continue
if is_bunny(new_region): if is_bunny(new_region):
queue.append((new_region, new_path)) # todo: if not owg or hmg and entrance is in bunny_impassible_doors, then skip this nonsense?
queue.append((new_region, new_path, new_seen))
else: else:
# we have reached pure light world, so we have a new possible option # we have reached pure light world, so we have a new possible option
possible_options.append(path_to_access_rule(new_path, entrance)) possible_options.append(path_to_access_rule(new_path, entrance))
@@ -1761,7 +1804,6 @@ def set_bunny_rules(world, player, inverted):
# Add requirements for bunny-impassible caves if they occur in the light world # Add requirements for bunny-impassible caves if they occur in the light world
for region in [world.get_region(name, player) for name in bunny_impassable_caves]: for region in [world.get_region(name, player) for name in bunny_impassable_caves]:
if not is_bunny(region): if not is_bunny(region):
continue continue
rule = get_rule_to_add(region) rule = get_rule_to_add(region)
@@ -1796,6 +1838,11 @@ def set_bunny_rules(world, player, inverted):
continue continue
add_rule(location, get_rule_to_add(region, location)) add_rule(location, get_rule_to_add(region, location))
for ent_name in bunny_pocket_entrances:
bunny_exit = world.get_entrance(ent_name, player)
if bunny_exit.connected_region and is_bunny(bunny_exit.parent_region) and not can_bunny_pocket_to(world, ent_name, player):
add_rule(bunny_exit, lambda state: state.has_Pearl(player))
drop_dungeon_entrances = { drop_dungeon_entrances = {
"Sewer Drop", "Sewer Drop",
@@ -1923,6 +1970,11 @@ bunny_impassible_if_trapped = {
'GT Speed Torch WN', 'Ice Lobby SE' 'GT Speed Torch WN', 'Ice Lobby SE'
} }
def add_hmg_key_logic_rules(world, player):
for toh_loc in world.key_logic[player]['Tower of Hera'].bk_restricted:
set_always_allow(world.get_location(toh_loc.name, player), allow_big_key_in_big_chest('Big Key (Tower of Hera)', player))
set_always_allow(world.get_location('Swamp Palace - Entrance', player), allow_big_key_in_big_chest('Big Key (Swamp Palace)', 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]
+278
View File
@@ -0,0 +1,278 @@
from BaseClasses import Entrance
import Rules
from OverworldGlitchRules import create_no_logic_connections
kikiskip_spots = [("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Portal")]
mireheraswamp_spots = [
("Mire to Hera Clip", "Mire Torches Top", "Hera Portal"),
("Hera to Swamp Clip", "Mire Torches Top", "Swamp Portal"),
]
icepalace_spots = [("Ice Lobby Clip", "Ice Portal", "Ice Bomb Drop")]
thievesdesert_spots = [
("Thieves to Desert Clip", "Thieves Attic", "Desert West Portal"),
("Thieves to Desert Clip", "Thieves Attic", "Desert South Portal"),
("Thieves to Desert Clip", "Thieves Attic", "Desert East Portal"),
]
specrock_spots = [("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave (Top)")]
paradox_spots = [("Paradox Front Teleport", "Paradox Cave Front", "Paradox Cave Chest Area")]
# We need to make connectors at a separate time from the connections, because of how dungeons are linked to regions
kikiskip_connectors = [("Kiki Skip", "Spectacle Rock Cave (Bottom)", "Palace of Darkness Exit")]
mireheraswamp_connectors = [
("Mire to Hera Clip", "Mire Torches Top", "Tower of Hera Exit"),
("Mire to Hera Clip", "Mire Torches Top", "Swamp Palace Exit"),
]
thievesdesert_connectors = [
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (West)"),
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (South)"),
("Thieves to Desert Clip", "Thieves Attic", "Desert Palace Exit (East)"),
]
specrock_connectors = [
("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave Exit (Top)"),
("Spec Rock Clip", "Spectacle Rock Cave (Peak)", "Spectacle Rock Cave Exit"),
]
# Create connections between dungeons/locations
def create_hybridmajor_connections(world, player):
for spots in [
kikiskip_spots,
mireheraswamp_spots,
icepalace_spots,
thievesdesert_spots,
specrock_spots,
paradox_spots,
]:
create_no_logic_connections(player, world, spots)
# Turn dungeons into connectors
def create_hybridmajor_connectors(world, player):
for connectors in [
kikiskip_connectors,
mireheraswamp_connectors,
thievesdesert_connectors,
specrock_connectors,
]:
new_connectors = [(connector[0], connector[1], world.get_entrance(connector[2], player).connected_region) for connector in connectors]
create_no_logic_connections(player, world, new_connectors)
# 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.
def fake_pearl_state(state, player):
if state.has("Moon Pearl", player):
return state
fake_state = state.copy()
fake_state.prog_items["Moon Pearl", player] += 1
return fake_state
# Sets the rules on where we can actually go using this clip.
# Behavior differs based on what type of ER shuffle we're playing.
def dungeon_reentry_rules(world, player, clip: Entrance, dungeon_region: str, dungeon_exit: str):
fix_dungeon_exits = world.fix_palaceofdarkness_exit[player]
fix_fake_worlds = world.fix_fake_world[player]
dungeon_entrance = [r for r in world.get_region(dungeon_region, player).entrances if r.name != clip.name][0]
if not fix_dungeon_exits: # vanilla, simple, restricted, dungeonssimple; should never have fake worlds fix
# Dungeons are only shuffled among themselves. We need to check SW, MM, and AT because they can't be reentered trivially.
# entrance doesn't exist until you fire rod it from the other side
if dungeon_entrance.name == "Skull Woods Final Section":
Rules.set_rule(clip, lambda state: False)
elif dungeon_entrance.name == "Misery Mire":
if world.swords[player] == "swordless":
Rules.add_rule(clip, lambda state: state.has_misery_mire_medallion(player))
else:
Rules.add_rule(clip, lambda state: state.has_sword(player) and state.has_misery_mire_medallion(player))
elif dungeon_entrance.name == "Agahnims Tower":
Rules.add_rule(
clip,
lambda state: state.has("Cape", player)
or state.has_beam_sword(player)
or state.has("Beat Agahnim 1", player),
)
# Then we set a restriction on exiting the dungeon, so you can't leave unless you got in normally.
Rules.add_rule(world.get_entrance(dungeon_exit, player), lambda state: dungeon_entrance.can_reach(state))
elif not fix_fake_worlds: # full, dungeonsfull; fixed dungeon exits, but no fake worlds fix
# Entry requires the entrance's requirements plus a fake pearl, but you don't gain logical access to the surrounding region.
Rules.add_rule(clip, lambda state: dungeon_entrance.access_rule(fake_pearl_state(state, player)))
# exiting restriction
Rules.add_rule(world.get_entrance(dungeon_exit, player), lambda state: dungeon_entrance.can_reach(state))
# Otherwise, the shuffle type is lean, lite, crossed, or insanity; all of these do not need additional rules on where we can go,
# since the clip links directly to the exterior region.
def underworld_glitches_rules(world, player):
# Ice Palace Entrance Clip, needs bombs or cane of somaria to exit bomb drop room
Rules.add_rule(
world.get_entrance("Ice Bomb Drop SE", player),
lambda state: state.can_dash_clip(world.get_region("Ice Lobby", player), player)
and (state.can_use_bombs(player) or state.has("Cane of Somaria", player)),
combine="or",
)
# Kiki Skip
kks = world.get_entrance("Kiki Skip", player)
Rules.set_rule(kks, lambda state: state.can_bomb_clip(kks.parent_region, player))
dungeon_reentry_rules(world, player, kks, "Palace of Darkness Portal", "Palace of Darkness Exit")
# Mire -> Hera -> Swamp
def mire_clip(state):
return state.can_reach("Mire Torches Top", "Region", player) and state.can_dash_clip(
world.get_region("Mire Torches Top", player), player
)
def hera_clip(state):
return state.can_reach("Hera 4F", "Region", player) and state.can_dash_clip(
world.get_region("Hera 4F", player), player
)
Rules.add_rule(
world.get_entrance("Hera Startile Corner NW", player),
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
combine="or",
)
Rules.add_rule(
world.get_location("Tower of Hera - Big Chest", player),
lambda state: mire_clip(state) and state.has("Big Key (Misery Mire)", player),
combine="or",
)
mire_to_hera = world.get_entrance("Mire to Hera Clip", player)
mire_to_swamp = world.get_entrance("Hera to Swamp Clip", player)
Rules.set_rule(mire_to_hera, mire_clip)
Rules.set_rule(mire_to_swamp, lambda state: mire_clip(state) and state.has("Flippers", player))
# Using the entrances for various ER types. Hera -> Swamp never matters because you can only logically traverse with the mire keys
dungeon_reentry_rules(world, player, mire_to_hera, "Hera Lobby", "Tower of Hera Exit")
dungeon_reentry_rules(world, player, mire_to_swamp, "Swamp Lobby", "Swamp Palace Exit")
# We need to set _all_ swamp doors to be openable with mire keys, otherwise the small key can't be behind them - 6 keys because of Pots
# Flippers required for all of these doors to prevent locks when flooding
for door in [
"Swamp Trench 1 Approach ES",
"Swamp Hammer Switch SW",
"Swamp Entrance Down Stairs",
"Swamp Pot Row WS",
"Swamp Trench 1 Key Ledge NW",
"Swamp Hub WN",
"Swamp Hub North Ledge N",
"Swamp Crystal Switch EN",
"Swamp Push Statue S",
"Swamp Waterway NW",
"Swamp T SW",
]:
Rules.add_rule(
world.get_entrance(door, player),
lambda state: mire_clip(state)
and state.has("Small Key (Misery Mire)", player, count=6)
and state.has("Flippers", player),
combine="or",
)
# Rules.add_rule(world.get_entrance(door, player), lambda state: mire_clip(state) and state.has('Flippers', player), combine="or")
Rules.add_rule(
world.get_location("Trench 1 Switch", player), lambda state: mire_clip(state) or hera_clip(state), combine="or"
)
# Build the rule for SP moat.
# We need to be able to s+q to old man, then go to either Mire or Hera at either Hera or GT.
# First we require a certain type of entrance shuffle, then build the rule from its pieces.
if not world.swamp_patch_required[player]:
if world.shuffle[player] in [
"vanilla",
"dungeonssimple",
"dungeonsfull",
"dungeonscrossed",
]:
rule_map = {
"Mire Portal": (lambda state: state.can_reach("Mire Torches Top", "Entrance", player)),
"Hera Portal": (lambda state: state.can_reach("Hera Startile Corner NW", "Entrance", player)),
}
inverted = world.mode[player] == "inverted"
def hera_rule(state):
return (state.has("Moon Pearl", player) or not inverted) and rule_map.get(
world.get_entrance("Tower of Hera", player).connected_region.name, lambda state: False
)(state)
def gt_rule(state):
return (state.has("Moon Pearl", player) or inverted) and rule_map.get(
world.get_entrance(("Ganons Tower"), player).connected_region.name, lambda state: False
)(state)
def mirrorless_moat_rule(state):
return (
state.can_reach("Old Man S&Q", "Entrance", player)
and state.has("Flippers", player)
and mire_clip(state)
and (hera_rule(state) or gt_rule(state))
)
Rules.add_rule(
world.get_entrance("Swamp Lobby Moat", player), lambda state: mirrorless_moat_rule(state), combine="or"
)
# Thieves -> Desert
Rules.add_rule(
world.get_entrance("Thieves to Desert Clip", player),
lambda state: state.can_dash_clip(world.get_region("Thieves Attic", player), player),
)
dungeon_reentry_rules(
world,
player,
world.get_entrance("Thieves to Desert Clip", player),
"Desert West Portal",
"Desert Palace Exit (West)",
)
dungeon_reentry_rules(
world,
player,
world.get_entrance("Thieves to Desert Clip", player),
"Desert South Portal",
"Desert Palace Exit (South)",
)
dungeon_reentry_rules(
world,
player,
world.get_entrance("Thieves to Desert Clip", player),
"Desert East Portal",
"Desert Palace Exit (East)",
)
# Collecting left chests in Paradox Cave using a dash clip -> dash citrus, 1f right, teleport up
paradox_left_chests = ["Paradox Cave Lower - Far Left", "Paradox Cave Lower - Left", "Paradox Cave Lower - Middle"]
for location in paradox_left_chests:
Rules.add_rule(
world.get_location(location, player),
lambda state: state.can_dash_clip(world.get_location(location, player).parent_region, player),
"or",
)
# Collecting right chests in Paradox Cave using a dash clip on left side -> dash citrus, 1f right, teleport up, then hitting the switch
paradox_right_chests = ["Paradox Cave Lower - Right", "Paradox Cave Lower - Far Right"]
for location in paradox_right_chests:
Rules.add_rule(
world.get_location(location, player),
lambda state: (
state.can_dash_clip(world.get_location(location, player).parent_region, player)
and state.can_hit_crystal(player)
),
"or",
)
+180 -152
View File
@@ -161,15 +161,22 @@ jsl.l OWWorldCheck16 : nop
org $02b16e ; AND #$3F : ORA 7EF3CA org $02b16e ; AND #$3F : ORA 7EF3CA
and #$7f : eor #$40 : nop #2 and #$7f : eor #$40 : nop #2
org $06AD4C org $09C3C4
jsl.l OWBonkDrops : nop #4 jsl.l OWBonkDropPrepSprite : nop #2
org $1EDE6F org $09C801
jsl.l OWBonkGoodBeeDrop : bra + jsl.l OWBonkDropPrepSprite : nop #2
org $06D052
jsl.l OWBonkDropSparkle
org $06AD49
jsl.l OWBonkDropsOverworld : nop
org $1EDE6A
jsl.l OWBonkDropSparkle : BNE GoldBee_Dormant_exit
jsl.l OWBonkDropsUnderworld : bra +
GoldBee_SpawnSelf_SetProperties: GoldBee_SpawnSelf_SetProperties:
phb : lda.b #$1E : pha : plb ; switch to bank 1E phb : lda.b #$1E : pha : plb ; switch to bank 1E
jsr GoldBee_SpawnSelf+12 jsr GoldBee_SpawnSelf+12
plb : rtl plb : rtl
nop #3 nop #2
+ +
;Code ;Code
@@ -408,7 +415,66 @@ LoadMapDarkOrMixed:
dw $0400+$0210 ; bottom right dw $0400+$0210 ; bottom right
} }
OWBonkGoodBeeDrop: OWBonkDropPrepSprite:
{
LDA.b $1B : BEQ +
LDA.w $0FB5 ; what we wrote over
PHA
BRA .continue
+
STZ.w $0F20,X : STZ.w $0E30,X ; what we wrote over
PHA
.continue
LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BEQ .return
+ LDA.w $0E20,X : CMP.b #$D9 : BNE +
LDA.b #$03 : STA.w $0F20,X
BRA .prep
+ CMP.b #$B2 : BEQ .prep
PLA : RTL
.prep
STZ.w !SPRITE_REDRAW,X
PHB : PHK : PLB : PHY
TXY : JSR OWBonkDropLookup : BCC .done
; found match ; X = rec + 1
INX : LDA.w OWBonkPrizeData,X : PHA
JSR OWBonkDropCollected : PLA : BCC .done
TYX : LDA.b #$01 : STA.w !SPRITE_REDRAW,X
.done
TYX : PLY : PLB
.return
PLA : RTL
}
OWBonkDropSparkle:
{
LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BEQ .nosparkle
LDA.w $0E90,X : BEQ .nosparkle
LDA.w !SPRITE_REDRAW,X : BNE .nosparkle
JSL Sprite_SpawnSparkleGarnish
; move sparkle down 1 tile
PHX : TYX : PLY
LDA.l $7FF81E,X : CLC : ADC.b #$10 : STA.l $7FF81E,X
LDA.l $7FF85A,X : ADC.b #$00 : STA.l $7FF85A,X
PHY : TXY : PLX
.nosparkle
LDA $0E20,X : CMP.b #$D9 : BEQ .greenrupee
CMP.b #$B2 : BEQ .goodbee
RTL
.goodbee
LDA $0E90,X ; what we wrote over
RTL
.greenrupee
JSL Sprite_DrawRippleIfInWater ; what we wrote over
RTL
}
OWBonkDropsUnderworld:
{ {
LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE .shuffled LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE .shuffled
.vanilla ; what we wrote over .vanilla ; what we wrote over
@@ -416,20 +482,63 @@ OWBonkGoodBeeDrop:
LDA.l BottleContentsOne : ORA.l BottleContentsTwo LDA.l BottleContentsOne : ORA.l BottleContentsTwo
ORA.l BottleContentsThree : ORA.l BottleContentsFour ORA.l BottleContentsThree : ORA.l BottleContentsFour
RTL RTL
.shuffled .shuffled
LDA.w $0DD0,X : BNE + LDA.w $0DD0,X : BNE +
JMP .return+1 BRA .return+1
+ PHY : TXY + PHY : TXY
LDA.l RoomDataWRAM[$0120].high : AND.b #$02 : PHA : BNE + ; check if collected JSL OWBonkDrops
LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx
+
LDA.l OWBonkPrizeTable[42].mw_player : BEQ + ; multiworld item
LDA.l OWBonkPrizeTable[42].loot
JMP .spawn_item
+
.determine_type ; S = Collected .return
LDA.l OWBonkPrizeTable[42].loot ; A = item id PLY
LDA #$08 ; makes original good bee not spawn
RTL
}
OWBonkDropsOverworld:
{
LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE .shuffled
BRA .vanilla
.shuffled
LDA.w $0DD0,Y : BNE +
BRA .vanilla
+ LDA.w $0E20,Y : CMP.b #$D9 : BEQ +
BRA .vanilla+3
+
LDA.b #$00 : STA.w $0F20,Y ; restore proper layer
JSL OWBonkDrops
.vanilla
LDA.w $0E20,Y : CMP.b #$D8 ; what we wrote over
RTL
}
OWBonkDrops:
{
PHB : PHK : PLB
LDA.b $1B : BEQ +
LDX.b #((UWBonkPrizeData-OWBonkPrizeData)+1)
BRA .found_match
+
JSR OWBonkDropLookup : BCS .found_match
JMP .return+2
.found_match
INX : LDA.w OWBonkPrizeData,X : PHX : PHA ; S = FlagBitmask, X (row + 2)
JSR OWBonkDropCollected : PHA : BCS .load_item_and_mw ; S = Collected, FlagBitmask, X (row + 2)
LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx
; JSLSpriteSFX_QueueSFX3WithPan
.load_item_and_mw
LDA 3,S : TAX : INX : LDA.w OWBonkPrizeData,X
PHA : INX : LDA.w OWBonkPrizeData,X : BEQ +
; multiworld item
DEX : PLA ; A = item id; X = row + 3
JMP .spawn_item
+ DEX : PLA ; A = item id; X = row + 3
.determine_type ; A = item id; X = row + 3; S = Collected, FlagBitmask, X (row + 2)
CMP.b #$B0 : BNE + CMP.b #$B0 : BNE +
LDA.b #$79 : JMP .sprite_transform ; transform to bees LDA.b #$79 : JMP .sprite_transform ; transform to bees
+ CMP.b #$42 : BNE + + CMP.b #$42 : BNE +
@@ -461,140 +570,12 @@ OWBonkGoodBeeDrop:
LDA.b #$AC : BRA .sprite_transform ; transform to apples LDA.b #$AC : BRA .sprite_transform ; transform to apples
+ CMP.b #$B2 : BNE + + CMP.b #$B2 : BNE +
LDA.b #$E3 : BRA .sprite_transform ; transform to fairy LDA.b #$E3 : BRA .sprite_transform ; transform to fairy
+ CMP.b #$B3 : BNE .spawn_item
INX : INX : LDA.l OWBonkPrizeTable[42].vert_offset
CLC : ADC.b #$08 : PHA
LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y
LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX
LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken
.sprite_transform
JSL.l OWBonkSpritePrep
.mark_collected ; S = Collected
PLA : BNE +
LDA.l RoomDataWRAM[$0120].high : ORA.b #$02 : STA.l RoomDataWRAM[$0120].high
REP #$20
LDA.l TotalItemCounter : INC : STA.l TotalItemCounter
SEP #$20
+ BRA .return
; spawn itemget item
.spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected
PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return
+ PHA
LDA.b #$01 : STA !FORCE_HEART_SPAWN
LDA.b #$EB : STA.l $7FFE00
JSL Sprite_SpawnDynamically+15 ; +15 to skip finding a new slot, use existing sprite
LDA.b #$01 : STA.w !SPRITE_REDRAW,Y
PLA : STA.w $0E80,Y
; affects the rate the item moves in the Y/X direction
LDA.b #$00 : STA.w $0D40,Y
LDA.b #$0A : STA.w $0D50,Y
LDA.b #$1A : STA.w $0F80,Y ; amount of force (gives height to the arch)
LDA.b #$FF : STA.w $0B58,Y ; stun timer
LDA.b #$30 : STA.w $0F10,Y ; aux delay timer 4 ?? dunno what that means
LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on
; sets the tile type that is underneath the sprite, water
TYX : LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this
; sets OW event bitmask flag, uses free RAM
LDA.l OWBonkPrizeTable[42].flag : STA.w $0ED0,Y
; determines the initial spawn point of item
LDA.w $0D00,Y : SEC : SBC.l OWBonkPrizeTable[42].vert_offset : STA.w $0D00,Y
LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y
.return
PLY
LDA #$08 ; makes original good bee not spawn
RTL
}
; Y = sprite slot index of bonk sprite
OWBonkDrops:
{
CMP.b #$D8 : BEQ +
RTL
+ LDA.l OWFlags+1 : AND.b #!FLAG_OW_BONKDROP : BNE +
JSL.l Sprite_TransmuteToBomb : RTL
+ LDA.w $0DD0,Y : BNE +
RTL
+
; loop thru rando bonk table to find match
PHB : PHK : PLB
LDA.b $8A
LDX.b #(41*6) ; 41 bonk items, 6 bytes each
- CMP.w OWBonkPrizeData,X : BNE +
INX
LDA.w $0D10,Y : LSR A : LSR A : LSR A : LSR A
EOR.w $0D00,Y : CMP.w OWBonkPrizeData,X : BNE ++ ; X = row + 1
BRA .found_match
++ DEX : LDA.b $8A
+ CPX.b #$00 : BNE +
PLB : RTL
+ DEX : DEX : DEX : DEX : DEX : DEX : BRA -
.found_match
INX : LDA.w OWBonkPrizeData,X : PHX : PHA ; S = FlagBitmask, X (row + 2)
LDX.b $8A : LDA.l OverworldEventDataWRAM,X : AND 1,S : PHA : BNE + ; S = Collected, FlagBitmask, X (row + 2)
LDA.b #$1B : STA $12F ; JSL Sound_SetSfx3PanLong ; seems that when you bonk, there is a pending bonk sfx, so we clear that out and replace with reveal secret sfx
+
LDA 3,S : TAX : INX : LDA.w OWBonkPrizeData,X
PHA : INX : LDA.w OWBonkPrizeData,X : BEQ +
; multiworld item
DEX : PLA ; X = row + 3
JMP .spawn_item
+ DEX : PLA ; X = row + 3
.determine_type ; A = item id ; S = Collected, FlagBitmask, X (row + 2)
CMP.b #$B0 : BNE +
LDA.b #$79 : JMP .sprite_transform ; transform to bees
+ CMP.b #$42 : BNE +
JSL.l Sprite_TransmuteToBomb ; transform a heart to bomb, vanilla behavior
JMP .mark_collected
+ CMP.b #$34 : BNE +
LDA.b #$D9 : CLC : JMP .sprite_transform ; transform to single rupee
+ CMP.b #$35 : BNE +
LDA.b #$DA : CLC : JMP .sprite_transform ; transform to blue rupee
+ CMP.b #$36 : BNE +
LDA.b #$DB : CLC : BRA .sprite_transform ; transform to red rupee
+ CMP.b #$27 : BNE +
LDA.b #$DC : CLC : BRA .sprite_transform ; transform to 1 bomb
+ CMP.b #$28 : BNE +
LDA.b #$DD : CLC : BRA .sprite_transform ; transform to 4 bombs
+ CMP.b #$31 : BNE +
LDA.b #$DE : CLC : BRA .sprite_transform ; transform to 8 bombs
+ CMP.b #$45 : BNE +
LDA.b #$DF : CLC : BRA .sprite_transform ; transform to small magic
+ CMP.b #$B4 : BNE +
LDA.b #$E0 : CLC : BRA .sprite_transform ; transform to big magic
+ CMP.b #$B5 : BNE +
LDA.b #$79 : JSL.l OWBonkSpritePrep
JSL.l GoldBee_SpawnSelf_SetProperties ; transform to good bee
BRA .mark_collected
+ CMP.b #$44 : BNE +
LDA.b #$E2 : CLC : BRA .sprite_transform ; transform to 10 arrows
+ CMP.b #$B1 : BNE +
LDA.b #$AC : BRA .sprite_transform ; transform to apples
+ CMP.b #$B2 : BNE +
LDA.b #$E3 : BRA .sprite_transform ; transform to fairy
+ CMP.b #$B3 : BNE .spawn_item + CMP.b #$B3 : BNE .spawn_item
INX : INX : LDA.w OWBonkPrizeData,X ; X = row + 5 INX : INX : LDA.w OWBonkPrizeData,X ; X = row + 5
CLC : ADC.b #$08 : PHA CLC : ADC.b #$08 : PHA
LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y LDA.w $0D00,Y : SEC : SBC.b 1,S : STA.w $0D00,Y
LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX LDA.w $0D20,Y : SBC.b #$00 : STA.w $0D20,Y : PLX
LDA.b #$0B : SEC ; BRA .sprite_transform ; transform to chicken LDA.b #$0B ; BRA .sprite_transform ; transform to chicken
.sprite_transform .sprite_transform
JSL.l OWBonkSpritePrep JSL.l OWBonkSpritePrep
@@ -602,16 +583,22 @@ OWBonkDrops:
.mark_collected ; S = Collected, FlagBitmask, X (row + 2) .mark_collected ; S = Collected, FlagBitmask, X (row + 2)
PLA : BNE + ; S = FlagBitmask, X (row + 2) PLA : BNE + ; S = FlagBitmask, X (row + 2)
TYX : JSL Sprite_IsOnscreen : BCC + TYX : JSL Sprite_IsOnscreen : BCC +
LDA.b $1B : BEQ ++
LDA.l RoomDataWRAM[$0120].high : ORA 1,S : STA.l RoomDataWRAM[$0120].high
LDA.w $0400 : ORA 1,S : STA.w $0400
BRA .increment_collection
++
LDX.b $8A : LDA.l OverworldEventDataWRAM,X : ORA 1,S : STA.l OverworldEventDataWRAM,X LDX.b $8A : LDA.l OverworldEventDataWRAM,X : ORA 1,S : STA.l OverworldEventDataWRAM,X
.increment_collection
REP #$20 REP #$20
LDA.l TotalItemCounter : INC : STA.l TotalItemCounter LDA.l TotalItemCounter : INC : STA.l TotalItemCounter
SEP #$20 SEP #$20
+ JMP .return + BRA .return
; spawn itemget item ; spawn itemget item
.spawn_item ; A = item id ; Y = tree sprite slot ; S = Collected, FlagBitmask, X (row + 2) .spawn_item ; A = item id ; Y = bonk sprite slot ; S = Collected, FlagBitmask, X (row + 2)
PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : JMP .return ; S = FlagBitmask, X (row + 2) PLX : BEQ + : LDA.b #$00 : STA.w $0DD0,Y : BRA .return ; S = FlagBitmask, X (row + 2)
+ PHA + PHA
LDA.b #$01 : STA !FORCE_HEART_SPAWN LDA.b #$01 : STA !FORCE_HEART_SPAWN
@@ -633,7 +620,12 @@ OWBonkDrops:
LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on LDA.b #$00 : STA.w $0F20,Y ; layer the sprite is on
; sets OW event bitmask flag, uses free RAM LDA.b $1B : BEQ +
; sets the tile type that is underneath the sprite, water
TYX : LDA.b #$09 : STA.l $7FF9C2,X ; TODO: Figure out how to get the game to set this
+
; sets bitmask flag, uses free RAM
PLA : STA.w $0ED0,Y ; S = X (row + 2) PLA : STA.w $0ED0,Y ; S = X (row + 2)
; determines the initial spawn point of item ; determines the initial spawn point of item
@@ -641,10 +633,44 @@ OWBonkDrops:
LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y LDA.w $0D00,Y : SEC : SBC.w OWBonkPrizeData,X : STA.w $0D00,Y
LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y LDA.w $0D20,Y : SBC #$00 : STA.w $0D20,Y
PLB : RTL BRA .return+2
.return .return
PLA : PLA : PLB : RTL PLA : PLA : PLB
RTL
}
; Y = sprite slot; returns X = row + 1
OWBonkDropLookup:
{
; loop thru rando bonk table to find match
LDA.b $8A
LDX.b #((UWBonkPrizeData-OWBonkPrizeData)-sizeof(OWBonkPrizeTable)) ; 41 bonk items, 6 bytes each
- CMP.w OWBonkPrizeData,X : BNE +
INX
LDA.w $0D10,Y : LSR A : LSR A : LSR A : LSR A
EOR.w $0D00,Y : CMP.w OWBonkPrizeData,X : BNE ++ ; X = row + 1
SEC : RTS
++ DEX : LDA.b $8A
+ CPX.b #$00 : BNE +
CLC : RTS
+ DEX : DEX : DEX : DEX : DEX : DEX : BRA -
}
; S = FlagBitmask ; returns SEC if collected
OWBonkDropCollected:
{
; check if collected
CLC
LDA.b $1B : BEQ +
LDA.l RoomDataWRAM[$0120].high : AND.b 3,S : BEQ .return ; S = Collected, FlagBitmask, X (row + 2)
SEC : RTS
+
LDX.b $8A : LDA.l OverworldEventDataWRAM,X : AND 3,S : BEQ .return ; S = Collected, FlagBitmask, X (row + 2)
SEC : RTS
.return
RTS
} }
; A = SpriteID, Y = Sprite Slot Index, X = free/overwritten ; A = SpriteID, Y = Sprite Slot Index, X = free/overwritten
@@ -1717,7 +1743,7 @@ db $18, $a8, $10, $b2, $00, $20
db $18, $36, $08, $35, $00, $20 db $18, $36, $08, $35, $00, $20
db $1a, $8a, $10, $42, $00, $20 db $1a, $8a, $10, $42, $00, $20
db $1a, $1d, $08, $b2, $00, $20 db $1a, $1d, $08, $b2, $00, $20
db $ff, $77, $04, $35, $00, $20 ; pre aga ONLY ; hijacked murahdahla bonk tree ;db $1a, $77, $04, $35, $00, $20 ; pre aga ONLY ; hijacked murahdahla bonk tree
db $1b, $46, $10, $b1, $00, $10 db $1b, $46, $10, $b1, $00, $10
db $1d, $6b, $10, $b1, $00, $20 db $1d, $6b, $10, $b1, $00, $20
db $1e, $72, $10, $b2, $00, $20 db $1e, $72, $10, $b2, $00, $20
@@ -1728,6 +1754,7 @@ db $2e, $9c, $10, $b2, $00, $20
db $2e, $b4, $08, $b0, $00, $20 db $2e, $b4, $08, $b0, $00, $20
db $32, $29, $10, $42, $00, $20 db $32, $29, $10, $42, $00, $20
db $32, $9a, $08, $b2, $00, $20 db $32, $9a, $08, $b2, $00, $20
;db $34, $xx, $10, $xx, $00, $1c ; pre aga ONLY
db $42, $66, $10, $b2, $00, $20 db $42, $66, $10, $b2, $00, $20
db $51, $08, $10, $b2, $00, $04 db $51, $08, $10, $b2, $00, $04
db $51, $09, $08, $b2, $00, $04 db $51, $09, $08, $b2, $00, $04
@@ -1743,6 +1770,7 @@ db $6e, $8c, $10, $35, $00, $10
db $6e, $90, $08, $b0, $00, $10 db $6e, $90, $08, $b0, $00, $10
db $6e, $a4, $04, $b1, $00, $10 db $6e, $a4, $04, $b1, $00, $10
db $74, $4e, $10, $b1, $00, $1c db $74, $4e, $10, $b1, $00, $1c
UWBonkPrizeData:
db $ff, $00, $02, $b5, $00, $08 db $ff, $00, $02, $b5, $00, $08
; temporary fix - murahdahla replaces one of the bonk tree prizes ; temporary fix - murahdahla replaces one of the bonk tree prizes
Binary file not shown.
+5 -1
View File
@@ -6,6 +6,10 @@ This can also be used to roll a mystery or mutli-mystery seed via the GUI. [Exam
The cli includes a couple arguments to help: The cli includes a couple arguments to help:
`--print_template_yaml` will create a yaml file based on the settings used. This does not contain any seed specific information.
Present on the GUI as `Export Yaml` on the bottom.
`--print_custom_yaml` will create a yaml file based on the seed rolled. Treat it like a spoiler. `--print_custom_yaml` will create a yaml file based on the seed rolled. Treat it like a spoiler.
`--customizer` takes a file as an argument. `--customizer` takes a file as an argument.
@@ -44,7 +48,7 @@ Start inventory is not supported here. It has a separate section.
###### Not Yet Implemented ###### Not Yet Implemented
Rom/Adjust flags like sprite, quickswap are not outputing with the print_custom_yaml settings Rom/Adjust flags like sprite, quickswap are not outputing with the print_template_yaml or print_custom_yaml settings
### item_pool ### item_pool
+9 -4
View File
@@ -23,6 +23,7 @@
"noglitches", "noglitches",
"minorglitches", "minorglitches",
"owglitches", "owglitches",
"hybridglitches",
"nologic" "nologic"
] ]
}, },
@@ -575,11 +576,15 @@
"action": "store_true", "action": "store_true",
"type": "bool" "type": "bool"
}, },
"saveonexit": { "aga_randomness": {
"action": "store_false",
"type": "bool"
},
"settingsonload": {
"choices": [ "choices": [
"ask", "default",
"always", "saved",
"never" "lastused"
] ]
}, },
"outputname": {}, "outputname": {},
+5 -2
View File
@@ -2,7 +2,7 @@
"cli": { "cli": {
"yes": "Yes", "yes": "Yes",
"no": "No", "no": "No",
"app.title": "ALttP Door Randomizer Version %s : --seed %s --code %s", "app.title": "ALttP Overworld Randomizer Version %s : --seed %s --code %s",
"version": "Version", "version": "Version",
"seed": "Seed", "seed": "Seed",
"player": "Player", "player": "Player",
@@ -56,7 +56,8 @@
"building.collection.spheres": "Building up collection spheres", "building.collection.spheres": "Building up collection spheres",
"building.calculating.spheres": "Calculated sphere %i, containing %i of %i progress items.", "building.calculating.spheres": "Calculated sphere %i, containing %i of %i progress items.",
"building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items.", "building.final.spheres": "Calculated final sphere %i, containing %i of %i progress items.",
"old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s" "old.python.version": "Door Rando may have issues with python versions earlier than 3.7. Detected version: %s",
"hybridglitches.door.shuffle": "Hybrid Major Glitches is not currently compatible with Door Shuffle."
}, },
"help": { "help": {
"lang": [ "App Language, if available, defaults to English" ], "lang": [ "App Language, if available, defaults to English" ],
@@ -67,6 +68,8 @@
"No Glitches: No Glitch knowledge required.", "No Glitches: No Glitch knowledge required.",
"Minor Glitches: May require Fake Flippers, Bunny Revival", "Minor Glitches: May require Fake Flippers, Bunny Revival",
" and Dark Room Navigation.", " and Dark Room Navigation.",
"Overworld Glitches: May require overworld clips and teleports.",
"Hybrid Major Glitches: May require underworld clips.",
"No Logic: Distribute items without regard for", "No Logic: Distribute items without regard for",
" item requirements." " item requirements."
], ],
+8 -5
View File
@@ -236,10 +236,10 @@
"randomizer.generation.calcplaythrough": "Calculate Playthrough", "randomizer.generation.calcplaythrough": "Calculate Playthrough",
"randomizer.generation.print_custom_yaml": "Print Customizer File", "randomizer.generation.print_custom_yaml": "Print Customizer File",
"randomizer.generation.saveonexit": "Save Settings on Exit", "randomizer.generation.settingsonload": "Settings On Load",
"randomizer.generation.saveonexit.ask": "Ask Me", "randomizer.generation.settingsonload.default": "Default",
"randomizer.generation.saveonexit.always": "Always", "randomizer.generation.settingsonload.saved": "Saved",
"randomizer.generation.saveonexit.never": "Never", "randomizer.generation.settingsonload.lastused": "Last Used",
"randomizer.generation.rom": "Base Rom: ", "randomizer.generation.rom": "Base Rom: ",
"randomizer.generation.rom.button": "Select Rom", "randomizer.generation.rom.button": "Select Rom",
@@ -263,6 +263,7 @@
"randomizer.item.logiclevel.noglitches": "No Glitches", "randomizer.item.logiclevel.noglitches": "No Glitches",
"randomizer.item.logiclevel.minorglitches": "Minor Glitches", "randomizer.item.logiclevel.minorglitches": "Minor Glitches",
"randomizer.item.logiclevel.owglitches": "Overworld Glitches", "randomizer.item.logiclevel.owglitches": "Overworld Glitches",
"randomizer.item.logiclevel.hybridglitches": "Hybrid Major Glitches",
"randomizer.item.logiclevel.nologic": "No Logic", "randomizer.item.logiclevel.nologic": "No Logic",
"randomizer.item.goal": "Goal", "randomizer.item.goal": "Goal",
@@ -389,10 +390,12 @@
"bottom.content.names": "Player names", "bottom.content.names": "Player names",
"bottom.content.seed": "Seed #", "bottom.content.seed": "Seed #",
"bottom.content.generationcount": "Count", "bottom.content.generationcount": "Count",
"bottom.content.go": "Generate Patched Rom", "bottom.content.go": "Generate Game",
"bottom.content.exportyaml": "Export Yaml",
"bottom.content.dialog.error": "Error while creating seed", "bottom.content.dialog.error": "Error while creating seed",
"bottom.content.dialog.success": "Success", "bottom.content.dialog.success": "Success",
"bottom.content.dialog.success.message": "Rom created successfully.", "bottom.content.dialog.success.message": "Rom created successfully.",
"bottom.content.savesettings": "Save Settings",
"bottom.content.outputdir": "Select Destination", "bottom.content.outputdir": "Select Destination",
"bottom.content.docs": "Open Documentation" "bottom.content.docs": "Open Documentation"
} }
@@ -1,11 +1,11 @@
{ {
"widgets": { "widgets": {
"saveonexit": { "settingsonload": {
"type": "selectbox", "type": "selectbox",
"options": [ "options": [
"ask", "default",
"always", "saved",
"never" "lastused"
] ]
} }
} }
@@ -21,6 +21,7 @@
"noglitches", "noglitches",
"minorglitches", "minorglitches",
"owglitches", "owglitches",
"hybridglitches",
"nologic" "nologic"
] ]
}, },
+36 -19
View File
@@ -48,11 +48,13 @@ class CustomSettings(object):
meta = defaultdict(lambda: None, self.file_source['meta']) meta = defaultdict(lambda: None, self.file_source['meta'])
return meta['players'] return meta['players']
def adjust_args(self, args): def adjust_args(self, args, resolve_weighted=True):
def get_setting(value: Any, default): def get_setting(value: Any, default):
if value or value == 0: if value or value == 0:
if isinstance(value, dict): if isinstance(value, dict):
if resolve_weighted:
return random.choices(list(value.keys()), list(value.values()), k=1)[0] return random.choices(list(value.keys()), list(value.values()), k=1)[0]
return None
else: else:
return value return value
return default return default
@@ -147,8 +149,8 @@ class CustomSettings(object):
args.mapshuffle[p] = True args.mapshuffle[p] = True
args.compassshuffle[p] = True args.compassshuffle[p] = True
args.shufflebosses[p] = get_setting(settings['boss_shuffle'], 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'], args.shuffleenemies[p]) args.shuffleenemies[p] = get_setting(settings['enemy_shuffle'], get_setting(settings['shuffleenemies'], args.shuffleenemies[p]))
args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p]) args.enemy_health[p] = get_setting(settings['enemy_health'], args.enemy_health[p])
args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p]) args.enemy_damage[p] = get_setting(settings['enemy_damage'], args.enemy_damage[p])
args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p]) args.shufflepots[p] = get_setting(settings['shufflepots'], args.shufflepots[p])
@@ -167,6 +169,7 @@ class CustomSettings(object):
args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p]) args.triforce_min_difference[p] = get_setting(settings['triforce_min_difference'], args.triforce_min_difference[p])
args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p]) args.triforce_max_difference[p] = get_setting(settings['triforce_max_difference'], args.triforce_max_difference[p])
args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p]) args.beemizer[p] = get_setting(settings['beemizer'], args.beemizer[p])
args.aga_randomness[p] = get_setting(settings['aga_randomness'], args.aga_randomness[p])
# mystery usage # mystery usage
args.usestartinventory[p] = get_setting(settings['usestartinventory'], args.usestartinventory[p]) args.usestartinventory[p] = get_setting(settings['usestartinventory'], args.usestartinventory[p])
@@ -262,10 +265,11 @@ class CustomSettings(object):
self.world_rep['meta'] = meta_dict self.world_rep['meta'] = meta_dict
meta_dict['players'] = world.players meta_dict['players'] = world.players
meta_dict['algorithm'] = world.algorithm meta_dict['algorithm'] = world.algorithm
meta_dict['seed'] = world.seed
meta_dict['race'] = settings.race meta_dict['race'] = settings.race
meta_dict['user_notes'] = settings.notes meta_dict['user_notes'] = settings.notes
self.world_rep['settings'] = settings_dict self.world_rep['settings'] = settings_dict
if world.precollected_items:
self.world_rep['start_inventory'] = start_inv = {}
for p in self.player_range: for p in self.player_range:
settings_dict[p] = {} settings_dict[p] = {}
settings_dict[p]['ow_shuffle'] = world.owShuffle[p] settings_dict[p]['ow_shuffle'] = world.owShuffle[p]
@@ -310,8 +314,8 @@ class CustomSettings(object):
settings_dict[p]['keyshuffle'] = world.keyshuffle[p] settings_dict[p]['keyshuffle'] = world.keyshuffle[p]
settings_dict[p]['mapshuffle'] = world.mapshuffle[p] settings_dict[p]['mapshuffle'] = world.mapshuffle[p]
settings_dict[p]['compassshuffle'] = world.compassshuffle[p] settings_dict[p]['compassshuffle'] = world.compassshuffle[p]
settings_dict[p]['shufflebosses'] = world.boss_shuffle[p] settings_dict[p]['boss_shuffle'] = world.boss_shuffle[p]
settings_dict[p]['shuffleenemies'] = world.enemy_shuffle[p] settings_dict[p]['enemy_shuffle'] = world.enemy_shuffle[p]
settings_dict[p]['enemy_health'] = world.enemy_health[p] settings_dict[p]['enemy_health'] = world.enemy_health[p]
settings_dict[p]['enemy_damage'] = world.enemy_damage[p] settings_dict[p]['enemy_damage'] = world.enemy_damage[p]
settings_dict[p]['shufflepots'] = world.potshuffle[p] settings_dict[p]['shufflepots'] = world.potshuffle[p]
@@ -323,6 +327,11 @@ class CustomSettings(object):
settings_dict[p]['triforce_goal'] = world.treasure_hunt_count[p] settings_dict[p]['triforce_goal'] = world.treasure_hunt_count[p]
settings_dict[p]['triforce_pool'] = world.treasure_hunt_total[p] settings_dict[p]['triforce_pool'] = world.treasure_hunt_total[p]
settings_dict[p]['beemizer'] = world.beemizer[p] settings_dict[p]['beemizer'] = world.beemizer[p]
settings_dict[p]['aga_randomness'] = world.aga_randomness[p]
if world.precollected_items:
start_inv[p] = []
for item in world.precollected_items:
start_inv[item.player].append(item.name)
# rom adjust stuff # rom adjust stuff
# settings_dict[p]['sprite'] = world.sprite[p] # settings_dict[p]['sprite'] = world.sprite[p]
@@ -335,34 +344,42 @@ class CustomSettings(object):
# settings_dict[p]['ow_palettes'] = world.ow_palettes[p] # settings_dict[p]['ow_palettes'] = world.ow_palettes[p]
# settings_dict[p]['uw_palettes'] = world.uw_palettes[p] # settings_dict[p]['uw_palettes'] = world.uw_palettes[p]
# settings_dict[p]['shuffle_sfx'] = world.shuffle_sfx[p] # settings_dict[p]['shuffle_sfx'] = world.shuffle_sfx[p]
# settings_dict[p]['shuffle_songinstruments'] = world.shuffle_songinstruments[p]
# more settings? # more settings?
def record_info(self, world): def record_info(self, world):
self.world_rep['meta']['seed'] = world.seed
self.world_rep['bosses'] = bosses = {} self.world_rep['bosses'] = bosses = {}
self.world_rep['start_inventory'] = start_inv = {} self.world_rep['medallions'] = medallions = {}
for p in self.player_range: for p in self.player_range:
bosses[p] = {} bosses[p] = {}
start_inv[p] = [] medallions[p] = {}
for dungeon in world.dungeons: for dungeon in world.dungeons:
for level, boss in dungeon.bosses.items(): for level, boss in dungeon.bosses.items():
location = dungeon.name if level is None else f'{dungeon.name} ({level})' location = dungeon.name if level is None else f'{dungeon.name} ({level})'
if boss and 'Agahnim' not in boss.name: if boss and 'Agahnim' not in boss.name:
bosses[dungeon.player][location] = boss.name bosses[dungeon.player][location] = boss.name
for item in world.precollected_items:
start_inv[item.player].append(item.name)
def record_item_pool(self, world):
self.world_rep['item_pool'] = item_pool = {}
self.world_rep['medallions'] = medallions = {}
for p in self.player_range:
item_pool[p] = defaultdict(int)
medallions[p] = {}
for item in world.itempool:
item_pool[item.player][item.name] += 1
for p, req_medals in world.required_medallions.items(): for p, req_medals in world.required_medallions.items():
medallions[p]['Misery Mire'] = req_medals[0] medallions[p]['Misery Mire'] = req_medals[0]
medallions[p]['Turtle Rock'] = req_medals[1] medallions[p]['Turtle Rock'] = req_medals[1]
def record_item_pool(self, world, use_custom_pool=False):
if not use_custom_pool or world.custom:
self.world_rep['item_pool'] = item_pool = {}
for p in self.player_range:
if not use_custom_pool or p in world.customitemarray:
item_pool[p] = defaultdict(int)
if use_custom_pool and world.custom:
import source.classes.constants as CONST
for p in world.customitemarray:
for i, c in world.customitemarray[p].items():
if c > 0:
item = CONST.CUSTOMITEMLABELS[CONST.CUSTOMITEMS.index(i)]
item_pool[p][item] += c
else:
for item in world.itempool:
item_pool[item.player][item.name] += 1
def record_item_placements(self, world): def record_item_placements(self, world):
self.world_rep['placements'] = placements = {} self.world_rep['placements'] = placements = {}
for p in self.player_range: for p in self.player_range:
+28 -28
View File
@@ -337,10 +337,10 @@ spc_instruments = { # table @ $19FB1C
0x02: SPCInstrument("Timpani", 0x02, [0xFF, 0xE0], 0xB8, 0x09C0).beat(), 0x02: SPCInstrument("Timpani", 0x02, [0xFF, 0xE0], 0xB8, 0x09C0).beat(),
0x03: SPCInstrument("Square Wave", 0x03, [0xFF, 0xE0], 0xB8, 0x0400).bass().mel(), 0x03: SPCInstrument("Square Wave", 0x03, [0xFF, 0xE0], 0xB8, 0x0400).bass().mel(),
0x04: SPCInstrument("Saw Wave", 0x04, [0xFF, 0xE0], 0xB8, 0x0400).bass(), 0x04: SPCInstrument("Saw Wave", 0x04, [0xFF, 0xE0], 0xB8, 0x0400).bass(),
0x05: SPCInstrument("Clink", 0x05, [0xFF, 0xE0], 0xB8, 0x0470).amb(), 0x05: SPCInstrument("Clink", 0x05, [0xFF, 0xE0], 0xB8, 0x0470),
0x06: SPCInstrument("Wobbly Lead", 0x06, [0xFF, 0xE0], 0xB8, 0x0470).amb(), 0x06: SPCInstrument("Wobbly Lead", 0x06, [0xFF, 0xE0], 0xB8, 0x0470).amb(),
0x07: SPCInstrument("Compound Saw", 0x07, [0xFF, 0xE0], 0xB8, 0x0470), 0x07: SPCInstrument("Compound Saw", 0x07, [0xFF, 0xE0], 0xB8, 0x0470),
0x08: SPCInstrument("Tweet", 0x08, [0xFF, 0xE0], 0xB8, 0x07A0).amb(), 0x08: SPCInstrument("Tweet", 0x08, [0xFF, 0xE0], 0xB8, 0x07A0).amb().beat(),
0x09: SPCInstrument("Strings A", 0x09, [0x8F, 0xE9], 0xB8, 0x01E0).mel().bass(True), 0x09: SPCInstrument("Strings A", 0x09, [0x8F, 0xE9], 0xB8, 0x01E0).mel().bass(True),
0x0A: SPCInstrument("Strings B", 0x0A, [0x8A, 0xE9], 0xB8, 0x01E0).mel().bass(True), 0x0A: SPCInstrument("Strings B", 0x0A, [0x8A, 0xE9], 0xB8, 0x01E0).mel().bass(True),
0x0B: SPCInstrument("Trombone", 0x0B, [0xFF, 0xE0], 0xB8, 0x0300).mel().bass(True).beat(), 0x0B: SPCInstrument("Trombone", 0x0B, [0xFF, 0xE0], 0xB8, 0x0300).mel().bass(True).beat(),
@@ -468,7 +468,7 @@ spc_instrument_changes = [
0x02: [0x1ABBE6], 0x02: [0x1ABBE6],
0x03: [0x1ABC0B]}, 0x09), 0x03: [0x1ABC0B]}, 0x09),
InstrumentChange(0x07, 0x00, {0x04: [0x1ABB53, 0x1AB8C9]}, 0x16), InstrumentChange(0x07, 0x00, {0x04: [0x1ABB53, 0x1AB8C9]}, 0x16),
InstrumentChange(0x07, 0x01, {0x04: [0x1AB8E6]}, 0x0E, type=Am|Me|Rh, ban=[0x06]), InstrumentChange(0x07, 0x01, {0x04: [0x1AB8E6]}, 0x0E, type=Am|Me|Rh, ban=[0x01, 0x05, 0x06, 0x17]),
InstrumentChange(0x07, 0x01, {0x05: [0x1AB8EB]}, 0x0A), InstrumentChange(0x07, 0x01, {0x05: [0x1AB8EB]}, 0x0A),
InstrumentChange(0x07, 0x02, {0x04: [0x1AB981]}, 0x16), InstrumentChange(0x07, 0x02, {0x04: [0x1AB981]}, 0x16),
InstrumentChange(0x07, 0x03, {0x02: [0x1ABC37], InstrumentChange(0x07, 0x03, {0x02: [0x1ABC37],
@@ -486,7 +486,7 @@ spc_instrument_changes = [
InstrumentChange(0x07, 0x06, {0x05: [0x1ABCE6]}, 0x0A), InstrumentChange(0x07, 0x06, {0x05: [0x1ABCE6]}, 0x0A),
InstrumentChange(0x08, 0x00, {0x00: [0x1ABD3A], InstrumentChange(0x08, 0x00, {0x00: [0x1ABD3A],
0x01: [0x1ABD5B]}, 0x06, type=Me|Rh|Am), 0x01: [0x1ABD5B]}, 0x06, type=Me|Rh|Am, ban=[0x05]),
InstrumentChange(0x08, 0x00, {0x02: [0x1ABD70], InstrumentChange(0x08, 0x00, {0x02: [0x1ABD70],
0x05: [0x1ABE06]}, 0x0F), 0x05: [0x1ABE06]}, 0x0F),
InstrumentChange(0x08, 0x00, {0x03: [0x1ABDAC]}, 0x0A), InstrumentChange(0x08, 0x00, {0x03: [0x1ABDAC]}, 0x0A),
@@ -495,22 +495,22 @@ spc_instrument_changes = [
InstrumentChange(0x09, 0x00, {0x00: [0x1AC25A], InstrumentChange(0x09, 0x00, {0x00: [0x1AC25A],
0x05: [0x1AC28E]}, 0x0A), 0x05: [0x1AC28E]}, 0x0A),
InstrumentChange(0x09, 0x00, {0x01: [0x1AC26E]}, 0x14), InstrumentChange(0x09, 0x00, {0x01: [0x1AC26E]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x01, {0x01: [0x1ABF0A]}, 0x14), InstrumentChange(0x09, 0x01, {0x01: [0x1ABF0A]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x01, {0x06: [0x1ABF43]}, 0x09), InstrumentChange(0x09, 0x01, {0x06: [0x1ABF43]}, 0x09),
InstrumentChange(0x09, 0x02, {0x00: [0x1AC450], InstrumentChange(0x09, 0x02, {0x00: [0x1AC450],
0x05: [0x1AC56D], 0x05: [0x1AC56D],
0x07: [0x1AC595]}, 0x0A), 0x07: [0x1AC595]}, 0x0A),
InstrumentChange(0x09, 0x02, {0x01: [0x1AC2AF]}, 0x14), InstrumentChange(0x09, 0x02, {0x01: [0x1AC2AF]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x02, {0x03: [0x1AC4B3], InstrumentChange(0x09, 0x02, {0x03: [0x1AC4B3],
0x04: [0x1AC510]}, 0x11), 0x04: [0x1AC510]}, 0x11),
InstrumentChange(0x09, 0x02, {0x06: [0x1AC2E9]}, 0x09), InstrumentChange(0x09, 0x02, {0x06: [0x1AC2E9]}, 0x09),
InstrumentChange(0x09, 0x03, {0x00: [0x1ABF63]}, 0x0A), InstrumentChange(0x09, 0x03, {0x00: [0x1ABF63]}, 0x0A),
InstrumentChange(0x09, 0x03, {0x01: [0x1ABF80]}, 0x14), InstrumentChange(0x09, 0x03, {0x01: [0x1ABF80]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x03, {0x03: [0x1ABFA4]}, 0x11), InstrumentChange(0x09, 0x03, {0x03: [0x1ABFA4]}, 0x11),
InstrumentChange(0x09, 0x03, {0x05: [0x1AC01C]}, 0x16), InstrumentChange(0x09, 0x03, {0x05: [0x1AC01C]}, 0x16),
InstrumentChange(0x09, 0x04, {0x00: [0x1AC04D]}, 0x0A), InstrumentChange(0x09, 0x04, {0x00: [0x1AC04D]}, 0x0A),
InstrumentChange(0x09, 0x04, {0x01: [0x1AC05D]}, 0x14), InstrumentChange(0x09, 0x04, {0x01: [0x1AC05D]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x04, {0x02: [0x1AC5CF]}, 0x18), InstrumentChange(0x09, 0x04, {0x02: [0x1AC5CF]}, 0x18),
InstrumentChange(0x09, 0x04, {0x03: [0x1AC085], InstrumentChange(0x09, 0x04, {0x03: [0x1AC085],
0x04: [0x1AC5ED]}, 0x11), 0x04: [0x1AC5ED]}, 0x11),
@@ -518,20 +518,20 @@ spc_instrument_changes = [
InstrumentChange(0x09, 0x04, {0x06: [0x1AC146]}, 0x12), InstrumentChange(0x09, 0x04, {0x06: [0x1AC146]}, 0x12),
InstrumentChange(0x09, 0x05, {0x00: [0x1AC178], InstrumentChange(0x09, 0x05, {0x00: [0x1AC178],
0x07: [0x1AC229]}, 0x0A), 0x07: [0x1AC229]}, 0x0A),
InstrumentChange(0x09, 0x05, {0x01: [0x1AC196]}, 0x14), InstrumentChange(0x09, 0x05, {0x01: [0x1AC196]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x05, {0x02: [0x1AC19E]}, 0x18), InstrumentChange(0x09, 0x05, {0x02: [0x1AC19E]}, 0x18),
InstrumentChange(0x09, 0x05, {0x03: [0x1AC1D3], InstrumentChange(0x09, 0x05, {0x03: [0x1AC1D3],
0x04: [0x1AC1F4]}, 0x12), 0x04: [0x1AC1F4]}, 0x12),
InstrumentChange(0x09, 0x06, {0x00: [0x1AC317], InstrumentChange(0x09, 0x06, {0x00: [0x1AC317],
0x07: [0x1AC3ED]}, 0x0A), 0x07: [0x1AC3ED]}, 0x0A),
InstrumentChange(0x09, 0x06, {0x01: [0x1AC332]}, 0x14), InstrumentChange(0x09, 0x06, {0x01: [0x1AC332]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x06, {0x02: [0x1AC33A]}, 0x18), InstrumentChange(0x09, 0x06, {0x02: [0x1AC33A]}, 0x18),
InstrumentChange(0x09, 0x06, {0x03: [0x1AC36F], InstrumentChange(0x09, 0x06, {0x03: [0x1AC36F],
0x04: [0x1AC3A4], 0x04: [0x1AC3A4],
0x05: [0x1AC3D9]}, 0x12), 0x05: [0x1AC3D9]}, 0x12),
InstrumentChange(0x09, 0x07, {0x00: [0x1AC40A], InstrumentChange(0x09, 0x07, {0x00: [0x1AC40A],
0x05: [0x1AC43C]}, 0x0A), 0x05: [0x1AC43C]}, 0x0A),
InstrumentChange(0x09, 0x07, {0x01: [0x1AC41C]}, 0x14), InstrumentChange(0x09, 0x07, {0x01: [0x1AC41C]}, 0x14, type=Am|Be, ban=[0x05, 0x06]),
InstrumentChange(0x09, 0x07, {0x02: [0x1AC492]}, 0x18), InstrumentChange(0x09, 0x07, {0x02: [0x1AC492]}, 0x18),
InstrumentChange(0x09, 0x07, {0x03: [0x1AC680], InstrumentChange(0x09, 0x07, {0x03: [0x1AC680],
0x04: [0x1AC6C1]}, 0x11), 0x04: [0x1AC6C1]}, 0x11),
@@ -563,21 +563,21 @@ spc_instrument_changes = [
0x05: [0x1AC87E]}, 0x0B), 0x05: [0x1AC87E]}, 0x0B),
InstrumentChange(0x0C, 0x01, {0x02: [0x1AC89A], InstrumentChange(0x0C, 0x01, {0x02: [0x1AC89A],
0x03: [0x1AC8AD]}, 0x11), 0x03: [0x1AC8AD]}, 0x11),
InstrumentChange(0x0C, 0x01, {0x04: [0x1AC8B7]}, 0x0E), InstrumentChange(0x0C, 0x01, {0x04: [0x1AC8B7]}, 0x0E, type=Rh|Am, ban=[0x05]),
InstrumentChange(0x0C, 0x01, {0x05: [0x1AC8C3]}, 0x02), InstrumentChange(0x0C, 0x01, {0x05: [0x1AC8C3]}, 0x02),
InstrumentChange(0x0C, 0x02, {0x02: [0x1AC8E0], InstrumentChange(0x0C, 0x02, {0x02: [0x1AC8E0],
0x03: [0x1AC8F3]}, 0x11), 0x03: [0x1AC8F3]}, 0x11),
InstrumentChange(0x0C, 0x02, {0x04: [0x1AC8FD]}, 0x0E), InstrumentChange(0x0C, 0x02, {0x04: [0x1AC8FD]}, 0x0E, type=Rh|Am, ban=[0x05]),
InstrumentChange(0x0C, 0x02, {0x05: [0x1AC909]}, 0x02), InstrumentChange(0x0C, 0x02, {0x05: [0x1AC909]}, 0x02),
InstrumentChange(0x0D, 0x00, {0x00: [0x1AD003], InstrumentChange(0x0D, 0x00, {0x00: [0x1AD003],
0x03: [0x1AD02C], 0x03: [0x1AD02C],
0x04: [0x1AD03A]}, 0x11), 0x04: [0x1AD03A]}, 0x11),
InstrumentChange(0x0D, 0x00, {0x01: [0x1AD010]}, 0x02), InstrumentChange(0x0D, 0x00, {0x01: [0x1AD010]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x06, 0x10, 0x17]),
InstrumentChange(0x0D, 0x00, {0x02: [0x1AD07F]}, 0x14), InstrumentChange(0x0D, 0x00, {0x02: [0x1AD07F]}, 0x14),
InstrumentChange(0x0D, 0x01, {0x00: [0x1ACD10], InstrumentChange(0x0D, 0x01, {0x00: [0x1ACD10],
0x04: [0x1ACD9A]}, 0x0B), 0x04: [0x1ACD9A]}, 0x0B),
InstrumentChange(0x0D, 0x01, {0x01: [0x1ACD41]}, 0x02), InstrumentChange(0x0D, 0x01, {0x01: [0x1ACD41]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x06, 0x10, 0x17]),
InstrumentChange(0x0D, 0x01, {0x03: [0x1ACD7F], InstrumentChange(0x0D, 0x01, {0x03: [0x1ACD7F],
0x05: [0x1ACDCA]}, 0x11), 0x05: [0x1ACDCA]}, 0x11),
InstrumentChange(0x0D, 0x03, {0x00: [0x1ACE8E], InstrumentChange(0x0D, 0x03, {0x00: [0x1ACE8E],
@@ -585,7 +585,7 @@ spc_instrument_changes = [
InstrumentChange(0x0D, 0x03, {0x02: [0x1ACED4]}, 0x14), InstrumentChange(0x0D, 0x03, {0x02: [0x1ACED4]}, 0x14),
InstrumentChange(0x0D, 0x03, {0x03: [0x1ACEE0], InstrumentChange(0x0D, 0x03, {0x03: [0x1ACEE0],
0x04: [0x1ACF07]}, 0x11), 0x04: [0x1ACF07]}, 0x11),
InstrumentChange(0x0D, 0x04, {0x05: [0x1ACFE3]}, 0x02), InstrumentChange(0x0D, 0x04, {0x05: [0x1ACFE3]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x06, 0x10, 0x17]),
InstrumentChange(0x0E, 0x00, {0x00: [0x1AD29C]}, 0x16), InstrumentChange(0x0E, 0x00, {0x00: [0x1AD29C]}, 0x16),
InstrumentChange(0x0E, 0x00, {0x01: [0x1AD2AD], InstrumentChange(0x0E, 0x00, {0x01: [0x1AD2AD],
@@ -710,7 +710,7 @@ spc_instrument_changes = [
InstrumentChange(0x13, 0x00, {0x06: [0x1B9650], InstrumentChange(0x13, 0x00, {0x06: [0x1B9650],
0x07: [0x1B9696]}, 0x0F), 0x07: [0x1B9696]}, 0x0F),
InstrumentChange(0x13, 0x00, {0x06: [0x1B967B], InstrumentChange(0x13, 0x00, {0x06: [0x1B967B],
0x07: [0x1B96C0]}, 0x02), 0x07: [0x1B96C0]}, 0x02, ban=[0x0B]),
InstrumentChange(0x14, 0x00, {0x00: [0x1B9901, 0x1B97A8]}, 0x15), InstrumentChange(0x14, 0x00, {0x00: [0x1B9901, 0x1B97A8]}, 0x15),
InstrumentChange(0x14, 0x01, {0x01: [0x1B97C4], InstrumentChange(0x14, 0x01, {0x01: [0x1B97C4],
@@ -723,13 +723,13 @@ spc_instrument_changes = [
0x01: [0x1B9A50], 0x01: [0x1B9A50],
0x02: [0x1B9A6D], 0x02: [0x1B9A6D],
0x03: [0x1B9A8A]}, 0x0B), 0x03: [0x1B9A8A]}, 0x0B),
InstrumentChange(0x15, 0x00, {0x04: [0x1B9AA0]}, 0x02), InstrumentChange(0x15, 0x00, {0x04: [0x1B9AA0]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x10]),
InstrumentChange(0x15, 0x01, {0x00: [0x1B9971]}, 0x02), InstrumentChange(0x15, 0x01, {0x00: [0x1B9971]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x10]),
InstrumentChange(0x15, 0x01, {0x01: [0x1B9984], InstrumentChange(0x15, 0x01, {0x01: [0x1B9984],
0x02: [0x1B99AA], 0x02: [0x1B99AA],
0x03: [0x1B99D7]}, 0x0B), 0x03: [0x1B99D7]}, 0x0B),
InstrumentChange(0x15, 0x01, {0x04: [0x1B9A04]}, 0x14), InstrumentChange(0x15, 0x01, {0x04: [0x1B9A04]}, 0x14),
InstrumentChange(0x15, 0x02, {0x00: [0x1B9B45]}, 0x02), InstrumentChange(0x15, 0x02, {0x00: [0x1B9B45]}, 0x02, type=Am|Be, ban=[0x01, 0x05, 0x10]),
InstrumentChange(0x15, 0x02, {0x01: [0x1B9B58], InstrumentChange(0x15, 0x02, {0x01: [0x1B9B58],
0x02: [0x1B9B7E], 0x02: [0x1B9B7E],
0x03: [0x1B9BAB]}, 0x0B), 0x03: [0x1B9BAB]}, 0x0B),
@@ -749,10 +749,10 @@ spc_instrument_changes = [
0x05: [0x1B9EE4]}, 0x09), 0x05: [0x1B9EE4]}, 0x09),
InstrumentChange(0x17, 0x00, {0x00: [0x1BA287], InstrumentChange(0x17, 0x00, {0x00: [0x1BA287],
0x03: [0x1BA26A]}, 0x0E, type=Am|Rh, ban=[0x01, 0x05, 0x06, 0x10, 0x17]), 0x03: [0x1BA26A]}, 0x0E, type=[0x0E, 0x0F, 0x18]),
InstrumentChange(0x17, 0x01, {0x01: [0x1BA20F], InstrumentChange(0x17, 0x01, {0x01: [0x1BA20F],
0x02: [0x1BA231], 0x03: [0x1BA24F]}, 0x0E, type=Rh, ban=[0x0B, 0x0D, 0x16]),
0x03: [0x1BA24F]}, 0x0E, type=Am|Rh, ban=[0x01, 0x05, 0x06, 0x10]), InstrumentChange(0x17, 0x01, {0x02: [0x1BA231]}, 0x0F),
InstrumentChange(0x19, 0x00, {0x00: [0x1BA476], InstrumentChange(0x19, 0x00, {0x00: [0x1BA476],
0x01: [0x1BA49C], 0x01: [0x1BA49C],
@@ -775,7 +775,7 @@ spc_instrument_changes = [
0x04: [0x1BA783], 0x04: [0x1BA783],
0x05: [0x1BA7A2], 0x05: [0x1BA7A2],
0x06: [0x1BA7B9], 0x06: [0x1BA7B9],
0x07: [0x1BA7D0]}, 0x0E), 0x07: [0x1BA7D0]}, 0x0E, type=Rh|Am, ban=[0x01, 0x05, 0x06, 0x10]),
InstrumentChange(0x1A, 0x01, {0x00: [0x1BA5C1], InstrumentChange(0x1A, 0x01, {0x00: [0x1BA5C1],
0x05: [0x1BA68F], 0x05: [0x1BA68F],
0x06: [0x1BA6A6], 0x06: [0x1BA6A6],
@@ -820,8 +820,8 @@ spc_instrument_changes = [
0x03: [0x1BAEC6], 0x03: [0x1BAEC6],
0x04: [0x1BAEE4]}, 0x0B), 0x04: [0x1BAEE4]}, 0x0B),
InstrumentChange(0x1F, 0x00, {0x00: [0x1BAE9C]}, 0x18), InstrumentChange(0x1F, 0x00, {0x00: [0x1BAE9C]}, 0x18),
InstrumentChange(0x1F, 0x00, {0x02: [0x1BAEBC]}, 0x13), InstrumentChange(0x1F, 0x00, {0x02: [0x1BAEBC]}, 0x13, type=Am|Be, ban=[0x01, 0x05, 0x0F]),
InstrumentChange(0x1F, 0x00, {0x06: [0x1BAF02]}, 0x02), InstrumentChange(0x1F, 0x00, {0x06: [0x1BAF02]}, 0x02, ban=[0x10]),
InstrumentChange(0x1F, 0x01, {0x03: [0x1BAE15], InstrumentChange(0x1F, 0x01, {0x03: [0x1BAE15],
0x04: [0x1BAE32], 0x04: [0x1BAE32],
0x05: [0x1BAE4F]}, 0x11), 0x05: [0x1BAE4F]}, 0x11),
@@ -829,7 +829,7 @@ spc_instrument_changes = [
InstrumentChange(0x1F, 0x02, {0x03: [0x1BAF53], InstrumentChange(0x1F, 0x02, {0x03: [0x1BAF53],
0x04: [0x1BAF69], 0x04: [0x1BAF69],
0x05: [0x1BAF7F]}, 0x11), 0x05: [0x1BAF7F]}, 0x11),
InstrumentChange(0x1F, 0x04, {0x02: [0x1BAFAA]}, 0x13), InstrumentChange(0x1F, 0x04, {0x02: [0x1BAFAA]}, 0x13, type=Am|Be, ban=[0x01, 0x05, 0x0F]),
InstrumentChange(0x20, 0x00, {0x00: [0x1AD49A], InstrumentChange(0x20, 0x00, {0x00: [0x1AD49A],
0x01: [0x1AD4BA], 0x01: [0x1AD4BA],
+1 -1
View File
@@ -148,7 +148,7 @@ SETTINGSTOPROCESS = {
"createrom": "create_rom", "createrom": "create_rom",
"calcplaythrough": "calc_playthrough", "calcplaythrough": "calc_playthrough",
"print_custom_yaml": "print_custom_yaml", "print_custom_yaml": "print_custom_yaml",
"saveonexit": "saveonexit" "settingsonload": "settingsonload"
} }
}, },
"startinventory": { "startinventory": {
+710
View File
@@ -0,0 +1,710 @@
UwGeneralDeny:
- [ 0x0002, 0, [ "RollerVerticalDown", "Statue" ] ] #"Sewers - Rat Pots - Rat 1"
- [ 0x0002, 1, [ "RollerVerticalDown", "Statue" ] ] #"Sewers - Rat Pots - Rat 2"
- [ 0x0002, 2, [ "RollerVerticalUp", "Statue" ] ] #"Sewers - Rat Pots - Rat 3"
- [ 0x0002, 3, [ "RollerVerticalUp", "Statue" ] ] #"Sewers - Rat Pots - Rat 4"
- [ 0x0002, 4, [ "Statue" ] ] #"Sewers - Rat Pots - Rat 5"
- [ 0x0002, 15, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Sewers - Rat Pots - Rat 6"
- [ 0x0002, 16, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Sewers - Rat Pots - Rat 7"
- [ 0x0004, 1, ["Statue"]]
- [ 0x0004, 2, ["Statue"]]
- [ 0x0004, 3, ["Statue"]]
- [ 0x0004, 4, ["Statue"]]
- [ 0x0004, 15, ["Statue"]]
- [ 0x000a, 0, [ "RollerVerticalDown", "RollerVerticalUp" ] ] #"Palace of Darkness - Basement Ledge - Terrorpin 1"
- [ 0x000a, 1, [ "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Palace of Darkness - Basement Ledge - Terrorpin 2"
- [ 0x000b, 1, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Callback - Terrorpin 1"
- [ 0x000e, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Entrance - Freezor"
- [ 0x000e, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Top Bari"
- [ 0x000e, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari Key - Middle Bari"
- [ 0x0016, 0, [ "RollerVerticalDown", "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 1"
- [ 0x0016, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Zol 2"
- [ 0x0016, 2, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Pool - Blue Bari"
- [ 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)"
- [ 0x0019, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Dark Maze - Kodongo 1"
- [ 0x0019, 1, [ "RollerVerticalUp" ] ] #"Palace of Darkness - Dark Maze - Kodongo 2"
- [ 0x0019, 2, [ "RollerVerticalDown", "RollerVerticalUp" ] ] #"Palace of Darkness - Dark Maze - Kodongo 3"
- [ 0x0019, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft" ] ] #"Palace of Darkness - Dark Maze - Kodongo 4"
- [ 0x001a, 0, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Compass Room - Mini Helmasaur 1"
- [ 0x001a, 5, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Compass Room - Mini Helmasaur 2"
- [ 0x001b, 3, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Palace of Darkness - Mimics 2 - Red Eyegore"
- [ 0x001b, 4, [ "RollerVerticalUp" ] ] #"Palace of Darkness - Mimics 2 - Green Eyegore L"
- [ 0x001e, 3, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Red Bari 3"
- [ 0x001e, 4, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Red Bari 4"
- [ 0x001e, 5, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Zol 1"
- [ 0x001e, 6, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Blob Ambush - Zol 2"
- [ 0x001f, 0, [ "RollerHorizontalRight" ] ] #"Ice Palace - Big Key View - Pengator 1"
- [ 0x001f, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x0021, 3, [ "RollerVerticalDown", "RollerVerticalUp" ] ] #"Sewers - Dark U - Rat 2"
- [ 0x0021, 4, [ "RollerVerticalDown", "RollerVerticalUp" ] ] #"Sewers - Dark U - Rat 3"
- [ 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, 8, [ "AntiFairyCircle", "Bumper", "Statue" ] ] #"Swamp Palace - Big Spoon - Red Bari 3"
- [ 0x0026, 9, [ "RollerHorizontalRight", "Statue" ] ] #"Swamp Palace - Big Spoon - Kyameron"
- [ 0x0026, 10, [ "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, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower Of Hera - Petting Zoo - Mini Moldorm 2"
- [ 0x0027, 2, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Tower Of Hera - Petting Zoo - Mini Moldorm 3"
- [ 0x0027, 4, ["Bumper", "BigSpike", "AntiFairyCircle", "RollerVerticalDown", "RollerVerticalUp"]]
- [ 0x0027, 5, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Tower Of Hera - Petting Zoo - Kodongo 1"
- [ 0x0028, 4, [ "RollerVerticalUp" ] ] #"Swamp Palace - Entrance Ledge - Spike Trap"
- [ 0x002a, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]] #"Palace of Darkness - Arena Main - Hardhat Beetle 1"
- [ 0x002a, 3, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 2"
- [ 0x002a, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ]]
- [ 0x002a, 6, [ "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Arena Main - Hardhat Beetle 5"
- [ 0x002b, 5, [ "RollerHorizontalRight" ] ] #"Palace of Darkness - Fairies - Red Bari 2"
- [ 0x002e, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 1"
- [ 0x002e, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 2"
- [ 0x002e, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 3"
- [ 0x002e, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 4"
- [ 0x002e, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 5"
- [ 0x002e, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "BigSpike", "FirebarCW", "FirebarCCW" ] ] #"Ice Palace - Penguin Chest - Pengator 6"
- [ 0x0034, 0, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Hover 1"
- [ 0x0034, 1, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Hover 2"
- [ 0x0034, 2, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Kyameron"
- [ 0x0034, 4, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - West Wing - Zol"
- [ 0x0035, 6, [ "RollerHorizontalRight" ] ] #"Swamp Palace - West Lever - Stalfos 2"
- [ 0x0035, 9, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Swamp Palace - West Lever - Blue Bari"
- [ 0x0036, 7, [ "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Lobby - Hover 3"
- [ 0x0037, 7, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Water 1 - Blue Bari"
- [ 0x0038, 4, [ "RollerHorizontalRight" ] ] #"Swamp Palace - Long Hall - Kyameron 2"
- [ 0x0039, 3, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Mini Helmasaur"
- [ 0x0039, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 1"
- [ 0x0039, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Skull Woods - Play Pen - Hardhat Beetle"
- [ 0x0039, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "FirebarCW", "FirebarCCW" ] ] #"Skull Woods - Play Pen - Spike Trap 2"
- [ 0x003b, 1, [ "Bumper" ]]
- [ 0x003c, 0, ["BigSpike"]]
- [ 0x003c, 1, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Hookshot Cave - Blue Bari 1"
- [ 0x003c, 2, [ "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Hookshot Cave - Blue Bari 2"
- [ 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, 12, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Bunny Beam"
- [ 0x003d, 13, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Torches 2 - Antifairy"
- [ 0x003f, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper", "Statue"] ] #"Ice Palace - P Room - Stalfos Knight 1"
- [ 0x003f, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper", "Statue"] ] #"Ice Palace - P Room - Stalfos Knight 2"
- [ 0x003f, 4, [ "Wizzrobe", "Statue", "Bumper", "BigSpike", "AntiFairyCircle"]] # Wizzrobes can't spawn on pots
- [ 0x0040, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] # Agahnims Tower - Bridge - Blue Guard 1
- [ 0x0040, 1, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] # Agahnims Tower - Bridge - Blue Guard 2
- [ 0x0041, 0, [ "RollerHorizontalLeft" ] ] #"Sewers - Dark Cactus - Rat 1"
- [ 0x0041, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Sewers - Dark Cactus - Rat 2"
- [ 0x0041, 2, [ "RollerVerticalUp" ] ] #"Sewers - Dark Cactus - Rat 3"
- [ 0x0042, 0, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 1"
- [ 0x0042, 1, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 2"
- [ 0x0042, 2, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 3"
- [ 0x0042, 3, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 4"
- [ 0x0042, 4, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 5"
- [ 0x0042, 5, [ "SparkCW", "SparkCCW", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sewers - Dark Rope Corridor - Rope 6"
- [ 0x0044, 4, [ "RollerVerticalUp", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Zol"
- [ 0x0044, 6, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "BigSpike" ] ] #"Thieves' Town - Joke Room - Red Bari"
- [ 0x0044, 8, [ "Statue", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Joke Room - Blue Bari 4"
- [ 0x0045, 1, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Thieves' Town - Basement Block Totems - Red Zazak"
- [ 0x0045, 4, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x0045, 7, [ "AntiFairyCircle", "Bumper" ] ] #"Thieves' Town - Cells - Blue Zazak 4"
- [ 0x0045, 8, [ "RollerHorizontalRight" ] ] #"Thieves' Town - Cells - Zol"
- [ 0x0046, 0, [ "RollerVerticalUp", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper", "Statue" ] ] #"Swamp Palace - Big O Top - Hover 1"
- [ 0x0046, 2, [ "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper", "Statue" ] ] #"Swamp Palace - Big O Top - Hover 2"
- [ 0x0046, 4, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper", "Statue" ] ] #"Swamp Palace - Big O Top - Hover 3"
- [ 0x0049, 5, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Bari Pits - Gibdo 2"
- [ 0x0049, 7, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Bari Pits - Gibdo 4"
- [ 0x0049, 8, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Skull Woods - Bari Pits - Gibdo 5"
- [ 0x004b, 0, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Palace of Darkness - Mimics 1 - Red Eyegore"
- [ 0x004b, 1, [ "RollerHorizontalRight" ] ] #"Palace of Darkness - Warp Hint - Antifairy 1"
- [ 0x004b, 5, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 1"
- [ 0x004b, 6, [ "AntiFairyCircle", "BigSpike" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 2"
- [ 0x004b, 7, [ "AntiFairyCircle", "BigSpike" ] ] #"Palace of Darkness - Jelly Hall - Blue Bari 3"
- [ 0x004e, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 1"
- [ 0x004e, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 2"
- [ 0x004e, 2, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Blob Alley - Zol 3"
- [ 0x0050, 0, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Hyrule Castle - North West Passage - Green Guard"
- [ 0x0050, 1, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Hyrule Castle - North West Passage - Green Knife Guard 1"
- [ 0x0050, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Hyrule Castle - North West Passage - Green Knife Guard 2"
- [ 0x0052, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Guard"
- [ 0x0052, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 1"
- [ 0x0052, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "Bumper" ] ] #"Hyrule Castle - North East Passage - Green Knife Guard 2"
- [ 0x0053, 1, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Beamos 1"
- [ 0x0053, 5, [ "RollerVerticalDown" ] ] #"Desert Palace - Popo Genocide - Popo TL"
- [ 0x0053, 7, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - Bridge - Popo 5"
- [ 0x0055, 1, [ "RollerVerticalUp", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Secret Passage Exit - Green Knife Guard 1"
- [ 0x0057, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x0057, 1, ["Statue"]] # Statue switch issues
- [ 0x0057, 2, [ "RollerVerticalUp", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Spike Trap"
- [ 0x0057, 3, ["Statue"]] # Statue switch issues
- [ 0x0057, 4, ["Statue"]] # Statue switch issues
- [ 0x0057, 5, ["Statue"]] # Statue switch issues
- [ 0x0057, 7, [ "RollerVerticalUp", "RollerVerticalDown", "Statue" ] ] #"Skull Woods - Big Key Room - Gibdo 2"
- [ 0x0057, 8, ["Statue"]] # Statue switch issues
- [ 0x0057, 9, ["Statue"]] # Statue switch issues
- [ 0x0057, 10, ["Statue"]] # Statue switch issues
- [ 0x0057, 11, ["Statue"]] # Statue switch issues
- [ 0x0057, 12, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "BigSpike", "SpikeBlock", "Statue"]] #"Skull Woods - Big Key Room - Gibdo 6"
- [ 0x0057, 13, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 1"
- [ 0x0057, 14, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "Statue" ] ] #"Skull Woods - Big Key Room - Blue Bari 2"
- [ 0x0058, 0, ["Statue"]]
- [ 0x0058, 1, ["Statue"]]
- [ 0x0058, 2, ["Statue"]]
- [ 0x0058, 3, ["Statue"]]
- [ 0x0058, 4, ["Statue"]]
- [ 0x0058, 6, ["Statue"]]
- [ 0x0058, 7, [ "RollerHorizontalLeft", "Statue" ] ] #"Skull Woods - Lever Room - Hardhat Beetle 2"
- [ 0x0058, 8, ["Statue"]]
- [ 0x0059, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Mini Moldorm 1"
- [ 0x0059, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Skull Woods - Bridge Room - Mini Moldorm 2"
- [ 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, 4, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ice Palace - Pit Trap - Fire Bar (Clockwise)"
- [ 0x005f, 0, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Ice Palace - Bari University - Blue Bari 1"
- [ 0x005f, 1, [ "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Ice Palace - Bari University - Blue Bari 2"
- [ 0x0060, 0, [ "RollerVerticalUp", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Hyrule Castle - West - Blue Guard"
- [ 0x0062, 0, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Hyrule Castle - East - Blue Guard"
- [ 0x0064, 2, [ "Bumper" , "Beamos" ] ] #"Thieves' Town - Attic Hall Left - Keese 2"
- [ 0x0064, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x0064, 4, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Attic Hall Left - Rat 1"
- [ 0x0065, 0, [ "RollerVerticalUp", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Attic Window - Rat 1"
- [ 0x0065, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Attic Window - Rat 2"
- [ 0x0065, 2, [ "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Thieves' Town - Attic Window - Rat 3"
- [ 0x0066, 0, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Swamp Palace - Waterfall Room - Hover 1"
- [ 0x0066, 2, [ "AntiFairyCircle", "Bumper"]]
- [ 0x0067, 1, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Blue Bari 1"
- [ 0x0067, 2, ["Bumper"]] #"Skull Woods - Firebar Pits - Blue Bari 2"
- [ 0x0067, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 1"
- [ 0x0067, 4, [ "AntiFairyCircle", "Bumper" ]]
- [ 0x0067, 5, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 3"
- [ 0x0067, 6, [ "RollerVerticalDown" ] ] #"Skull Woods - Firebar Pits - Hardhat Beetle 4"
- [ 0x0067, 7, [ "Beamos", "AntiFairyCircle", "Bumper", "BunnyBeam" ] ] #"Skull Woods - Firebar Pits - Fire Bar (Clockwise)"
- [ 0x006a, 0, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 1"
- [ 0x006a, 1, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 2"
- [ 0x006a, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Palace of Darkness - Dark Alley - Antifairy 1"
- [ 0x006a, 4, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Palace of Darkness - Dark Alley - Terrorpin 3"
- [ 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"
- [ 0x0071, 0, [ "RollerHorizontalLeft" ] ] #"Hyrule Castle - Basement Trap - Green Guard"
- [ 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, 4, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - North Hallway - Leever 1"
- [ 0x0074, 5, [ "AntiFairyCircle", "Bumper" ] ] #"Desert Palace - North Hallway - Leever 2"
- [ 0x0076, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Hover 1"
- [ 0x0076, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Kyameron"
- [ 0x0076, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Hover 2"
- [ 0x0076, 4, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Swamp Palace - Toilet Left - Zol"
- [ 0x0076, 6, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Swamp Palace - Toilet Left - Blue Bari"
- [ 0x007b, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - DMs Room - Blue Bari 1"
- [ 0x007b, 1, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - DMs Room - Blue Bari 2"
- [ 0x007b, 6, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - DMs Room - Statue"
- [ 0x007b, 7, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - DMs Room - Hardhat Beetle"
- [ 0x007c, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Counterclockwise)"
- [ 0x007c, 2, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Spike Trap"
- [ 0x007c, 3, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Fire Bar (Clockwise)"
- [ 0x007c, 4, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Randomizer Room - Hardhat Beetle"
- [ 0x007d, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 1"
- [ 0x007d, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 2"
- [ 0x007d, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 3"
- [ 0x007d, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - The Zoo - Fire Snake 4"
- [ 0x007d, 4, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
- [ 0x007d, 7, ["RollerVerticalUp", "RollerHorizontalLeft", "StalfosKnight", "Geldman", "Blob", "Stal"]] #"Ganon's Tower - The Zoo - Mini Helmasaur"
- [ 0x007d, 8, ["RollerVerticalUp", "RollerHorizontalLeft", "RollerHorizontalRight", "StalfosKnight", "Geldman", "Blob", "Stal"]] #"Ganon's Tower - The Zoo - Red Bari"
- [ 0x007d, 10, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
# todo - consider adding firesnake to 0-3: has a hard time moving, could block hookshots for quite a while
- [ 0x007f, 0, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Big Spikes - Red Bari 1"
- [ 0x007f, 1, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper", "ArmosStatue" ] ] #"Ice Palace - Big Spikes - Red Bari 2"
- [ 0x007f, 2, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Big Spikes - Red Bari 3"
- [ 0x007f, 3, [ "Statue", "SparkCW", "SparkCCW", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Big Spikes - Red Bari 4"
- [ 0x007f, 4, [ "RollerVerticalDown" ] ] #"Ice Palace - Big Spikes - Big Spike Trap 1"
- [ 0x007f, 5, [ "RollerVerticalDown" ] ] #"Ice Palace - Big Spikes - Big Spike Trap 2"
- [ 0x0082, 0, [ "RollerVerticalDown" ] ] #"Hyrule Castle - Basement Playpit - Blue Guard 1"
- [ 0x0082, 2, [ "RollerVerticalUp" ] ] #"Hyrule Castle - Basement Playpit - Blue Guard 3"
- [ 0x0083, 0, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Desert Palace - Left Hallway - Blue Devalant 1"
- [ 0x0084, 0, [ "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - Main Room - Left - Leever 1"
- [ 0x0084, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - Main Room - Left - Leever 2"
- [ 0x0085, 2, [ "RollerHorizontalRight" ] ] #"Desert Palace - Compass Room - Popo TL"
- [ 0x0085, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Desert Palace - Right Hallway - Leever 2"
- [ 0x008b, 3, ["RollerHorizontalRight"]]
- [ 0x008b, 4, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper", "BigSpike"]] #"Ganon's Tower - Map Room - Spike Trap"
- [ 0x008b, 6, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Map Room - Fire Bar (Clockwise)"
- [ 0x008b, 7, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Map Room - Fire Bar (Counterclockwise)"
- [ 0x008c, 14, ["AntiFairyCircle", "BigSpike", "Bumper"]]
- [ 0x008d, 1, [ "AntiFairyCircle", "Bumper" ] ] #"Ganon's Tower - Tile Room - Yomo Medusa T"
- [ 0x008d, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Tile Room - Spike Trap"
- [ 0x008d, 8, [ "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Tile Room - Stalfos"
- [ 0x008d, 9, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Tile Room - Fire Bar (Clockwise)"
- [ 0x008d, 10, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ganon's Tower - Tile Room - Blue Bari 1"
- [ 0x008d, 12, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Ganon's Tower - Tile Room - Blue Bari 2"
- [ 0x008e, 2, [ "Wizzrobe", "Statue"] ] # Wizzrobes can't spawn on pots
- [ 0x0092, 8, [ "RollerVerticalUp", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Misery Mire - Dark Weave - Spike Trap"
- [ 0x0092, 9, [ "RollerHorizontalRight" ] ] #"Misery Mire - Dark Weave - Antifairy 3"
- [ 0x0092, 10, [ "RollerHorizontalLeft" ] ] #"Misery Mire - Dark Weave - Stalfos"
- [ 0x0095, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 1"
- [ 0x0095, 1, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 2"
- [ 0x0095, 2, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 3"
- [ 0x0095, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock" ] ] #"Ganon's Tower - Conveyer Falling Bridge - Red Spear Guard 4"
- [ 0x0096, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Torches 1 - Fire Bar (Clockwise)"
- [ 0x0098, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 1"
- [ 0x0098, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 2"
- [ 0x0098, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 3"
- [ 0x0098, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 4"
- [ 0x0098, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Entrance - Zol 5"
- [ 0x009b, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 1"
- [ 0x009b, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 2"
- [ 0x009b, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ]
- [ 0x009b, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 4"
- [ 0x009b, 8, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 5"
- [ 0x009b, 9, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 6"
- [ 0x009b, 10, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Spike Switch - Spike Trap 7"
- [ 0x009c, 1, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Mini Helmasaur"
- [ 0x009c, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 2"
- [ 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, 5, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Invisible Floor Maze - Hardhat Beetle 5"
- [ 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, 7, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Compass Room - Blue Bari 2"
- [ 0x009d, 8, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Ganon's Tower - Compass Room - Blue Bari 3"
- [ 0x009e, 0, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Fairy Drop - blue - Red Bari 1"
- [ 0x009e, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Fairy Drop - blue - Red Bari 2"
- [ 0x009e, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Fairy Drop - blue - Stalfos Knight"
- [ 0x009e, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Fairy Drop - blue - Red Bari 3"
- [ 0x00a0, 1, [ "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Boss Antechamber - Antifairy"
- [ 0x00a1, 2, [ "Statue", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Fish Room - Spark (Clockwise) 2"
- [ 0x00a1, 7, [ "Wizzrobe", "Statue"] ] # Wizzrobes can't spawn on pots
- [ 0x00a5, 2, [ "BigSpike" ] ] #"GT Wizzrobes 1 - Wizzrobe 3"
- [ 0x00a5, 10, [ "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ganon's Tower - Laser Bridge - Red Spear Guard"
- [ 0x00a8, 1, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Eastern Palace - West Wing - Top - Stalfos 2"
- [ 0x00a8, 3, [ "RollerVerticalDown", "RollerHorizontalLeft" ] ] #"Eastern Palace - West Wing - Top - Stalfos 4"
- [ 0x00a9, 1, [ "RollerHorizontalRight", "RollerHorizontalLeft" ] ]
- [ 0x00aa, 4, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - East Wing - Top - Stalfos 3"
- [ 0x00aa, 5, [ "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - East Wing - Top - Popo B 2"
- [ 0x00ab, 7, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Thieves' Town - Spike Dodge - Spike Trap 6"
- [ 0x00ae, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 1"
- [ 0x00ae, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Ice Palace - Ice T - Blue Bari 2"
- [ 0x00af, 0, [ "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Ice Clock - Fire Bar (Clockwise)"
- [ 0x00b1, 2, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 1"
- [ 0x00b1, 3, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Misery Mire - Hourglass - Spike Trap 2"
- [ 0x00b1, 4, ["Bumper", "BigSpike", "AntiFairyCircle" ]]
- [ 0x00b2, 1, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00b2, 3, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00b2, 6, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Misery Mire - Sluggula Cross - Sluggula TR"
- [ 0x00b2, 8, [ "RollerVerticalDown" ] ] #"Misery Mire - Popo Push - Medusa 1"
- [ 0x00b2, 9, [ "RollerVerticalUp" ] ] #"Misery Mire - Sluggula Cross - Sluggula BL"
- [ 0x00b3, 0, [ "RollerVerticalUp", "RollerHorizontalRight", "BigSpike", "SpikeBlock" ] ] #"Misery Mire - Spike Room - Stalfos 1"
- [ 0x00b3, 2, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "Bumper" ] ] #"Misery Mire - Spike Room - Beamos"
- [ 0x00b3, 3, [ "AntiFairyCircle", "Bumper" ] ] #"Misery Mire - Spike Room - Yomo Medusa"
- [ 0x00b6, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 1"
- [ 0x00b6, 8, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Tile Room - Zol 2"
- [ 0x00ba, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Antifairy 1"
- [ 0x00ba, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Antifairy 2"
- [ 0x00ba, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Popo B 1"
- [ 0x00ba, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Dark Stalfos - Popo B 2"
- [ 0x00bb, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Spikeveyer - Gibo 1"
- [ 0x00bb, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "Bumper" ] ] #"Thieves' Town - Spikeveyer - Antifairy 1"
- [ 0x00bb, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Spikeveyer - Gibo 3"
- [ 0x00bb, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Spikeveyer - Fire Snake"
- [ 0x00bb, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Spikeveyer - Gibo 4"
- [ 0x00bb, 8, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Spikeveyer - Gibo 5"
- [ 0x00bb, 9, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Thieves' Town - Spikeveyer - Antifairy 2"
- [ 0x00bc, 6, [ "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Toilet - Stalfos 2"
- [ 0x00bc, 7, [ "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Toilet - Stalfos 3"
- [ 0x00bc, 8, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Thieves' Town - Toilet - Stalfos 4"
- [ 0x00bf, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on collision
- [ 0x00c1, 3, [ "RollerVerticalUp", "RollerHorizontalLeft" ] ] #"Misery Mire - 4 Rails - Stalfos 1"
- [ 0x00c2, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Misery Mire - Main Lobby - blue - Fire Snake 1"
- [ 0x00c2, 5, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00c5, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Catwalk - Mini Helmasaur"
- [ 0x00c5, 7, [ "Statue" ] ] #"Turtle Rock - Catwalk - Laser Eye (Left) 4"
- [ 0x00cb, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00cb, 3, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Grand Room NW - Zol 1"
- [ 0x00cb, 5, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Thieves' Town - Grand Room NW - Zol 2"
- [ 0x00cb, 9, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ]
- [ 0x00cb, 10, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ]
- [ 0x00cb, 11, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00cc, 8, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #Prevents Pot access (Beamos okay?)
- [ 0x00cc, 12, [ "RollerVerticalUp", "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #Prevents Pot access (Beamos okay?)
- [ 0x00ce, 0, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "Antifairy", "BigSpike", "FirebarCCW", "Bumper" ] ] #"Ice Palace - Over Boss - top - Red Bari 1"
- [ 0x00ce, 1, [ "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "AntiFairyCircle", "Antifairy", "BigSpike", "FirebarCW", "Bumper" ] ] #"Ice Palace - Over Boss - top - Red Bari 2"
- [ 0x00ce, 3, [ "SparkCW", "SparkCCW", "RollerVerticalDown", "RollerVerticalUp", "RollerHorizontalRight", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "Antifairy", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Ice Palace - Over Boss - top - Statue"
- [ 0x00ce, 4, [ "RollerVerticalDown", "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Beamos", "Bumper", "FirebarCW", "FirebarCCW"]]
- [ 0x00ce, 5, [ "RollerVerticalDown", "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Beamos", "Bumper", "FirebarCW", "FirebarCCW"]]
- [ 0x00ce, 6, [ "RollerVerticalDown", "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Beamos", "Bumper", "FirebarCW", "FirebarCCW"]]
- [ 0x00ce, 7, [ "RollerVerticalDown", "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Beamos", "Bumper", "FirebarCW", "FirebarCCW"]]
- [ 0x00d0, 0, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
- [ 0x00d0, 1, [ "AntiFairyCircle", "BigSpike", "Bumper"]]
- [ 0x00d0, 4, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
- [ 0x00d0, 5, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
- [ 0x00d0, 6, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
- [ 0x00d0, 7, [ "Statue", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper"]]
- [ 0x00d0, 9, [ "AntiFairyCircle", "BigSpike", "Bumper"]]
- [ 0x00d0, 6, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] # Agahnims Tower - Dark Maze - Blue Guard 2
- [ 0x00d2, 8, [ "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Misery Mire - Mire 2 - Popo BL"
- [ 0x00d5, 4, [ "Statue", "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "FirebarCW", "FirebarCCW", "SpikeBlock", "Bumper" ] ] #"Turtle Rock - Eye Bridge - Hardhat Beetle"
- [ 0x00d8, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Red Eyegore L"
- [ 0x00d8, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Red Eyegore R"
- [ 0x00d8, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo B TL"
- [ 0x00d8, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo B TR"
- [ 0x00d8, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo B LT"
- [ 0x00d8, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo B RT"
- [ 0x00d8, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo LB"
- [ 0x00d8, 7, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Eastern Palace - Kill Room 2 - Popo RB"
- [ 0x00d8, 8, [ "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Eastern Palace - Kill Room 1 - Red Eyegore"
- [ 0x00d9, 1, [ "RollerHorizontalRight" ] ] #"Eastern Palace - Dodgeball - Green Eyegore 1"
- [ 0x00db, 0, [ "Wizzrobe", "Statue" ] ] # Wizzrobes can't spawn on pots
- [ 0x00dc, 2, [ "AntiFairyCircle", "BigSpike", "Bumper" ] ]
- [ 0x00dc, 9, [ "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Thieves' Town - Grand Room SE - Fire Snake 2"
- [ 0x00df, 0, [ "RollerVerticalDown", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Paradox Cave - Top - Mini Moldorm 1"
- [ 0x00df, 1, [ "RollerVerticalDown", "RollerHorizontalRight", "AntiFairyCircle" ] ] #"Paradox Cave - Top - Mini Moldorm 2"
- [ 0x00e4, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 1"
- [ 0x00e4, 1, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 2"
- [ 0x00e4, 2, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home - Keese 3"
- [ 0x00e5, 4, [ "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home Circle - Keese 5"
- [ 0x00e5, 5, [ "RollerVerticalDown", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Old Man Home Circle - Keese 6"
- [ 0x00e7, 0, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Death Mountain Descent Cave Right - Keese 1"
- [ 0x00e7, 1, [ "RollerVerticalUp", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Death Mountain Descent Cave Right - Keese 2"
- [ 0x00e7, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Death Mountain Descent Cave Right - Keese 3"
- [ 0x00e7, 3, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Death Mountain Descent Cave Right - Keese 4"
- [ 0x00e7, 4, [ "RollerVerticalDown", "Beamos", "AntiFairyCircle", "Bumper" ] ] #"Death Mountain Descent Cave Right - Keese 5"
- [ 0x00e7, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Death Mountain Descent Cave Right - Keese 6"
- [ 0x00e7, 6, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalRight" ] ] #"Death Mountain Descent Cave Right - Keese 7"
- [ 0x00e8, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "AntiFairyCircle", "SpikeBlock", "Bumper" ] ] #"Super Bunny Exit - Hardhat Beetle 1"
- [ 0x00e8, 1, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Super Bunny Exit - Hardhat Beetle 2"
- [ 0x00ee, 0, [ "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "Bumper" ] ] #"Sprial Cave Top - Mini Moldorm 1"
- [ 0x00ee, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sprial Cave Top - Mini Moldorm 2"
- [ 0x00ee, 2, [ "RollerHorizontalLeft", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sprial Cave Top - Mini Moldorm 3"
- [ 0x00ee, 3, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sprial Cave Top - Blue Bari 1"
- [ 0x00ee, 4, [ "RollerVerticalUp", "RollerVerticalDown", "Beamos", "AntiFairyCircle", "BigSpike", "SpikeBlock", "Bumper" ] ] #"Sprial Cave Top - Blue Bari 2"
- [ 0x00ef, 1, [ "RollerVerticalUp", "RollerVerticalDown" ] ] #"Paradox Cave - Middle - Mini Moldorm 2"
- [ 0x00f1, 0, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 1"
- [ 0x00f1, 1, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 2"
- [ 0x00f1, 2, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 3"
- [ 0x00f1, 3, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 4"
- [ 0x00f1, 4, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 5"
- [ 0x00f1, 5, [ "RollerVerticalUp", "RollerVerticalDown", "RollerHorizontalLeft", "RollerHorizontalRight" ] ] #"Old Man Maze - Keese 6"
- [ 0x00fd, 0, [ "Bumper" ] ]
- [ 0x0107, 1, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
- [ 0x0107, 2, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]]
- [0x010b, 6, ["RollerHorizontalRight"]]
- [0x010c, 6, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
- [0x010c, 7, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
OwGeneralDeny:
- [0x03, 2, ["Gibo"]] # OldMan eating Gibo
- [0x03, 4, ["Gibo"]] # OldMan eating Gibo
- [0x03, 5, ["Gibo"]] # OldMan eating Gibo
- [0x03, 6, ["Gibo"]] # OldMan eating Gibo
- [0x03, 8, ["Gibo"]] # OldMan eating Gibo
- [0x03, 9, ["Gibo"]] # OldMan eating Gibo
- [0x03, 10, ["Gibo"]] # OldMan eating Gibo
- [0x05, 11, ["Bumper", "AntiFairyCircle"]] # Blocks path to portal
- [0x1e, 3, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle"]] # forbid a beamos here
- [0x40, 0, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x40, 7, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x40, 13, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x40, 14, ["Beamos", "Bumper", "BigSpike", "AntiFairyCircle", "Thief"]]
- [0x5e, 0, ["Gibo"]] # kiki eating Gibo
- [0x5e, 1, ["Gibo"]] # kiki eating Gibo
- [0x5e, 2, ["Gibo"]] # kiki eating Gibo
- [0x5e, 3, ["Gibo"]] # kiki eating Gibo
- [0x5e, 4, ["RollerVerticalUp", "Gibo"]] # forbid that one roller for kiki pod, and the kiki eating Gibo
- [0x5e, 5, ["Gibo"]] # kiki eating Gibo
- [0x5e, 6, ["Gibo"]] # kiki eating Gibo
- [0x5e, 7, ["Gibo"]] # kiki eating Gibo
- [0x5e, 8, ["Gibo"]] # kiki eating Gibo
- [0x5e, 9, ["Gibo"]] # kiki eating Gibo
- [0x5e, 10, ["Gibo"]] # kiki eating Gibo
- [0x5e, 11, ["Gibo"]] # kiki eating Gibo
- [0x5e, 12, ["Gibo"]] # kiki eating Gibo
- [0x5e, 13, ["Gibo"]] # kiki eating Gibo
- [0x5e, 14, ["Gibo"]] # kiki eating Gibo
- [0x5e, 15, ["Gibo"]] # kiki eating Gibo
- [0x5e, 16, ["Gibo"]] # kiki eating Gibo
- [0x5e, 17, ["Gibo"]] # kiki eating Gibo
- [0x5e, 18, ["Gibo"]] # kiki eating Gibo
- [0x5e, 19, ["Gibo"]] # kiki eating Gibo
- [0x5e, 20, ["Gibo"]] # kiki eating Gibo
- [0x77, 1, ["Bumper"]] # soft-lock potential near ladder
UwEnemyDrop:
- [0x0085, 9, ["Babasu"]] # ran off the edge and didn't return
- [0x00cb, 3, ["Zoro"]] # layer issues
- [0x00cb, 5, ["Zoro"]] # layer issues
- [0x00cb, 9, ["Zoro"]] # layer issues
- [0x00cb, 10, ["Zoro"]] # layer issues
- [0x00cc, 5, ["Babasu"]] # little hard to see and kill appropriately
# the following are behind rails or otherwise unactivate-able
- [0x0077, 4, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]] # can't activate here
- [0x0077, 5, ["StalfosKnight", "Geldman", "Blob", "Stal", "Wizzrobe"]]
- [0x008D, 10, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
- [0x008D, 12, ["StalfosKnight", "Geldman", "Blob", "Stal"]]
- [0x00b0, 7, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
- [0x00b0, 8, ["StalfosKnight", "Blob", "Stal", "Wizzrobe"]] # blocked, but Geldmen are probably okay
# the following are not allowed at certain pits (or on conveyors near pits)
# because they despawned or clipped away or immediately fell, etc
- [0x003d, 9, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x003d, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0044, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0044, 8, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0049, 10, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x007b, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x007b, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x007f, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x007f, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x0095, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x0095, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic"]]
- [0x00b5, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00b5, 1, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00b5, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 2, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 3, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 4, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 5, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Bumper", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00c6, 6, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
- [0x00e6, 0, ["HardhatBeetle", "Wizzrobe", "MiniHelmasaur", "BlueGuard", "GreenGuard", "RedSpearGuard",
"BluesainBolt", "UsainBolt", "BlueArcher", "GreenBushGuard", "RedJavelinGuard", "RedBushGuard",
"BombGuard", "GreenKnifeGuard", "Stal", "GreenMimic", "RedMimic", "StalfosKnight", "Geldman", "Blob"]]
# wizzrobe despawn issues - on pots/blocks - too close to some object
- [0x0013, 3, ["Wizzrobe"]]
- [0x0016, 0, ["Wizzrobe"]]
- [0x0016, 1, ["Wizzrobe"]]
- [0x0016, 2, ["Wizzrobe"]]
- [0x0016, 3, ["Wizzrobe"]]
- [0x0017, 5, ["Wizzrobe", "Stal"]]
- [0x0019, 2, ["Wizzrobe"]]
- [0x0019, 3, ["Wizzrobe"]]
- [0x001e, 1, ["Wizzrobe"]]
- [0x001e, 2, ["Wizzrobe"]]
- [0x0027, 5, ["Wizzrobe"]]
- [0x0027, 6, ["Wizzrobe"]]
- [0x002a, 3, ["Wizzrobe"]]
- [0x002a, 7, ["Wizzrobe"]]
- [0x002e, 4, ["Wizzrobe"]]
- [0x0035, 5, ["Wizzrobe"]]
- [0x0036, 8, ["Wizzrobe"]]
- [0x003b, 0, ["Wizzrobe"]]
- [0x003b, 2, ["Wizzrobe"]]
- [0x003b, 4, ["Wizzrobe"]]
- [0x003b, 6, ["Wizzrobe"]]
- [0x003c, 1, ["Wizzrobe"]]
- [0x003d, 11, ["Wizzrobe"]]
- [0x003d, 12, ["Wizzrobe"]]
- [0x003d, 13, ["Wizzrobe"]]
- [0x004b, 2, ["Wizzrobe"]]
- [0x004b, 6, ["Wizzrobe"]]
- [0x004b, 7, ["Wizzrobe"]]
- [0x004e, 3, ["Wizzrobe", "Stal"]]
- [0x0054, 3, ["Wizzrobe", "Stal"]]
- [0x0055, 2, ["Wizzrobe"]] # slightly on wall
- [0x005e, 4, ["Wizzrobe", "Stal"]]
- [0x0065, 3, ["Wizzrobe"]]
- [0x0067, 5, ["Wizzrobe"]]
- [0x0067, 6, ["Wizzrobe"]]
- [0x0067, 7, ["Wizzrobe", "Stal"]]
- [0x0067, 8, ["Wizzrobe", "Stal"]]
- [0x0074, 5, ["Wizzrobe"]]
- [0x007c, 1, ["Wizzrobe", "Stal"]]
- [0x007c, 3, ["Wizzrobe", "Stal"]]
- [0x007e, 1, ["Wizzrobe", "Stal"]]
- [0x007e, 6, ["Wizzrobe", "Stal"]]
- [0x0083, 9, ["Wizzrobe"]]
- [0x008b, 6, ["Wizzrobe", "Stal"]]
- [0x008b, 7, ["Wizzrobe", "Stal"]]
- [0x008d, 9, ["Wizzrobe", "Stal"]]
- [0x0096, 0, ["Wizzrobe", "Stal"]]
- [0x009b, 11, ["Wizzrobe"]]
- [0x009f, 5, ["Wizzrobe", "Stal"]]
- [0x00a1, 1, ["Wizzrobe"]]
- [0x00aa, 5, ["Wizzrobe"]]
- [0x00af, 0, ["Wizzrobe", "Stal"]]
- [0x00b0, 1, ["Wizzrobe"]]
- [0x00b0, 2, ["Wizzrobe"]]
- [0x00b2, 4, ["Wizzrobe"]]
- [0x00b8, 2, ["Wizzrobe"]]
- [0x00bf, 1, ["Wizzrobe"]]
- [0x00c1, 3, ["Wizzrobe", "Stal"]]
- [0x00c2, 0, ["Wizzrobe"]]
- [0x00c2, 3, ["Wizzrobe"]]
- [0x00c2, 7, ["Wizzrobe"]]
- [0x00ce, 4, ["Wizzrobe", "Leever", "BlueGuard", "GreenGuard", "RedSpearGuard", "BluesainBolt", "UsainBolt",
"BlueArcher", "RedJavelinGuard", "GreenKnifeGuard", "GreenMimic", "RedMimic"]]
- [0x00ce, 5, ["Wizzrobe", "Leever", "BlueGuard", "GreenGuard", "RedSpearGuard", "BluesainBolt", "UsainBolt",
"BlueArcher", "RedJavelinGuard", "GreenKnifeGuard", "GreenMimic", "RedMimic"]]
- [0x00ce, 6, ["Wizzrobe", "Leever", "BlueGuard", "GreenGuard", "RedSpearGuard", "BluesainBolt", "UsainBolt",
"BlueArcher", "RedJavelinGuard", "GreenKnifeGuard", "GreenMimic", "RedMimic"]]
- [0x00ce, 7, ["Wizzrobe", "Leever", "BlueGuard", "GreenGuard", "RedSpearGuard", "BluesainBolt", "UsainBolt",
"BlueArcher", "RedJavelinGuard", "GreenKnifeGuard", "GreenMimic", "RedMimic"]]
- [0x00d0, 0, ["Wizzrobe"]]
- [0x00d0, 2, ["Wizzrobe"]]
- [0x00d0, 4, ["Wizzrobe"]]
- [0x00d0, 5, ["Wizzrobe"]]
- [0x00d0, 9, ["Wizzrobe"]]
- [0x00d5, 4, ["Wizzrobe"]]
- [0x00df, 1, ["Wizzrobe"]] # slightly on wall
- [0x00e7, 4, ["Wizzrobe"]] # slightly on wall
- [0x00fd, 1, ["Wizzrobe"]] # slightly on rock
- [0x010c, 4, ["Wizzrobe"]]
- [0x010c, 5, ["Wizzrobe"]]
# other mimic cave spots are in the rail section
# enemies that have problems with conveyors
- [0x003b, 0, ["GreenMimic", "RedMimic"]]
- [0x003b, 1, ["GreenMimic", "RedMimic"]]
- [0x003b, 2, ["GreenMimic", "RedMimic"]]
- [0x003b, 3, ["GreenMimic", "RedMimic"]]
- [0x003b, 4, ["GreenMimic", "RedMimic"]]
- [0x003b, 5, ["GreenMimic", "RedMimic"]]
- [0x003b, 6, ["GreenMimic", "RedMimic"]]
- [0x003d, 6, ["GreenMimic", "RedMimic"]]
- [0x003d, 7, ["GreenMimic", "RedMimic"]]
- [0x003e, 8, ["GreenMimic", "RedMimic"]]
- [0x003e, 9, ["GreenMimic", "RedMimic"]]
- [0x003e, 10, ["GreenMimic", "RedMimic"]]
- [0x003e, 11, ["GreenMimic", "RedMimic"]]
- [0x0044, 0, ["GreenMimic", "RedMimic"]]
- [0x0044, 1, ["GreenMimic", "RedMimic"]]
- [0x0044, 2, ["GreenMimic", "RedMimic"]]
- [0x0044, 3, ["GreenMimic", "RedMimic"]]
- [0x0044, 5, ["GreenMimic", "RedMimic"]]
- [0x004c, 0, ["GreenMimic", "RedMimic"]]
- [0x004c, 1, ["GreenMimic", "RedMimic"]]
- [0x004c, 2, ["GreenMimic", "RedMimic"]]
- [0x004c, 3, ["GreenMimic", "RedMimic"]]
- [0x004c, 4, ["GreenMimic", "RedMimic"]]
- [0x004c, 5, ["GreenMimic", "RedMimic"]]
- [0x004c, 6, ["GreenMimic", "RedMimic"]]
- [0x004c, 7, ["GreenMimic", "RedMimic"]]
- [0x005d, 3, ["GreenMimic", "RedMimic"]]
- [0x005d, 4, ["GreenMimic", "RedMimic"]]
- [0x005d, 5, ["GreenMimic", "RedMimic"]]
- [0x005d, 6, ["GreenMimic", "RedMimic"]]
- [0x005d, 8, ["GreenMimic", "RedMimic"]]
- [0x005d, 9, ["GreenMimic", "RedMimic"]]
- [0x005d, 10, ["GreenMimic", "RedMimic"]]
- [0x005d, 11, ["GreenMimic", "RedMimic"]]
- [0x005d, 12, ["GreenMimic", "RedMimic"]]
# - [0x006d, ?, ["GreenMimic", "RedMimic"]] # conveyor doesn't hit edge
# - [0x008b, ?, ["GreenMimic", "RedMimic"]] # conveyor doesn't hit edge
- [0x0092, 2, ["GreenMimic", "RedMimic"]]
- [0x00a5, 0, ["GreenMimic", "RedMimic"]]
- [0x00a5, 1, ["GreenMimic", "RedMimic"]]
- [0x00a5, 4, ["GreenMimic", "RedMimic"]]
- [0x00a5, 5, ["GreenMimic", "RedMimic"]]
- [0x00a5, 6, ["GreenMimic", "RedMimic"]]
- [0x00bb, 1, ["GreenMimic", "RedMimic"]]
- [0x00bb, 4, ["GreenMimic", "RedMimic"]]
- [0x00bb, 5, ["GreenMimic", "RedMimic"]]
- [0x00bb, 6, ["GreenMimic", "RedMimic"]]
- [0x00bb, 7, ["GreenMimic", "RedMimic"]]
- [0x00bb, 8, ["GreenMimic", "RedMimic"]]
- [0x00bb, 9, ["GreenMimic", "RedMimic"]]
- [0x00bb, 10, ["GreenMimic", "RedMimic"]]
- [0x00bc, 0, ["GreenMimic", "RedMimic"]]
- [0x00bc, 1, ["GreenMimic", "RedMimic"]]
- [0x00bc, 2, ["GreenMimic", "RedMimic"]]
- [0x00bc, 3, ["GreenMimic", "RedMimic"]]
- [0x00bc, 4, ["GreenMimic", "RedMimic"]]
- [0x00bc, 5, ["GreenMimic", "RedMimic"]]
- [0x00c1, 5, ["GreenMimic", "RedMimic"]]
- [0x00c1, 8, ["GreenMimic", "RedMimic"]]
- [0x00c1, 9, ["GreenMimic", "RedMimic"]]
- [0x00c1, 10, ["GreenMimic", "RedMimic"]]
- [0x00c1, 11, ["GreenMimic", "RedMimic"]]
- [0x00d1, 5, ["GreenMimic", "RedMimic"]]
- [0x00d1, 6, ["GreenMimic", "RedMimic"]]
# the following are all slightly in the wall on spawn - not too applicable right now, these don't drop anyway
- [0x0064, 0, ["Leever"]]
- [0x00e5, 3, ["Wizzrobe"]]
- [0x00e5, 4, ["Leever", "Wizzrobe"]]
- [0x00e5, 5, ["Leever", "Wizzrobe"]]
# the pit one in 0xe6 room is in the pit section
- [0x00e6, 1, ["Leever", "Wizzrobe"]]
- [0x00e6, 2, ["Leever", "Wizzrobe"]]
- [0x00e6, 3, ["Leever", "Wizzrobe"]]
- [0x00e6, 4, ["Leever", "Wizzrobe"]]
- [0x00e7, 0, ["Wizzrobe"]]
- [0x00e7, 1, ["Wizzrobe"]]
- [0x00e7, 2, ["Wizzrobe"]]
- [0x00e7, 3, ["Leever"]]
- [0x00e7, 4, ["Leever", "Wizzrobe"]]
- [0x00e7, 5, ["Leever", "Wizzrobe"]]
- [0x00e7, 6, ["Wizzrobe"]]
- [0x00f0, 2, ["Leever"]] # clipped away
- [0x00f0, 3, ["Leever"]]
- [0x00f0, 4, ["Leever"]]
- [0x00f0, 5, ["Leever"]]
- [0x00f0, 6, ["Leever"]]
- [0x00f0, 8, ["Leever"]]
- [0x00f1, 0, ["Leever", "Wizzrobe"]]
- [0x00f1, 1, ["Leever", "Wizzrobe"]]
- [0x00f1, 2, ["Wizzrobe"]]
- [0x00f1, 3, ["Wizzrobe"]]
- [0x00f1, 4, ["Wizzrobe"]]
- [0x00f1, 5, ["Wizzrobe"]]
- [0x00f1, 6, ["Leever", "Wizzrobe"]]
- [0x00f1, 7, ["Leever", "Wizzrobe"]]
- [0x00f1, 8, ["Leever", "Wizzrobe"]]
- [0x00f1, 9, ["Leever", "Wizzrobe"]]
+57 -8
View File
@@ -6,7 +6,7 @@ import random
import re import re
from CLI import parse_cli from CLI import parse_cli
from Fill import FillError from Fill import FillError
from Main import main, EnemizerError from Main import main, export_yaml, EnemizerError
from Utils import local_path, output_path, open_file, update_deprecated_args from Utils import local_path, output_path, open_file, update_deprecated_args
import source.classes.constants as CONST import source.classes.constants as CONST
from source.gui.randomize.multiworld import multiworld_page from source.gui.randomize.multiworld import multiworld_page
@@ -68,6 +68,15 @@ def bottom_frame(self, parent, args=None):
self.widgets[key].pack(side=LEFT) self.widgets[key].pack(side=LEFT)
def generateRom(): def generateRom():
guiargs = create_guiargs(parent)
argsDump = vars(guiargs)
from Gui import save_settings
if parent.randomSprite.get():
argsDump['sprite'] = 'random'
elif argsDump['sprite']:
argsDump['sprite'] = argsDump['sprite'].name
save_settings(parent, argsDump, "last.json")
guiargs = create_guiargs(parent) guiargs = create_guiargs(parent)
# get default values for missing parameters # get default values for missing parameters
for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items(): for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items():
@@ -141,9 +150,45 @@ def bottom_frame(self, parent, args=None):
# button # button
self.widgets[widget].type = "button" self.widgets[widget].type = "button"
self.widgets[widget].pieces["button"] = Button(self, text='Generate Patched Rom', command=generateRom) self.widgets[widget].pieces["button"] = Button(self, command=generateRom)
# button: pack # button: pack
self.widgets[widget].pieces["button"].pack(side=LEFT) self.widgets[widget].pieces["button"].pack(side=LEFT)
self.widgets[widget].pieces["button"].configure(bg="#CCCCCC")
def exportYaml():
guiargs = create_guiargs(parent)
# get default values for missing parameters
for k,v in vars(parse_cli(['--multi', str(guiargs.multi)])).items():
if k not in vars(guiargs):
setattr(guiargs, k, v)
elif type(v) is dict: # use same settings for every player
setattr(guiargs, k, {player: getattr(guiargs, k) for player in range(1, guiargs.multi + 1)})
filename = None
try:
from tkinter import filedialog
filename = filedialog.asksaveasfilename(initialdir=guiargs.outputpath, title="Save file", filetypes=(("Yaml Files", (".yaml", ".yml")), ("All Files", "*")))
if filename is not None and filename != '':
guiargs.outputpath = parent.settings["outputpath"] = os.path.dirname(filename)
guiargs.outputname = os.path.splitext(os.path.basename(filename))[0]
export_yaml(args=guiargs, fish=parent.fish)
except (FillError, EnemizerError, Exception, RuntimeError) as e:
logging.exception(e)
messagebox.showerror(title="Error while exporting yaml", message=str(e))
else:
if filename is not None and filename != '':
successMsg = "File Exported"
# FIXME: English
messagebox.showinfo(title="Success", message=successMsg)
## Export Yaml Button
widget = "exportyaml"
self.widgets[widget] = Empty()
self.widgets[widget].pieces = {}
# button
self.widgets[widget].type = "button"
self.widgets[widget].pieces["button"] = Button(self, command=exportYaml)
self.widgets[widget].pieces["button"].pack(side=LEFT)
def open_output(): def open_output():
if output_path.cached_path is None: if output_path.cached_path is None:
@@ -161,12 +206,8 @@ def bottom_frame(self, parent, args=None):
args.outputpath = parent.settings["outputpath"] = folder_selected args.outputpath = parent.settings["outputpath"] = folder_selected
## Output Button ## Output Button
# widget ID
widget = "outputdir" widget = "outputdir"
# Empty object
self.widgets[widget] = Empty() self.widgets[widget] = Empty()
# pieces
self.widgets[widget].pieces = {} self.widgets[widget].pieces = {}
# storagevar # storagevar
@@ -174,8 +215,16 @@ def bottom_frame(self, parent, args=None):
# button # button
self.widgets[widget].type = "button" self.widgets[widget].type = "button"
self.widgets[widget].pieces["button"] = Button(self, text='Open Output Directory', command=select_output) self.widgets[widget].pieces["button"] = Button(self, command=select_output)
# button: pack self.widgets[widget].pieces["button"].pack(side=RIGHT)
## Save Settings Button
widget = "savesettings"
self.widgets[widget] = Empty()
self.widgets[widget].pieces = {}
# button
self.widgets[widget].type = "button"
self.widgets[widget].pieces["button"] = Button(self)
self.widgets[widget].pieces["button"].pack(side=RIGHT) self.widgets[widget].pieces["button"].pack(side=RIGHT)
## Documentation Button ## Documentation Button
+16
View File
@@ -158,6 +158,22 @@ def loadcliargs(gui, args, settings=None):
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget) label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget)
gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label) gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label)
# Set Export Yaml button
mainpage = "bottom"
subpage = "content"
widget = "exportyaml"
# set textbox/frame label
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget)
gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label)
# Set Save Settings button
mainpage = "bottom"
subpage = "content"
widget = "savesettings"
# set textbox/frame label
label = fish.translate("gui","gui",mainpage + '.' + subpage + '.' + widget)
gui.pages[mainpage].pages[subpage].widgets[widget].pieces["button"].configure(text=label)
# Set Output Directory button # Set Output Directory button
mainpage = "bottom" mainpage = "bottom"
subpage = "content" subpage = "content"
+9 -4
View File
@@ -1317,7 +1317,7 @@ def do_mandatory_connections(avail, entrances, cave_options, must_exit):
invalid_connections = Must_Exit_Invalid_Connections.copy() invalid_connections = Must_Exit_Invalid_Connections.copy()
invalid_cave_connections = defaultdict(set) invalid_cave_connections = defaultdict(set)
if avail.world.logic[avail.player] in ['owglitches', 'nologic']: if avail.world.logic[avail.player] in ['owglitches', 'hybridglitches', 'nologic']:
import OverworldGlitchRules import OverworldGlitchRules
for entrance in OverworldGlitchRules.get_non_mandatory_exits(avail.world, avail.player): for entrance in OverworldGlitchRules.get_non_mandatory_exits(avail.world, avail.player):
invalid_connections[entrance] = set() invalid_connections[entrance] = set()
@@ -1686,13 +1686,18 @@ def connect_exit(exit_name, entrancename, avail):
if exit.connected_region is not None: if exit.connected_region is not None:
exit.connected_region.entrances.remove(exit) exit.connected_region.entrances.remove(exit)
exit.connect(entrance.parent_region, door_addresses[entrance.name][1], exit_ids[exit.name][1]) dest_region = entrance.parent_region
if dest_region.name == 'Pyramid Crack':
# Needs to logically exit into greater Pyramid Area
dest_region = entrance.parent_region.entrances[0].parent_region
exit.connect(dest_region, door_addresses[entrance.name][1], exit_ids[exit.name][1])
if exit_name != 'Chris Houlihan Room Exit': if exit_name != 'Chris Houlihan Room Exit':
if avail.coupled: if avail.coupled:
avail.entrances.remove(entrancename) avail.entrances.remove(entrancename)
avail.exits.remove(exit_name) avail.exits.remove(exit_name)
world.spoiler.set_entrance(entrance.name, exit.name, 'exit', player) world.spoiler.set_entrance(entrance.name, exit.name, 'exit', player)
logging.getLogger('').debug(f'Connected (exit) {entrance.name} to {exit.name}') logging.getLogger('').debug(f'Connected (exit) {exit.name} to {entrance.name}')
def connect_two_way(entrancename, exit_name, avail): def connect_two_way(entrancename, exit_name, avail):
@@ -2659,7 +2664,7 @@ door_addresses = {'Links House': (0x00, (0x0104, 0x2c
'Mire Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00), 'Mire Hint': (0x61, (0x0114, 0x70, 0x0654, 0x0cc5, 0x02aa, 0x0d16, 0x0328, 0x0d32, 0x032f, 0x09, 0xf7, 0x0000, 0x0000), 0x00),
'Mire Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00), 'Mire Fairy': (0x55, (0x0115, 0x70, 0x03a8, 0x0c6a, 0x013a, 0x0cb7, 0x01b8, 0x0cd7, 0x01bf, 0x06, 0xfa, 0x0000, 0x0000), 0x00),
'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Spike Cave': (0x40, (0x0117, 0x43, 0x0ed4, 0x01e4, 0x08aa, 0x0236, 0x0928, 0x0253, 0x092f, 0x0a, 0xf6, 0x0000, 0x0000), 0x00),
'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0daa, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Dark Death Mountain Shop': (0x6D, (0x0112, 0x45, 0x0ee0, 0x01e3, 0x0d00, 0x0236, 0x0da8, 0x0252, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00),
'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000), 0x00), 'Dark Death Mountain Fairy': (0x6F, (0x0115, 0x43, 0x1400, 0x0294, 0x0600, 0x02e8, 0x0678, 0x0303, 0x0685, 0x0a, 0xf6, 0x0000, 0x0000), 0x00),
'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00), 'Mimic Cave': (0x4E, (0x010c, 0x05, 0x07e0, 0x0103, 0x0d00, 0x0156, 0x0d78, 0x0172, 0x0d7d, 0x0b, 0xf5, 0x0000, 0x0000), 0x00),
'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000), 0x00), 'Big Bomb Shop': (0x52, (0x011c, 0x6c, 0x0506, 0x0a9a, 0x0832, 0x0ae7, 0x08b8, 0x0b07, 0x08bf, 0x06, 0xfa, 0x0816, 0x0000), 0x00),
+4 -2
View File
@@ -46,8 +46,9 @@ def roll_settings(weights):
ret.algorithm = get_choice('algorithm') ret.algorithm = get_choice('algorithm')
glitch_map = {'none': 'noglitches', 'no_logic': 'nologic', 'owglitches': 'owglitches', glitch_map = {'none': 'noglitches', 'minorglitches': 'minorglitches', 'no_logic': 'nologic',
'owg': 'owglitches', 'minorglitches': 'minorglitches'} 'hmg': 'hybridglitches', 'hybridglitches': 'hybridglitches',
'owg': 'owglitches', 'owglitches': 'owglitches'}
glitches_required = get_choice('glitches_required') glitches_required = get_choice('glitches_required')
if glitches_required is not None: if glitches_required is not None:
if glitches_required not in glitch_map.keys(): if glitches_required not in glitch_map.keys():
@@ -114,6 +115,7 @@ def roll_settings(weights):
ret.pottery = 'keys' if ret.pottery == 'none' and keydropshuffle else ret.pottery ret.pottery = 'keys' if ret.pottery == 'none' and keydropshuffle else ret.pottery
ret.colorizepots = get_choice_default('colorizepots', default='on') == 'on' ret.colorizepots = get_choice_default('colorizepots', default='on') == 'on'
ret.shufflepots = get_choice('pot_shuffle') == 'on' ret.shufflepots = get_choice('pot_shuffle') == 'on'
ret.aga_randomness = get_choice('aga_randomness') == 'on'
ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent' ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent'
ret.standardize_palettes = (get_choice('standardize_palettes') if 'standardize_palettes' in weights ret.standardize_palettes = (get_choice('standardize_palettes') if 'standardize_palettes' in weights
else 'standardize') else 'standardize')
+35
View File
@@ -0,0 +1,35 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: vanilla
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
placements:
1:
Ice Palace - Compass Chest: Fire Rod
Ice Palace - Freezor Chest: Bombos
+42
View File
@@ -0,0 +1,42 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: vanilla
start_inventory:
1:
- Flippers
- Lamp
- Tempered Sword
- Boss Heart Container
- Boss Heart Container
- Boss Heart Container
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
placements:
1:
Swamp Palace - Big Chest: Hammer
+34
View File
@@ -0,0 +1,34 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: vanilla
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
placements:
1:
Palace of Darkness - Shooter Room: Moon Pearl
+42
View File
@@ -0,0 +1,42 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: vanilla
start_inventory:
1:
- Flippers
- Lamp
- Tempered Sword
- Boss Heart Container
- Boss Heart Container
- Boss Heart Container
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
placements:
1:
Swamp Palace - Big Chest: Magic Mirror
+44
View File
@@ -0,0 +1,44 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: crossed
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
entrances:
1:
entrances:
Dark Lake Hylia Ledge Hint: Dark World Hammer Peg Cave
exits:
Links House: Chris Houlihan Room Exit
two-way:
Dark Lake Hylia Ledge Fairy: Palace of Darkness Exit
Lake Hylia Fortune Teller: Spectacle Rock Cave Exit
Links House: Links House Exit
placements:
1:
Peg Cave: Moon Pearl
@@ -0,0 +1,55 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: crossed
start_inventory:
1:
- Hookshot
- Lamp
- Hammer
- Magic Mirror
- Tempered Sword
- Boss Heart Container
- Boss Heart Container
- Boss Heart Container
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
entrances:
1:
entrances:
Dark Lake Hylia Ledge Hint: Dark World Hammer Peg Cave
exits:
Links House: Chris Houlihan Room Exit
two-way:
Dark Lake Hylia Ledge Fairy: Swamp Palace Exit
Lake Hylia Fortune Teller: Misery Mire Exit
Links House: Links House Exit
placements:
1:
Peg Cave: Moon Pearl
@@ -0,0 +1,44 @@
meta:
players: 1
settings:
1:
accessibility: items
door_shuffle: vanilla
logic: hybridglitches
mode: open
shuffle: vanilla
start_inventory:
1:
- Hookshot
- Lamp
- Hammer
- Magic Mirror
- Tempered Sword
- Boss Heart Container
- Boss Heart Container
- Boss Heart Container
doors:
1:
doors:
Hera Beetles WS: Hera Startile Corner ES
Hera Startile Corner ES: Hera Beetles WS
Hera Startile Corner NW: Hera Startile Wide SW
Hera Startile Wide SW: Hera Startile Corner NW
Skull 1 Lobby ES: Skull Map Room WS
Skull 2 West Lobby ES: Skull Small Hall WS
Skull 2 West Lobby NW: Skull X Room SW
Skull Big Chest N: Skull Pull Switch S
Skull Compass Room WS: Skull Left Drop ES
Skull Final Drop WS: Skull Spike Corner ES
Skull Left Drop ES: Skull Compass Room WS
Skull Map Room WS: Skull 1 Lobby ES
Skull Pot Circle WN: Skull Pull Switch EN
Skull Pull Switch EN: Skull Pot Circle WN
Skull Pull Switch S: Skull Big Chest N
Skull Small Hall WS: Skull 2 West Lobby ES
Skull Spike Corner ES: Skull Final Drop WS
Skull X Room SW: Skull 2 West Lobby NW
lobbies: {}
# placements:
# 1:
# Swamp Palace - Entrance: Boss Heart Container
@@ -0,0 +1,34 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
shuffle: crossed
start_inventory:
1:
- Flippers
- Pegasus Boots
- Progressive Sword
- Hammer
- Progressive Glove
- Progressive Glove
- Fire Rod
- Book of Mudora
- Bottle
- Magic Mirror
- Lamp
advanced_placements:
1:
- type: Verification
item: Moon Pearl
locations:
Pyramid Fairy - Left: True
entrances:
1:
entrances:
Skull Woods Final Section: Pyramid Fairy
two-way:
Chicken House: Two Brothers House Exit (West)
Skull Woods Second Section Door (West): Two Brothers House Exit (East)
+17
View File
@@ -0,0 +1,17 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Flippers
- Moon Pearl
- Progressive Sword
- Hammer
- Progressive Glove
- Progressive Glove
placements:
1:
Ice Palace - Map Chest: Bombos
Ice Palace - Iced T Room: Fire Rod
@@ -0,0 +1,20 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Pegasus Boots
- Moon Pearl
- Progressive Sword
advanced_placements:
1:
- type: Verification
item: Flippers
locations:
Zora's Ledge: True
Hobo: True
Ice Palace - Boss: True
Swamp Palace - Entrance: False
+29
View File
@@ -0,0 +1,29 @@
meta:
players: 1
settings:
1:
logic: owglitches
start_inventory:
1:
- Pegasus Boots
- Moon Pearl
- Progressive Sword
- Flippers
placements:
1:
Peg Cave: Magic Mirror
advanced_placements:
1:
- type: Verification
item: Hammer
locations:
Link's House: True
Magic Bat: False
advanced_placements:
1:
- type: Verification
item: Progressive Glove
locations:
Link's House: True
Ice Palace - Freezor Chest: False
+26
View File
@@ -0,0 +1,26 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Flippers
- Moon Pearl
- Progressive Sword
- Lamp
- Magic Mirror
- Ether
- Quake
- Bombos
advanced_placements:
1:
- type: Verification
item: Big Key (Tower of Hera)
locations:
Tower of Hera - Big Key Chest: True
Tower of Hera - Basement Cage: True
Tower of Hera - Map Chest: True
Tower of Hera - Compass Chest: True
Tower of Hera - Big Chest: True
Tower of Hera - Boss: True
@@ -0,0 +1,26 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
mode: inverted
shuffle: crossed
start_inventory:
1:
- Pegasus Boots
- Progressive Sword
- Hammer
- Fire Rod
placements:
1:
Desert Palace - Boss: Moon Pearl
entrances:
1:
two-way:
Skull Woods Final Section: Desert Palace Exit (West)
Skull Woods Second Section Door (West): Desert Palace Exit (East)
Thieves Town: Thieves Town Exit
Hyrule Castle Entrance (East): Desert Palace Exit (South)
Hyrule Castle Entrance (West): Desert Palace Exit (North)
@@ -0,0 +1,31 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
mode: inverted
start_inventory:
1:
- Flippers
- Progressive Sword
- Progressive Sword
- Book of Mudora
- Lamp
- Magic Mirror
- Ether
- Quake
- Bombos
advanced_placements:
1:
- type: Verification
item: Moon Pearl
locations:
Tower of Hera - Big Chest: True
Desert Palace - Big Chest: True
Eastern Palace - Big Chest: True
Bombos Tablet: True
Cave 45: True
+48
View File
@@ -0,0 +1,48 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Pegasus Boots
- Flippers
- Fire Rod
- Book of Mudora
- Progressive Sword
- Progressive Sword
- Lamp
- Magic Mirror
- Ether
- Quake
- Bombos
advanced_placements:
1:
- type: Verification
item: Moon Pearl
locations:
Skull Woods - Compass Chest: True
Skull Woods - Bridge Room: True
Palace of Darkness - Shooter Room: True
Palace of Darkness - The Arena - Bridge: True
Palace of Darkness - Stalfos Basement: True
Palace of Darkness - Big Key Chest: True
Palace of Darkness - The Arena - Ledge: True
Palace of Darkness - Map Chest: True
Palace of Darkness - Compass Chest: True
Palace of Darkness - Dark Basement - Left: True
Palace of Darkness - Dark Basement - Right: True
Palace of Darkness - Dark Maze - Top: True
Palace of Darkness - Dark Maze - Bottom: True
Palace of Darkness - Big Chest: True
Palace of Darkness - Harmless Hellway: True
Palace of Darkness - Boss: True
Bombos Tablet: True
C-Shaped House: True
Pyramid Fairy - Left: True
Swamp Palace - Entrance: False
Thieves' Town - Map Chest: False
+25
View File
@@ -0,0 +1,25 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Flippers
- Pegasus Boots
- Progressive Sword
- Hammer
- Progressive Glove
- Progressive Glove
- Fire Rod
- Book of Mudora
- Bottle
- Magic Mirror
- Lamp
advanced_placements:
1:
- type: Verification
item: Moon Pearl
locations:
Skull Woods - Bridge Room: True
+43
View File
@@ -0,0 +1,43 @@
meta:
players: 1
settings:
1:
logic: hybridglitches
start_inventory:
1:
- Flippers
- Moon Pearl
- Progressive Sword
- Lamp
- Magic Mirror
- Ether
- Quake
- Bombos
advanced_placements:
1:
- type: Verification
item: Small Key (Swamp Palace)
locations:
Swamp Palace - Entrance: True
Swamp Palace - Map Chest: True
Swamp Palace - Big Chest: True
Swamp Palace - Compass Chest: True
Swamp Palace - West Chest: True
Swamp Palace - Big Key Chest: True
Swamp Palace - Flooded Room - Left: True
Swamp Palace - Flooded Room - Right: True
Swamp Palace - Waterfall Room: True
Swamp Palace - Boss: True
- type: Verification
item: Big Key (Swamp Palace)
locations:
Swamp Palace - Entrance: True
Swamp Palace - Map Chest: True
Swamp Palace - Big Chest: True
Swamp Palace - Compass Chest: True
Swamp Palace - West Chest: True
Swamp Palace - Big Key Chest: True
Swamp Palace - Flooded Room - Left: True
Swamp Palace - Flooded Room - Right: True
Swamp Palace - Waterfall Room: True
Swamp Palace - Boss: True