shopsanity

This commit is contained in:
Fabian Dill 2020-08-23 21:38:21 +02:00
parent 26ab3dd69a
commit 9cabd41d3b
8 changed files with 175 additions and 80 deletions

View File

@ -5,7 +5,7 @@ from enum import Enum, unique
import logging import logging
import json import json
from collections import OrderedDict, Counter, deque from collections import OrderedDict, Counter, deque
from typing import Union, Optional from typing import Union, Optional, List
import secrets import secrets
import random import random
@ -521,6 +521,10 @@ class CollectionState(object):
return any(shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self) for return any(shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self) for
shop in self.world.shops) shop in self.world.shops)
def can_buy(self, item: str, player: int) -> bool:
return any(shop.region.player == player and shop.has(item) and shop.region.can_reach(self) for
shop in self.world.shops)
def item_count(self, item, player: int) -> int: def item_count(self, item, player: int) -> int:
return self.prog_items[item, player] return self.prog_items[item, player]
@ -598,7 +602,7 @@ class CollectionState(object):
def can_shoot_arrows(self, player: int) -> bool: def can_shoot_arrows(self, player: int) -> bool:
if self.world.retro[player]: if self.world.retro[player]:
# TODO: Progressive and Non-Progressive silvers work differently (progressive is not usable until the shop arrow is bought) # TODO: Progressive and Non-Progressive silvers work differently (progressive is not usable until the shop arrow is bought)
return (self.has('Bow', player) or self.has('Silver Bow', player)) and self.can_buy_unlimited('Single Arrow', player) return (self.has('Bow', player) or self.has('Silver Bow', player)) and self.can_buy('Single Arrow', player)
return self.has('Bow', player) or self.has('Silver Bow', player) return self.has('Bow', player) or self.has('Silver Bow', player)
def can_get_good_bee(self, player: int) -> bool: def can_get_good_bee(self, player: int) -> bool:
@ -1054,11 +1058,12 @@ class ShopType(Enum):
class Shop(object): class Shop(object):
slots = 3 slots = 3
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked: bool):
self.region = region self.region = region
self.room_id = room_id self.room_id = room_id
self.type = type self.type = type
self.inventory = [None, None, None] self.inventory: List[Union[None, dict]] = [None, None, None]
self.shopkeeper_config = shopkeeper_config self.shopkeeper_config = shopkeeper_config
self.custom = custom self.custom = custom
self.locked = locked self.locked = locked
@ -1085,20 +1090,31 @@ class Shop(object):
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: str) -> bool:
for inv in self.inventory: for inv in self.inventory:
if inv is None: if inv is None:
continue continue
if inv['item'] == item:
return True
if inv['max'] != 0 and inv['replacement'] is not None and inv['replacement'] == item: if inv['max'] != 0 and inv['replacement'] is not None and inv['replacement'] == item:
return True return True
elif inv['item'] is not None and inv['item'] == item: return False
def has(self, item: str) -> bool:
for inv in self.inventory:
if inv is None:
continue
if inv['item'] == item:
return True
if inv['max'] != 0 and inv['replacement'] == item:
return True return True
return False return False
def clear_inventory(self): def clear_inventory(self):
self.inventory = [None, None, None] self.inventory = [None, None, None]
def add_inventory(self, slot, item, price, max=0, replacement=None, replacement_price=0, create_location=False): def add_inventory(self, slot: int, item: str, price: int, max: int = 0,
replacement: Optional[str] = None, replacement_price: int = 0, create_location: bool = False):
self.inventory[slot] = { self.inventory[slot] = {
'item': item, 'item': item,
'price': price, 'price': price,
@ -1108,6 +1124,18 @@ class Shop(object):
'create_location': create_location 'create_location': create_location
} }
def push_inventory(self, slot: int, item: str, price: int, max: int = 1):
if not self.inventory[slot]:
raise ValueError("Inventory can't be pushed back if it doesn't exist")
self.inventory[slot] = {
'item': item,
'price': price,
'max': max,
'replacement': self.inventory[slot]["item"],
'replacement_price': self.inventory[slot]["price"],
'create_location': self.inventory[slot]["create_location"]
}
class Spoiler(object): class Spoiler(object):
world: World world: World
@ -1243,6 +1271,7 @@ class Spoiler(object):
'progression_balancing': self.world.progression_balancing, 'progression_balancing': self.world.progression_balancing,
'triforce_pieces_available': self.world.triforce_pieces_available, 'triforce_pieces_available': self.world.triforce_pieces_available,
'triforce_pieces_required': self.world.triforce_pieces_required, 'triforce_pieces_required': self.world.triforce_pieces_required,
'shop_shuffle': self.world.shop_shuffle
} }
def to_json(self): def to_json(self):
@ -1290,15 +1319,15 @@ class Spoiler(object):
outfile.write('Progression Balanced: %s\n' % ( outfile.write('Progression Balanced: %s\n' % (
'Yes' if self.metadata['progression_balancing'][player] else 'No')) 'Yes' if self.metadata['progression_balancing'][player] else 'No'))
outfile.write('Mode: %s\n' % self.metadata['mode'][player]) outfile.write('Mode: %s\n' % self.metadata['mode'][player])
outfile.write( outfile.write('Retro: %s\n' %
'Retro: %s\n' % ('Yes' if self.metadata['retro'][player] else 'No')) ('Yes' if self.metadata['retro'][player] else 'No'))
outfile.write('Swords: %s\n' % self.metadata['weapons'][player]) outfile.write('Swords: %s\n' % self.metadata['weapons'][player])
outfile.write('Goal: %s\n' % self.metadata['goal'][player]) outfile.write('Goal: %s\n' % self.metadata['goal'][player])
if "triforce" in self.metadata["goal"][player]: # triforce hunt if "triforce" in self.metadata["goal"][player]: # triforce hunt
outfile.write( outfile.write("Pieces available for Triforce: %s\n" %
"Pieces available for Triforce: %s\n" % self.metadata['triforce_pieces_available'][player]) self.metadata['triforce_pieces_available'][player])
outfile.write( outfile.write("Pieces required for Triforce: %s\n" %
"Pieces required for Triforce: %s\n" % self.metadata["triforce_pieces_required"][player]) self.metadata["triforce_pieces_required"][player])
outfile.write('Difficulty: %s\n' % self.metadata['item_pool'][player]) outfile.write('Difficulty: %s\n' % self.metadata['item_pool'][player])
outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality'][player]) outfile.write('Item Functionality: %s\n' % self.metadata['item_functionality'][player])
outfile.write('Item Progression: %s\n' % self.metadata['progressive'][player]) outfile.write('Item Progression: %s\n' % self.metadata['progressive'][player])
@ -1308,14 +1337,20 @@ class Spoiler(object):
outfile.write('Pyramid hole pre-opened: %s\n' % ( outfile.write('Pyramid hole pre-opened: %s\n' % (
'Yes' if self.metadata['open_pyramid'][player] else 'No')) 'Yes' if self.metadata['open_pyramid'][player] else 'No'))
outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player]) outfile.write('Accessibility: %s\n' % self.metadata['accessibility'][player])
outfile.write( outfile.write('Map shuffle: %s\n' %
'Map shuffle: %s\n' % ('Yes' if self.metadata['mapshuffle'][player] else 'No')) ('Yes' if self.metadata['mapshuffle'][player] else 'No'))
outfile.write('Compass shuffle: %s\n' % ( outfile.write('Compass shuffle: %s\n' %
'Yes' if self.metadata['compassshuffle'][player] else 'No')) ('Yes' if self.metadata['compassshuffle'][player] else 'No'))
outfile.write( outfile.write(
'Small Key shuffle: %s\n' % (bool_to_text(self.metadata['keyshuffle'][player]))) 'Small Key shuffle: %s\n' % (bool_to_text(self.metadata['keyshuffle'][player])))
outfile.write('Big Key shuffle: %s\n' % ( outfile.write('Big Key shuffle: %s\n' % (
'Yes' if self.metadata['bigkeyshuffle'][player] else 'No')) 'Yes' if self.metadata['bigkeyshuffle'][player] else 'No'))
outfile.write('Shop inventory shuffle: %s\n' %
bool_to_text("i" in self.metadata["shop_shuffle"][player]))
outfile.write('Shop price shuffle: %s\n' %
bool_to_text("p" in self.metadata["shop_shuffle"][player]))
outfile.write('Shop upgrade shuffle: %s\n' %
bool_to_text("u" in self.metadata["shop_shuffle"][player]))
outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player]) outfile.write('Boss shuffle: %s\n' % self.metadata['boss_shuffle'][player])
outfile.write( outfile.write(
'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player])) 'Enemy shuffle: %s\n' % bool_to_text(self.metadata['enemy_shuffle'][player]))
@ -1331,7 +1366,11 @@ class Spoiler(object):
'Pot shuffle %s\n' % ('Yes' if self.metadata['shufflepots'][player] else 'No')) 'Pot shuffle %s\n' % ('Yes' if self.metadata['shufflepots'][player] else 'No'))
if self.entrances: if self.entrances:
outfile.write('\n\nEntrances:\n\n') outfile.write('\n\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 '', entry['entrance'], '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', 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 '', entry['entrance'],
'<=>' if entry['direction'] == 'both' else
'<=' if entry['direction'] == 'exit' else '=>',
entry['exit']) for entry in self.entrances.values()]))
outfile.write('\n\nMedallions:\n') outfile.write('\n\nMedallions:\n')
for dungeon, medallion in self.medallions.items(): for dungeon, medallion in self.medallions.items():
outfile.write(f'\n{dungeon}: {medallion}') outfile.write(f'\n{dungeon}: {medallion}')

View File

@ -312,7 +312,12 @@ def parse_arguments(argv, no_defaults=False):
parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos']) parser.add_argument('--enemy_damage', default=defval('default'), choices=['default', 'shuffled', 'chaos'])
parser.add_argument('--shufflepots', default=defval(False), action='store_true') parser.add_argument('--shufflepots', default=defval(False), action='store_true')
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4)) parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4))
parser.add_argument('--shop_shuffle', default='off', choices=['off', 'inventory', 'price', 'inventory_price']) parser.add_argument('--shop_shuffle', default='', help='''\
combine letters for options:
i: shuffle the inventories of the shops around
p: randomize the prices of the items in shop inventories
u: shuffle capacity upgrades into the item pool
''')
parser.add_argument('--remote_items', default=defval(False), action='store_true') parser.add_argument('--remote_items', default=defval(False), action='store_true')
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
parser.add_argument('--names', default=defval('')) parser.add_argument('--names', default=defval(''))

View File

@ -1061,7 +1061,8 @@ def link_entrances(world, player):
# place remaining doors # place remaining doors
connect_doors(world, single_doors, door_targets, player) connect_doors(world, single_doors, door_targets, player)
else: else:
raise NotImplementedError(f'{world.shuffle[player]} Shuffling not supported yet. Player {player}') raise NotImplementedError(
f'{world.shuffle[player]} Shuffling not supported yet. Player {world.get_player_names(player)}')
# check for swamp palace fix # check for swamp palace fix
if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Palace (Entrance)': if world.get_entrance('Dam', player).connected_region.name != 'Dam' or world.get_entrance('Swamp Palace', player).connected_region.name != 'Swamp Palace (Entrance)':

30
Gui.py
View File

@ -75,14 +75,14 @@ def guiMain(args=None):
compassshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Compasses", variable=compassshuffleVar) compassshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Compasses", variable=compassshuffleVar)
bigkeyshuffleVar = IntVar() bigkeyshuffleVar = IntVar()
bigkeyshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="BigKeys", variable=bigkeyshuffleVar) bigkeyshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Big Keys", variable=bigkeyshuffleVar)
keyshuffleFrame = Frame(checkBoxFrame) keyshuffleFrame = Frame(checkBoxFrame)
keyshuffleVar = StringVar() keyshuffleVar = StringVar()
keyshuffleVar.set('off') keyshuffleVar.set('off')
modeOptionMenu = OptionMenu(keyshuffleFrame, keyshuffleVar, 'off', 'universal', 'on') modeOptionMenu = OptionMenu(keyshuffleFrame, keyshuffleVar, 'off', 'universal', 'on')
modeOptionMenu.pack(side=LEFT) modeOptionMenu.pack(side=LEFT)
modeLabel = Label(keyshuffleFrame, text='Key Shuffle') modeLabel = Label(keyshuffleFrame, text='Small Key Shuffle')
modeLabel.pack(side=LEFT) modeLabel.pack(side=LEFT)
retroVar = IntVar() retroVar = IntVar()
@ -447,6 +447,20 @@ def guiMain(args=None):
killable_thievesShuffleButton = Checkbutton(enemizerFrame, text="Killable Thieves", variable=killableThievesVar) killable_thievesShuffleButton = Checkbutton(enemizerFrame, text="Killable Thieves", variable=killableThievesVar)
killable_thievesShuffleButton.grid(row=2, column=3, sticky=W) killable_thievesShuffleButton.grid(row=2, column=3, sticky=W)
shopframe = LabelFrame(randomizerWindow, text="Shops", padx=5, pady=2)
shopPriceShuffleVar = IntVar()
shopPriceShuffleButton = Checkbutton(shopframe, text="Random Prices", variable=shopPriceShuffleVar)
shopPriceShuffleButton.grid(row=0, column=0, sticky=W)
shopShuffleVar = IntVar()
shopShuffleButton = Checkbutton(shopframe, text="Shuffle Inventories", variable=shopShuffleVar)
shopShuffleButton.grid(row=0, column=1, sticky=W)
shopUpgradeShuffleVar = IntVar()
shopUpgradeShuffleButton = Checkbutton(shopframe, text="Lootable Upgrades", variable=shopUpgradeShuffleVar)
shopUpgradeShuffleButton.grid(row=0, column=2, sticky=W)
multiworldframe = LabelFrame(randomizerWindow, text="Multiworld", padx=5, pady=2) multiworldframe = LabelFrame(randomizerWindow, text="Multiworld", padx=5, pady=2)
worldLabel = Label(multiworldframe, text='Worlds') worldLabel = Label(multiworldframe, text='Worlds')
@ -521,6 +535,13 @@ def guiMain(args=None):
guiargs.custom = bool(customVar.get()) guiargs.custom = bool(customVar.get())
guiargs.triforce_pieces_required = min(90, int(triforcecountVar.get())) guiargs.triforce_pieces_required = min(90, int(triforcecountVar.get()))
guiargs.triforce_pieces_available = min(90, int(triforcepieceVar.get())) guiargs.triforce_pieces_available = min(90, int(triforcepieceVar.get()))
guiargs.shop_shuffle = ""
if shopShuffleVar.get():
guiargs.shop_shuffle += "i"
if shopPriceShuffleVar.get():
guiargs.shop_shuffle += "p"
if shopUpgradeShuffleVar.get():
guiargs.shop_shuffle += "u"
guiargs.customitemarray = [int(bowVar.get()), int(silverarrowVar.get()), int(boomerangVar.get()), guiargs.customitemarray = [int(bowVar.get()), int(silverarrowVar.get()), int(boomerangVar.get()),
int(magicboomerangVar.get()), int(hookshotVar.get()), int(mushroomVar.get()), int(magicboomerangVar.get()), int(hookshotVar.get()), int(mushroomVar.get()),
int(magicpowderVar.get()), int(firerodVar.get()), int(magicpowderVar.get()), int(firerodVar.get()),
@ -567,9 +588,9 @@ def guiMain(args=None):
main(seed=guiargs.seed, args=guiargs) main(seed=guiargs.seed, args=guiargs)
except Exception as e: except Exception as e:
logging.exception(e) logging.exception(e)
messagebox.showerror(title="Error while creating seed", message=str(e)) messagebox.showerror(title="Error while creating multiworld", message=str(e))
else: else:
messagebox.showinfo(title="Success", message="Rom patched successfully") messagebox.showinfo(title="Success", message="Multiworld created successfully")
generateButton = Button(farBottomFrame, text='Generate Patched Rom', command=generateRom) generateButton = Button(farBottomFrame, text='Generate Patched Rom', command=generateRom)
@ -590,6 +611,7 @@ def guiMain(args=None):
topFrame.pack(side=TOP) topFrame.pack(side=TOP)
multiworldframe.pack(side=BOTTOM, expand=True, fill=X) multiworldframe.pack(side=BOTTOM, expand=True, fill=X)
enemizerFrame.pack(side=BOTTOM, fill=BOTH) enemizerFrame.pack(side=BOTTOM, fill=BOTH)
shopframe.pack(side=BOTTOM, expand=True, fill=X)
# Adjuster Controls # Adjuster Controls

View File

@ -311,8 +311,6 @@ def generate_itempool(world, player: int):
progressionitems += [ItemFactory("Triforce Piece", player)] * (triforce_pieces - 30) progressionitems += [ItemFactory("Triforce Piece", player)] * (triforce_pieces - 30)
nonprogressionitems = nonprogressionitems[(triforce_pieces - 30):] nonprogressionitems = nonprogressionitems[(triforce_pieces - 30):]
world.itempool += progressionitems + nonprogressionitems
# shuffle medallions # shuffle medallions
mm_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)] mm_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)]
tr_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)] tr_medallion = ['Ether', 'Quake', 'Bombos'][world.random.randint(0, 2)]
@ -323,43 +321,64 @@ def generate_itempool(world, player: int):
if world.retro[player]: if world.retro[player]:
set_up_take_anys(world, player) set_up_take_anys(world, player)
if world.shop_shuffle[player] != 'off': if world.shop_shuffle[player]:
shuffle_shops(world, player) shuffle_shops(world, nonprogressionitems, player)
create_dynamic_shop_locations(world, player) create_dynamic_shop_locations(world, player)
world.itempool += progressionitems + nonprogressionitems
def shuffle_shops(world, player: int):
def shuffle_shops(world, items, player: int):
option = world.shop_shuffle[player] option = world.shop_shuffle[player]
shops = [] if 'u' in option:
total_inventory = [] if world.retro[player]:
for shop in world.shops: new_items = ["Bomb Upgrade (+5)"] * 7
if shop.type == ShopType.Shop and shop.region.player == player: else:
shops.append(shop) new_items = ["Bomb Upgrade (+5)", "Arrow Upgrade (+5)"] * 7
total_inventory.extend(shop.inventory)
if 'price' in option:
def price_adjust(price: int) -> int:
# it is important that a base price of 0 always returns 0 as new price!
return int(price * (0.5 + world.random.random() * 2))
for item in total_inventory:
if item:
item["price"] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
for shop in world.shops: for shop in world.shops:
if shop.type == ShopType.UpgradeShop and shop.region.player == player: if shop.type == ShopType.UpgradeShop and shop.region.player == player and \
for item in shop.inventory: shop.region.name == "Capacity Upgrade":
if item: shop.clear_inventory()
item['price'] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
if 'inventory' in option: for i, item in enumerate(items):
world.random.shuffle(total_inventory) if item.name.startswith(("Bombs", "Arrows", "Rupees")):
i = 0 items[i] = ItemFactory(new_items.pop(), player)
for shop in shops: if not new_items:
slots = shop.slots break
shop.inventory = total_inventory[i:i + slots] else:
i += slots logging.warning(f"Not all upgrades put into Player{player}' item pool. Still missing: {new_items}")
if 'p' in option or 'i' in option:
shops = []
total_inventory = []
for shop in world.shops:
if shop.type == ShopType.Shop and shop.region.player == player:
shops.append(shop)
total_inventory.extend(shop.inventory)
if 'p' in option:
def price_adjust(price: int) -> int:
# it is important that a base price of 0 always returns 0 as new price!
return int(price * (0.5 + world.random.random() * 2))
for item in total_inventory:
if item:
item["price"] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
for shop in world.shops:
if shop.type == ShopType.UpgradeShop and shop.region.player == player:
for item in shop.inventory:
if item:
item['price'] = price_adjust(item["price"])
item['replacement_price'] = price_adjust(item["price"])
if 'i' in option:
world.random.shuffle(total_inventory)
i = 0
for shop in shops:
slots = shop.slots
shop.inventory = total_inventory[i:i + slots]
i += slots
take_any_locations = [ take_any_locations = [
@ -466,21 +485,21 @@ def set_up_shops(world, player: int):
if world.retro[player]: if world.retro[player]:
rss = world.get_region('Red Shield Shop', player).shop rss = world.get_region('Red Shield Shop', player).shop
if not rss.locked: rss.add_inventory(2, 'Single Arrow', 80)
rss.add_inventory(2, 'Single Arrow', 80)
rss.locked = True rss.locked = True
if world.keyshuffle[player] == "universal": if world.keyshuffle[player] == "universal" or world.retro[player]:
for shop in world.random.sample([s for s in world.shops if 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], s.custom and not s.locked and s.type == ShopType.Shop and s.region.player == player],
5): 5):
shop.locked = True shop.locked = True
slots = [0, 1, 2]
world.random.shuffle(slots)
slots = iter(slots)
if world.retro[player]: if world.retro[player]:
shop.add_inventory(0, 'Single Arrow', 80) shop.push_inventory(next(slots), 'Single Arrow', 80)
else: if world.keyshuffle[player] == "universal":
shop.add_inventory(0, "Red Potion", 150) shop.add_inventory(next(slots), 'Small Key (Universal)', 100)
shop.add_inventory(1, 'Small Key (Universal)', 100)
shop.add_inventory(2, 'Bombs (10)', 50)
def get_pool_core(world, player: int): def get_pool_core(world, player: int):

View File

@ -312,7 +312,7 @@ def roll_settings(weights):
ret.shop_shuffle = get_choice('shop_shuffle', weights, False) ret.shop_shuffle = get_choice('shop_shuffle', weights, False)
if not ret.shop_shuffle: if not ret.shop_shuffle:
ret.shop_shuffle = 'off' ret.shop_shuffle = ''
ret.mode = get_choice('world_state', weights, None) # legacy support ret.mode = get_choice('world_state', weights, None) # legacy support
if ret.mode == 'retro': if ret.mode == 'retro':

25
Rom.py
View File

@ -1157,20 +1157,27 @@ def patch_rom(world, rom, player, team, enemized):
assert equip[:0x340] == [0] * 0x340 assert equip[:0x340] == [0] * 0x340
rom.write_bytes(0x183000, equip[0x340:]) rom.write_bytes(0x183000, equip[0x340:])
rom.write_bytes(0x271A6, equip[0x340:0x340+60]) rom.write_bytes(0x271A6, equip[0x340:0x340 + 60])
rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode rom.write_byte(0x18004A, 0x00 if world.mode[player] != 'inverted' else 0x01) # Inverted mode
rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier rom.write_byte(0x18005D, 0x00) # Hammer always breaks barrier
rom.write_byte(0x2AF79, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both) rom.write_byte(0x2AF79, 0xD0 if world.mode[
rom.write_byte(0x3A943, 0xD0 if world.mode[player] != 'inverted' else 0xF0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both) player] != 'inverted' else 0xF0) # vortexes: Normal (D0=light to dark, F0=dark to light, 42 = both)
rom.write_byte(0x3A96D, 0xF0 if world.mode[player] != 'inverted' else 0xD0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader)) rom.write_byte(0x3A943, 0xD0 if world.mode[
rom.write_byte(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader)) player] != 'inverted' else 0xF0) # Mirror: Normal (D0=Dark to Light, F0=light to dark, 42 = both)
rom.write_byte(0x3A96D, 0xF0 if world.mode[
rom.write_bytes(0x180080, [50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10) player] != 'inverted' else 0xD0) # Residual Portal: Normal (F0= Light Side, D0=Dark Side, 42 = both (Darth Vader))
rom.write_byte(0x3A9A7, 0xD0) # Residual Portal: Normal (D0= Light Side, F0=Dark Side, 42 = both (Darth Vader))
if 'u' in world.shop_shuffle[player]:
rom.write_bytes(0x180080,
[5, 10, 5, 10]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10)
else:
rom.write_bytes(0x180080,
[50, 50, 70, 70]) # values to fill for Capacity Upgrades (Bomb5, Bomb10, Arrow5, Arrow10)
rom.write_byte(0x18004D, ((0x01 if 'arrows' in world.escape_assist[player] else 0x00) | rom.write_byte(0x18004D, ((0x01 if 'arrows' in world.escape_assist[player] else 0x00) |
(0x02 if 'bombs' in world.escape_assist[player] else 0x00) | (0x02 if 'bombs' in world.escape_assist[player] else 0x00) |
(0x04 if 'magic' in world.escape_assist[player] else 0x00))) # Escape assist (0x04 if 'magic' in world.escape_assist[player] else 0x00))) # Escape assist
if world.goal[player] in ['pedestal', 'triforcehunt', 'localtriforcehunt']: if world.goal[player] in ['pedestal', 'triforcehunt', 'localtriforcehunt']:
rom.write_byte(0x18003E, 0x01) # make ganon invincible rom.write_byte(0x18003E, 0x01) # make ganon invincible

View File

@ -190,10 +190,13 @@ beemizer: # Remove items from the global item pool and replace them with single
3: 0 # 100% of the non-essential item pool is replaced with bee traps, of which 50% could be single bees 3: 0 # 100% of the non-essential item pool is replaced with bee traps, of which 50% could be single bees
4: 0 # 100% of the non-essential item pool is replaced with bee traps 4: 0 # 100% of the non-essential item pool is replaced with bee traps
shop_shuffle: shop_shuffle:
off: 1 none: 1
inventory: 0 # shuffle the inventories of the shops around i: 0 # shuffle the inventories of the shops around
price: 0 # randomize the prices of the items in shop inventories p: 0 # randomize the prices of the items in shop inventories
inventory_price: 0 # shuffle inventories and randomize prices u: 0 # shuffle capacity upgrades into the item pool (and allow them to traverse the multiworld)
ip: 0 # shuffle inventories and randomize prices
uip: 0 # shuffle inventories, randomize prices and shuffle capacity upgrades into the item pool
# you can add more combos
timer: timer:
none: 1 none: 1
timed: 0 timed: 0
@ -245,7 +248,6 @@ linked_options:
full: 1 full: 1
random: 1 random: 1
singularity: 1 singularity: 1
duality: 1
enemy_damage: enemy_damage:
shuffled: 1 shuffled: 1
random: 1 random: 1