make "universal" small key shuffle a thing and split it out of retro
also make retro usable independently from the other world modes in mystery
This commit is contained in:
		
							parent
							
								
									bea54d91de
								
							
						
					
					
						commit
						685ff49711
					
				| 
						 | 
				
			
			@ -516,17 +516,13 @@ class CollectionState(object):
 | 
			
		|||
    def has_key(self, item, player, count: int = 1):
 | 
			
		||||
        if self.world.logic[player] == 'nologic':
 | 
			
		||||
            return True
 | 
			
		||||
        if self.world.retro[player]:
 | 
			
		||||
        if self.world.keyshuffle[player] == "universal":
 | 
			
		||||
            return self.can_buy_unlimited('Small Key (Universal)', player)
 | 
			
		||||
        if count == 1:
 | 
			
		||||
            return (item, player) in self.prog_items
 | 
			
		||||
        return self.prog_items[item, player] >= count
 | 
			
		||||
 | 
			
		||||
    def can_buy_unlimited(self, item: str, player: int) -> bool:
 | 
			
		||||
        for shop in self.world.shops:
 | 
			
		||||
            if shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self):
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
        return any(shop.region.player == player and shop.has_unlimited(item) and shop.region.can_reach(self) for
 | 
			
		||||
                   shop in self.world.shops)
 | 
			
		||||
 | 
			
		||||
    def item_count(self, item, player: int) -> int:
 | 
			
		||||
        return self.prog_items[item, player]
 | 
			
		||||
| 
						 | 
				
			
			@ -619,9 +615,10 @@ class CollectionState(object):
 | 
			
		|||
        )
 | 
			
		||||
 | 
			
		||||
    def has_sword(self, player: int) -> bool:
 | 
			
		||||
        return self.has('Fighter Sword', player) or self.has('Master Sword', player) or self.has('Tempered Sword',
 | 
			
		||||
                                                                                                 player) or self.has(
 | 
			
		||||
            'Golden Sword', player)
 | 
			
		||||
        return self.has('Fighter Sword', player) \
 | 
			
		||||
               or self.has('Master Sword', player) \
 | 
			
		||||
               or self.has('Tempered Sword', player) \
 | 
			
		||||
               or self.has('Golden Sword', player)
 | 
			
		||||
 | 
			
		||||
    def has_beam_sword(self, player: int) -> bool:
 | 
			
		||||
        return self.has('Master Sword', player) or self.has('Tempered Sword', player) or self.has('Golden Sword', player)
 | 
			
		||||
| 
						 | 
				
			
			@ -1267,13 +1264,15 @@ class Spoiler(object):
 | 
			
		|||
    def to_file(self, filename):
 | 
			
		||||
        self.parse_data()
 | 
			
		||||
 | 
			
		||||
        def bool_to_text(variable: bool) -> str:
 | 
			
		||||
        def bool_to_text(variable: Union[bool, str]) -> str:
 | 
			
		||||
            if type(variable) == str:
 | 
			
		||||
                return variable
 | 
			
		||||
            return 'Yes' if variable else 'No'
 | 
			
		||||
 | 
			
		||||
        with open(filename, 'w', encoding="utf-8-sig") as outfile:
 | 
			
		||||
            outfile.write(
 | 
			
		||||
                'ALttP Berserker\'s Multiworld Version %s  -  Seed: %s\n\n' % (
 | 
			
		||||
                self.metadata['version'], self.world.seed))
 | 
			
		||||
                    self.metadata['version'], self.world.seed))
 | 
			
		||||
            outfile.write('Filling Algorithm:               %s\n' % self.world.algorithm)
 | 
			
		||||
            outfile.write('Players:                         %d\n' % self.world.players)
 | 
			
		||||
            outfile.write('Teams:                           %d\n' % self.world.teams)
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,7 +1311,7 @@ class Spoiler(object):
 | 
			
		|||
                outfile.write('Compass shuffle:                 %s\n' % (
 | 
			
		||||
                    'Yes' if self.metadata['compassshuffle'][player] else 'No'))
 | 
			
		||||
                outfile.write(
 | 
			
		||||
                    'Small Key shuffle:               %s\n' % ('Yes' if self.metadata['keyshuffle'][player] else 'No'))
 | 
			
		||||
                    'Small Key shuffle:               %s\n' % (bool_to_text(self.metadata['keyshuffle'][player])))
 | 
			
		||||
                outfile.write('Big Key shuffle:                 %s\n' % (
 | 
			
		||||
                    'Yes' if self.metadata['bigkeyshuffle'][player] else 'No'))
 | 
			
		||||
                outfile.write('Boss shuffle:                    %s\n' % self.metadata['boss_shuffle'][player])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,8 @@ from Items import ItemFactory
 | 
			
		|||
 | 
			
		||||
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.retro[player] else small_keys, dungeon_items, player)
 | 
			
		||||
        dungeon = Dungeon(name, dungeon_regions, big_key, [] if world.keyshuffle[player] == "universal" else small_keys,
 | 
			
		||||
                          dungeon_items, player)
 | 
			
		||||
        dungeon.boss = BossFactory(default_boss, player)
 | 
			
		||||
        for region in dungeon.regions:
 | 
			
		||||
            world.get_region(region, player).dungeon = dungeon
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -231,17 +231,27 @@ def parse_arguments(argv, no_defaults=False):
 | 
			
		|||
                             --seed given will produce the same 10 (different) roms each
 | 
			
		||||
                             time).
 | 
			
		||||
                             ''', type=int)
 | 
			
		||||
    parser.add_argument('--fastmenu', default=defval('normal'), const='normal', nargs='?', choices=['normal', 'instant', 'double', 'triple', 'quadruple', 'half'],
 | 
			
		||||
    parser.add_argument('--fastmenu', default=defval('normal'), const='normal', nargs='?',
 | 
			
		||||
                        choices=['normal', 'instant', 'double', 'triple', 'quadruple', 'half'],
 | 
			
		||||
                        help='''\
 | 
			
		||||
                             Select the rate at which the menu opens and closes.
 | 
			
		||||
                             (default: %(default)s)
 | 
			
		||||
                             ''')
 | 
			
		||||
    parser.add_argument('--quickswap', help='Enable quick item swapping with L and R.', action='store_true')
 | 
			
		||||
    parser.add_argument('--disablemusic', help='Disables game music.', action='store_true')
 | 
			
		||||
    parser.add_argument('--mapshuffle', default=defval(False), help='Maps are no longer restricted to their dungeons, but can be anywhere', action='store_true')
 | 
			
		||||
    parser.add_argument('--compassshuffle', default=defval(False), help='Compasses are no longer restricted to their dungeons, but can be anywhere', action='store_true')
 | 
			
		||||
    parser.add_argument('--keyshuffle', default=defval(False), help='Small Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true')
 | 
			
		||||
    parser.add_argument('--bigkeyshuffle', default=defval(False), help='Big Keys are no longer restricted to their dungeons, but can be anywhere', action='store_true')
 | 
			
		||||
    parser.add_argument('--mapshuffle', default=defval(False),
 | 
			
		||||
                        help='Maps are no longer restricted to their dungeons, but can be anywhere',
 | 
			
		||||
                        action='store_true')
 | 
			
		||||
    parser.add_argument('--compassshuffle', default=defval(False),
 | 
			
		||||
                        help='Compasses are no longer restricted to their dungeons, but can be anywhere',
 | 
			
		||||
                        action='store_true')
 | 
			
		||||
    parser.add_argument('--keyshuffle', default=defval("off"), help='\
 | 
			
		||||
                        on: Small Keys are no longer restricted to their dungeons, but can be anywhere.\
 | 
			
		||||
                        universal: Makes all Small Keys usable in any dungeon and places shops to buy more keys.',
 | 
			
		||||
                        choices=["on", "universal", "off"])
 | 
			
		||||
    parser.add_argument('--bigkeyshuffle', default=defval(False),
 | 
			
		||||
                        help='Big Keys are no longer restricted to their dungeons, but can be anywhere',
 | 
			
		||||
                        action='store_true')
 | 
			
		||||
    parser.add_argument('--keysanity', default=defval(False), help=argparse.SUPPRESS, action='store_true')
 | 
			
		||||
    parser.add_argument('--retro', default=defval(False), help='''\
 | 
			
		||||
                             Keys are universal, shooting arrows costs rupees,
 | 
			
		||||
| 
						 | 
				
			
			@ -326,9 +336,13 @@ def parse_arguments(argv, no_defaults=False):
 | 
			
		|||
        ret.dungeon_counters = True
 | 
			
		||||
    elif ret.dungeon_counters == 'off':
 | 
			
		||||
        ret.dungeon_counters = False
 | 
			
		||||
    if ret.keysanity:
 | 
			
		||||
        ret.mapshuffle, ret.compassshuffle, ret.keyshuffle, ret.bigkeyshuffle = [True] * 4
 | 
			
		||||
 | 
			
		||||
    if ret.keysanity:
 | 
			
		||||
        ret.mapshuffle = ret.compassshuffle = ret.keyshuffle = ret.bigkeyshuffle = True
 | 
			
		||||
    elif ret.keyshuffle == "on":
 | 
			
		||||
        ret.keyshuffle = True
 | 
			
		||||
    elif ret.keyshuffle == "off":
 | 
			
		||||
        ret.keyshuffle = False
 | 
			
		||||
    if multiargs.multi:
 | 
			
		||||
        defaults = copy.deepcopy(ret)
 | 
			
		||||
        for player in range(1, multiargs.multi + 1):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								Fill.py
								
								
								
								
							
							
						
						
									
										8
									
								
								Fill.py
								
								
								
								
							| 
						 | 
				
			
			@ -203,7 +203,13 @@ def fill_restrictive(world, base_state: CollectionState, locations, itempool, si
 | 
			
		|||
                        logging.warning(
 | 
			
		||||
                            f'Not all items placed. Game beatable anyway. (Could not place {item_to_place})')
 | 
			
		||||
                        continue
 | 
			
		||||
                    raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid')
 | 
			
		||||
                    placements = []
 | 
			
		||||
                    for region in world.regions:
 | 
			
		||||
                        for location in region.locations:
 | 
			
		||||
                            if location.item and not location.event:
 | 
			
		||||
                                placements.append(location)
 | 
			
		||||
                    raise FillError(f'No more spots to place {item_to_place}, locations {locations} are invalid. '
 | 
			
		||||
                                    f'\nAlready placed {len(placements)}: {", ".join(placements)}')
 | 
			
		||||
 | 
			
		||||
                world.push_item(spot_to_fill, item_to_place, False)
 | 
			
		||||
                locations.remove(spot_to_fill)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								Gui.py
								
								
								
								
							
							
						
						
									
										21
									
								
								Gui.py
								
								
								
								
							| 
						 | 
				
			
			@ -67,16 +67,27 @@ def guiMain(args=None):
 | 
			
		|||
    openpyramidCheckbutton = Checkbutton(checkBoxFrame, text="Pre-open Pyramid Hole", variable=openpyramidVar)
 | 
			
		||||
    mcsbshuffleFrame = Frame(checkBoxFrame)
 | 
			
		||||
    mcsbLabel = Label(mcsbshuffleFrame, text="Shuffle: ")
 | 
			
		||||
 | 
			
		||||
    mapshuffleVar = IntVar()
 | 
			
		||||
    mapshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Maps", variable=mapshuffleVar)
 | 
			
		||||
 | 
			
		||||
    compassshuffleVar = IntVar()
 | 
			
		||||
    compassshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Compasses", variable=compassshuffleVar)
 | 
			
		||||
    keyshuffleVar = IntVar()
 | 
			
		||||
    keyshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="Keys", variable=keyshuffleVar)
 | 
			
		||||
 | 
			
		||||
    bigkeyshuffleVar = IntVar()
 | 
			
		||||
    bigkeyshuffleCheckbutton = Checkbutton(mcsbshuffleFrame, text="BigKeys", variable=bigkeyshuffleVar)
 | 
			
		||||
 | 
			
		||||
    keyshuffleFrame = Frame(checkBoxFrame)
 | 
			
		||||
    keyshuffleVar = StringVar()
 | 
			
		||||
    keyshuffleVar.set('off')
 | 
			
		||||
    modeOptionMenu = OptionMenu(keyshuffleFrame, keyshuffleVar, 'off', 'universal', 'on')
 | 
			
		||||
    modeOptionMenu.pack(side=LEFT)
 | 
			
		||||
    modeLabel = Label(keyshuffleFrame, text='Key Shuffle')
 | 
			
		||||
    modeLabel.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    retroVar = IntVar()
 | 
			
		||||
    retroCheckbutton = Checkbutton(checkBoxFrame, text="Retro mode (universal keys)", variable=retroVar)
 | 
			
		||||
    retroCheckbutton = Checkbutton(checkBoxFrame, text="Retro mode", variable=retroVar)
 | 
			
		||||
 | 
			
		||||
    shuffleGanonVar = IntVar()
 | 
			
		||||
    shuffleGanonVar.set(1)  # set default
 | 
			
		||||
    shuffleGanonCheckbutton = Checkbutton(checkBoxFrame, text="Include Ganon's Tower and Pyramid Hole in shuffle pool",
 | 
			
		||||
| 
						 | 
				
			
			@ -99,8 +110,8 @@ def guiMain(args=None):
 | 
			
		|||
    mcsbLabel.grid(row=0, column=0)
 | 
			
		||||
    mapshuffleCheckbutton.grid(row=0, column=1)
 | 
			
		||||
    compassshuffleCheckbutton.grid(row=0, column=2)
 | 
			
		||||
    keyshuffleCheckbutton.grid(row=0, column=3)
 | 
			
		||||
    bigkeyshuffleCheckbutton.grid(row=0, column=4)
 | 
			
		||||
    keyshuffleFrame.pack(expand=True, anchor=W)
 | 
			
		||||
    retroCheckbutton.pack(expand=True, anchor=W)
 | 
			
		||||
    shuffleGanonCheckbutton.pack(expand=True, anchor=W)
 | 
			
		||||
    hintsCheckbutton.pack(expand=True, anchor=W)
 | 
			
		||||
| 
						 | 
				
			
			@ -476,7 +487,7 @@ def guiMain(args=None):
 | 
			
		|||
        guiargs.openpyramid = bool(openpyramidVar.get())
 | 
			
		||||
        guiargs.mapshuffle = bool(mapshuffleVar.get())
 | 
			
		||||
        guiargs.compassshuffle = bool(compassshuffleVar.get())
 | 
			
		||||
        guiargs.keyshuffle = bool(keyshuffleVar.get())
 | 
			
		||||
        guiargs.keyshuffle = {"on": True, "universal": "universal", "off": False}[keyshuffleVar.get()]
 | 
			
		||||
        guiargs.bigkeyshuffle = bool(bigkeyshuffleVar.get())
 | 
			
		||||
        guiargs.retro = bool(retroVar.get())
 | 
			
		||||
        guiargs.quickswap = bool(quickSwapVar.get())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								ItemPool.py
								
								
								
								
							
							
						
						
									
										40
									
								
								ItemPool.py
								
								
								
								
							| 
						 | 
				
			
			@ -43,7 +43,7 @@ Difficulty = namedtuple('Difficulty',
 | 
			
		|||
                        ['baseitems', 'bottles', 'bottle_count', 'same_bottle', 'progressiveshield',
 | 
			
		||||
                         'basicshield', 'progressivearmor', 'basicarmor', 'swordless', 'progressivemagic', 'basicmagic',
 | 
			
		||||
                         'progressivesword', 'basicsword', 'progressivebow', 'basicbow', 'timedohko', 'timedother',
 | 
			
		||||
                         'triforcehunt', 'retro',
 | 
			
		||||
                         'triforcehunt', 'universal_keys',
 | 
			
		||||
                         'extras', 'progressive_sword_limit', 'progressive_shield_limit',
 | 
			
		||||
                         'progressive_armor_limit', 'progressive_bottle_limit',
 | 
			
		||||
                         'progressive_bow_limit', 'heart_piece_limit', 'boss_heart_container_limit'])
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ difficulties = {
 | 
			
		|||
        timedohko=['Green Clock'] * 25,
 | 
			
		||||
        timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
 | 
			
		||||
        triforcehunt=['Triforce Piece'] * 30,
 | 
			
		||||
        retro=['Small Key (Universal)'] * 28,
 | 
			
		||||
        universal_keys=['Small Key (Universal)'] * 28,
 | 
			
		||||
        extras=[easyfirst15extra, easysecond15extra, easythird10extra, easyfourth5extra, easyfinal25extra],
 | 
			
		||||
        progressive_sword_limit=8,
 | 
			
		||||
        progressive_shield_limit=6,
 | 
			
		||||
| 
						 | 
				
			
			@ -99,15 +99,15 @@ difficulties = {
 | 
			
		|||
        timedohko=['Green Clock'] * 25,
 | 
			
		||||
        timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
 | 
			
		||||
        triforcehunt=['Triforce Piece'] * 30,
 | 
			
		||||
        retro=['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10,
 | 
			
		||||
        universal_keys=['Small Key (Universal)'] * 18 + ['Rupees (20)'] * 10,
 | 
			
		||||
        extras=[normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
 | 
			
		||||
        progressive_sword_limit=4,
 | 
			
		||||
        progressive_shield_limit=3,
 | 
			
		||||
        progressive_armor_limit=2,
 | 
			
		||||
        progressive_bow_limit=2,
 | 
			
		||||
        progressive_bottle_limit = 4,
 | 
			
		||||
        boss_heart_container_limit = 10,
 | 
			
		||||
        heart_piece_limit = 24,
 | 
			
		||||
        progressive_bottle_limit=4,
 | 
			
		||||
        boss_heart_container_limit=10,
 | 
			
		||||
        heart_piece_limit=24,
 | 
			
		||||
    ),
 | 
			
		||||
    'hard': Difficulty(
 | 
			
		||||
        baseitems = normalbaseitems,
 | 
			
		||||
| 
						 | 
				
			
			@ -128,7 +128,7 @@ difficulties = {
 | 
			
		|||
        timedohko=['Green Clock'] * 25,
 | 
			
		||||
        timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
 | 
			
		||||
        triforcehunt=['Triforce Piece'] * 30,
 | 
			
		||||
        retro=['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 16,
 | 
			
		||||
        universal_keys=['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 16,
 | 
			
		||||
        extras=[normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
 | 
			
		||||
        progressive_sword_limit=3,
 | 
			
		||||
        progressive_shield_limit=2,
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ difficulties = {
 | 
			
		|||
        timedohko=['Green Clock'] * 20 + ['Red Clock'] * 5,
 | 
			
		||||
        timedother=['Green Clock'] * 20 + ['Blue Clock'] * 10 + ['Red Clock'] * 10,
 | 
			
		||||
        triforcehunt=['Triforce Piece'] * 30,
 | 
			
		||||
        retro=['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 16,
 | 
			
		||||
        universal_keys=['Small Key (Universal)'] * 12 + ['Rupees (5)'] * 16,
 | 
			
		||||
        extras=[normalfirst15extra, normalsecond15extra, normalthird10extra, normalfourth5extra, normalfinal25extra],
 | 
			
		||||
        progressive_sword_limit=2,
 | 
			
		||||
        progressive_shield_limit=1,
 | 
			
		||||
| 
						 | 
				
			
			@ -425,21 +425,26 @@ def fill_prizes(world, attempts=15):
 | 
			
		|||
            raise FillError('Unable to place dungeon prizes')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_up_shops(world, player):
 | 
			
		||||
    # TODO: move hard+ mode changes for sheilds here, utilizing the new shops
 | 
			
		||||
def set_up_shops(world, player: int):
 | 
			
		||||
    # TODO: move hard+ mode changes for shields here, utilizing the new shops
 | 
			
		||||
 | 
			
		||||
    if world.retro[player]:
 | 
			
		||||
        rss = world.get_region('Red Shield Shop', player).shop
 | 
			
		||||
        if not rss.locked:
 | 
			
		||||
            rss.add_inventory(2, 'Single Arrow', 80)
 | 
			
		||||
        rss.locked = True
 | 
			
		||||
 | 
			
		||||
    if world.keyshuffle[player] == "universal":
 | 
			
		||||
        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):
 | 
			
		||||
            shop.locked = True
 | 
			
		||||
            shop.add_inventory(0, 'Single Arrow', 80)
 | 
			
		||||
            if world.retro[player]:
 | 
			
		||||
                shop.add_inventory(0, 'Single Arrow', 80)
 | 
			
		||||
            else:
 | 
			
		||||
                shop.add_inventory(0, "Red Potion", 150)
 | 
			
		||||
            shop.add_inventory(1, 'Small Key (Universal)', 100)
 | 
			
		||||
            shop.add_inventory(2, 'Bombs (10)', 50)
 | 
			
		||||
        rss.locked = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_pool_core(world, player: int):
 | 
			
		||||
| 
						 | 
				
			
			@ -592,7 +597,8 @@ def get_pool_core(world, player: int):
 | 
			
		|||
        pool = [item.replace('Arrows (10)', 'Rupees (5)') for item in pool]
 | 
			
		||||
        pool = [item.replace('Arrow Upgrade (+5)', 'Rupees (5)') for item in pool]
 | 
			
		||||
        pool = [item.replace('Arrow Upgrade (+10)', 'Rupees (5)') for item in pool]
 | 
			
		||||
        pool.extend(diff.retro)
 | 
			
		||||
    if world.keyshuffle[player] == "universal":
 | 
			
		||||
        pool.extend(diff.universal_keys)
 | 
			
		||||
        if mode == 'standard':
 | 
			
		||||
            key_location = world.random.choice(
 | 
			
		||||
                ['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest',
 | 
			
		||||
| 
						 | 
				
			
			@ -609,7 +615,6 @@ def make_custom_item_pool(world, player):
 | 
			
		|||
    timer = world.timer[player]
 | 
			
		||||
    goal = world.goal[player]
 | 
			
		||||
    mode = world.mode[player]
 | 
			
		||||
    retro = world.retro[player]
 | 
			
		||||
    customitemarray = world.customitemarray[player]
 | 
			
		||||
 | 
			
		||||
    pool = []
 | 
			
		||||
| 
						 | 
				
			
			@ -726,7 +731,7 @@ def make_custom_item_pool(world, player):
 | 
			
		|||
        itemtotal = itemtotal + 1
 | 
			
		||||
 | 
			
		||||
    if mode == 'standard':
 | 
			
		||||
        if retro:
 | 
			
		||||
        if world.keyshuffle == "universal":
 | 
			
		||||
            key_location = world.random.choice(
 | 
			
		||||
                ['Secret Passage', 'Hyrule Castle - Boomerang Chest', 'Hyrule Castle - Map Chest',
 | 
			
		||||
                 'Hyrule Castle - Zelda\'s Chest', 'Sewers - Dark Cross'])
 | 
			
		||||
| 
						 | 
				
			
			@ -749,9 +754,10 @@ def make_custom_item_pool(world, player):
 | 
			
		|||
        pool.extend(['Magic Mirror'] * customitemarray[22])
 | 
			
		||||
        pool.extend(['Moon Pearl'] * customitemarray[28])
 | 
			
		||||
 | 
			
		||||
    if retro:
 | 
			
		||||
        itemtotal = itemtotal - 28 # Corrects for small keys not being in item pool in Retro Mode
 | 
			
		||||
    if world.keyshuffle == "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))
 | 
			
		||||
        logging.warning(f"Pool was filled up with {total_items_to_place - itemtotal} Nothing's for player {player}")
 | 
			
		||||
 | 
			
		||||
    return (pool, placed_items, precollected_items, clock_mode, treasure_hunt_count, treasure_hunt_icon)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -278,7 +278,8 @@ def roll_settings(weights):
 | 
			
		|||
 | 
			
		||||
    ret.mapshuffle = get_choice('map_shuffle', weights, 'm' in dungeon_items)
 | 
			
		||||
    ret.compassshuffle = get_choice('compass_shuffle', weights, 'c' in dungeon_items)
 | 
			
		||||
    ret.keyshuffle = get_choice('smallkey_shuffle', weights, 's' in dungeon_items)
 | 
			
		||||
    ret.keyshuffle = get_choice('smallkey_shuffle', weights,
 | 
			
		||||
                                'universal' if 'u' in dungeon_items else 's' in dungeon_items)
 | 
			
		||||
    ret.bigkeyshuffle = get_choice('bigkey_shuffle', weights, 'b' in dungeon_items)
 | 
			
		||||
 | 
			
		||||
    ret.accessibility = get_choice('accessibility', weights)
 | 
			
		||||
| 
						 | 
				
			
			@ -309,10 +310,13 @@ def roll_settings(weights):
 | 
			
		|||
    ret.triforce_pieces_required = get_choice('triforce_pieces_required', weights, 20)
 | 
			
		||||
    ret.triforce_pieces_required = min(max(1, int(ret.triforce_pieces_required)), 90)
 | 
			
		||||
 | 
			
		||||
    ret.mode = get_choice('world_state', weights)
 | 
			
		||||
    ret.mode = get_choice('world_state', weights, None)  # legacy support
 | 
			
		||||
    if ret.mode == 'retro':
 | 
			
		||||
        ret.mode = 'open'
 | 
			
		||||
        ret.retro = True
 | 
			
		||||
    elif ret.mode is None:
 | 
			
		||||
        ret.mode = get_choice("mode", weights)
 | 
			
		||||
        ret.retro = get_choice("retro", weights)
 | 
			
		||||
 | 
			
		||||
    ret.hints = get_choice('hints', weights)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										2
									
								
								Rom.py
								
								
								
								
							| 
						 | 
				
			
			@ -1237,7 +1237,7 @@ def patch_rom(world, rom, player, team, enemized):
 | 
			
		|||
    write_int16(rom, 0x18017A, get_reveal_bytes('Green Pendant') if world.mapshuffle[player] else 0x0000) # Sahasrahla reveal
 | 
			
		||||
    write_int16(rom, 0x18017C, get_reveal_bytes('Crystal 5')|get_reveal_bytes('Crystal 6') if world.mapshuffle[player] else 0x0000) # Bomb Shop Reveal
 | 
			
		||||
 | 
			
		||||
    rom.write_byte(0x180172, 0x01 if world.retro[player] else 0x00)  # universal keys
 | 
			
		||||
    rom.write_byte(0x180172, int(world.keyshuffle == "universal"))  # universal keys
 | 
			
		||||
    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
 | 
			
		||||
    rom.write_byte(0x180178, 0x32 if world.retro[player] else 0x00)  # silver arrow cost
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								Rules.py
								
								
								
								
							
							
						
						
									
										10
									
								
								Rules.py
								
								
								
								
							| 
						 | 
				
			
			@ -206,8 +206,9 @@ def global_rules(world, player):
 | 
			
		|||
    set_rule(world.get_location('Hookshot Cave - Bottom Left', player), lambda state: state.has('Hookshot', player))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_entrance('Sewers Door', player),
 | 
			
		||||
             lambda state: state.has_key('Small Key (Hyrule Castle)', player) or (world.retro[player] and world.mode[
 | 
			
		||||
                 player] == 'standard'))  # standard retro cannot access the shop
 | 
			
		||||
             lambda state: state.has_key('Small Key (Hyrule Castle)', player) or (
 | 
			
		||||
                         world.keyshuffle[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))
 | 
			
		||||
    set_rule(world.get_entrance('Agahnim 1', player),
 | 
			
		||||
| 
						 | 
				
			
			@ -896,7 +897,7 @@ 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.keyshuffle[player] and not world.retro[player]:
 | 
			
		||||
        if not can_reach_front and not world.keyshuffle[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:
 | 
			
		||||
| 
						 | 
				
			
			@ -905,7 +906,8 @@ def set_trock_key_rules(world, player):
 | 
			
		|||
            if world.accessibility[player] == 'locations':
 | 
			
		||||
                if world.bigkeyshuffle[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']:
 | 
			
		||||
                    for location in ['Turtle Rock - Chain Chomps', 'Turtle Rock - Compass Chest',
 | 
			
		||||
                                     'Turtle Rock - Roller Room - Left', 'Turtle Rock - Roller Room - Right']:
 | 
			
		||||
                        forbid_item(world.get_location(location, player), 'Big Key (Turtle Rock)', player)
 | 
			
		||||
                else:
 | 
			
		||||
                    # A key is required in the Big Key Chest to prevent a possible softlock.  Place an extra key to ensure 100% locations still works
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ compass_shuffle: # Shuffle compasses into the world and other dungeons, includin
 | 
			
		|||
  off: 1
 | 
			
		||||
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: 1
 | 
			
		||||
bigkey_shuffle: # Shuffle big keys into the world and other dungeons, including other players' worlds
 | 
			
		||||
  on: 0
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +51,8 @@ dungeon_items: # Alternative to the 4 shuffles and local_keys above this, does n
 | 
			
		|||
  none: 1 # Shuffle none of the 4
 | 
			
		||||
  mcsb: 0 # Shuffle all of the 4, any combination of m, c, s and b will shuffle the respective item, or not if it's missing, so you can add more options here
 | 
			
		||||
  lmcsb: 0 # Like mcsb above, but with keys kept local to your world. l is what makes your keys local, or not if it's missing
 | 
			
		||||
  ub: 0 # universal small keys and shuffled big keys
 | 
			
		||||
  # you can add more combos of these letters here
 | 
			
		||||
dungeon_counters:
 | 
			
		||||
  on: 0 # Always display amount of items checked in a dungeon
 | 
			
		||||
  pickup: 1 # Show when compass is picked up
 | 
			
		||||
| 
						 | 
				
			
			@ -119,11 +122,13 @@ ganon_open: # Crystals required to hurt Ganon
 | 
			
		|||
  '6': 2
 | 
			
		||||
  '7': 1
 | 
			
		||||
  random: 0
 | 
			
		||||
world_state:
 | 
			
		||||
mode:
 | 
			
		||||
  standard: 1 # Begin the game by rescuing Zelda from her cell and escorting her to the Sanctuary
 | 
			
		||||
  open: 1 # Begin the game from your choice of Link's House or the Sanctuary
 | 
			
		||||
  inverted: 0 # Begin in the Dark World. The Moon Pearl is required to avoid bunny-state in Light World, and the Light World game map is altered
 | 
			
		||||
  retro: 0 # Small keys are universal, you must buy a quiver, take-any caves and an old-man cave are added to the world. You may need to find your sword from the old man's cave
 | 
			
		||||
retro:
 | 
			
		||||
  on: 0 # you must buy a quiver to use the bow, take-any caves and an old-man cave are added to the world. You may need to find your sword from the old man's cave
 | 
			
		||||
  off: 1
 | 
			
		||||
hints:
 | 
			
		||||
  'on': 1 # Hint tiles sometimes give item location hints
 | 
			
		||||
  'off': 0 # Hint tiles provide gameplay tips
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue