Merge branch 'OverworldShuffleDev' into OverworldShuffle

This commit is contained in:
codemann8
2025-11-22 09:23:40 -06:00
161 changed files with 498 additions and 264 deletions
+1
View File
@@ -47,6 +47,7 @@ def main():
Alternatively, can be a ALttP Rom patched with a Link
sprite that will be extracted.
''')
parser.add_argument('--triforce_gfx', help='Name of the triforce graphics to use.')
parser.add_argument('--names', default='', type=str)
args = parser.parse_args()
+7 -3
View File
@@ -30,9 +30,11 @@ def adjust(args):
if not hasattr(args,"sprite"):
args.sprite = None
if not hasattr(args,"triforce_gfx"):
args.triforce_gfx = None
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic,
args.sprite, args.ow_palettes, args.uw_palettes, args.reduce_flashing, args.shuffle_sfx,
args.sprite, args.triforce_gfx, args.ow_palettes, args.uw_palettes, args.reduce_flashing, args.shuffle_sfx,
args.shuffle_sfxinstruments, args.shuffle_songinstruments, args.msu_resume)
output_path.cached_path = args.outputpath
@@ -65,10 +67,12 @@ def patch(args):
if not hasattr(args, "sprite"):
args.sprite = None
if not hasattr(args, "triforce_gfx"):
args.triforce_gfx = None
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic,
args.sprite, args.ow_palettes, args.uw_palettes, args.reduce_flashing, args.shuffle_sfx,
args.shuffle_sfxinstruments, args.shuffle_songinstruments, args.msu_resume)
args.sprite, args.triforce_gfx, args.ow_palettes, args.uw_palettes, args.reduce_flashing,
args.shuffle_sfx, args.shuffle_sfxinstruments, args.shuffle_songinstruments, args.msu_resume)
output_path.cached_path = args.outputpath
rom.write_to_file(output_path('%s.sfc' % outfile_base))
+4 -4
View File
@@ -65,7 +65,7 @@ class World(object):
self.lock_aga_door_in_escape = False
self.save_and_quit_from_boss = True
self.override_bomb_check = False
self.is_copied_world = False
self.is_premature_copied_world = False
self.accessibility = accessibility.copy()
self.fix_skullwoods_exit = {}
self.fix_palaceofdarkness_exit = {}
@@ -2701,8 +2701,8 @@ class Location(object):
self.recursion_count = 0
self.staleness_count = 0
self.locked = False
self.real = True
self.always_allow = lambda item, state: False
self.real = not crystal
self.always_allow = None
self.access_rule = lambda state: True
self.verbose_rule = None
self.item_rule = lambda item: True
@@ -2716,7 +2716,7 @@ class Location(object):
def can_fill(self, state, item, check_access=True):
if not self.valid_multiworld(state, item):
return False
return self.always_allow(state, item) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state)))
return (self.always_allow and self.always_allow(state, item)) or (self.parent_region.can_fill(item) and self.item_rule(item) and (not check_access or self.can_reach(state)))
def valid_multiworld(self, state, item):
if self.type == LocationType.Pot and self.player != item.player:
+9
View File
@@ -1,5 +1,14 @@
# Changelog
## 0.6.1.3
- Added new post-gen option to change Triforce Piece GFX
- Added new GFX for 10/11 keys to replace the A/B GFX
- Fixed issue with Follower Sprite GFX after mirroring
- Fixed VRAM issue with Crystal Maiden cutscene
- Some performance updates
- \~Merged in DR v1.4.11~
- Enemizer bans update
## 0.6.1.2
- Various fixes for Custom Goal Framework
- Added custom gfx for Pedestal and Murahdahla
+2 -1
View File
@@ -141,7 +141,7 @@ def parse_cli(argv, no_defaults=False):
'skullwoods', 'linked_drops',
'pseudoboots', 'mirrorscroll', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots',
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'ow_palettes', 'uw_palettes', 'sprite', 'triforce_gfx', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle',
'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'shuffle_sfxinstruments',
'shuffle_songinstruments', 'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode',
@@ -264,6 +264,7 @@ def parse_settings():
"heartcolor": "red",
"heartbeep": "normal",
"sprite": None,
"triforce_gfx": None,
"fastmenu": "normal",
"ow_palettes": "default",
"uw_palettes": "default",
+5 -1
View File
@@ -183,9 +183,13 @@ def fill_restrictive(world, base_state, locations, itempool, key_pool=None, sing
spot_to_fill = None
item_locations = filter_locations(item_to_place, locations, world, vanilla)
# for dungeon items, it is worth reducing this list further by excluding locations outside of the respective dungeon
reduced_locations = item_locations if not item_to_place.dungeon else \
[location for location in item_locations if not location.always_allow and location.parent_region.can_fill(item_to_place)]
verify(item_to_place, item_locations, maximum_exploration_state, single_player_placement,
perform_access_check, key_pool, world)
for location in item_locations:
for location in reduced_locations:
spot_to_fill = verify_spot_to_fill(location, item_to_place, maximum_exploration_state,
single_player_placement, perform_access_check, key_pool, world)
if spot_to_fill:
+10 -10
View File
@@ -17,7 +17,7 @@ from OverworldGlitchRules import create_owg_connections
from PotShuffle import shuffle_pots, shuffle_pot_switches
from Regions import create_regions, create_shops, mark_light_dark_world_regions, create_dungeon_regions, adjust_locations
from OWEdges import create_owedges
from OverworldShuffle import link_overworld, update_world_regions, create_dynamic_exits
from OverworldShuffle import link_overworld, update_world_regions, create_dynamic_flute_exits, create_dynamic_mirror_exits
from Rom import patch_rom, patch_race_rom, apply_rom_settings, LocalRom, JsonRom, get_hash_string
from Doors import create_doors
from DoorShuffle import link_doors, connect_portal, link_doors_prep
@@ -40,7 +40,7 @@ from source.enemizer.DamageTables import DamageTable
from source.enemizer.Enemizer import randomize_enemies
from source.rom.DataTables import init_data_tables
version_number = '1.4.10'
version_number = '1.4.11'
version_branch = '-u'
__version__ = f'{version_number}{version_branch}'
@@ -170,9 +170,7 @@ def main(args, seed=None, fish=None):
for player in range(1, world.players + 1):
link_overworld(world, player)
create_shops(world, player)
update_world_regions(world, player)
mark_light_dark_world_regions(world, player)
create_dynamic_exits(world, player)
init_districts(world)
@@ -299,7 +297,7 @@ def main(args, seed=None, fish=None):
world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash)
apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player],
args.fastmenu[player], args.disablemusic[player], args.sprite[player],
args.fastmenu[player], args.disablemusic[player], args.sprite[player], args.triforce_gfx[player],
args.ow_palettes[player], args.uw_palettes[player], args.reduce_flashing[player],
args.shuffle_sfx[player], args.shuffle_sfxinstruments[player], args.shuffle_songinstruments[player],
args.msu_resume[player])
@@ -809,13 +807,13 @@ def copy_world(world):
update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player)
create_dynamic_exits(ret, player)
create_dungeon_regions(ret, player)
create_owedges(ret, player)
create_shops(ret, player)
#create_doors(ret, player)
create_rooms(ret, player)
create_dungeons(ret, player)
create_dynamic_mirror_exits(ret, player)
create_dynamic_flute_exits(ret, player)
# there are region references here they must be migrated to preserve integrity
# ret.exp_cache = world.exp_cache.copy()
@@ -940,7 +938,7 @@ def copy_world(world):
return ret
def copy_world_premature(world, player):
def copy_world_premature(world, player, create_flute_exits=True):
# ToDo: Not good yet
ret = World(world.players, world.owShuffle, world.owCrossed, world.owMixed, world.shuffle, world.doorShuffle, world.logic, world.mode, world.swords,
world.difficulty, world.difficulty_adjustments, world.timer, world.progressive, world.goal, world.algorithm,
@@ -1026,19 +1024,21 @@ def copy_world_premature(world, player):
ret.key_logic = world.key_logic.copy()
ret.settings = world.settings
ret.is_copied_world = True
ret.is_premature_copied_world = True
create_regions(ret, player)
update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player)
create_dynamic_exits(ret, player)
create_dungeon_regions(ret, player)
create_owedges(ret, player)
create_shops(ret, player)
create_doors(ret, player)
create_rooms(ret, player)
create_dungeons(ret, player)
create_dynamic_mirror_exits(ret, player) # assumes these have already been added to world
if create_flute_exits:
create_dynamic_flute_exits(ret, player)
if world.mode[player] == 'standard':
parent = ret.get_region('Menu', player)
+18 -27
View File
@@ -8,7 +8,7 @@ from OWEdges import OWTileRegions, OWEdgeGroups, OWEdgeGroupsTerrain, OWExitType
from OverworldGlitchRules import create_owg_connections
from Utils import bidict
version_number = '0.6.1.2'
version_number = '0.6.1.3'
# branch indicator is intentionally different across branches
version_branch = ''
@@ -200,6 +200,7 @@ def link_overworld(world, player):
connect_simple(world, exitname, regionname, player)
categorize_world_regions(world, player)
create_dynamic_mirror_exits(world, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(world, player)
@@ -424,8 +425,6 @@ def link_overworld(world, player):
assert len(forward_set) == len(back_set)
for (forward_edge, back_edge) in zip(forward_set, back_set):
connect_two_way(world, forward_edge, back_edge, player, connected_edges)
world.owsectors[player] = build_sectors(world, player)
else:
if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel':
for exitname, destname in parallelsimilar_connections:
@@ -558,12 +557,13 @@ def link_overworld(world, player):
remove_connected(forward_edge_sets, back_edge_sets)
assert len(connected_edges) == len(default_connections) * 2, connected_edges
world.owsectors[player] = build_sectors(world, player)
valid_layout = validate_layout(world, player)
tries -= 1
assert valid_layout, 'Could not find a valid OW layout'
world.owsectors[player] = build_sectors(world, player)
# flute shuffle
logging.getLogger('').debug('Shuffling flute spots')
def connect_flutes(flute_destinations):
@@ -725,6 +725,8 @@ def link_overworld(world, player):
s[0x3a],s[0x3b],s[0x3c], s[0x3f])
world.spoiler.set_map('flute', text_output, new_spots, player)
create_dynamic_flute_exits(world, player)
def connect_custom(world, connected_edges, groups, forced, player):
forced_crossed, forced_noncrossed = forced
def remove_pair_from_pool(edgename1, edgename2, is_crossed):
@@ -1292,7 +1294,7 @@ def adjust_edge_groups(world, trimmed_groups, edges_to_swap, player):
groups[(mode, wrld, dir, terrain, parallel, count, group_name)][i].extend(matches)
return groups
def create_flute_exits(world, player):
def create_dynamic_flute_exits(world, player):
flute_in_pool = True if player not in world.customitemarray else any(i for i, n in world.customitemarray[player].items() if i == 'flute' and n > 0)
if not flute_in_pool:
return
@@ -1303,6 +1305,7 @@ def create_flute_exits(world, player):
exit.spot_type = 'Flute'
exit.connect(world.get_region('Flute Sky', player))
region.exits.append(exit)
world.initialize_regions()
def get_mirror_exit_name(from_region, to_region):
if from_region in mirror_connections and to_region in mirror_connections[from_region]:
@@ -1329,7 +1332,7 @@ def get_mirror_edges(world, region, player):
mirror_exits.append(tuple([get_mirror_exit_name(other_world_region_name, region.name), region.name]))
return mirror_exits
def create_mirror_exits(world, player):
def create_dynamic_mirror_exits(world, player):
mirror_exits = set()
for region in (r for r in world.regions if r.player == player and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):
if region.type == (RegionType.DarkWorld if world.mode[player] != 'inverted' else RegionType.LightWorld):
@@ -1350,12 +1353,6 @@ def create_mirror_exits(world, player):
region.exits.append(exit)
mirror_exits.add(exitname)
elif region.terrain == Terrain.Land:
pass
def create_dynamic_exits(world, player):
create_flute_exits(world, player)
create_mirror_exits(world, player)
world.initialize_regions()
def categorize_world_regions(world, player):
@@ -1433,7 +1430,7 @@ def build_sectors(world, player):
# perform accessibility check on duplicate world
for p in range(1, world.players + 1):
world.key_logic[p] = {}
base_world = copy_world_premature(world, player)
base_world = copy_world_premature(world, player, create_flute_exits=False)
# build lists of contiguous regions accessible with full inventory (excl portals/mirror/flute/entrances)
regions = list(OWTileRegions.copy().keys())
@@ -1510,7 +1507,7 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F
if build_copy_world:
for p in range(1, world.players + 1):
world.key_logic[p] = {}
base_world = copy_world_premature(world, player)
base_world = copy_world_premature(world, player, create_flute_exits=True)
base_world.override_bomb_check = True
else:
base_world = world
@@ -1554,8 +1551,6 @@ def validate_layout(world, player):
'Pyramid Area': ['Pyramid Exit Ledge']
}
from Main import copy_world_premature
from Utils import stack_size3a
# TODO: Find a better source for the below lists, original sourced was deprecated
from source.overworld.EntranceData import default_dungeon_connections, default_connector_connections, default_item_connections, default_shop_connections, default_drop_connections, default_dropexit_connections
@@ -1567,12 +1562,11 @@ def validate_layout(world, player):
flute_in_pool = True if player not in world.customitemarray else any(i for i, n in world.customitemarray[player].items() if i == 'flute' and n > 0)
def explore_region(region_name, region=None):
if stack_size3a() > 500:
raise GenerationException(f'Infinite loop detected for "{region_name}" located at \'validate_layout\'')
explored_regions.append(region_name)
if region_name in explored_regions:
return
explored_regions.add(region_name)
if not region:
region = base_world.get_region(region_name, player)
region = world.get_region(region_name, player)
for exit in region.exits:
if exit.connected_region is not None and exit.connected_region.name not in explored_regions \
and exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld]:
@@ -1587,10 +1581,7 @@ def validate_layout(world, player):
if dest_region not in explored_regions:
explore_region(dest_region)
for p in range(1, world.players + 1):
world.key_logic[p] = {}
base_world = copy_world_premature(world, player)
explored_regions = list()
explored_regions = set()
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] or not world.shufflelinks[player]:
if not world.is_bombshop_start(player):
@@ -1616,14 +1607,14 @@ def validate_layout(world, player):
start_region = 'Hyrule Castle Ledge'
explore_region(start_region)
unreachable_regions = OrderedDict()
unreachable_regions = {}
unreachable_count = -1
while unreachable_count != len(unreachable_regions):
# find unreachable regions
unreachable_regions = {}
for region_name in list(OWTileRegions.copy().keys()):
if region_name not in explored_regions and region_name not in isolated_regions:
region = base_world.get_region(region_name, player)
region = world.get_region(region_name, player)
unreachable_regions[region_name] = region
# loop thru unreachable regions to check if some can be excluded
+5 -1
View File
@@ -5,7 +5,11 @@
# Patch Notes
Changelog archive
* 1.4.10
* Logic: Changed the rule surrounding the Bumper Cave Ledge Drop (the murderdactyl) to only require Pearl AND (Cape OR Byrna OR a Sword) in OHKO mode for now. This is a temporary solution until a better way to prevent needing to use a framerule to get past the bird is invented.
* Helmacopter Fix.
* Fixed a bug in shopsanity that caused the generation to fail with certain prices.
* Enemizer: fairies were invalid on the overworld (unless a bonk occurred nearby), so they will no longer be randomized there.
* 1.4.9
* Attempted fix for Moth conveyor room timing. Thanks for many people's input. Unsure if Helmacopter is still acceptable.
* Mirror scroll will show up on file start screen if enabled (thanks Clearmouse!)
+1 -1
View File
@@ -76,7 +76,7 @@ def main(args):
rom = LocalRom(args.rom)
patch_rom(world, rom, 1, 1, False, str(args.rom_header) if args.rom_header else None)
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, args.sprite, args.ow_palettes, args.uw_palettes)
apply_rom_settings(rom, args.heartbeep, args.heartcolor, args.quickswap, args.fastmenu, args.disablemusic, args.sprite, args.triforce_gfx, args.ow_palettes, args.uw_palettes)
for textname, texttype, text in text_patches:
if texttype == 'text':
+11 -5
View File
@@ -141,8 +141,14 @@ These are now independent of retro mode and have three options: None, Random, an
# Patch Notes
* 1.4.10
* Logic: Changed the rule surrounding the Bumper Cave Ledge Drop (the murderdactyl) to only require Pearl AND (Cape OR Byrna OR a Sword) in OHKO mode for now. This is a temporary solution until a better way to prevent needing to use a framerule to get past the bird is invented.
* Helmacopter Fix.
* Fixed a bug in shopsanity that caused the generation to fail with certain prices.
* Enemizer: fairies were invalid on the overworld (unless a bonk occurred nearby), so they will no longer be randomized there.
* 1.4.11
* Rom fixes (all thanks to Codemann, I believe)
* Pot bug when at sprite limit
* Kodongo AI vanilla in vanilla rooms
* Issue with music silencing across certain room transitions
* Glitched: Some HMG logic fixed. Thanks Muffins! (Sorry it took me forever to get this PR in)
* Glitched: Blind fight VRAM fix. Thanks Mufffins!
* Text: Updated tourney winners. Thanks clearmouse!
* Enemizer: Banned Swamola enemy everywhere as they may be causing crashes
* Enemizer: Enemy bans from Q2 and Q3. Thank you for all the reports.
+16 -2
View File
@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '2039c11b935d3b81f78810d9f4be19d6'
RANDOMIZERBASEHASH = '35f2b275114fcec150981e9cb28de373'
class JsonRom(object):
@@ -1875,7 +1875,7 @@ def hud_format_text(text):
return output[:32]
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite,
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite, triforce_gfx,
ow_palettes, uw_palettes, reduce_flashing, shuffle_sfx,
shuffle_sfxinstruments, shuffle_songinstruments, msu_resume):
@@ -1934,6 +1934,20 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
if sprite is not None:
write_sprite(rom, sprite)
if triforce_gfx is not None:
from Tables import item_gfx_table
if triforce_gfx in item_gfx_table.keys():
(is_custom, address, palette, pal_addr, size) = item_gfx_table[triforce_gfx]
address = address if is_custom else 0x8000 + address
write_int16(rom, snes_to_pc(0xA2C600+(0x6C*2)), address)
write_int16(rom, snes_to_pc(0xA2C800+(0x6C*2)), address)
rom.write_byte(snes_to_pc(0xA2B100+0x6C), 0 if size == 2 else 4)
rom.write_byte(snes_to_pc(0xA2BA00+0x6C), size)
rom.write_byte(snes_to_pc(0xA2BB00+0x6C), size)
rom.write_byte(snes_to_pc(0xA2BC00+0x6C), palette)
rom.write_byte(snes_to_pc(0xA2BD00+0x6C), palette)
write_int16(rom, snes_to_pc(0xA2BE00+(0x6C*2)), pal_addr)
# sprite author credits
padded_author = sprite.author_name if sprite is not None else "Nintendo"
padded_author = padded_author[:28] if len(padded_author) > 28 else padded_author
+15 -16
View File
@@ -50,9 +50,11 @@ def set_rules(world, player):
ow_bunny_rules(world, player)
ow_terrain_rules(world, player)
if world.is_premature_copied_world:
return
if world.mode[player] == 'standard':
if not world.is_copied_world:
standard_rules(world, player)
standard_rules(world, player)
else:
misc_key_rules(world, player)
@@ -91,23 +93,20 @@ def set_rules(world, player):
if (world.flute_mode[player] != 'active' and not world.is_tile_swapped(0x18, player)
and 'Ocarina (Activated)' not in list(map(str, [i for i in world.precollected_items if i.player == player]))):
if not world.is_copied_world:
# Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory
# kak_region = self.world.get_region('Kakariko Village', player)
# add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player) and state.is_not_bunny(kak_region, player))
add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player))
# Commented out below, this would be needed for rando implementations where Inverted requires flute activation in bunny territory
# kak_region = self.world.get_region('Kakariko Village', player)
# add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player) and state.is_not_bunny(kak_region, player))
add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', player))
# if swamp and dam have not been moved we require mirror for swamp palace
if not world.swamp_patch_required[player]:
add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(player))
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':
if not world.is_copied_world:
underworld_glitches_rules(world, player)
underworld_glitches_rules(world, 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.
@@ -399,7 +398,7 @@ def global_rules(world, player):
# bonk items
if world.shuffle_bonk_drops[player]:
if not world.is_copied_world:
if not world.is_premature_copied_world:
from Regions import bonk_prize_table
for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items():
loc = world.get_location(location_name, player)
@@ -983,7 +982,7 @@ def global_rules(world, player):
add_key_logic_rules(world, player)
if world.logic[player] == 'hybridglitches' and not world.is_copied_world:
if world.logic[player] == 'hybridglitches' and not world.is_premature_copied_world:
add_hmg_key_logic_rules(world, player)
# End of door rando rules.
@@ -1490,7 +1489,7 @@ def no_glitches_rules(world, player):
set_rule(world.get_entrance('Paradox Cave Push Block Reverse', player), lambda state: False) # no glitches does not require block override
set_rule(world.get_entrance('Ice Lake Northeast Pier Hop', player), lambda state: False)
forbid_bomb_jump_requirements(world, player)
if not world.is_copied_world:
if not world.is_premature_copied_world:
add_conditional_lamps(world, player)
@@ -1801,11 +1800,11 @@ def standard_rules(world, player):
add_rule(world.get_entrance(entrance, player), lambda state: state.has('Zelda Delivered', player))
if world.shuffle_bonk_drops[player]:
if not world.is_copied_world:
if not world.is_premature_copied_world:
add_rule(world.get_location('Hyrule Castle Tree', player), lambda state: state.has('Zelda Delivered', player))
add_rule(world.get_location('Central Bonk Rocks Tree', player), lambda state: state.has('Zelda Delivered', player))
if not world.is_copied_world:
if not world.is_premature_copied_world:
add_rule(world.get_location('Hyrule Castle Courtyard Tree Pull', player), lambda state: state.has('Zelda Delivered', player))
# don't allow bombs to get past here before zelda is rescued
+132 -93
View File
@@ -147,101 +147,140 @@ bonk_prize_lookup = {
'Fairy': (0xe3, 15, None)
}
# item name: (custom gfx, address offset, palette)
# item name: (custom gfx, address offset, palette, palette address, size)
# decompressed gfx loaded at $7F8000
# custom gfx loaded at $228000
item_gfx_table = {
'Green Rupees (20)': (False, 0x0000, 0x04),
'Pegasus Boots': (False, 0x0040, 0x01),
'Psuedoboots': (False, 0x0040, 0x02),
'Blue Pendant': (False, 0x0080, 0x02),
'Red Pendant': (False, 0x0080, 0x01),
'Warp Tile': (False, 0x00C0, 0x04),
'Open Chest': (False, 0x0100, 0x02),
'Chicken': (False, 0x0140, 0x04),
'Duck': (False, 0x0180, 0x01),
'Chest': (False, 0x0400, 0x02),
'Frog': (False, 0x0440, 0x04),
'Kiki (Head)': (False, 0x0480, 0x04),
'Purple Chest': (False, 0x0500, 0x04),
'Super Bomb': (False, 0x0540, 0x04),
'Blacksmith': (False, 0x0580, 0x04),
'Bug Net': (False, 0x0860, 0x01),
'Crystal': (False, 0x08A0, 0x06),
'Silver Arrows': (False, 0x08E0, 0x01),
'Bow': (False, 0x0920, 0x02),
'Bottle (Fairy)': (False, 0x0960, 0x02),
'Bottle (Bee)': (False, 0x09A0, 0x02),
'Piece of Heart': (False, 0x0C00, 0x01),
'Ocarina': (False, 0x0C40, 0x02),
'Mirror Shield': (False, 0x0C80, 0x04),
'Rupees (100)': (False, 0x0D20, 0x04),
'Rupees (50)': (False, 0x0D60, 0x04),
'Rupees (300)': (False, 0x0DA0, 0x04),
'Flippers': (False, 0x1000, 0x02),
'Mirror': (False, 0x1040, 0x02),
'Bomb': (False, 0x1080, 0x02),
'Lamp': (False, 0x10C0, 0x01),
'Psuedolamp': (False, 0x10C0, 0x02),
'Magic Cape': (False, 0x1100, 0x01),
'Compass': (False, 0x1140, 0x02),
'Moon Pearl': (False, 0x1180, 0x01),
'Ether': (False, 0x1400, 0x04),
'Bombos': (False, 0x1440, 0x04),
'Quake': (False, 0x1480, 0x04),
'Bottle': (False, 0x14C0, 0x01),
'Bottle (Red Potion)': (False, 0x1500, 0x01),
'Bottle (Green Potion)': (False, 0x1500, 0x04),
'Bottle (Blue Potion)': (False, 0x1500, 0x02),
'Mushroom': (False, 0x1540, 0x04),
'Map': (False, 0x1580, 0x04),
'Big Key': (False, 0x15C0, 0x04),
'Bombs (3)': (False, 0x1840, 0x02),
'Arrows (10)': (False, 0x1880, 0x02),
'Heart Container': (False, 0x18C0, 0x01),
'Green Mail': (False, 0x1900, 0x04),
'Blue Mail': (False, 0x1900, 0x02),
'Red Mail': (False, 0x1900, 0x01),
'Fire Sheild': (False, 0x1980, 0x04),
'Blue Shield': (False, 0x19C0, 0x02),
'Magic Powder': (False, 0x1CC0, 0x02),
'Bombs (10)': (False, 0x1D00, 0x02),
'Power Glove': (False, 0x1D40, 0x01),
'Titans Mitts': (False, 0x1D40, 0x04),
'Book of Mudora': (False, 0x1D80, 0x04),
'Maiden (Head)': (False, 0x2000, 0x04),
'Zelda (Head)': (False, 0x2080, 0x04),
'Old Man (Head)': (False, 0x2140, 0x04),
'Locksmith (Head)': (False, 0x2180, 0x04),
'Fire': (False, 0x25C0, 0x04),
'Apples': (False, 0x30A0, 0x04),
'Fairy': (False, 0x3140, 0x01),
'Whirlpool': (False, 0x31C0, 0x01),
'Green Rupees (20)': (False, 0x0000, 0x04, 0x0000, 2),
'Pegasus Boots': (False, 0x0040, 0x01, 0x0000, 2),
'Psuedoboots': (False, 0x0040, 0x02, 0x0000, 2),
'Blue Pendant': (False, 0x0080, 0x02, 0x0000, 2),
'Red Pendant': (False, 0x0080, 0x01, 0x0000, 2),
'Warp Tile': (False, 0x00C0, 0x04, 0x0000, 2),
'Open Chest': (False, 0x0100, 0x02, 0x0000, 2),
'Chicken': (False, 0x0140, 0x04, 0x0000, 2),
'Duck': (False, 0x0180, 0x01, 0x0000, 2),
'Chest': (False, 0x0400, 0x02, 0x0000, 2),
'Frog': (False, 0x0440, 0x04, 0x0000, 2),
'Kiki (Head)': (False, 0x0480, 0x04, 0x0000, 2),
'Purple Chest': (False, 0x0500, 0x04, 0x0000, 2),
'Super Bomb': (False, 0x0540, 0x04, 0x0000, 2),
'Blacksmith': (False, 0x0580, 0x04, 0x0000, 2),
'Bug Net': (False, 0x0860, 0x01, 0x0000, 2),
'Crystal': (False, 0x08A0, 0x86, 0xB240, 2),
'Silver Arrows': (False, 0x08E0, 0x01, 0x0000, 2),
'Progressive Bow': (False, 0x0920, 0x02, 0x0000, 2),
'Bottle (Fairy)': (False, 0x0960, 0x02, 0x0000, 2),
'Bottle (Bee)': (False, 0x09A0, 0x02, 0x0000, 2),
'Piece of Heart': (False, 0x0C00, 0x01, 0x0000, 2),
'Ocarina': (False, 0x0C40, 0x02, 0x0000, 2),
'Mirror Shield': (False, 0x0C80, 0x80, 0xB230, 2),
'Rupees (100)': (False, 0x0D20, 0x04, 0x0000, 2),
'Rupees (50)': (False, 0x0D60, 0x04, 0x0000, 2),
'Rupees (300)': (False, 0x0DA0, 0x04, 0x0000, 2),
'Flippers': (False, 0x1000, 0x02, 0x0000, 2),
'Magic Mirror': (False, 0x1040, 0x02, 0x0000, 2),
'Bomb': (False, 0x1080, 0x02, 0x0000, 2),
'Lamp': (False, 0x10C0, 0x01, 0x0000, 2),
'Psuedolamp': (False, 0x10C0, 0x02, 0x0000, 2),
'Magic Cape': (False, 0x1100, 0x01, 0x0000, 2),
'Compass': (False, 0x1140, 0x02, 0x0000, 2),
'Moon Pearl': (False, 0x1180, 0x01, 0x0000, 2),
'Ether': (False, 0x1400, 0x04, 0x0000, 2),
'Bombos': (False, 0x1440, 0x04, 0x0000, 2),
'Quake': (False, 0x1480, 0x04, 0x0000, 2),
'Bottle': (False, 0x14C0, 0x01, 0x0000, 2),
'Bottle (Red Potion)': (False, 0x1500, 0x01, 0x0000, 2),
'Bottle (Green Potion)': (False, 0x1500, 0x04, 0x0000, 2),
'Bottle (Blue Potion)': (False, 0x1500, 0x02, 0x0000, 2),
'Mushroom': (False, 0x1540, 0x04, 0x0000, 2),
'Map': (False, 0x1580, 0x04, 0x0000, 2),
'Big Key': (False, 0x15C0, 0x04, 0x0000, 2),
'Green Potion': (False, 0x1800, 0x04, 0x0000, 2),
'Blue Potion': (False, 0x1800, 0x02, 0x0000, 2),
'Red Potion': (False, 0x1800, 0x01, 0x0000, 2),
'Bombs (3)': (False, 0x1840, 0x02, 0x0000, 2),
'Arrows (10)': (False, 0x1880, 0x02, 0x0000, 2),
'Heart Container': (False, 0x18C0, 0x01, 0x0000, 2),
'Heart Container (Green)': (False, 0x18C0, 0x04, 0x0000, 2),
'Heart Container (Blue)': (False, 0x18C0, 0x02, 0x0000, 2),
'Green Mail': (False, 0x1900, 0x04, 0x0000, 2),
'Blue Mail': (False, 0x1900, 0x02, 0x0000, 2),
'Red Mail': (False, 0x1900, 0x01, 0x0000, 2),
'Fire Shield': (False, 0x1940, 0x80, 0xB220, 2),
'Blue Shield': (False, 0x19C0, 0x02, 0x0000, 2),
'Magic Powder': (False, 0x1CC0, 0x02, 0x0000, 2),
'Bombs (10)': (False, 0x1D00, 0x02, 0x0000, 2),
'Power Glove': (False, 0x1D40, 0x01, 0x0000, 2),
'Titans Mitt': (False, 0x1D40, 0x04, 0x0000, 2),
'Book of Mudora': (False, 0x1D80, 0x04, 0x0000, 2),
'Maiden (Head)': (False, 0x2000, 0x04, 0x0000, 2),
'Zelda (Head)': (False, 0x2080, 0x04, 0x0000, 2),
'Old Man (Head)': (False, 0x2140, 0x04, 0x0000, 2),
'Locksmith (Head)': (False, 0x2180, 0x04, 0x0000, 2),
'Fire': (False, 0x25C0, 0x04, 0x0000, 2),
'Apples': (False, 0x30A0, 0x04, 0x0000, 2),
'Fairy': (False, 0x3140, 0x01, 0x0000, 2),
'Whirlpool': (False, 0x31C0, 0x02, 0x0000, 2),
'Triforce': (True, 0x0060, 0x04),
'Fighter Sword': (True, 0x00A0, 0x02),
'Master Sword': (True, 0x00E0, 0x02),
'Tempered Sword': (True, 0x0120, 0x01),
'Golden Sword': (True, 0x0160, 0x04),
'Half Magic': (True, 0x01A0, 0x04),
'Quarter Magic': (True, 0x01E0, 0x04),
'Bomb Upgrade (+5)': (True, 0x0420, 0x04),
'Bomb Upgrade (+10)': (True, 0x0460, 0x04),
'Bomb Upgrade (50)': (True, 0x04A0, 0x04),
'Bombbag': (True, 0x04E0, 0x02),
'Arrow Upgrade (+5)': (True, 0x0520, 0x02),
'Arrow Upgrade (+10)': (True, 0x0560, 0x02),
'Arrows (70)': (True, 0x05A0, 0x02),
'Silver Arrows (Ag)': (True, 0x05E0, 0x01),
'Green Pendant': (True, 0x0820, 0x04),
'Sword and Shield': (True, 0x0860, 0x02),
'Green Potion': (True, 0x08A0, 0x04),
'Blue Potion': (True, 0x08E0, 0x02),
'Red Potion': (True, 0x0920, 0x01),
'Bee Trap': (True, 0x0960, 0x02),
'Red Crystal': (True, 0x0C60, 0x01),
'Egg': (True, 0x1020, 0x02),
'Master Key': (True, 0x1060, 0x02),
'Lumberjack (Head)': (True, 0x11A0, 0x02),
'Power Star': (True, 0x11E0, 0x04),
'Nothing': (True, 0x0020, 0x01, 0x0000, 2),
'Triforce': (True, 0x0060, 0x04, 0x0000, 2),
'Fighter Sword': (True, 0x00A0, 0x02, 0x0000, 2),
'Master Sword': (True, 0x00E0, 0x02, 0x0000, 2),
'Tempered Sword': (True, 0x0120, 0x01, 0x0000, 2),
'Golden Sword': (True, 0x0160, 0x04, 0x0000, 2),
'Half Magic': (True, 0x01A0, 0x04, 0x0000, 2),
'Quarter Magic': (True, 0x01E0, 0x04, 0x0000, 2),
'Bomb Upgrade (+5)': (True, 0x0420, 0x04, 0x0000, 2),
'Bomb Upgrade (+10)': (True, 0x0460, 0x04, 0x0000, 2),
'Bomb Upgrade (50)': (True, 0x04A0, 0x04, 0x0000, 2),
'Bombbag': (True, 0x04E0, 0x02, 0x0000, 2),
'Arrow Upgrade (+5)': (True, 0x0520, 0x02, 0x0000, 2),
'Arrow Upgrade (+10)': (True, 0x0560, 0x02, 0x0000, 2),
'Arrow Upgrade (70)': (True, 0x05A0, 0x02, 0x0000, 2),
'Silver Arrows (Ag)': (True, 0x05E0, 0x01, 0x0000, 2),
'Green Pendant': (True, 0x0820, 0x04, 0x0000, 2),
'Sword and Shield': (True, 0x0860, 0x02, 0xD244, 2),
'Green Potion (G)': (True, 0x08A0, 0x04, 0x0000, 2),
'Blue Potion (B)': (True, 0x08E0, 0x02, 0x0000, 2),
'Red Potion (R)': (True, 0x0920, 0x01, 0x0000, 2),
'Bee Trap': (True, 0x0960, 0x02, 0x0000, 2),
'Red Crystal': (True, 0x0C60, 0x01, 0x0000, 2),
'Green Clock': (True, 0x0DE0, 0x04, 0x0000, 2),
'Blue Clock': (True, 0x0DE0, 0x02, 0x0000, 2),
'Red Clock': (True, 0x0DE0, 0x01, 0x0000, 2),
'Egg': (True, 0x1020, 0x02, 0x0000, 2),
'Master Key': (True, 0x1060, 0x02, 0x0000, 2),
'Lumberjack (Head)': (True, 0x11A0, 0x02, 0x0000, 2),
'Power Star': (True, 0x11E0, 0x04, 0x0000, 2),
# Thin GFX
'Rupee (1)': (False, 0x0800, 0x04, 0x0000, 0),
'Rupees (5)': (False, 0x0800, 0x02, 0x0000, 0),
'Rupees (20)': (False, 0x0800, 0x01, 0x0000, 0),
'Blue Shield (Thin)': (False, 0x09E0, 0x02, 0x0000, 0),
'Heart': (False, 0x0CC0, 0x01, 0x0000, 0),
'Heart (Green)': (False, 0x0CC0, 0x04, 0x0000, 0),
'Heart (Blue)': (False, 0x0CC0, 0x02, 0x0000, 0),
'Small Magic': (False, 0x0CE0, 0x04, 0x0000, 0),
'Arrow': (False, 0x0D00, 0x02, 0x0000, 0),
'Nothing (Thin)': (False, 0x0DE0, 0x01, 0x0000, 0),
'Master Sword (Thin)': (False, 0x11C0, 0x05, 0x0000, 0),
'Tempered Sword (Thin)': (False, 0x11C0, 0x01, 0x0000, 0),
'Golden Sword (Thin)': (False, 0x11C0, 0x04, 0x0000, 0),
'Shovel': (False, 0x11E0, 0x01, 0x0000, 0),
'Bow': (False, 0x1C00, 0x01, 0x0000, 0),
'Fighter Sword (Thin)': (False, 0x1C20, 0x02, 0x0000, 0),
'Somaria': (False, 0x1C40, 0x01, 0x0000, 0),
'Byrna': (False, 0x1C40, 0x02, 0x0000, 0),
'Hookshot': (False, 0x1C60, 0x01, 0x0000, 0),
'Fire Rod': (False, 0x1C80, 0x01, 0x0000, 0),
'Ice Rod': (False, 0x1C80, 0x02, 0x0000, 0),
'Hammer': (False, 0x1CA0, 0x01, 0x0000, 0),
'Small Key': (False, 0x1DC0, 0x04, 0x0000, 0),
'Boomerang': (False, 0x1DE0, 0x02, 0x0000, 0),
'Red Boomerang': (False, 0x1DE0, 0x01, 0x0000, 0),
'Full Magic': (True, 0x01A0, 0x04, 0x0000, 0),
}
+1 -1
View File
@@ -192,7 +192,7 @@ Blind_texts = [
"Gloves open\na handful\nof checks",
"Red mail?\nReturn to\nsender.",
"For sale:\nBaby boots,\nNever found",
"SRL or rtGG?\nI prefer the\nLadder",
"SRL or rtGG?\nI prefer the\nStepladder",
"Ladders are\nalways up\nto something",
"Zelda's\nfashion is\nvery chic",
"Zombie geese\nare waterfoul.\n",
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Some files were not shown because too many files have changed in this diff Show More