LttP: make shuffle names consistent

This commit is contained in:
Fabian Dill 2021-08-30 18:00:39 +02:00
parent 1c42564d90
commit cc70a6fa26
10 changed files with 74 additions and 65 deletions

View File

@ -569,7 +569,7 @@ class CollectionState(object):
def has_key(self, item, player, count: int = 1):
if self.world.logic[player] == 'nologic':
return True
if self.world.smallkeyshuffle[player] == "universal":
if self.world.smallkey_shuffle[player] == "universal":
return self.can_buy_unlimited('Small Key (Universal)', player)
return self.prog_items[item, player] >= count

View File

@ -243,14 +243,14 @@ if __name__ == "__main__":
from worlds.alttp.Options import Logic
import argparse
mapshuffle = Toggle
compassshuffle = Toggle
map_shuffle = Toggle
compass_shuffle = Toggle
keyshuffle = Toggle
bigkeyshuffle = Toggle
bigkey_shuffle = Toggle
hints = Toggle
test = argparse.Namespace()
test.logic = Logic.from_text("no_logic")
test.mapshuffle = mapshuffle.from_text("ON")
test.map_shuffle = map_shuffle.from_text("ON")
test.hints = hints.from_text('OFF')
try:
test.logic = Logic.from_text("overworld_glitches_typo")
@ -260,7 +260,7 @@ if __name__ == "__main__":
test.logic_owg = Logic.from_text("owg")
except KeyError as e:
print(e)
if test.mapshuffle:
print("Mapshuffle is on")
if test.map_shuffle:
print("map_shuffle is on")
print(f"Hints are {bool(test.hints)}")
print(test)

View File

@ -279,22 +279,31 @@ A Link to the Past:
on: 0 # prevents unshuffled compasses, maps and keys to be boss drops, they can still drop keysanity and other players' items
off: 50
### End of Logic Section ###
map_shuffle: # Shuffle dungeon maps into the world and other dungeons, including other players' worlds
on: 0
off: 50
compass_shuffle: # Shuffle compasses into the world and other dungeons, including other players' worlds
on: 0
off: 50
smallkey_shuffle: # Shuffle small keys into the world and other dungeons, including other players' worlds
on: 0
universal: 0 # allows small keys to be used in any dungeon and adds shops to buy more
off: 50
bigkey_shuffle: # Shuffle big keys into the world and other dungeons, including other players' worlds
on: 0
off: 50
local_keys: # Keep small keys and big keys local to your world
on: 0
off: 50
bigkey_shuffle: # Big Key Placement
original_dungeon: 50
own_dungeons: 0
own_world: 0
any_world: 0
different_world: 0
smallkey_shuffle: # Small Key Placement
original_dungeon: 50
own_dungeons: 0
own_world: 0
any_world: 0
different_world: 0
universal: 0
compass_shuffle: # Compass Placement
original_dungeon: 50
own_dungeons: 0
own_world: 0
any_world: 0
different_world: 0
map_shuffle: # Map Placement
original_dungeon: 50
own_dungeons: 0
own_world: 0
any_world: 0
different_world: 0
dungeon_items: # Alternative to the 4 shuffles and local_keys above this, does nothing until the respective 4 shuffles and local_keys above are deleted
mc: 0 # Shuffle maps and compasses
none: 50 # Shuffle none of the 4

View File

@ -8,7 +8,7 @@ from worlds.alttp.Regions import lookup_boss_drops
def create_dungeons(world, player):
def make_dungeon(name, default_boss, dungeon_regions, big_key, small_keys, dungeon_items):
dungeon = Dungeon(name, dungeon_regions, big_key,
[] if world.smallkeyshuffle[player] == "universal" else small_keys,
[] if world.smallkey_shuffle[player] == "universal" else small_keys,
dungeon_items, player)
for item in dungeon.all_items:
item.dungeon = dungeon

View File

@ -274,7 +274,7 @@ def generate_itempool(world):
itempool.extend(['Rupees (300)'] * 34)
itempool.extend(['Bombs (10)'] * 5)
itempool.extend(['Arrows (10)'] * 7)
if world.smallkeyshuffle[player] == 'universal':
if world.smallkey_shuffle[player] == 'universal':
itempool.extend(itemdiff.universal_keys)
itempool.append('Small Key (Universal)')
@ -633,7 +633,7 @@ def get_pool_core(world, player: int):
if retro:
replace = {'Single Arrow', 'Arrows (10)', 'Arrow Upgrade (+5)', 'Arrow Upgrade (+10)'}
pool = ['Rupees (5)' if item in replace else item for item in pool]
if world.smallkeyshuffle[player] == "universal":
if world.smallkey_shuffle[player] == "universal":
pool.extend(diff.universal_keys)
item_to_place = 'Small Key (Universal)' if goal != 'icerodhunt' else 'Nothing'
if mode == 'standard':
@ -770,7 +770,7 @@ def make_custom_item_pool(world, player):
itemtotal = itemtotal + 1
if mode == 'standard':
if world.smallkeyshuffle[player] == "universal":
if world.smallkey_shuffle[player] == "universal":
key_location = world.random.choice(
['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest',
'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
@ -793,7 +793,7 @@ def make_custom_item_pool(world, player):
pool.extend(['Magic Mirror'] * customitemarray[22])
pool.extend(['Moon Pearl'] * customitemarray[28])
if world.smallkeyshuffle == "universal":
if world.smallkey_shuffle == "universal":
itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode
if itemtotal < total_items_to_place:
pool.extend(['Nothing'] * (total_items_to_place - itemtotal))

View File

@ -43,26 +43,26 @@ class DungeonItem(Choice):
return self.value in {0, 1}
class BigKeyShuffle(DungeonItem):
class bigkey_shuffle(DungeonItem):
"""Big Key Placement"""
item_name_group = "Big Keys"
displayname = "Big Key Shuffle"
class SmallKeyShuffle(DungeonItem):
class smallkey_shuffle(DungeonItem):
"""Small Key Placement"""
option_universal = 5
item_name_group = "Small Keys"
displayname = "Small Key Shuffle"
class CompassShuffle(DungeonItem):
class compass_shuffle(DungeonItem):
"""Compass Placement"""
item_name_group = "Compasses"
displayname = "Compass Shuffle"
class MapShuffle(DungeonItem):
class map_shuffle(DungeonItem):
"""Map Placement"""
item_name_group = "Maps"
displayname = "Map Shuffle"
@ -221,10 +221,10 @@ class TriforceHud(Choice):
alttp_options: typing.Dict[str, type(Option)] = {
"crystals_needed_for_gt": CrystalsTower,
"crystals_needed_for_ganon": CrystalsGanon,
"bigkeyshuffle": BigKeyShuffle,
"smallkeyshuffle": SmallKeyShuffle,
"compassshuffle": CompassShuffle,
"mapshuffle": MapShuffle,
"bigkey_shuffle": bigkey_shuffle,
"smallkey_shuffle": smallkey_shuffle,
"compass_shuffle": compass_shuffle,
"map_shuffle": map_shuffle,
"progressive": Progressive,
"shop_item_slots": ShopItemSlots,
"ow_palettes": OWPalette,

View File

@ -802,14 +802,14 @@ def patch_rom(world, rom, player, enemized):
# patch music
music_addresses = dungeon_music_addresses[location.name]
if world.mapshuffle[player]:
if world.map_shuffle[player]:
music = local_random.choice([0x11, 0x16])
else:
music = 0x11 if 'Pendant' in location.item.name else 0x16
for music_address in music_addresses:
rom.write_byte(music_address, music)
if world.mapshuffle[player]:
if world.map_shuffle[player]:
rom.write_byte(0x155C9, local_random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle
# patch entrance/exits/holes
@ -1491,18 +1491,18 @@ def patch_rom(world, rom, player, enemized):
# block HC upstairs doors in rain state in standard mode
rom.write_byte(0x18008A, 0x01 if world.mode[player] == "standard" and world.shuffle[player] != 'vanilla' else 0x00)
rom.write_byte(0x18016A, 0x10 | ((0x01 if world.smallkeyshuffle[player] else 0x00)
| (0x02 if world.compassshuffle[player] else 0x00)
| (0x04 if world.mapshuffle[player] else 0x00)
| (0x08 if world.bigkeyshuffle[player] else 0x00))) # free roaming item text boxes
rom.write_byte(0x18003B, 0x01 if world.mapshuffle[player] else 0x00) # maps showing crystals on overworld
rom.write_byte(0x18016A, 0x10 | ((0x01 if world.smallkey_shuffle[player] else 0x00)
| (0x02 if world.compass_shuffle[player] else 0x00)
| (0x04 if world.map_shuffle[player] else 0x00)
| (0x08 if world.bigkey_shuffle[player] else 0x00))) # free roaming item text boxes
rom.write_byte(0x18003B, 0x01 if world.map_shuffle[player] else 0x00) # maps showing crystals on overworld
# compasses showing dungeon count
if world.clock_mode[player] or not world.dungeon_counters[player]:
rom.write_byte(0x18003C, 0x00) # Currently must be off if timer is on, because they use same HUD location
elif world.dungeon_counters[player] is True:
rom.write_byte(0x18003C, 0x02) # always on
elif world.compassshuffle[player] or world.dungeon_counters[player] == 'pickup':
elif world.compass_shuffle[player] or world.dungeon_counters[player] == 'pickup':
rom.write_byte(0x18003C, 0x01) # show on pickup
else:
rom.write_byte(0x18003C, 0x00)
@ -1515,10 +1515,10 @@ def patch_rom(world, rom, player, enemized):
# b - Big Key
# a - Small Key
#
rom.write_byte(0x180045, ((0x01 if world.smallkeyshuffle[player] is True else 0x00)
| (0x02 if world.bigkeyshuffle[player] else 0x00)
| (0x04 if world.mapshuffle[player] else 0x00)
| (0x08 if world.compassshuffle[player] else 0x00))) # free roaming items in menu
rom.write_byte(0x180045, ((0x01 if world.smallkey_shuffle[player] is True else 0x00)
| (0x02 if world.bigkey_shuffle[player] else 0x00)
| (0x04 if world.map_shuffle[player] else 0x00)
| (0x08 if world.compass_shuffle[player] else 0x00))) # free roaming items in menu
# Map reveals
reveal_bytes = {
@ -1544,11 +1544,11 @@ def patch_rom(world, rom, player, enemized):
return 0x0000
rom.write_int16(0x18017A,
get_reveal_bytes('Green Pendant') if world.mapshuffle[player] else 0x0000) # Sahasrahla reveal
rom.write_int16(0x18017C, get_reveal_bytes('Crystal 5') | get_reveal_bytes('Crystal 6') if world.mapshuffle[
get_reveal_bytes('Green Pendant') if world.map_shuffle[player] else 0x0000) # Sahasrahla reveal
rom.write_int16(0x18017C, get_reveal_bytes('Crystal 5') | get_reveal_bytes('Crystal 6') if world.map_shuffle[
player] else 0x0000) # Bomb Shop Reveal
rom.write_byte(0x180172, 0x01 if world.smallkeyshuffle[player] == "universal" else 0x00) # universal keys
rom.write_byte(0x180172, 0x01 if world.smallkey_shuffle[player] == "universal" else 0x00) # universal keys
rom.write_byte(0x18637E, 0x01 if world.retro[player] else 0x00) # Skip quiver in item shops once bought
rom.write_byte(0x180175, 0x01 if world.retro[player] else 0x00) # rupee bow
rom.write_byte(0x180176, 0x0A if world.retro[player] else 0x00) # wood arrow cost
@ -2247,9 +2247,9 @@ def write_strings(rom, world, player):
# Lastly we write hints to show where certain interesting items are. It is done the way it is to re-use the silver code and also to give one hint per each type of item regardless of how many exist. This supports many settings well.
items_to_hint = RelevantItems.copy()
if world.smallkeyshuffle[player]:
if world.smallkey_shuffle[player]:
items_to_hint.extend(SmallKeys)
if world.bigkeyshuffle[player]:
if world.bigkey_shuffle[player]:
items_to_hint.extend(BigKeys)
local_random.shuffle(items_to_hint)
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull', 'dungeonscrossed'] else 8

View File

@ -212,7 +212,7 @@ def global_rules(world, player):
set_rule(world.get_entrance('Sewers Door', player),
lambda state: state.has_key('Small Key (Hyrule Castle)', player) or (
world.smallkeyshuffle[player] == "universal" and world.mode[
world.smallkey_shuffle[player] == "universal" and world.mode[
player] == 'standard')) # standard universal small keys cannot access the shop
set_rule(world.get_entrance('Sewers Back Door', player),
lambda state: state.has_key('Small Key (Hyrule Castle)', player))
@ -243,7 +243,7 @@ def global_rules(world, player):
set_rule(world.get_location('Desert Palace - Boss', player), lambda state: state.has_key('Small Key (Desert Palace)', player) and state.has('Big Key (Desert Palace)', player) and state.has_fire_source(player) and state.world.get_location('Desert Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state))
# logic patch to prevent placing a crystal in Desert that's required to reach the required keys
if not (world.smallkeyshuffle[player] and world.bigkeyshuffle[player]):
if not (world.smallkey_shuffle[player] and world.bigkey_shuffle[player]):
add_rule(world.get_location('Desert Palace - Prize', player), lambda state: state.world.get_region('Desert Palace Main (Outer)', player).can_reach(state))
set_rule(world.get_entrance('Tower of Hera Small Key Door', player), lambda state: state.has_key('Small Key (Tower of Hera)', player) or item_name(state, 'Tower of Hera - Big Key Chest', player) == ('Small Key (Tower of Hera)', player))
@ -260,7 +260,7 @@ def global_rules(world, player):
if world.accessibility[player] != 'locations':
set_always_allow(world.get_location('Swamp Palace - Big Chest', player), lambda state, item: item.name == 'Big Key (Swamp Palace)' and item.player == player)
set_rule(world.get_entrance('Swamp Palace (North)', player), lambda state: state.has('Hookshot', player))
if not world.smallkeyshuffle[player] and world.logic[player] != 'nologic':
if not world.smallkey_shuffle[player] and world.logic[player] != 'nologic':
forbid_item(world.get_location('Swamp Palace - Entrance', player), 'Big Key (Swamp Palace)', player)
set_rule(world.get_entrance('Thieves Town Big Key Door', player), lambda state: state.has('Big Key (Thieves Town)', player))
@ -915,14 +915,14 @@ def set_trock_key_rules(world, player):
return 4
# If TR is only accessible from the middle, the big key must be further restricted to prevent softlock potential
if not can_reach_front and not world.smallkeyshuffle[player]:
if not can_reach_front and not world.smallkey_shuffle[player]:
# Must not go in the Big Key Chest - only 1 other chest available and 2+ keys required for all other chests
forbid_item(world.get_location('Turtle Rock - Big Key Chest', player), 'Big Key (Turtle Rock)', player)
if not can_reach_big_chest:
# Must not go in the Chain Chomps chest - only 2 other chests available and 3+ keys required for all other chests
forbid_item(world.get_location('Turtle Rock - Chain Chomps', player), 'Big Key (Turtle Rock)', player)
if world.accessibility[player] == 'locations' and world.goal[player] != 'icerodhunt':
if world.bigkeyshuffle[player] and can_reach_big_chest:
if world.bigkey_shuffle[player] and can_reach_big_chest:
# Must not go in the dungeon - all 3 available chests (Chomps, Big Chest, Crystaroller) must be keys to access laser bridge, and the big key is required first
for location in ['Turtle Rock - Chain Chomps', 'Turtle Rock - Compass Chest',
'Turtle Rock - Roller Room - Left', 'Turtle Rock - Roller Room - Right']:

View File

@ -271,7 +271,7 @@ def create_shops(world, player: int):
# make sure that blue potion is available in inverted, special case locked = None; lock when done.
player_shop_table["Dark Lake Hylia Shop"] = \
player_shop_table["Dark Lake Hylia Shop"]._replace(items=_inverted_hylia_shop_defaults, locked=None)
chance_100 = int(world.retro[player])*0.25+int(world.smallkeyshuffle[player] == "universal") * 0.5
chance_100 = int(world.retro[player])*0.25+int(world.smallkey_shuffle[player] == "universal") * 0.5
for region_name, (room_id, type, shopkeeper, custom, locked, inventory, sram_offset) in player_shop_table.items():
region = world.get_region(region_name, player)
shop: Shop = shop_class_mapping[type](region, room_id, shopkeeper, custom, locked, sram_offset)
@ -371,13 +371,13 @@ def set_up_shops(world, player: int):
rss = world.get_region('Red Shield Shop', player).shop
replacement_items = [['Red Potion', 150], ['Green Potion', 75], ['Blue Potion', 200], ['Bombs (10)', 50],
['Blue Shield', 50], ['Small Heart', 10]] # Can't just replace the single arrow with 10 arrows as retro doesn't need them.
if world.smallkeyshuffle[player] == "universal":
if world.smallkey_shuffle[player] == "universal":
replacement_items.append(['Small Key (Universal)', 100])
replacement_item = world.random.choice(replacement_items)
rss.add_inventory(2, 'Single Arrow', 80, 1, replacement_item[0], replacement_item[1])
rss.locked = True
if world.smallkeyshuffle[player] == "universal" or world.retro[player]:
if world.smallkey_shuffle[player] == "universal" or world.retro[player]:
for shop in world.random.sample([s for s in world.shops if
s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player],
5):
@ -385,7 +385,7 @@ def set_up_shops(world, player: int):
slots = [0, 1, 2]
world.random.shuffle(slots)
slots = iter(slots)
if world.smallkeyshuffle[player] == "universal":
if world.smallkey_shuffle[player] == "universal":
shop.add_inventory(next(slots), 'Small Key (Universal)', 100)
if world.retro[player]:
shop.push_inventory(next(slots), 'Single Arrow', 80)

View File

@ -65,7 +65,7 @@ class ALTTPWorld(World):
world.er_seeds[player] = seed
elif world.shuffle[player] == "vanilla":
world.er_seeds[player] = "vanilla"
for dungeon_item in ["smallkeyshuffle", "bigkeyshuffle", "compassshuffle", "mapshuffle"]:
for dungeon_item in ["smallkey_shuffle", "bigkey_shuffle", "compass_shuffle", "map_shuffle"]:
option = getattr(world, dungeon_item)[player]
if option == "own_world":
world.local_items[player] |= self.item_name_groups[option.item_name_group]
@ -324,8 +324,8 @@ class ALTTPWorld(World):
trash_counts = {}
standard_keyshuffle_players = set()
for player in world.get_game_players("A Link to the Past"):
if world.mode[player] == 'standard' and world.smallkeyshuffle[player] \
and world.smallkeyshuffle[player] != "universal":
if world.mode[player] == 'standard' and world.smallkey_shuffle[player] \
and world.smallkey_shuffle[player] != "universal":
standard_keyshuffle_players.add(player)
if not world.ganonstower_vanilla[player] or \
world.logic[player] in {'owglitches', 'hybridglitches', "nologic"}: