New Logic:
Enemy Shuffle awareness Easy Item Functionality awareness Dark Room Logic option Boss Item Shuffle option Silverless Ganon is a Minor Glitch Faster Dungeon Item Fill
This commit is contained in:
		
							parent
							
								
									a855fc4133
								
							
						
					
					
						commit
						b5d91af752
					
				| 
						 | 
				
			
			@ -5,7 +5,7 @@ from enum import Enum, unique
 | 
			
		|||
import logging
 | 
			
		||||
import json
 | 
			
		||||
from collections import OrderedDict, Counter, deque
 | 
			
		||||
from typing import Union, Optional, List, Set
 | 
			
		||||
from typing import Union, Optional, List, Set, Dict
 | 
			
		||||
import secrets
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ class World(object):
 | 
			
		|||
    _region_cache: dict
 | 
			
		||||
    difficulty_requirements: dict
 | 
			
		||||
    required_medallions: dict
 | 
			
		||||
    dark_room_logic: Dict[int, str]
 | 
			
		||||
    restrict_dungeon_item_on_boss: Dict[int, bool]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, players: int, shuffle, logic, mode, swords, difficulty, difficulty_adjustments, timer,
 | 
			
		||||
                 progressive,
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +128,8 @@ class World(object):
 | 
			
		|||
            set_player_attr('shop_shuffle', 'off')
 | 
			
		||||
            set_player_attr('shuffle_prizes', "g")
 | 
			
		||||
            set_player_attr('sprite_pool', [])
 | 
			
		||||
            set_player_attr('dark_room_logic', "lamp")
 | 
			
		||||
            set_player_attr('restrict_dungeon_item_on_boss', False)
 | 
			
		||||
 | 
			
		||||
    def secure(self):
 | 
			
		||||
        self.random = secrets.SystemRandom()
 | 
			
		||||
| 
						 | 
				
			
			@ -357,6 +361,9 @@ class World(object):
 | 
			
		|||
                    location.player == player and not location.item]
 | 
			
		||||
        return [location for location in self.get_locations() if not location.item]
 | 
			
		||||
 | 
			
		||||
    def get_unfilled_dungeon_locations(self):
 | 
			
		||||
        return [location for location in self.get_locations() if not location.item and location.parent_region.dungeon]
 | 
			
		||||
 | 
			
		||||
    def get_filled_locations(self, player=None) -> list:
 | 
			
		||||
        if player is not None:
 | 
			
		||||
            return [location for location in self.get_locations() if
 | 
			
		||||
| 
						 | 
				
			
			@ -601,7 +608,6 @@ class CollectionState(object):
 | 
			
		|||
 | 
			
		||||
    def can_shoot_arrows(self, player: int) -> bool:
 | 
			
		||||
        if self.world.retro[player]:
 | 
			
		||||
            # 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('Single Arrow', player)
 | 
			
		||||
        return self.has('Bow', player) or self.has('Silver Bow', player)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -615,6 +621,11 @@ class CollectionState(object):
 | 
			
		|||
                self.is_not_bunny(cave, player)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def can_retrieve_tablet(self, player:int) -> bool:
 | 
			
		||||
        return self.has('Book of Mudora', player) and (self.has_beam_sword(player) or
 | 
			
		||||
               ((self.world.swords[player] == "swordless" or self.world.difficulty_adjustments[player] == "easy") and
 | 
			
		||||
                self.has("Hammer", player)))
 | 
			
		||||
 | 
			
		||||
    def has_sword(self, player: int) -> bool:
 | 
			
		||||
        return self.has('Fighter Sword', player) \
 | 
			
		||||
               or self.has('Master Sword', player) \
 | 
			
		||||
| 
						 | 
				
			
			@ -644,7 +655,10 @@ class CollectionState(object):
 | 
			
		|||
        return self.has('Flute', player) and lw.can_reach(self) and self.is_not_bunny(lw, player)
 | 
			
		||||
 | 
			
		||||
    def can_melt_things(self, player: int) -> bool:
 | 
			
		||||
        return self.has('Fire Rod', player) or (self.has('Bombos', player) and (self.has_sword(player) or self.world.swords[player] == "swordless"))
 | 
			
		||||
        return self.has('Fire Rod', player) or \
 | 
			
		||||
               (self.has('Bombos', player) and
 | 
			
		||||
                (self.world.difficulty_adjustments[player] == "easy" or self.world.swords[player] == "swordless" or
 | 
			
		||||
                 self.has_sword(player)))
 | 
			
		||||
 | 
			
		||||
    def can_avoid_lasers(self, player: int) -> bool:
 | 
			
		||||
        return self.has('Mirror Shield', player) or self.has('Cane of Byrna', player) or self.has('Cape', player)
 | 
			
		||||
| 
						 | 
				
			
			@ -1260,6 +1274,7 @@ class Spoiler(object):
 | 
			
		|||
        from Utils import __version__ as ERVersion
 | 
			
		||||
        self.metadata = {'version': ERVersion,
 | 
			
		||||
                         'logic': self.world.logic,
 | 
			
		||||
                         'dark_room_logic': self.world.dark_room_logic,
 | 
			
		||||
                         'mode': self.world.mode,
 | 
			
		||||
                         'retro': self.world.retro,
 | 
			
		||||
                         'weapons': self.world.swords,
 | 
			
		||||
| 
						 | 
				
			
			@ -1293,7 +1308,8 @@ class Spoiler(object):
 | 
			
		|||
                         'triforce_pieces_required': self.world.triforce_pieces_required,
 | 
			
		||||
                         'shop_shuffle': self.world.shop_shuffle,
 | 
			
		||||
                         'shuffle_prizes': self.world.shuffle_prizes,
 | 
			
		||||
                         'sprite_pool': self.world.sprite_pool
 | 
			
		||||
                         'sprite_pool': self.world.sprite_poolm,
 | 
			
		||||
                         'restrict_dungeon_item_on_boss': self.world.restrict_dungeon_item_on_boss
 | 
			
		||||
                         }
 | 
			
		||||
 | 
			
		||||
    def to_json(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,6 +1353,9 @@ class Spoiler(object):
 | 
			
		|||
                        f"Hash - {self.world.player_names[player][team]} (Team {team + 1}): " if self.world.teams > 1 else 'Hash: ',
 | 
			
		||||
                        self.hashes[player, team]))
 | 
			
		||||
                outfile.write('Logic:                           %s\n' % self.metadata['logic'][player])
 | 
			
		||||
                outfile.write('Dark Room Logic:                 %s\n' % self.metadata['dark_room_logic'][player])
 | 
			
		||||
                outfile.write('Restricted Boss Drops:           %s\n' %
 | 
			
		||||
                              bool_to_text(self.metadata['restrict_dungeon_item_on_boss'][player]))
 | 
			
		||||
                if self.world.players > 1:
 | 
			
		||||
                    outfile.write('Progression Balanced:            %s\n' % (
 | 
			
		||||
                        'Yes' if self.metadata['progression_balancing'][player] else 'No'))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								Bosses.py
								
								
								
								
							
							
						
						
									
										21
									
								
								Bosses.py
								
								
								
								
							| 
						 | 
				
			
			@ -116,6 +116,27 @@ def AgahnimDefeatRule(state, player: int):
 | 
			
		|||
    return state.has_sword(player) or state.has('Hammer', player) or state.has('Bug Catching Net', player)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def GanonDefeatRule(state, player: int):
 | 
			
		||||
    if state.world.swords[player] == "swordless":
 | 
			
		||||
        return state.has('Hammer', player) and \
 | 
			
		||||
               state.has_fire_source(player) and \
 | 
			
		||||
               state.has('Silver Bow', player) and \
 | 
			
		||||
               state.can_shoot_arrows(player)
 | 
			
		||||
    easy_hammer = state.world.difficulty_adjustments[player] == "easy" and state.has("Hammer", player) and \
 | 
			
		||||
        state.has('Silver Bow', player) and state.can_shoot_arrows(player)
 | 
			
		||||
    can_hurt = state.has_beam_sword(player) or easy_hammer
 | 
			
		||||
    common = can_hurt and state.has_fire_source(player)
 | 
			
		||||
    # silverless ganon may be needed in minor glitches
 | 
			
		||||
    if state.world.logic[player] in {"owglitches", "minorglitches", "none"}:
 | 
			
		||||
        # need to light torch a sufficient amount of times
 | 
			
		||||
        return common and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (
 | 
			
		||||
                state.has('Silver Bow', player) and state.can_shoot_arrows(player)) or
 | 
			
		||||
               state.has('Lamp', player) or state.can_extend_magic(player, 12))
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        return common and state.has('Silver Bow', player) and state.can_shoot_arrows(player)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
boss_table = {
 | 
			
		||||
    'Armos Knights': ('Armos', ArmosKnightsDefeatRule),
 | 
			
		||||
    'Lanmolas': ('Lanmola', LanmolasDefeatRule),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								Dungeons.py
								
								
								
								
							
							
						
						
									
										22
									
								
								Dungeons.py
								
								
								
								
							| 
						 | 
				
			
			@ -2,6 +2,7 @@ from BaseClasses import Dungeon
 | 
			
		|||
from Bosses import BossFactory
 | 
			
		||||
from Fill import fill_restrictive
 | 
			
		||||
from Items import ItemFactory
 | 
			
		||||
from Regions import lookup_boss_drops
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def create_dungeons(world, player):
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +117,14 @@ def fill_dungeons(world):
 | 
			
		|||
def get_dungeon_item_pool(world):
 | 
			
		||||
    return [item for dungeon in world.dungeons for item in dungeon.all_items]
 | 
			
		||||
 | 
			
		||||
def fill_dungeons_restrictive(world, shuffled_locations):
 | 
			
		||||
def fill_dungeons_restrictive(world):
 | 
			
		||||
    """Places dungeon-native items into their dungeons, places nothing if everything is shuffled outside."""
 | 
			
		||||
    restricted_players = {player for player, restricted in world.restrict_dungeon_item_on_boss.items() if restricted}
 | 
			
		||||
 | 
			
		||||
    locations = [location for location in world.get_unfilled_dungeon_locations()
 | 
			
		||||
                 if not (location.player in restricted_players and location.name in lookup_boss_drops)] # filter boss
 | 
			
		||||
 | 
			
		||||
    world.random.shuffle(locations)
 | 
			
		||||
    all_state_base = world.get_all_state()
 | 
			
		||||
 | 
			
		||||
    # with shuffled dungeon items they are distributed as part of the normal item pool
 | 
			
		||||
| 
						 | 
				
			
			@ -131,13 +139,11 @@ def fill_dungeons_restrictive(world, shuffled_locations):
 | 
			
		|||
                                                                       or (item.bigkey and not world.bigkeyshuffle[item.player])
 | 
			
		||||
                                                                       or (item.map and not world.mapshuffle[item.player])
 | 
			
		||||
                                                                       or (item.compass and not world.compassshuffle[item.player]))]
 | 
			
		||||
 | 
			
		||||
    # sort in the order Big Key, Small Key, Other before placing dungeon items
 | 
			
		||||
    sort_order = {"BigKey": 3, "SmallKey": 2}
 | 
			
		||||
    dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))
 | 
			
		||||
 | 
			
		||||
    fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items, True)
 | 
			
		||||
 | 
			
		||||
    if dungeon_items:
 | 
			
		||||
        # sort in the order Big Key, Small Key, Other before placing dungeon items
 | 
			
		||||
        sort_order = {"BigKey": 3, "SmallKey": 2}
 | 
			
		||||
        dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))
 | 
			
		||||
        fill_restrictive(world, all_state_base, locations, dungeon_items, True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dungeon_music_addresses = {'Eastern Palace - Prize': [0x1559A],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -317,6 +317,11 @@ def parse_arguments(argv, no_defaults=False):
 | 
			
		|||
    parser.add_argument('--shuffle_prizes', default=defval('g'), choices=['', 'g', 'b', 'gb'])
 | 
			
		||||
    parser.add_argument('--sprite_pool', help='''\
 | 
			
		||||
    Specifies a colon separated list of sprites used for random/randomonevent. If not specified, the full sprite pool is used.''')
 | 
			
		||||
    parser.add_argument('--dark_room_logic', default=('Lamp'), choices=["lamp", "torches", "none"], help='''\
 | 
			
		||||
    For unlit dark rooms, require the Lamp to be considered in logic by default. 
 | 
			
		||||
    Torches means additionally easily accessible Torches that can be lit with Fire Rod are considered doable.
 | 
			
		||||
    None means full traversal through dark rooms without tools is considered doable.''')
 | 
			
		||||
    parser.add_argument('--restrict_dungeon_item_on_boss', 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('--names', default=defval(''))
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +367,7 @@ def parse_arguments(argv, no_defaults=False):
 | 
			
		|||
                         'heartbeep', "skip_progression_balancing", "triforce_pieces_available",
 | 
			
		||||
                         "triforce_pieces_required", "shop_shuffle",
 | 
			
		||||
                         'remote_items', 'progressive', 'dungeon_counters', 'glitch_boots', 'killable_thieves',
 | 
			
		||||
                         'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool']:
 | 
			
		||||
                         'tile_shuffle', 'bush_shuffle', 'shuffle_prizes', 'sprite_pool', 'dark_room_logic', 'restrict_dungeon_item_on_boss']:
 | 
			
		||||
                value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
 | 
			
		||||
                if player == 1:
 | 
			
		||||
                    setattr(ret, name, {1: value})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								Gui.py
								
								
								
								
							
							
						
						
									
										13
									
								
								Gui.py
								
								
								
								
							| 
						 | 
				
			
			@ -256,6 +256,15 @@ def guiMain(args=None):
 | 
			
		|||
    logicLabel = Label(logicFrame, text='Game logic')
 | 
			
		||||
    logicLabel.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    darklogicFrame = Frame(drowDownFrame)
 | 
			
		||||
    darklogicVar = StringVar()
 | 
			
		||||
    darklogicVar.set('Lamp')
 | 
			
		||||
    darklogicOptionMenu = OptionMenu(darklogicFrame, darklogicVar, 'Lamp', 'Lamp or easy Fire Rod torches',
 | 
			
		||||
                                     'dark traversal')
 | 
			
		||||
    darklogicOptionMenu.pack(side=RIGHT)
 | 
			
		||||
    darklogicLabel = Label(darklogicFrame, text='Dark Room Logic')
 | 
			
		||||
    darklogicLabel.pack(side=LEFT)
 | 
			
		||||
 | 
			
		||||
    goalFrame = Frame(drowDownFrame)
 | 
			
		||||
    goalVar = StringVar()
 | 
			
		||||
    goalVar.set('ganon')
 | 
			
		||||
| 
						 | 
				
			
			@ -366,6 +375,7 @@ def guiMain(args=None):
 | 
			
		|||
 | 
			
		||||
    modeFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    logicFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    darklogicFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    goalFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    crystalsGTFrame.pack(expand=True, anchor=E)
 | 
			
		||||
    crystalsGanonFrame.pack(expand=True, anchor=E)
 | 
			
		||||
| 
						 | 
				
			
			@ -488,6 +498,9 @@ def guiMain(args=None):
 | 
			
		|||
        guiargs.count = int(countVar.get()) if countVar.get() != '1' else None
 | 
			
		||||
        guiargs.mode = modeVar.get()
 | 
			
		||||
        guiargs.logic = logicVar.get()
 | 
			
		||||
        guiargs.dark_room_logic = {"Lamp": "lamp",
 | 
			
		||||
                                   "Lamp or easy Fire Rod torches": "torches",
 | 
			
		||||
                                   "dark traversal": "none"}[darklogicVar.get()]
 | 
			
		||||
        guiargs.goal = goalVar.get()
 | 
			
		||||
        guiargs.crystals_gt = crystalsGTVar.get()
 | 
			
		||||
        guiargs.crystals_ganon = crystalsGanonVar.get()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -608,13 +608,13 @@ def get_pool_core(world, player: int):
 | 
			
		|||
 | 
			
		||||
    if want_progressives():
 | 
			
		||||
        pool.extend(diff.progressivebow)
 | 
			
		||||
    elif swords != 'swordless':
 | 
			
		||||
        pool.extend(diff.basicbow)
 | 
			
		||||
    else:
 | 
			
		||||
    elif swords == 'swordless' or logic == 'noglitches':
 | 
			
		||||
        swordless_bows = ['Bow', 'Silver Bow']
 | 
			
		||||
        if difficulty == "easy":
 | 
			
		||||
            swordless_bows *= 2
 | 
			
		||||
        pool.extend(swordless_bows)
 | 
			
		||||
    else:
 | 
			
		||||
        pool.extend(diff.basicbow)
 | 
			
		||||
 | 
			
		||||
    if swords == 'swordless':
 | 
			
		||||
        pool.extend(diff.swordless)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								Main.py
								
								
								
								
							
							
						
						
									
										12
									
								
								Main.py
								
								
								
								
							| 
						 | 
				
			
			@ -82,6 +82,8 @@ def main(args, seed=None):
 | 
			
		|||
    world.progression_balancing = {player: not balance for player, balance in args.skip_progression_balancing.items()}
 | 
			
		||||
    world.shuffle_prizes = args.shuffle_prizes.copy()
 | 
			
		||||
    world.sprite_pool = args.sprite_pool.copy()
 | 
			
		||||
    world.dark_room_logic = args.dark_room_logic.copy()
 | 
			
		||||
    world.restrict_dungeon_item_on_boss = args.restrict_dungeon_item_on_boss.copy()
 | 
			
		||||
 | 
			
		||||
    world.rom_seeds = {player: random.Random(world.random.randint(0, 999999999)) for player in range(1, world.players + 1)}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,9 +102,6 @@ def main(args, seed=None):
 | 
			
		|||
    for player in range(1, world.players + 1):
 | 
			
		||||
        world.difficulty_requirements[player] = difficulties[world.difficulty[player]]
 | 
			
		||||
 | 
			
		||||
        if world.mode[player] == 'standard' and world.enemy_shuffle[player] != 'none':
 | 
			
		||||
            world.escape_assist[player].append('bombs') # enemized escape assumes infinite bombs available and will likely be unbeatable without it
 | 
			
		||||
 | 
			
		||||
        for tok in filter(None, args.startinventory[player].split(',')):
 | 
			
		||||
            item = ItemFactory(tok.strip(), player)
 | 
			
		||||
            if item:
 | 
			
		||||
| 
						 | 
				
			
			@ -151,9 +150,7 @@ def main(args, seed=None):
 | 
			
		|||
    shuffled_locations = None
 | 
			
		||||
    if args.algorithm in ['balanced', 'vt26'] or any(list(args.mapshuffle.values()) + list(args.compassshuffle.values()) +
 | 
			
		||||
                                                     list(args.keyshuffle.values()) + list(args.bigkeyshuffle.values())):
 | 
			
		||||
        shuffled_locations = world.get_unfilled_locations()
 | 
			
		||||
        world.random.shuffle(shuffled_locations)
 | 
			
		||||
        fill_dungeons_restrictive(world, shuffled_locations)
 | 
			
		||||
        fill_dungeons_restrictive(world)
 | 
			
		||||
    else:
 | 
			
		||||
        fill_dungeons(world)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -373,6 +370,9 @@ def copy_world(world):
 | 
			
		|||
    ret.beemizer = world.beemizer.copy()
 | 
			
		||||
    ret.timer = world.timer.copy()
 | 
			
		||||
    ret.shufflepots = world.shufflepots.copy()
 | 
			
		||||
    ret.shuffle_prizes = world.shuffle_prizes.copy()
 | 
			
		||||
    ret.dark_room_logic = world.dark_room_logic.copy()
 | 
			
		||||
    ret.restrict_dungeon_item_on_boss = world.restrict_dungeon_item_on_boss.copy()
 | 
			
		||||
 | 
			
		||||
    for player in range(1, world.players + 1):
 | 
			
		||||
        if world.mode[player] != 'inverted':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								Mystery.py
								
								
								
								
							
							
						
						
									
										11
									
								
								Mystery.py
								
								
								
								
							| 
						 | 
				
			
			@ -275,6 +275,17 @@ def roll_settings(weights):
 | 
			
		|||
    ret.logic = {None: 'noglitches', 'none': 'noglitches', 'no_logic': 'nologic', 'overworld_glitches': 'owglitches',
 | 
			
		||||
                 'minor_glitches': 'minorglitches'}[
 | 
			
		||||
        glitches_required]
 | 
			
		||||
 | 
			
		||||
    ret.dark_room_logic = get_choice("dark_room_logic", weights, "lamp")
 | 
			
		||||
    if not ret.dark_room_logic: # None/False
 | 
			
		||||
        ret.dark_room_logic = "none"
 | 
			
		||||
    if ret.dark_room_logic == "sconces":
 | 
			
		||||
        ret.dark_room_logic = "torches"
 | 
			
		||||
    if ret.dark_room_logic not in {"lamp", "torches", "none"}:
 | 
			
		||||
        raise ValueError(f"Unknown Dark Room Logic: \"{ret.dark_room_logic}\"")
 | 
			
		||||
 | 
			
		||||
    ret.restrict_dungeon_item_on_boss = get_choice('restrict_dungeon_item_on_boss', weights, False)
 | 
			
		||||
 | 
			
		||||
    ret.progression_balancing = get_choice('progression_balancing', weights, True)
 | 
			
		||||
    # item_placement = get_choice('item_placement')
 | 
			
		||||
    # not supported in ER
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -746,3 +746,6 @@ lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 19125
 | 
			
		|||
                                       60127: 'Ganons Tower', 60118: 'Ganons Tower', 60148: 'Ganons Tower',
 | 
			
		||||
                                       60151: 'Ganons Tower', 60145: 'Ganons Tower', 60157: 'Ganons Tower',
 | 
			
		||||
                                       60160: 'Ganons Tower', 60163: 'Ganons Tower', 60166: 'Ganons Tower'}
 | 
			
		||||
 | 
			
		||||
lookup_prizes = {location for location in location_table if location.endswith(" - Prize")}
 | 
			
		||||
lookup_boss_drops = {location for location in location_table if location.endswith(" - Boss")}
 | 
			
		||||
							
								
								
									
										4
									
								
								Rom.py
								
								
								
								
							
							
						
						
									
										4
									
								
								Rom.py
								
								
								
								
							| 
						 | 
				
			
			@ -802,7 +802,7 @@ def patch_rom(world, rom, player, team, enemized):
 | 
			
		|||
    #Work around for json patch ordering issues - write bow limit separately so that it is replaced in the patch
 | 
			
		||||
    rom.write_bytes(0x180098, [difficulty.progressive_bow_limit, overflow_replacement])
 | 
			
		||||
 | 
			
		||||
    if difficulty.progressive_bow_limit < 2 and world.swords[player] == 'swordless':
 | 
			
		||||
    if difficulty.progressive_bow_limit < 2 and (world.swords[player] == 'swordless' or world.logic[player] == 'noglitches'):
 | 
			
		||||
        rom.write_bytes(0x180098, [2, overflow_replacement])
 | 
			
		||||
        rom.write_byte(0x180181, 0x01) # Make silver arrows work only on ganon
 | 
			
		||||
        rom.write_byte(0x180182, 0x00) # Don't auto equip silvers on pickup
 | 
			
		||||
| 
						 | 
				
			
			@ -1880,7 +1880,7 @@ def write_strings(rom, world, player, team):
 | 
			
		|||
 | 
			
		||||
    prog_bow_locs = world.find_items('Progressive Bow', player)
 | 
			
		||||
    distinguished_prog_bow_loc = next((location for location in prog_bow_locs if location.item.code == 0x65), None)
 | 
			
		||||
    progressive_silvers = world.difficulty_requirements[player].progressive_bow_limit >= 2 or world.swords[player] == 'swordless'
 | 
			
		||||
    progressive_silvers = world.difficulty_requirements[player].progressive_bow_limit >= 2 or (world.swords[player] == 'swordless' or world.logic[player] == 'noglitches')
 | 
			
		||||
    if distinguished_prog_bow_loc:
 | 
			
		||||
        prog_bow_locs.remove(distinguished_prog_bow_loc)
 | 
			
		||||
        silverarrow_hint = (' %s?' % hint_text(distinguished_prog_bow_loc).replace('Ganon\'s', 'my')) if progressive_silvers else '?\nI think not!'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										136
									
								
								Rules.py
								
								
								
								
							
							
						
						
									
										136
									
								
								Rules.py
								
								
								
								
							| 
						 | 
				
			
			@ -4,6 +4,7 @@ import OverworldGlitchRules
 | 
			
		|||
from BaseClasses import RegionType, World, Entrance
 | 
			
		||||
from Items import ItemFactory, progression_items, item_name_groups
 | 
			
		||||
from OverworldGlitchRules import overworld_glitches_rules, no_logic_rules
 | 
			
		||||
from Bosses import GanonDefeatRule
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_rules(world, player):
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,8 @@ def set_rules(world, player):
 | 
			
		|||
                exit.hide_path = True
 | 
			
		||||
            return
 | 
			
		||||
        else:
 | 
			
		||||
            # Set access rules according to max glitches for multiworld progression.  Set accessibility to none, and shuffle assuming the no logic players can always win
 | 
			
		||||
            # Set access rules according to max glitches for multiworld progression.
 | 
			
		||||
            # Set accessibility to none, and shuffle assuming the no logic players can always win
 | 
			
		||||
            world.accessibility[player] = 'none'
 | 
			
		||||
            world.progression_balancing[player] = False
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,8 +124,18 @@ def add_rule(spot, rule, combine='and'):
 | 
			
		|||
        spot.access_rule = lambda state: rule(state) and old_rule(state)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_lamp_requirement(spot, player):
 | 
			
		||||
    add_rule(spot, lambda state: state.has('Lamp', player))
 | 
			
		||||
def add_lamp_requirement(world: World, spot, player: int, has_accessible_torch: bool = False):
 | 
			
		||||
    if world.dark_room_logic[player] == "lamp":
 | 
			
		||||
        add_rule(spot, lambda state: state.has('Lamp', player))
 | 
			
		||||
    elif world.dark_room_logic[player] == "torch":  # implicitly lamp as well
 | 
			
		||||
        if has_accessible_torch:
 | 
			
		||||
            add_rule(spot, lambda state: state.has('Lamp', player) or state.has('Fire Rod', player))
 | 
			
		||||
        else:
 | 
			
		||||
            add_rule(spot, lambda state: state.has('Lamp', player))
 | 
			
		||||
    elif world.dark_room_logic[player] == "none":
 | 
			
		||||
        pass
 | 
			
		||||
    else:
 | 
			
		||||
        raise ValueError(f"Unknown Dark Room Logic: {world.dark_room_logic[player]}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def forbid_item(location, item, player: int):
 | 
			
		||||
| 
						 | 
				
			
			@ -131,10 +143,15 @@ def forbid_item(location, item, player: int):
 | 
			
		|||
    location.item_rule = lambda i: (i.name != item or i.player != player) and old_rule(i)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def forbid_items(location, items: set, player: int):
 | 
			
		||||
def forbid_items_for_player(location, items: set, player: int):
 | 
			
		||||
    old_rule = location.item_rule
 | 
			
		||||
    location.item_rule = lambda i: (i.player != player or i.name not in items) and old_rule(i)
 | 
			
		||||
 | 
			
		||||
def forbid_items(location, items: set):
 | 
			
		||||
    """unused, but kept as a debugging tool."""
 | 
			
		||||
    old_rule = location.item_rule
 | 
			
		||||
    location.item_rule = lambda i: i.name not in items and old_rule(i)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_item_rule(location, rule):
 | 
			
		||||
    old_rule = location.item_rule
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +178,7 @@ def locality_rules(world, player):
 | 
			
		|||
    if world.local_items[player]:
 | 
			
		||||
        for location in world.get_locations():
 | 
			
		||||
            if location.player != player:
 | 
			
		||||
                forbid_items(location, world.local_items[player], player)
 | 
			
		||||
                forbid_items_for_player(location, world.local_items[player], player)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
non_crossover_items = (item_name_groups["Small Keys"] | item_name_groups["Big Keys"] | progression_items) - {
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +199,7 @@ def global_rules(world, player):
 | 
			
		|||
    set_rule(world.get_location('Dark Blacksmith Ruins', player), lambda state: state.has('Return Smith', player))
 | 
			
		||||
    set_rule(world.get_location('Purple Chest', player),
 | 
			
		||||
             lambda state: state.has('Pick Up Purple Chest', player))  # Can S&Q with chest
 | 
			
		||||
    set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
 | 
			
		||||
    set_rule(world.get_location('Ether Tablet', player), lambda state: state.can_retrieve_tablet(player))
 | 
			
		||||
    set_rule(world.get_location('Master Sword Pedestal', player), lambda state: state.has('Red Pendant', player) and state.has('Blue Pendant', player) and state.has('Green Pendant', player))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_location('Missing Smith', player), lambda state: state.has('Get Frog', player) and state.can_reach('Blacksmiths Hut', 'Region', player)) # Can't S&Q with smith
 | 
			
		||||
| 
						 | 
				
			
			@ -225,13 +242,16 @@ def global_rules(world, player):
 | 
			
		|||
    set_rule(world.get_location('Eastern Palace - Big Chest', player),
 | 
			
		||||
             lambda state: state.has('Big Key (Eastern Palace)', player))
 | 
			
		||||
    set_rule(world.get_location('Eastern Palace - Boss', player),
 | 
			
		||||
             lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)',
 | 
			
		||||
                                                                        player) and state.world.get_location(
 | 
			
		||||
             lambda state: state.has('Big Key (Eastern Palace)', player) and state.world.get_location(
 | 
			
		||||
                 'Eastern Palace - Boss', player).parent_region.dungeon.boss.can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Eastern Palace - Prize', player),
 | 
			
		||||
             lambda state: state.can_shoot_arrows(player) and state.has('Big Key (Eastern Palace)',
 | 
			
		||||
                                                                        player) and state.world.get_location(
 | 
			
		||||
             lambda state: state.has('Big Key (Eastern Palace)', player) and state.world.get_location(
 | 
			
		||||
                 'Eastern Palace - Prize', player).parent_region.dungeon.boss.can_defeat(state))
 | 
			
		||||
    if not world.enemy_shuffle[player]:
 | 
			
		||||
        add_rule(world.get_location('Eastern Palace - Boss', player),
 | 
			
		||||
                 lambda state: state.can_shoot_arrows(player))
 | 
			
		||||
        add_rule(world.get_location('Eastern Palace - Prize', player),
 | 
			
		||||
                 lambda state: state.can_shoot_arrows(player))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_location('Desert Palace - Big Chest', player), lambda state: state.has('Big Key (Desert Palace)', player))
 | 
			
		||||
    set_rule(world.get_location('Desert Palace - Torch', player), lambda state: state.has_Boots(player))
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +348,8 @@ def global_rules(world, player):
 | 
			
		|||
    set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Boss', player))
 | 
			
		||||
    set_defeat_dungeon_boss_rule(world.get_location('Turtle Rock - Prize', player))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_entrance('Palace of Darkness Bonk Wall', player), lambda state: state.can_shoot_arrows(player))
 | 
			
		||||
    if not world.enemy_shuffle[player]:
 | 
			
		||||
        set_rule(world.get_entrance('Palace of Darkness Bonk Wall', player), lambda state: state.can_shoot_arrows(player))
 | 
			
		||||
    set_rule(world.get_entrance('Palace of Darkness Hammer Peg Drop', player), lambda state: state.has('Hammer', player))
 | 
			
		||||
    set_rule(world.get_entrance('Palace of Darkness Bridge Room', player), lambda state: state.has_key('Small Key (Palace of Darkness)', player, 1))  # If we can reach any other small key door, we already have back door access to this area
 | 
			
		||||
    set_rule(world.get_entrance('Palace of Darkness Big Key Door', player), lambda state: state.has_key('Small Key (Palace of Darkness)', player, 6) and state.has('Big Key (Palace of Darkness)', player) and state.can_shoot_arrows(player) and state.has('Hammer', player))
 | 
			
		||||
| 
						 | 
				
			
			@ -377,23 +398,33 @@ def global_rules(world, player):
 | 
			
		|||
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Chest', player), lambda state: state.has('Big Key (Ganons Tower)', player))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Room - Left', player), lambda state: state.world.get_location('Ganons Tower - Big Key Room - Left', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Chest', player), lambda state: state.world.get_location('Ganons Tower - Big Key Chest', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Room - Right', player), lambda state: state.world.get_location('Ganons Tower - Big Key Room - Right', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Big Key Door', player), lambda state: state.has('Big Key (Ganons Tower)', player) and state.can_shoot_arrows(player))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Torch Rooms', player), lambda state: state.has_fire_source(player) and state.world.get_entrance('Ganons Tower Torch Rooms', player).parent_region.dungeon.bosses['middle'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Pre-Moldorm Chest', player), lambda state: state.has_key('Small Key (Ganons Tower)', player, 3))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Moldorm Door', player), lambda state: state.has_key('Small Key (Ganons Tower)', player, 4))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Moldorm Gap', player), lambda state: state.has('Hookshot', player) and state.world.get_entrance('Ganons Tower Moldorm Gap', player).parent_region.dungeon.bosses['top'].can_defeat(state))
 | 
			
		||||
    set_defeat_dungeon_boss_rule(world.get_location('Agahnim 2', player))
 | 
			
		||||
 | 
			
		||||
    if world.goal[player] in ['ganontriforcehunt', 'localganontriforcehunt']:
 | 
			
		||||
        set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_triforce_pieces(world.treasure_hunt_count[player], player)
 | 
			
		||||
            and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Bow', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12)))  # need to light torch a sufficient amount of times
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Room - Left', player),
 | 
			
		||||
             lambda state: state.world.get_location('Ganons Tower - Big Key Room - Left', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Chest', player),
 | 
			
		||||
             lambda state: state.world.get_location('Ganons Tower - Big Key Chest', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Big Key Room - Right', player),
 | 
			
		||||
             lambda state: state.world.get_location('Ganons Tower - Big Key Room - Right', player).parent_region.dungeon.bosses['bottom'].can_defeat(state))
 | 
			
		||||
    if world.enemy_shuffle[player]:
 | 
			
		||||
        set_rule(world.get_entrance('Ganons Tower Big Key Door', player),
 | 
			
		||||
                 lambda state: state.has('Big Key (Ganons Tower)', player))
 | 
			
		||||
    else:
 | 
			
		||||
        set_rule(world.get_location('Ganon', player), lambda state: state.has_beam_sword(player) and state.has_fire_source(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player)
 | 
			
		||||
            and (state.has('Tempered Sword', player) or state.has('Golden Sword', player) or (state.has('Silver Bow', player) and state.can_shoot_arrows(player)) or state.has('Lamp', player) or state.can_extend_magic(player, 12)))  # need to light torch a sufficient amount of times
 | 
			
		||||
        set_rule(world.get_entrance('Ganons Tower Big Key Door', player),
 | 
			
		||||
                 lambda state: state.has('Big Key (Ganons Tower)', player) and state.can_shoot_arrows(player))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Torch Rooms', player),
 | 
			
		||||
             lambda state: state.has_fire_source(player) and state.world.get_entrance('Ganons Tower Torch Rooms', player).parent_region.dungeon.bosses['middle'].can_defeat(state))
 | 
			
		||||
    set_rule(world.get_location('Ganons Tower - Pre-Moldorm Chest', player),
 | 
			
		||||
             lambda state: state.has_key('Small Key (Ganons Tower)', player, 3))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Moldorm Door', player),
 | 
			
		||||
             lambda state: state.has_key('Small Key (Ganons Tower)', player, 4))
 | 
			
		||||
    set_rule(world.get_entrance('Ganons Tower Moldorm Gap', player),
 | 
			
		||||
             lambda state: state.has('Hookshot', player) and state.world.get_entrance('Ganons Tower Moldorm Gap', player).parent_region.dungeon.bosses['top'].can_defeat(state))
 | 
			
		||||
    set_defeat_dungeon_boss_rule(world.get_location('Agahnim 2', player))
 | 
			
		||||
    ganon = world.get_location('Ganon', player)
 | 
			
		||||
    set_rule(ganon, lambda state: GanonDefeatRule(state, player))
 | 
			
		||||
    if world.goal[player] in ['ganontriforcehunt', 'localganontriforcehunt']:
 | 
			
		||||
        add_rule(ganon, lambda state: state.has_triforce_pieces(world.treasure_hunt_count[player], player))
 | 
			
		||||
    else:
 | 
			
		||||
        add_rule(ganon, lambda state: state.has_crystals(world.crystals_needed_for_ganon[player], player))
 | 
			
		||||
    set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has_beam_sword(player))  # need to damage ganon to get tiles to drop
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -452,7 +483,7 @@ def default_rules(world, player):
 | 
			
		|||
    set_rule(world.get_entrance('Hyrule Castle Ledge Mirror Spot', player), lambda state: state.has_Mirror(player))
 | 
			
		||||
    set_rule(world.get_entrance('Hyrule Castle Main Gate', player), lambda state: state.has_Mirror(player))
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: (state.has_Pearl(player) and state.has('Flippers', player) or state.has_Mirror(player)))  # Overworld Bunny Revival
 | 
			
		||||
    set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
 | 
			
		||||
    set_rule(world.get_location('Bombos Tablet', player), lambda state: state.can_retrieve_tablet(player))
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Drop (South)', player), lambda state: state.has_Pearl(player) and state.has('Flippers', player))  # ToDo any fake flipper set up?
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Ledge Fairy', player), lambda state: state.has_Pearl(player)) # bomb required
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player) and state.has_Pearl(player))
 | 
			
		||||
| 
						 | 
				
			
			@ -586,7 +617,7 @@ def inverted_rules(world, player):
 | 
			
		|||
    set_rule(world.get_entrance('Bonk Fairy (Dark)', player), lambda state: state.has_Boots(player))
 | 
			
		||||
    set_rule(world.get_entrance('West Dark World Gap', player), lambda state: state.has('Hookshot', player))
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Drop (East)', player), lambda state: state.has('Flippers', player))
 | 
			
		||||
    set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has_beam_sword(player))
 | 
			
		||||
    set_rule(world.get_location('Bombos Tablet', player), lambda state: state.can_retrieve_tablet(player))
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Drop (South)', player), lambda state: state.has('Flippers', player))  # ToDo any fake flipper set up?
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Ledge Pier', player), lambda state: state.has('Flippers', player))
 | 
			
		||||
    set_rule(world.get_entrance('Dark Lake Hylia Ledge Spike Cave', player), lambda state: state.can_lift_rocks(player))
 | 
			
		||||
| 
						 | 
				
			
			@ -740,41 +771,44 @@ def add_conditional_lamps(world, player):
 | 
			
		|||
    # Light cones in standard depend on which world we actually are in, not which one the location would normally be
 | 
			
		||||
    # We add Lamp requirements only to those locations which lie in the dark world (or everything if open
 | 
			
		||||
 | 
			
		||||
    def add_conditional_lamp(spot, region, spottype='Location'):
 | 
			
		||||
        if spottype == 'Location':
 | 
			
		||||
            spot = world.get_location(spot, player)
 | 
			
		||||
        else:
 | 
			
		||||
            spot = world.get_entrance(spot, player)
 | 
			
		||||
        if (not world.dark_world_light_cone and check_is_dark_world(world.get_region(region, player))) or (not world.light_world_light_cone and not check_is_dark_world(world.get_region(region, player))):
 | 
			
		||||
            add_lamp_requirement(spot, player)
 | 
			
		||||
    def add_conditional_lamp(spot, region, spottype='Location', accessible_torch=False):
 | 
			
		||||
        if (not world.dark_world_light_cone and check_is_dark_world(world.get_region(region, player))) or (
 | 
			
		||||
                not world.light_world_light_cone and not check_is_dark_world(world.get_region(region, player))):
 | 
			
		||||
            if spottype == 'Location':
 | 
			
		||||
                spot = world.get_location(spot, player)
 | 
			
		||||
            else:
 | 
			
		||||
                spot = world.get_entrance(spot, player)
 | 
			
		||||
            add_lamp_requirement(world, spot, player, accessible_torch)
 | 
			
		||||
 | 
			
		||||
    add_conditional_lamp('Misery Mire (Vitreous)', 'Misery Mire (Entrance)', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Turtle Rock (Dark Room) (North)', 'Turtle Rock (Entrance)', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Turtle Rock (Dark Room) (South)', 'Turtle Rock (Entrance)', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness Big Key Door', 'Palace of Darkness (Entrance)', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness Maze Door', 'Palace of Darkness (Entrance)', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)', 'Location')
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)', 'Location')
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness - Dark Basement - Left', 'Palace of Darkness (Entrance)',
 | 
			
		||||
                         'Location', True)
 | 
			
		||||
    add_conditional_lamp('Palace of Darkness - Dark Basement - Right', 'Palace of Darkness (Entrance)',
 | 
			
		||||
                         'Location', True)
 | 
			
		||||
    if world.mode[player] != 'inverted':
 | 
			
		||||
        add_conditional_lamp('Agahnim 1', 'Agahnims Tower', 'Entrance')
 | 
			
		||||
        add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower', 'Location')
 | 
			
		||||
        add_conditional_lamp('Castle Tower - Dark Maze', 'Agahnims Tower')
 | 
			
		||||
    else:
 | 
			
		||||
        add_conditional_lamp('Agahnim 1', 'Inverted Agahnims Tower', 'Entrance')
 | 
			
		||||
        add_conditional_lamp('Castle Tower - Dark Maze', 'Inverted Agahnims Tower', 'Location')
 | 
			
		||||
    add_conditional_lamp('Old Man', 'Old Man Cave', 'Location')
 | 
			
		||||
        add_conditional_lamp('Castle Tower - Dark Maze', 'Inverted Agahnims Tower')
 | 
			
		||||
    add_conditional_lamp('Old Man', 'Old Man Cave')
 | 
			
		||||
    add_conditional_lamp('Old Man Cave Exit (East)', 'Old Man Cave', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Death Mountain Return Cave Exit (East)', 'Death Mountain Return Cave', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Death Mountain Return Cave Exit (West)', 'Death Mountain Return Cave', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Old Man House Front to Back', 'Old Man House', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Old Man House Back to Front', 'Old Man House', 'Entrance')
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Big Key Chest', 'Eastern Palace', 'Location')
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Boss', 'Eastern Palace', 'Location')
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location')
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Big Key Chest', 'Eastern Palace')
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Boss', 'Eastern Palace', 'Location', True)
 | 
			
		||||
    add_conditional_lamp('Eastern Palace - Prize', 'Eastern Palace', 'Location', True)
 | 
			
		||||
 | 
			
		||||
    if not world.sewer_light_cone[player]:
 | 
			
		||||
        add_lamp_requirement(world.get_location('Sewers - Dark Cross', player), player)
 | 
			
		||||
        add_lamp_requirement(world.get_entrance('Sewers Back Door', player), player)
 | 
			
		||||
        add_lamp_requirement(world.get_entrance('Throne Room', player), player)
 | 
			
		||||
        add_lamp_requirement(world, world.get_location('Sewers - Dark Cross', player), player)
 | 
			
		||||
        add_lamp_requirement(world, world.get_entrance('Sewers Back Door', player), player)
 | 
			
		||||
        add_lamp_requirement(world, world.get_entrance('Throne Room', player), player)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def open_rules(world, player):
 | 
			
		||||
| 
						 | 
				
			
			@ -786,27 +820,19 @@ def open_rules(world, player):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def swordless_rules(world, player):
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_entrance('Agahnim 1', player), lambda state: (state.has('Hammer', player) or state.has('Fire Rod', player) or state.can_shoot_arrows(player) or state.has('Cane of Somaria', player)) and state.has_key('Small Key (Agahnims Tower)', player, 2))
 | 
			
		||||
    set_rule(world.get_location('Ether Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player))
 | 
			
		||||
    set_rule(world.get_entrance('Skull Woods Torch Room', player), lambda state: state.has_key('Small Key (Skull Woods)', player, 3) and state.has('Fire Rod', player))  # no curtain
 | 
			
		||||
    set_rule(world.get_entrance('Ice Palace Entrance Room', player), lambda state: state.has('Fire Rod', player) or state.has('Bombos', player)) #in swordless mode bombos pads are present in the relevant parts of ice palace
 | 
			
		||||
    if world.goal[player] in ['ganontriforcehunt', 'localganontriforcehunt']:
 | 
			
		||||
        set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Bow', player) and state.can_shoot_arrows(player) and state.has_triforce_pieces(world.treasure_hunt_count[player], player))
 | 
			
		||||
    else:
 | 
			
		||||
        set_rule(world.get_location('Ganon', player), lambda state: state.has('Hammer', player) and state.has_fire_source(player) and state.has('Silver Bow', player) and state.can_shoot_arrows(player) and state.has_crystals(world.crystals_needed_for_ganon[player], player))
 | 
			
		||||
    set_rule(world.get_entrance('Ganon Drop', player), lambda state: state.has('Hammer', player))  # need to damage ganon to get tiles to drop
 | 
			
		||||
 | 
			
		||||
    if world.mode[player] != 'inverted':
 | 
			
		||||
        set_rule(world.get_entrance('Agahnims Tower', player), lambda state: state.has('Cape', player) or state.has('Hammer', player) or state.has('Beat Agahnim 1', player))  # barrier gets removed after killing agahnim, relevant for entrance shuffle
 | 
			
		||||
        set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_Pearl(player) and state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player))   # sword not required to use medallion for opening in swordless (!)
 | 
			
		||||
        set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_Pearl(player) and state.has_misery_mire_medallion(player))  # sword not required to use medallion for opening in swordless (!)
 | 
			
		||||
        set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player) and state.has_Mirror(player))
 | 
			
		||||
    else:
 | 
			
		||||
        # only need ddm access for aga tower in inverted
 | 
			
		||||
        set_rule(world.get_entrance('Turtle Rock', player), lambda state: state.has_turtle_rock_medallion(player) and state.can_reach('Turtle Rock (Top)', 'Region', player))   # sword not required to use medallion for opening in swordless (!)
 | 
			
		||||
        set_rule(world.get_entrance('Misery Mire', player), lambda state: state.has_misery_mire_medallion(player))  # sword not required to use medallion for opening in swordless (!)
 | 
			
		||||
        set_rule(world.get_location('Bombos Tablet', player), lambda state: state.has('Book of Mudora', player) and state.has('Hammer', player))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def add_connection(parent_name, target_name, entrance_name, world, player):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,12 +19,21 @@
 | 
			
		|||
 | 
			
		||||
description: Template Name # Used to describe your yaml. Useful if you have multiple files
 | 
			
		||||
name: YourName # Your name in-game. Spaces will be replaced with underscores and there is a 16 character limit
 | 
			
		||||
### Logic Section ###
 | 
			
		||||
glitches_required: # Determine the logic required to complete the seed
 | 
			
		||||
  none: 50 # No glitches required
 | 
			
		||||
  minor_glitches: 0 # Puts fake flipper, waterwalk, super bunny shenanigans, and etc into logic
 | 
			
		||||
  overworld_glitches: 0 # Assumes the player has knowledge of both overworld major glitches (boots clips, mirror clips) and minor glitches (fake flipper, super bunny shenanigans, water walk and etc.)
 | 
			
		||||
  no_logic: 0 # Your own items are placed with no regard to any logic; such as your Fire Rod can be on your Trinexx.
 | 
			
		||||
  # Other players items are placed into your world under OWG logic
 | 
			
		||||
dark_room_logic: # Logic for unlit dark rooms
 | 
			
		||||
  lamp: 50 # require the Lamp for these rooms to be considered accessible.
 | 
			
		||||
  sconces: 0 # in addition to lamp, allow the fire rod and presence of easily accessible sconces for access
 | 
			
		||||
  none: 0 # all dark rooms are always considered doable, meaning this may force completion of rooms in complete darkness
 | 
			
		||||
restrict_dungeon_item_on_boss: # aka ambrosia boss items
 | 
			
		||||
  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 ###
 | 
			
		||||
meta_ignore: # Nullify options specified in the meta.yaml file. Adding an option here guarantees it will not occur in your seed, even if the .yaml file specifies it
 | 
			
		||||
  mode:
 | 
			
		||||
    - inverted # Never play inverted seeds
 | 
			
		||||
| 
						 | 
				
			
			@ -305,8 +314,8 @@ rom:
 | 
			
		|||
    on: 0
 | 
			
		||||
    off: 50
 | 
			
		||||
  quickswap: # Enable switching items by pressing the L+R shoulder buttons
 | 
			
		||||
    on: 0
 | 
			
		||||
    off: 50
 | 
			
		||||
    on: 50
 | 
			
		||||
    off: 0
 | 
			
		||||
  menuspeed: # Controls how fast the item menu opens and closes
 | 
			
		||||
    normal: 50
 | 
			
		||||
    instant: 0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue