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

View File

@@ -47,6 +47,7 @@ def main():
Alternatively, can be a ALttP Rom patched with a Link Alternatively, can be a ALttP Rom patched with a Link
sprite that will be extracted. 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) parser.add_argument('--names', default='', type=str)
args = parser.parse_args() args = parser.parse_args()

View File

@@ -30,9 +30,11 @@ def adjust(args):
if not hasattr(args,"sprite"): if not hasattr(args,"sprite"):
args.sprite = None 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, 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) args.shuffle_sfxinstruments, args.shuffle_songinstruments, args.msu_resume)
output_path.cached_path = args.outputpath output_path.cached_path = args.outputpath
@@ -65,10 +67,12 @@ def patch(args):
if not hasattr(args, "sprite"): if not hasattr(args, "sprite"):
args.sprite = None 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, 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_sfxinstruments, args.shuffle_songinstruments, args.msu_resume) args.shuffle_sfx, args.shuffle_sfxinstruments, args.shuffle_songinstruments, args.msu_resume)
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))

View File

@@ -65,7 +65,7 @@ class World(object):
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
self.is_copied_world = False self.is_premature_copied_world = False
self.accessibility = accessibility.copy() self.accessibility = accessibility.copy()
self.fix_skullwoods_exit = {} self.fix_skullwoods_exit = {}
self.fix_palaceofdarkness_exit = {} self.fix_palaceofdarkness_exit = {}
@@ -2701,8 +2701,8 @@ class Location(object):
self.recursion_count = 0 self.recursion_count = 0
self.staleness_count = 0 self.staleness_count = 0
self.locked = False self.locked = False
self.real = True self.real = not crystal
self.always_allow = lambda item, state: False self.always_allow = None
self.access_rule = lambda state: True self.access_rule = lambda state: True
self.verbose_rule = None self.verbose_rule = None
self.item_rule = lambda item: True self.item_rule = lambda item: True
@@ -2716,7 +2716,7 @@ class Location(object):
def can_fill(self, state, item, check_access=True): def can_fill(self, state, item, check_access=True):
if not self.valid_multiworld(state, item): if not self.valid_multiworld(state, item):
return False 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): def valid_multiworld(self, state, item):
if self.type == LocationType.Pot and self.player != item.player: if self.type == LocationType.Pot and self.player != item.player:

View File

@@ -1,5 +1,14 @@
# Changelog # 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 ## 0.6.1.2
- Various fixes for Custom Goal Framework - Various fixes for Custom Goal Framework
- Added custom gfx for Pedestal and Murahdahla - Added custom gfx for Pedestal and Murahdahla

3
CLI.py
View File

@@ -141,7 +141,7 @@ def parse_cli(argv, no_defaults=False):
'skullwoods', 'linked_drops', 'skullwoods', 'linked_drops',
'pseudoboots', 'mirrorscroll', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters', 'pseudoboots', 'mirrorscroll', 'retro', 'accessibility', 'hints', 'beemizer', 'experimental', 'dungeon_counters',
'shufflebosses', 'shuffleenemies', 'enemy_health', 'enemy_damage', 'shufflepots', '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', 'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle',
'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'shuffle_sfxinstruments', 'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'shuffle_sfxinstruments',
'shuffle_songinstruments', 'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode', 'shuffle_songinstruments', 'msu_resume', 'collection_rate', 'colorizepots', 'decoupledoors', 'door_type_mode',
@@ -264,6 +264,7 @@ def parse_settings():
"heartcolor": "red", "heartcolor": "red",
"heartbeep": "normal", "heartbeep": "normal",
"sprite": None, "sprite": None,
"triforce_gfx": None,
"fastmenu": "normal", "fastmenu": "normal",
"ow_palettes": "default", "ow_palettes": "default",
"uw_palettes": "default", "uw_palettes": "default",

View File

@@ -183,9 +183,13 @@ def fill_restrictive(world, base_state, locations, itempool, key_pool=None, sing
spot_to_fill = None spot_to_fill = None
item_locations = filter_locations(item_to_place, locations, world, vanilla) 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, verify(item_to_place, item_locations, maximum_exploration_state, single_player_placement,
perform_access_check, key_pool, world) 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, spot_to_fill = verify_spot_to_fill(location, item_to_place, maximum_exploration_state,
single_player_placement, perform_access_check, key_pool, world) single_player_placement, perform_access_check, key_pool, world)
if spot_to_fill: if spot_to_fill:

20
Main.py
View File

@@ -17,7 +17,7 @@ from OverworldGlitchRules import create_owg_connections
from PotShuffle import shuffle_pots, shuffle_pot_switches 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 Regions import create_regions, create_shops, mark_light_dark_world_regions, create_dungeon_regions, adjust_locations
from OWEdges import create_owedges 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 Rom import patch_rom, patch_race_rom, apply_rom_settings, LocalRom, JsonRom, get_hash_string
from Doors import create_doors from Doors import create_doors
from DoorShuffle import link_doors, connect_portal, link_doors_prep 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.enemizer.Enemizer import randomize_enemies
from source.rom.DataTables import init_data_tables from source.rom.DataTables import init_data_tables
version_number = '1.4.10' version_number = '1.4.11'
version_branch = '-u' version_branch = '-u'
__version__ = f'{version_number}{version_branch}' __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): for player in range(1, world.players + 1):
link_overworld(world, player) link_overworld(world, player)
create_shops(world, player) create_shops(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)
init_districts(world) init_districts(world)
@@ -299,7 +297,7 @@ def main(args, seed=None, fish=None):
world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash) world.spoiler.hashes[(player, team)] = get_hash_string(rom.hash)
apply_rom_settings(rom, args.heartbeep[player], args.heartcolor[player], args.quickswap[player], 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.ow_palettes[player], args.uw_palettes[player], args.reduce_flashing[player],
args.shuffle_sfx[player], args.shuffle_sfxinstruments[player], args.shuffle_songinstruments[player], args.shuffle_sfx[player], args.shuffle_sfxinstruments[player], args.shuffle_songinstruments[player],
args.msu_resume[player]) args.msu_resume[player])
@@ -809,13 +807,13 @@ def copy_world(world):
update_world_regions(ret, player) update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player) create_owg_connections(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)
create_shops(ret, player) create_shops(ret, player)
#create_doors(ret, player)
create_rooms(ret, player) create_rooms(ret, player)
create_dungeons(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 # there are region references here they must be migrated to preserve integrity
# ret.exp_cache = world.exp_cache.copy() # ret.exp_cache = world.exp_cache.copy()
@@ -940,7 +938,7 @@ def copy_world(world):
return ret return ret
def copy_world_premature(world, player): def copy_world_premature(world, player, create_flute_exits=True):
# 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,
world.difficulty, world.difficulty_adjustments, world.timer, world.progressive, world.goal, world.algorithm, 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.key_logic = world.key_logic.copy()
ret.settings = world.settings ret.settings = world.settings
ret.is_copied_world = True ret.is_premature_copied_world = True
create_regions(ret, player) create_regions(ret, player)
update_world_regions(ret, player) update_world_regions(ret, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(ret, player) create_owg_connections(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)
create_shops(ret, player) create_shops(ret, player)
create_doors(ret, player) create_doors(ret, player)
create_rooms(ret, player) create_rooms(ret, player)
create_dungeons(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': if world.mode[player] == 'standard':
parent = ret.get_region('Menu', player) parent = ret.get_region('Menu', player)

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.6.1.2' version_number = '0.6.1.3'
# branch indicator is intentionally different across branches # branch indicator is intentionally different across branches
version_branch = '' version_branch = ''
@@ -200,6 +200,7 @@ def link_overworld(world, player):
connect_simple(world, exitname, regionname, player) connect_simple(world, exitname, regionname, player)
categorize_world_regions(world, player) categorize_world_regions(world, player)
create_dynamic_mirror_exits(world, player)
if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'): if world.logic[player] in ('owglitches', 'hybridglitches', 'nologic'):
create_owg_connections(world, player) create_owg_connections(world, player)
@@ -424,8 +425,6 @@ def link_overworld(world, player):
assert len(forward_set) == len(back_set) assert len(forward_set) == len(back_set)
for (forward_edge, back_edge) in zip(forward_set, back_set): for (forward_edge, back_edge) in zip(forward_set, back_set):
connect_two_way(world, forward_edge, back_edge, player, connected_edges) connect_two_way(world, forward_edge, back_edge, player, connected_edges)
world.owsectors[player] = build_sectors(world, player)
else: else:
if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel': if world.owKeepSimilar[player] and world.owShuffle[player] == 'parallel':
for exitname, destname in parallelsimilar_connections: for exitname, destname in parallelsimilar_connections:
@@ -557,13 +556,14 @@ def link_overworld(world, player):
connect_set(forward_edge_sets[0], back_edge_sets[0], connected_edges) connect_set(forward_edge_sets[0], back_edge_sets[0], connected_edges)
remove_connected(forward_edge_sets, back_edge_sets) remove_connected(forward_edge_sets, back_edge_sets)
assert len(connected_edges) == len(default_connections) * 2, connected_edges assert len(connected_edges) == len(default_connections) * 2, connected_edges
world.owsectors[player] = build_sectors(world, player)
valid_layout = validate_layout(world, player) valid_layout = validate_layout(world, player)
tries -= 1 tries -= 1
assert valid_layout, 'Could not find a valid OW layout' assert valid_layout, 'Could not find a valid OW layout'
world.owsectors[player] = build_sectors(world, player)
# flute shuffle # flute shuffle
logging.getLogger('').debug('Shuffling flute spots') logging.getLogger('').debug('Shuffling flute spots')
def connect_flutes(flute_destinations): def connect_flutes(flute_destinations):
@@ -725,6 +725,8 @@ def link_overworld(world, player):
s[0x3a],s[0x3b],s[0x3c], s[0x3f]) s[0x3a],s[0x3b],s[0x3c], s[0x3f])
world.spoiler.set_map('flute', text_output, new_spots, player) 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): def connect_custom(world, connected_edges, groups, forced, player):
forced_crossed, forced_noncrossed = forced forced_crossed, forced_noncrossed = forced
def remove_pair_from_pool(edgename1, edgename2, is_crossed): 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) groups[(mode, wrld, dir, terrain, parallel, count, group_name)][i].extend(matches)
return groups 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) 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: if not flute_in_pool:
return return
@@ -1303,6 +1305,7 @@ def create_flute_exits(world, player):
exit.spot_type = 'Flute' exit.spot_type = 'Flute'
exit.connect(world.get_region('Flute Sky', player)) exit.connect(world.get_region('Flute Sky', player))
region.exits.append(exit) region.exits.append(exit)
world.initialize_regions()
def get_mirror_exit_name(from_region, to_region): def get_mirror_exit_name(from_region, to_region):
if from_region in mirror_connections and to_region in mirror_connections[from_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])) mirror_exits.append(tuple([get_mirror_exit_name(other_world_region_name, region.name), region.name]))
return mirror_exits return mirror_exits
def create_mirror_exits(world, player): def create_dynamic_mirror_exits(world, player):
mirror_exits = set() 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']): 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): 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) region.exits.append(exit)
mirror_exits.add(exitname) 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() world.initialize_regions()
def categorize_world_regions(world, player): def categorize_world_regions(world, player):
@@ -1433,7 +1430,7 @@ def build_sectors(world, player):
# perform accessibility check on duplicate world # perform accessibility check on duplicate world
for p in range(1, world.players + 1): for p in range(1, world.players + 1):
world.key_logic[p] = {} 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) # build lists of contiguous regions accessible with full inventory (excl portals/mirror/flute/entrances)
regions = list(OWTileRegions.copy().keys()) 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: if build_copy_world:
for p in range(1, world.players + 1): for p in range(1, world.players + 1):
world.key_logic[p] = {} 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 base_world.override_bomb_check = True
else: else:
base_world = world base_world = world
@@ -1554,11 +1551,9 @@ def validate_layout(world, player):
'Pyramid Area': ['Pyramid Exit Ledge'] '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 # 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 from source.overworld.EntranceData import default_dungeon_connections, default_connector_connections, default_item_connections, default_shop_connections, default_drop_connections, default_dropexit_connections
dungeon_entrances = list(zip(*default_dungeon_connections + [('Ganons Tower', '')]))[0] dungeon_entrances = list(zip(*default_dungeon_connections + [('Ganons Tower', '')]))[0]
connector_entrances = list(zip(*default_connector_connections))[0] connector_entrances = list(zip(*default_connector_connections))[0]
item_entrances = list(zip(*default_item_connections))[0] item_entrances = list(zip(*default_item_connections))[0]
@@ -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) 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): def explore_region(region_name, region=None):
if stack_size3a() > 500: if region_name in explored_regions:
raise GenerationException(f'Infinite loop detected for "{region_name}" located at \'validate_layout\'') return
explored_regions.add(region_name)
explored_regions.append(region_name)
if not region: if not region:
region = base_world.get_region(region_name, player) region = world.get_region(region_name, player)
for exit in region.exits: for exit in region.exits:
if exit.connected_region is not None and exit.connected_region.name not in explored_regions \ 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]: and exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld]:
@@ -1586,11 +1580,8 @@ def validate_layout(world, player):
for dest_region in sane_connectors[region_name]: for dest_region in sane_connectors[region_name]:
if dest_region not in explored_regions: if dest_region not in explored_regions:
explore_region(dest_region) explore_region(dest_region)
for p in range(1, world.players + 1): explored_regions = set()
world.key_logic[p] = {}
base_world = copy_world_premature(world, player)
explored_regions = list()
if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] or not world.shufflelinks[player]: if world.shuffle[player] in ['vanilla', 'dungeonssimple', 'dungeonsfull'] or not world.shufflelinks[player]:
if not world.is_bombshop_start(player): if not world.is_bombshop_start(player):
@@ -1616,14 +1607,14 @@ def validate_layout(world, player):
start_region = 'Hyrule Castle Ledge' start_region = 'Hyrule Castle Ledge'
explore_region(start_region) explore_region(start_region)
unreachable_regions = OrderedDict() unreachable_regions = {}
unreachable_count = -1 unreachable_count = -1
while unreachable_count != len(unreachable_regions): while unreachable_count != len(unreachable_regions):
# find unreachable regions # find unreachable regions
unreachable_regions = {} unreachable_regions = {}
for region_name in list(OWTileRegions.copy().keys()): for region_name in list(OWTileRegions.copy().keys()):
if region_name not in explored_regions and region_name not in isolated_regions: 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 unreachable_regions[region_name] = region
# loop thru unreachable regions to check if some can be excluded # loop thru unreachable regions to check if some can be excluded

View File

@@ -5,7 +5,11 @@
# Patch Notes # Patch Notes
Changelog archive 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 * 1.4.9
* Attempted fix for Moth conveyor room timing. Thanks for many people's input. Unsure if Helmacopter is still acceptable. * 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!) * Mirror scroll will show up on file start screen if enabled (thanks Clearmouse!)

View File

@@ -76,7 +76,7 @@ def main(args):
rom = LocalRom(args.rom) rom = LocalRom(args.rom)
patch_rom(world, rom, 1, 1, False, str(args.rom_header) if args.rom_header else None) 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: for textname, texttype, text in text_patches:
if texttype == 'text': if texttype == 'text':

View File

@@ -141,8 +141,14 @@ These are now independent of retro mode and have three options: None, Random, an
# Patch Notes # Patch Notes
* 1.4.10 * 1.4.11
* 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. * Rom fixes (all thanks to Codemann, I believe)
* Helmacopter Fix. * Pot bug when at sprite limit
* Fixed a bug in shopsanity that caused the generation to fail with certain prices. * Kodongo AI vanilla in vanilla rooms
* Enemizer: fairies were invalid on the overworld (unless a bonk occurred nearby), so they will no longer be randomized there. * 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.

18
Rom.py
View File

@@ -43,7 +43,7 @@ from source.enemizer.Enemizer import write_enemy_shuffle_settings
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '2039c11b935d3b81f78810d9f4be19d6' RANDOMIZERBASEHASH = '35f2b275114fcec150981e9cb28de373'
class JsonRom(object): class JsonRom(object):
@@ -1875,7 +1875,7 @@ def hud_format_text(text):
return output[:32] 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, ow_palettes, uw_palettes, reduce_flashing, shuffle_sfx,
shuffle_sfxinstruments, shuffle_songinstruments, msu_resume): shuffle_sfxinstruments, shuffle_songinstruments, msu_resume):
@@ -1933,6 +1933,20 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
# write link sprite if required # write link sprite if required
if sprite is not None: if sprite is not None:
write_sprite(rom, sprite) 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 # sprite author credits
padded_author = sprite.author_name if sprite is not None else "Nintendo" padded_author = sprite.author_name if sprite is not None else "Nintendo"

View File

@@ -50,9 +50,11 @@ def set_rules(world, player):
ow_bunny_rules(world, player) ow_bunny_rules(world, player)
ow_terrain_rules(world, player) ow_terrain_rules(world, player)
if world.is_premature_copied_world:
return
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
if not world.is_copied_world: standard_rules(world, player)
standard_rules(world, player)
else: else:
misc_key_rules(world, player) 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) 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]))): 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
# 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)
# 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) and state.is_not_bunny(kak_region, player)) add_rule(world.get_location('Flute Activation', player), lambda state: state.has('Ocarina', 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 swamp and dam have not been moved we require mirror for swamp palace
if not world.swamp_patch_required[player]: if not world.swamp_patch_required[player]:
add_rule(world.get_entrance('Swamp Lobby Moat', player), lambda state: state.has_Mirror(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 # These rules go here because they overwrite/add to some of the above rules
if world.logic[player] == 'hybridglitches': 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): 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.
@@ -399,7 +398,7 @@ def global_rules(world, player):
# bonk items # bonk items
if world.shuffle_bonk_drops[player]: 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 from Regions import bonk_prize_table
for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items(): for location_name, (_, _, aga_required, _, _, _) in bonk_prize_table.items():
loc = world.get_location(location_name, player) loc = world.get_location(location_name, player)
@@ -983,7 +982,7 @@ def global_rules(world, player):
add_key_logic_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) add_hmg_key_logic_rules(world, player)
# End of door rando rules. # 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('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) set_rule(world.get_entrance('Ice Lake Northeast Pier Hop', player), lambda state: False)
forbid_bomb_jump_requirements(world, player) forbid_bomb_jump_requirements(world, player)
if not world.is_copied_world: if not world.is_premature_copied_world:
add_conditional_lamps(world, player) 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)) add_rule(world.get_entrance(entrance, player), lambda state: state.has('Zelda Delivered', player))
if world.shuffle_bonk_drops[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('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)) 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)) 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 # don't allow bombs to get past here before zelda is rescued

225
Tables.py
View File

@@ -147,101 +147,140 @@ bonk_prize_lookup = {
'Fairy': (0xe3, 15, None) '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 # decompressed gfx loaded at $7F8000
# custom gfx loaded at $228000 # custom gfx loaded at $228000
item_gfx_table = { item_gfx_table = {
'Green Rupees (20)': (False, 0x0000, 0x04), 'Green Rupees (20)': (False, 0x0000, 0x04, 0x0000, 2),
'Pegasus Boots': (False, 0x0040, 0x01), 'Pegasus Boots': (False, 0x0040, 0x01, 0x0000, 2),
'Psuedoboots': (False, 0x0040, 0x02), 'Psuedoboots': (False, 0x0040, 0x02, 0x0000, 2),
'Blue Pendant': (False, 0x0080, 0x02), 'Blue Pendant': (False, 0x0080, 0x02, 0x0000, 2),
'Red Pendant': (False, 0x0080, 0x01), 'Red Pendant': (False, 0x0080, 0x01, 0x0000, 2),
'Warp Tile': (False, 0x00C0, 0x04), 'Warp Tile': (False, 0x00C0, 0x04, 0x0000, 2),
'Open Chest': (False, 0x0100, 0x02), 'Open Chest': (False, 0x0100, 0x02, 0x0000, 2),
'Chicken': (False, 0x0140, 0x04), 'Chicken': (False, 0x0140, 0x04, 0x0000, 2),
'Duck': (False, 0x0180, 0x01), 'Duck': (False, 0x0180, 0x01, 0x0000, 2),
'Chest': (False, 0x0400, 0x02), 'Chest': (False, 0x0400, 0x02, 0x0000, 2),
'Frog': (False, 0x0440, 0x04), 'Frog': (False, 0x0440, 0x04, 0x0000, 2),
'Kiki (Head)': (False, 0x0480, 0x04), 'Kiki (Head)': (False, 0x0480, 0x04, 0x0000, 2),
'Purple Chest': (False, 0x0500, 0x04), 'Purple Chest': (False, 0x0500, 0x04, 0x0000, 2),
'Super Bomb': (False, 0x0540, 0x04), 'Super Bomb': (False, 0x0540, 0x04, 0x0000, 2),
'Blacksmith': (False, 0x0580, 0x04), 'Blacksmith': (False, 0x0580, 0x04, 0x0000, 2),
'Bug Net': (False, 0x0860, 0x01), 'Bug Net': (False, 0x0860, 0x01, 0x0000, 2),
'Crystal': (False, 0x08A0, 0x06), 'Crystal': (False, 0x08A0, 0x86, 0xB240, 2),
'Silver Arrows': (False, 0x08E0, 0x01), 'Silver Arrows': (False, 0x08E0, 0x01, 0x0000, 2),
'Bow': (False, 0x0920, 0x02), 'Progressive Bow': (False, 0x0920, 0x02, 0x0000, 2),
'Bottle (Fairy)': (False, 0x0960, 0x02), 'Bottle (Fairy)': (False, 0x0960, 0x02, 0x0000, 2),
'Bottle (Bee)': (False, 0x09A0, 0x02), 'Bottle (Bee)': (False, 0x09A0, 0x02, 0x0000, 2),
'Piece of Heart': (False, 0x0C00, 0x01), 'Piece of Heart': (False, 0x0C00, 0x01, 0x0000, 2),
'Ocarina': (False, 0x0C40, 0x02), 'Ocarina': (False, 0x0C40, 0x02, 0x0000, 2),
'Mirror Shield': (False, 0x0C80, 0x04), 'Mirror Shield': (False, 0x0C80, 0x80, 0xB230, 2),
'Rupees (100)': (False, 0x0D20, 0x04), 'Rupees (100)': (False, 0x0D20, 0x04, 0x0000, 2),
'Rupees (50)': (False, 0x0D60, 0x04), 'Rupees (50)': (False, 0x0D60, 0x04, 0x0000, 2),
'Rupees (300)': (False, 0x0DA0, 0x04), 'Rupees (300)': (False, 0x0DA0, 0x04, 0x0000, 2),
'Flippers': (False, 0x1000, 0x02), 'Flippers': (False, 0x1000, 0x02, 0x0000, 2),
'Mirror': (False, 0x1040, 0x02), 'Magic Mirror': (False, 0x1040, 0x02, 0x0000, 2),
'Bomb': (False, 0x1080, 0x02), 'Bomb': (False, 0x1080, 0x02, 0x0000, 2),
'Lamp': (False, 0x10C0, 0x01), 'Lamp': (False, 0x10C0, 0x01, 0x0000, 2),
'Psuedolamp': (False, 0x10C0, 0x02), 'Psuedolamp': (False, 0x10C0, 0x02, 0x0000, 2),
'Magic Cape': (False, 0x1100, 0x01), 'Magic Cape': (False, 0x1100, 0x01, 0x0000, 2),
'Compass': (False, 0x1140, 0x02), 'Compass': (False, 0x1140, 0x02, 0x0000, 2),
'Moon Pearl': (False, 0x1180, 0x01), 'Moon Pearl': (False, 0x1180, 0x01, 0x0000, 2),
'Ether': (False, 0x1400, 0x04), 'Ether': (False, 0x1400, 0x04, 0x0000, 2),
'Bombos': (False, 0x1440, 0x04), 'Bombos': (False, 0x1440, 0x04, 0x0000, 2),
'Quake': (False, 0x1480, 0x04), 'Quake': (False, 0x1480, 0x04, 0x0000, 2),
'Bottle': (False, 0x14C0, 0x01), 'Bottle': (False, 0x14C0, 0x01, 0x0000, 2),
'Bottle (Red Potion)': (False, 0x1500, 0x01), 'Bottle (Red Potion)': (False, 0x1500, 0x01, 0x0000, 2),
'Bottle (Green Potion)': (False, 0x1500, 0x04), 'Bottle (Green Potion)': (False, 0x1500, 0x04, 0x0000, 2),
'Bottle (Blue Potion)': (False, 0x1500, 0x02), 'Bottle (Blue Potion)': (False, 0x1500, 0x02, 0x0000, 2),
'Mushroom': (False, 0x1540, 0x04), 'Mushroom': (False, 0x1540, 0x04, 0x0000, 2),
'Map': (False, 0x1580, 0x04), 'Map': (False, 0x1580, 0x04, 0x0000, 2),
'Big Key': (False, 0x15C0, 0x04), 'Big Key': (False, 0x15C0, 0x04, 0x0000, 2),
'Bombs (3)': (False, 0x1840, 0x02), 'Green Potion': (False, 0x1800, 0x04, 0x0000, 2),
'Arrows (10)': (False, 0x1880, 0x02), 'Blue Potion': (False, 0x1800, 0x02, 0x0000, 2),
'Heart Container': (False, 0x18C0, 0x01), 'Red Potion': (False, 0x1800, 0x01, 0x0000, 2),
'Green Mail': (False, 0x1900, 0x04), 'Bombs (3)': (False, 0x1840, 0x02, 0x0000, 2),
'Blue Mail': (False, 0x1900, 0x02), 'Arrows (10)': (False, 0x1880, 0x02, 0x0000, 2),
'Red Mail': (False, 0x1900, 0x01), 'Heart Container': (False, 0x18C0, 0x01, 0x0000, 2),
'Fire Sheild': (False, 0x1980, 0x04), 'Heart Container (Green)': (False, 0x18C0, 0x04, 0x0000, 2),
'Blue Shield': (False, 0x19C0, 0x02), 'Heart Container (Blue)': (False, 0x18C0, 0x02, 0x0000, 2),
'Magic Powder': (False, 0x1CC0, 0x02), 'Green Mail': (False, 0x1900, 0x04, 0x0000, 2),
'Bombs (10)': (False, 0x1D00, 0x02), 'Blue Mail': (False, 0x1900, 0x02, 0x0000, 2),
'Power Glove': (False, 0x1D40, 0x01), 'Red Mail': (False, 0x1900, 0x01, 0x0000, 2),
'Titans Mitts': (False, 0x1D40, 0x04), 'Fire Shield': (False, 0x1940, 0x80, 0xB220, 2),
'Book of Mudora': (False, 0x1D80, 0x04), 'Blue Shield': (False, 0x19C0, 0x02, 0x0000, 2),
'Maiden (Head)': (False, 0x2000, 0x04), 'Magic Powder': (False, 0x1CC0, 0x02, 0x0000, 2),
'Zelda (Head)': (False, 0x2080, 0x04), 'Bombs (10)': (False, 0x1D00, 0x02, 0x0000, 2),
'Old Man (Head)': (False, 0x2140, 0x04), 'Power Glove': (False, 0x1D40, 0x01, 0x0000, 2),
'Locksmith (Head)': (False, 0x2180, 0x04), 'Titans Mitt': (False, 0x1D40, 0x04, 0x0000, 2),
'Fire': (False, 0x25C0, 0x04), 'Book of Mudora': (False, 0x1D80, 0x04, 0x0000, 2),
'Apples': (False, 0x30A0, 0x04), 'Maiden (Head)': (False, 0x2000, 0x04, 0x0000, 2),
'Fairy': (False, 0x3140, 0x01), 'Zelda (Head)': (False, 0x2080, 0x04, 0x0000, 2),
'Whirlpool': (False, 0x31C0, 0x01), '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), 'Nothing': (True, 0x0020, 0x01, 0x0000, 2),
'Fighter Sword': (True, 0x00A0, 0x02), 'Triforce': (True, 0x0060, 0x04, 0x0000, 2),
'Master Sword': (True, 0x00E0, 0x02), 'Fighter Sword': (True, 0x00A0, 0x02, 0x0000, 2),
'Tempered Sword': (True, 0x0120, 0x01), 'Master Sword': (True, 0x00E0, 0x02, 0x0000, 2),
'Golden Sword': (True, 0x0160, 0x04), 'Tempered Sword': (True, 0x0120, 0x01, 0x0000, 2),
'Half Magic': (True, 0x01A0, 0x04), 'Golden Sword': (True, 0x0160, 0x04, 0x0000, 2),
'Quarter Magic': (True, 0x01E0, 0x04), 'Half Magic': (True, 0x01A0, 0x04, 0x0000, 2),
'Bomb Upgrade (+5)': (True, 0x0420, 0x04), 'Quarter Magic': (True, 0x01E0, 0x04, 0x0000, 2),
'Bomb Upgrade (+10)': (True, 0x0460, 0x04), 'Bomb Upgrade (+5)': (True, 0x0420, 0x04, 0x0000, 2),
'Bomb Upgrade (50)': (True, 0x04A0, 0x04), 'Bomb Upgrade (+10)': (True, 0x0460, 0x04, 0x0000, 2),
'Bombbag': (True, 0x04E0, 0x02), 'Bomb Upgrade (50)': (True, 0x04A0, 0x04, 0x0000, 2),
'Arrow Upgrade (+5)': (True, 0x0520, 0x02), 'Bombbag': (True, 0x04E0, 0x02, 0x0000, 2),
'Arrow Upgrade (+10)': (True, 0x0560, 0x02), 'Arrow Upgrade (+5)': (True, 0x0520, 0x02, 0x0000, 2),
'Arrows (70)': (True, 0x05A0, 0x02), 'Arrow Upgrade (+10)': (True, 0x0560, 0x02, 0x0000, 2),
'Silver Arrows (Ag)': (True, 0x05E0, 0x01), 'Arrow Upgrade (70)': (True, 0x05A0, 0x02, 0x0000, 2),
'Green Pendant': (True, 0x0820, 0x04), 'Silver Arrows (Ag)': (True, 0x05E0, 0x01, 0x0000, 2),
'Sword and Shield': (True, 0x0860, 0x02), 'Green Pendant': (True, 0x0820, 0x04, 0x0000, 2),
'Green Potion': (True, 0x08A0, 0x04), 'Sword and Shield': (True, 0x0860, 0x02, 0xD244, 2),
'Blue Potion': (True, 0x08E0, 0x02), 'Green Potion (G)': (True, 0x08A0, 0x04, 0x0000, 2),
'Red Potion': (True, 0x0920, 0x01), 'Blue Potion (B)': (True, 0x08E0, 0x02, 0x0000, 2),
'Bee Trap': (True, 0x0960, 0x02), 'Red Potion (R)': (True, 0x0920, 0x01, 0x0000, 2),
'Red Crystal': (True, 0x0C60, 0x01), 'Bee Trap': (True, 0x0960, 0x02, 0x0000, 2),
'Egg': (True, 0x1020, 0x02), 'Red Crystal': (True, 0x0C60, 0x01, 0x0000, 2),
'Master Key': (True, 0x1060, 0x02), 'Green Clock': (True, 0x0DE0, 0x04, 0x0000, 2),
'Lumberjack (Head)': (True, 0x11A0, 0x02), 'Blue Clock': (True, 0x0DE0, 0x02, 0x0000, 2),
'Power Star': (True, 0x11E0, 0x04), '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),
} }

View File

@@ -192,7 +192,7 @@ Blind_texts = [
"Gloves open\na handful\nof checks", "Gloves open\na handful\nof checks",
"Red mail?\nReturn to\nsender.", "Red mail?\nReturn to\nsender.",
"For sale:\nBaby boots,\nNever found", "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", "Ladders are\nalways up\nto something",
"Zelda's\nfashion is\nvery chic", "Zelda's\nfashion is\nvery chic",
"Zombie geese\nare waterfoul.\n", "Zombie geese\nare waterfoul.\n",

Binary file not shown.

BIN
data/itemgfx/Apples.gif Normal file

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

BIN
data/itemgfx/Arrow.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

BIN
data/itemgfx/Bee Trap.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

BIN
data/itemgfx/Big Key.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

BIN
data/itemgfx/Blacksmith.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

BIN
data/itemgfx/Blue Clock.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

BIN
data/itemgfx/Blue Mail.gif Normal file

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

BIN
data/itemgfx/Bomb.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

BIN
data/itemgfx/Bombbag.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

BIN
data/itemgfx/Bombos.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

BIN
data/itemgfx/Bombs (10).gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

BIN
data/itemgfx/Bombs (3).gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
data/itemgfx/Boomerang.gif Normal file

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

BIN
data/itemgfx/Bottle.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

BIN
data/itemgfx/Bow.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
data/itemgfx/Bug Net.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

BIN
data/itemgfx/Byrna.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

BIN
data/itemgfx/Chest.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

BIN
data/itemgfx/Chicken.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

BIN
data/itemgfx/Compass.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

BIN
data/itemgfx/Crystal.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

BIN
data/itemgfx/Duck.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

BIN
data/itemgfx/Egg.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

BIN
data/itemgfx/Ether.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

BIN
data/itemgfx/Fairy.gif Normal file

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

BIN
data/itemgfx/Fire Rod.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

BIN
data/itemgfx/Fire.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
data/itemgfx/Flippers.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

BIN
data/itemgfx/Frog.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

BIN
data/itemgfx/Full Magic.gif Normal file

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

BIN
data/itemgfx/Green Mail.gif Normal file

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

BIN
data/itemgfx/Half Magic.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

BIN
data/itemgfx/Hammer.gif Normal file

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

BIN
data/itemgfx/Heart.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

BIN
data/itemgfx/Hookshot.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

BIN
data/itemgfx/Ice Rod.gif Normal file

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

BIN
data/itemgfx/Lamp.gif Normal file

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

BIN
data/itemgfx/Magic Cape.gif Normal file

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

BIN
data/itemgfx/Map.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

BIN
data/itemgfx/Master Key.gif Normal file

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