fix(key logic): typo

This commit is contained in:
aerinon
2023-11-11 20:00:31 -07:00
parent 13f9fe8f92
commit f4a702951c
2 changed files with 69 additions and 66 deletions

View File

@@ -10,7 +10,6 @@ try:
except ImportError: except ImportError:
from enum import IntFlag as FastEnum from enum import IntFlag as FastEnum
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish
from EntranceShuffle import door_addresses, indirect_connections from EntranceShuffle import door_addresses, indirect_connections
from Utils import int16_as_bytes from Utils import int16_as_bytes
@@ -94,6 +93,7 @@ class World(object):
for player in range(1, players + 1): for player in range(1, players + 1):
def set_player_attr(attr, val): def set_player_attr(attr, val):
self.__dict__.setdefault(attr, {})[player] = val self.__dict__.setdefault(attr, {})[player] = val
set_player_attr('_region_cache', {}) set_player_attr('_region_cache', {})
set_player_attr('player_names', []) set_player_attr('player_names', [])
set_player_attr('remote_items', False) set_player_attr('remote_items', False)
@@ -1013,7 +1013,6 @@ class CollectionState(object):
self.collect(event.item, True, event) self.collect(event.item, True, event)
new_locations = True new_locations = True
def can_reach_blue(self, region, player): def can_reach_blue(self, region, player):
return region in self.reachable_regions[player] and self.reachable_regions[player][region] in [CrystalBarrier.Blue, CrystalBarrier.Either] return region in self.reachable_regions[player] and self.reachable_regions[player][region] in [CrystalBarrier.Blue, CrystalBarrier.Either]
@@ -1124,7 +1123,7 @@ class CollectionState(object):
def can_lift_heavy_rocks(self, player): def can_lift_heavy_rocks(self, player):
return self.has('Titans Mitts', player) return self.has('Titans Mitts', player)
def can_extend_magic(self, player, smallmagic=16, fullrefill=False): #This reflects the total magic Link has, not the total extra he has. def can_extend_magic(self, player, smallmagic=16, fullrefill=False): # This reflects the total magic Link has, not the total extra he has.
basemagic = 8 basemagic = 8
if self.has('Magic Upgrade (1/4)', player): if self.has('Magic Upgrade (1/4)', player):
basemagic = 32 basemagic = 32
@@ -1174,7 +1173,7 @@ class CollectionState(object):
def can_shoot_arrows(self, player): def can_shoot_arrows(self, player):
if self.world.bow_mode[player] in ['retro', 'retro_silvers']: if self.world.bow_mode[player] in ['retro', 'retro_silvers']:
#todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe # todo: Non-progressive silvers grant wooden arrows, but progressive bows do not. Always require shop arrows to be safe
return self.has('Bow', player) and (self.can_buy_unlimited('Single Arrow', player) or self.has('Single Arrow', player)) return self.has('Bow', player) and (self.can_buy_unlimited('Single Arrow', player) or self.has('Single Arrow', player))
return self.has('Bow', player) return self.has('Bow', player)
@@ -1403,13 +1402,14 @@ class CollectionState(object):
def __getattr__(self, item): def __getattr__(self, item):
if item.startswith('can_reach_'): if item.startswith('can_reach_'):
return self.can_reach(item[10]) return self.can_reach(item[10])
#elif item.startswith('has_'): # elif item.startswith('has_'):
# return self.has(item[4]) # return self.has(item[4])
if item == '__len__': if item == '__len__':
return return
raise RuntimeError('Cannot parse %s.' % item) raise RuntimeError('Cannot parse %s.' % item)
@unique @unique
class RegionType(Enum): class RegionType(Enum):
Menu = 0 Menu = 0
@@ -1747,7 +1747,7 @@ class Door(object):
self.edge_id = None self.edge_id = None
self.edge_width = None self.edge_width = None
#portal items # portal items
self.portalAble = False self.portalAble = False
self.roomLayout = 0x22 # free scroll- both directions self.roomLayout = 0x22 # free scroll- both directions
self.entranceFlag = False self.entranceFlag = False
@@ -2093,17 +2093,17 @@ class Portal(object):
return self.door.roomIndex return self.door.roomIndex
def relative_coords(self): def relative_coords(self):
y_rel = (self.door.roomIndex & 0xf0) >> 3 #todo: fix the shift!!!! y_rel = (self.door.roomIndex & 0xf0) >> 3 # todo: fix the shift!!!!
x_rel = (self.door.roomIndex & 0x0f) * 2 x_rel = (self.door.roomIndex & 0x0f) * 2
quad = self.door.quadrant quad = self.door.quadrant
if quad == 0: if quad == 0:
return [y_rel, y_rel, y_rel, y_rel+1, x_rel, x_rel, x_rel, x_rel+1] return [y_rel, y_rel, y_rel, y_rel + 1, x_rel, x_rel, x_rel, x_rel + 1]
elif quad == 1: elif quad == 1:
return [y_rel, y_rel, y_rel, y_rel+1, x_rel+1, x_rel, x_rel+1, x_rel+1] return [y_rel, y_rel, y_rel, y_rel + 1, x_rel + 1, x_rel, x_rel + 1, x_rel + 1]
elif quad == 2: elif quad == 2:
return [y_rel+1, y_rel, y_rel+1, y_rel+1, x_rel, x_rel, x_rel, x_rel+1] return [y_rel + 1, y_rel, y_rel + 1, y_rel + 1, x_rel, x_rel, x_rel, x_rel + 1]
else: else:
return [y_rel+1, y_rel, y_rel+1, y_rel+1, x_rel+1, x_rel, x_rel+1, x_rel+1] return [y_rel + 1, y_rel, y_rel + 1, y_rel + 1, x_rel + 1, x_rel, x_rel + 1, x_rel + 1]
def scroll_x(self): def scroll_x(self):
x_rel = (self.door.roomIndex & 0x0f) * 2 x_rel = (self.door.roomIndex & 0x0f) * 2
@@ -2112,7 +2112,7 @@ class Portal(object):
elif self.door.doorIndex == 1: elif self.door.doorIndex == 1:
return [0x80, x_rel] return [0x80, x_rel]
else: else:
return [0x00, x_rel+1] return [0x00, x_rel + 1]
def scroll_y(self): def scroll_y(self):
y_rel = ((self.door.roomIndex & 0xf0) >> 3) + 1 y_rel = ((self.door.roomIndex & 0xf0) >> 3) + 1
@@ -2132,7 +2132,7 @@ class Portal(object):
elif self.door.doorIndex == 1: elif self.door.doorIndex == 1:
return [0xf8, x_rel] return [0xf8, x_rel]
else: else:
return [0x78, x_rel+1] return [0x78, x_rel + 1]
# def camera_y(self): # def camera_y(self):
# return [0x87, 0x01] # return [0x87, 0x01]
@@ -2191,6 +2191,7 @@ class Boss(object):
def can_defeat(self, state): def can_defeat(self, state):
return self.defeat_rule(state, self.player) return self.defeat_rule(state, self.player)
class Location(object): class Location(object):
def __init__(self, player, name='', address=None, crystal=False, hint_text=None, parent=None, forced_item=None, def __init__(self, player, name='', address=None, crystal=False, hint_text=None, parent=None, forced_item=None,
player_address=None, note=None): player_address=None, note=None):
@@ -2353,12 +2354,14 @@ class Item(object):
class Crystal(Item): class Crystal(Item):
pass pass
@unique @unique
class ShopType(Enum): class ShopType(Enum):
Shop = 0 Shop = 0
TakeAny = 1 TakeAny = 1
UpgradeShop = 2 UpgradeShop = 2
class Shop(object): class Shop(object):
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked, sram_address): def __init__(self, region, room_id, type, shopkeeper_config, custom, locked, sram_address):
self.region = region self.region = region
@@ -2382,7 +2385,7 @@ class Shop(object):
entrances = self.region.entrances entrances = self.region.entrances
config = self.item_count config = self.item_count
if len(entrances) == 1 and entrances[0].name in door_addresses: if len(entrances) == 1 and entrances[0].name in door_addresses:
door_id = door_addresses[entrances[0].name][0]+1 door_id = door_addresses[entrances[0].name][0] + 1
else: else:
door_id = 0 door_id = 0
config |= 0x40 # ignore door id config |= 0x40 # ignore door id
@@ -2390,7 +2393,7 @@ class Shop(object):
config |= 0x80 config |= 0x80
if self.type == ShopType.UpgradeShop: if self.type == ShopType.UpgradeShop:
config |= 0x10 # Alt. VRAM config |= 0x10 # Alt. VRAM
return [0x00]+int16_as_bytes(self.room_id)+[door_id, 0x00, config, self.shopkeeper_config, 0x00] return [0x00] + int16_as_bytes(self.room_id) + [door_id, 0x00, config, self.shopkeeper_config, 0x00]
def has_unlimited(self, item): def has_unlimited(self, item):
for inv in self.inventory: for inv in self.inventory:
@@ -2632,7 +2635,7 @@ class Spoiler(object):
out['Special'] = self.medallions out['Special'] = self.medallions
out['Bottles'] = self.bottles out['Bottles'] = self.bottles
if self.hashes: if self.hashes:
out['Hashes'] = {f"{self.world.player_names[player][team]} (Team {team+1})": hash for (player, team), hash in self.hashes.items()} out['Hashes'] = {f"{self.world.player_names[player][team]} (Team {team + 1})": hash for (player, team), hash in self.hashes.items()}
if self.shops: if self.shops:
out['Shops'] = self.shops out['Shops'] = self.shops
out['playthrough'] = self.playthrough out['playthrough'] = self.playthrough
@@ -2723,7 +2726,7 @@ class Spoiler(object):
if self.startinventory: if self.startinventory:
outfile.write('Starting Inventory:'.ljust(line_width)) outfile.write('Starting Inventory:'.ljust(line_width))
outfile.write('\n'.ljust(line_width+1).join(self.startinventory) + '\n') outfile.write('\n'.ljust(line_width + 1).join(self.startinventory) + '\n')
def hashes_to_file(self, filename): def hashes_to_file(self, filename):
with open(filename, 'r') as infile: with open(filename, 'r') as infile:
@@ -2743,7 +2746,7 @@ class Spoiler(object):
if len(self.hashes) > 0: if len(self.hashes) > 0:
for team in range(self.world.teams): for team in range(self.world.teams):
player_name = self.world.player_names[player][team] player_name = self.world.player_names[player][team]
label = f"Hash - {player_name} (Team {team+1}): " if self.world.teams > 1 else 'Hash: ' label = f"Hash - {player_name} (Team {team + 1}): " if self.world.teams > 1 else 'Hash: '
idx = insert(contents, idx, f'{label}{self.hashes[player, team]}\n') idx = insert(contents, idx, f'{label}{self.hashes[player, team]}\n')
if self.world.players > 1: if self.world.players > 1:
insert(contents, idx, '\n') # return value ignored here, if you want to add more lines insert(contents, idx, '\n') # return value ignored here, if you want to add more lines
@@ -2774,16 +2777,16 @@ class Spoiler(object):
if self.entrances: if self.entrances:
# entrances: To/From overworld; Checking w/ & w/out "Exit" and translating accordingly # entrances: To/From overworld; Checking w/ & w/out "Exit" and translating accordingly
outfile.write('\nEntrances:\n\n') outfile.write('\nEntrances:\n\n')
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: ' if self.world.players > 1 else '', self.world.fish.translate("meta","entrances",entry['entrance']), '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', self.world.fish.translate("meta","entrances",entry['exit'])) for entry in self.entrances.values()])) outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: ' if self.world.players > 1 else '', self.world.fish.translate("meta", "entrances", entry['entrance']), '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', self.world.fish.translate("meta", "entrances", entry['exit'])) for entry in self.entrances.values()]))
if self.doors: if self.doors:
outfile.write('\n\nDoors:\n\n') outfile.write('\n\nDoors:\n\n')
outfile.write('\n'.join( outfile.write('\n'.join(
['%s%s %s %s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', ['%s%s %s %s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '',
self.world.fish.translate("meta","doors",entry['entrance']), self.world.fish.translate("meta", "doors", entry['entrance']),
'<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>',
self.world.fish.translate("meta","doors",entry['exit']), self.world.fish.translate("meta", "doors", entry['exit']),
'({0})'.format(entry['dname']) if self.world.doorShuffle[entry['player']] == 'crossed' else '') for '({0})'.format(entry['dname']) if self.world.doorShuffle[entry['player']] != 'basic' else '') for
entry in self.doors.values()])) entry in self.doors.values()]))
if self.lobbies: if self.lobbies:
outfile.write('\n\nDungeon Lobbies:\n\n') outfile.write('\n\nDungeon Lobbies:\n\n')
@@ -2795,7 +2798,7 @@ class Spoiler(object):
# doorNames: For some reason these come in combined, somehow need to split on the thing to translate # doorNames: For some reason these come in combined, somehow need to split on the thing to translate
# doorTypes: Small Key, Bombable, Bonkable # doorTypes: Small Key, Bombable, Bonkable
outfile.write('\n\nDoor Types:\n\n') outfile.write('\n\nDoor Types:\n\n')
outfile.write('\n'.join(['%s%s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', self.world.fish.translate("meta","doors",entry['doorNames']), self.world.fish.translate("meta","doorTypes",entry['type'])) for entry in self.doorTypes.values()])) outfile.write('\n'.join(['%s%s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', self.world.fish.translate("meta", "doors", entry['doorNames']), self.world.fish.translate("meta", "doorTypes", entry['type'])) for entry in self.doorTypes.values()]))
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name # locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names # items: Item names
@@ -2805,7 +2808,7 @@ class Spoiler(object):
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name # locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names # items: Item names
outfile.write('\n\nShops:\n\n') outfile.write('\n\nShops:\n\n')
outfile.write('\n'.join("{} [{}]\n {}".format(self.world.fish.translate("meta","locations",shop['location']), shop['type'], "\n ".join(self.world.fish.translate("meta","items",item) for item in [shop.get('item_0', None), shop.get('item_1', None), shop.get('item_2', None)] if item)) for shop in self.shops)) outfile.write('\n'.join("{} [{}]\n {}".format(self.world.fish.translate("meta", "locations", shop['location']), shop['type'], "\n ".join(self.world.fish.translate("meta", "items", item) for item in [shop.get('item_0', None), shop.get('item_1', None), shop.get('item_2', None)] if item)) for shop in self.shops))
for player in range(1, self.world.players + 1): for player in range(1, self.world.players + 1):
if self.world.boss_shuffle[player] != 'none': if self.world.boss_shuffle[player] != 'none':
@@ -2818,23 +2821,23 @@ class Spoiler(object):
with open(filename, 'a') as outfile: with open(filename, 'a') as outfile:
outfile.write('\n\nOverworld Enemies:\n\n') outfile.write('\n\nOverworld Enemies:\n\n')
for player in range(1, self.world.players + 1): for player in range(1, self.world.players + 1):
player_tag = ' '+self.world.get_player_names(player) if self.world.players > 1 else '' player_tag = ' ' + self.world.get_player_names(player) if self.world.players > 1 else ''
for area, sprite_list in self.world.data_tables[player].ow_enemy_table.items(): for area, sprite_list in self.world.data_tables[player].ow_enemy_table.items():
for idx, sprite in enumerate(sprite_list): for idx, sprite in enumerate(sprite_list):
outfile.write(f'{hex(area)} Enemy #{idx+1}{player_tag}: {str(sprite)}\n') outfile.write(f'{hex(area)} Enemy #{idx + 1}{player_tag}: {str(sprite)}\n')
outfile.write('\n\nUnderworld Enemies:\n\n') outfile.write('\n\nUnderworld Enemies:\n\n')
for player in range(1, self.world.players + 1): for player in range(1, self.world.players + 1):
player_tag = ' '+self.world.get_player_names(player) if self.world.players > 1 else '' player_tag = ' ' + self.world.get_player_names(player) if self.world.players > 1 else ''
for area, sprite_list in self.world.data_tables[player].uw_enemy_table.room_map.items(): for area, sprite_list in self.world.data_tables[player].uw_enemy_table.room_map.items():
for idx, sprite in enumerate(sprite_list): for idx, sprite in enumerate(sprite_list):
outfile.write(f'{hex(area)} Enemy #{idx+1}{player_tag}: {str(sprite)}\n') outfile.write(f'{hex(area)} Enemy #{idx + 1}{player_tag}: {str(sprite)}\n')
def playthrough_to_file(self, filename): def playthrough_to_file(self, filename):
with open(filename, 'a') as outfile: with open(filename, 'a') as outfile:
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name # locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names # items: Item names
outfile.write('\n\nPlaythrough:\n\n') outfile.write('\n\nPlaythrough:\n\n')
outfile.write('\n'.join(['%s: {\n%s\n}' % (sphere_nr, '\n'.join([' %s: %s' % (self.world.fish.translate("meta","locations",location), self.world.fish.translate("meta","items",item)) for (location, item) in sphere.items()] if sphere_nr != '0' else [f' {item}' for item in sphere])) for (sphere_nr, sphere) in self.playthrough.items()])) outfile.write('\n'.join(['%s: {\n%s\n}' % (sphere_nr, '\n'.join([' %s: %s' % (self.world.fish.translate("meta", "locations", location), self.world.fish.translate("meta", "items", item)) for (location, item) in sphere.items()] if sphere_nr != '0' else [f' {item}' for item in sphere])) for (sphere_nr, sphere) in self.playthrough.items()]))
if self.unreachables: if self.unreachables:
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name # locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names # items: Item names
@@ -2852,10 +2855,10 @@ class Spoiler(object):
path_lines = [] path_lines = []
for region, exit in path: for region, exit in path:
if exit is not None: if exit is not None:
path_lines.append("{} -> {}".format(self.world.fish.translate("meta","rooms",region), self.world.fish.translate("meta","entrances",exit))) path_lines.append("{} -> {}".format(self.world.fish.translate("meta", "rooms", region), self.world.fish.translate("meta", "entrances", exit)))
else: else:
path_lines.append(self.world.fish.translate("meta","rooms",region)) path_lines.append(self.world.fish.translate("meta", "rooms", region))
path_listings.append("{}\n {}".format(self.world.fish.translate("meta","locations",location), "\n => ".join(path_lines))) path_listings.append("{}\n {}".format(self.world.fish.translate("meta", "locations", location), "\n => ".join(path_lines)))
outfile.write('\n'.join(path_listings)) outfile.write('\n'.join(path_listings))
@@ -2887,6 +2890,7 @@ dungeon_keys = {
'Universal': 'Small Key (Universal)' 'Universal': 'Small Key (Universal)'
} }
class PotItem(FastEnum): class PotItem(FastEnum):
Nothing = 0x0 Nothing = 0x0
OneRupee = 0x1 OneRupee = 0x1
@@ -3008,7 +3012,6 @@ rb_mode = {"none": 0, "mapcompass": 1, "dungeon": 2}
algo_mode = {"balanced": 0, "equitable": 1, "vanilla_fill": 2, "dungeon_only": 3, "district": 4, 'major_only': 5} algo_mode = {"balanced": 0, "equitable": 1, "vanilla_fill": 2, "dungeon_only": 3, "district": 4, 'major_only': 5}
boss_mode = {"none": 0, "simple": 1, "full": 2, "chaos": 3, 'random': 3, 'unique': 4} boss_mode = {"none": 0, "simple": 1, "full": 2, "chaos": 3, 'random': 3, 'unique': 4}
# byte 10: settings_version # byte 10: settings_version
# byte 11: FBBB TTSS (flute_mode, bow_mode, take_any, small_key_mode) # byte 11: FBBB TTSS (flute_mode, bow_mode, take_any, small_key_mode)
flute_mode = {'normal': 0, 'active': 1} flute_mode = {'normal': 0, 'active': 1}

View File

@@ -1800,7 +1800,7 @@ def imp_locations_factory(world, player):
imp_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden'] imp_locations = ['Agahnim 1', 'Agahnim 2', 'Attic Cracked Floor', 'Suspicious Maiden']
if world.mode[player] == 'standard': if world.mode[player] == 'standard':
imp_locations.append('Zelda Pickup') imp_locations.append('Zelda Pickup')
imp_locations.append('Zelda Dropoff') imp_locations.append('Zelda Drop Off')
return imp_locations return imp_locations