* first commit (not including OoT data files yet) * added some basic options * rule parser works now at least * make sure to commit everything this time * temporary change to BaseClasses for oot * overworld location graph builds mostly correctly * adding oot data files * commenting out world options until later since they only existed to make the RuleParser work * conversion functions between AP ids and OOT ids * world graph outputs * set scrub prices * itempool generates, entrances connected, way too many options added * fixed set_rules and set_shop_rules * temp baseclasses changes * Reaches the fill step now, old event-based system retained in case the new way breaks * Song placements and misc fixes everywhere * temporary changes to make oot work * changed root exits for AP fill framework * prevent infinite recursion due to OoT sharing usage of the address field * age reachability works hopefully, songs are broken again * working spoiler log generation on beatable-only * Logic tricks implemented * need this for logic tricks * fixed map/compass being placed on Serenade location * kill unreachable events before filling the world * add a bunch of utility functions to prepare for rom patching * move OptionList into generic options * fixed some silly bugs with OptionList * properly seed all random behavior (so far) * ROM generation working * fix hints trying to get alttp dungeon hint texts * continue fixing hints * add oot to network data package * change item and location IDs to 66000 and 67000 range respectively * push removed items to precollected items * fixed various issues with cross-contamination with multiple world generation * reenable glitched logic (hopefully) * glitched world files age-check fix * cleaned up some get_locations calls * added token shuffle and scrub shuffle, modified some options slightly to make the parsing work * reenable MQ dungeons * fix forest mq exception * made targeting style an option for now, will be cosmetic later * reminder to move targeting to cosmetics * some oot option maintenance * enabled starting time of day * fixed issue breaking shop slots in multiworld generation * added "off" option for text shuffle and hints * shopsanity functionality restored * change patch file extension * remove unnecessary utility functions + imports * update MIT license * change option to "patch_uncompressed_rom" instead of "compress_rom" * compliance with new AutoWorld systems * Kill only internal events, remove non-internal big poe event in code * re-add the big poe event and handle it correctly * remove extra method in Range option * fix typo * Starting items, starting with consumables option * do not remove nonexistent item * move set_shop_rules to after shop items are placed * some cleanup * add retries for song placement * flagged Skull Mask and Mask of Truth as advancement items * update OoT to use LogicMixin * Fixed trying to assign starting items from the wrong players * fixed song retry step * improved option handling, comments, and starting item replacements * DefaultOnToggle writes Yes or No to spoiler * enable compression of output if Compress executable is present * clean up compression * check whether (de)compressor exists before running the process * allow specification of rom path in host.yaml * check if decompressed file already exists before decompressing again * fix triforce hunt generation * rename all the oot state functions with prefix * OoT: mark triforce pieces as completion goal for triforce hunt * added overworld and any-dungeon shuffle for dungeon items * Hide most unshuffled locations and events from the list of locations in spoiler * build oot option ranges with a generic function instead of defining each separately * move oot output-type control to host.yaml instead of individual yamls * implement dungeon song shuffle * minor improvements to overworld dungeon item shuffle * remove random ice trap names in shops, mostly to avoid maintaining a massive censor list * always output patch file to folder, remove option to generate ROM in preparation for removal * re-add the fix for infinite recursion due to not being light or dark world * change AP-sendable to Ocarina of Time model, since the triforce piece has some extra code apparently * oot: remove item_names and location_names * oot: minor fixes * oot: comment out ROM patching * oot: only add CollectionState objects on creation if actually needed * main entrance shuffle method and entrances-based rules * fix entrances based rules * disable master quest and big poe count options for client compatibility * use get_player_name instead of get_player_names * fix OptionList * fix oot options for new option system * new coop section in oot rom: expand player names to 16 bytes, write AP_PLAYER_NAME at end of PLAYER_NAMES * fill AP player name in oot rom with 0 instead of 0xDF * encode player name with ASCII for fixed-width * revert oot player name array to 8 bytes per name * remove Pierre location if fast scarecrow is on * check player name length * "free_scarecrow" not "fast_scarecrow" * OoT locations now properly store the AP ID instead of the oot internal ID * oot __version__ updates in lockstep with AP version * pull in unmodified oot cosmetic files * also grab JSONDump since it's needed apparently * gather extra needed methods, modify imports * delete cosmetics log, replace all instances of SettingsList with OOTWorld * cosmetic options working, except for sound effects (due to ear-safe issues) * SFX, Music, and Fanfare randomization reenabled * move OoT data files into the worlds folder * move Compress and Decompress into oot data folder * Replace get_all_state with custom method to avoid the cache * OoT ROM: increment item counter before setting incoming item/player values to 0, preventing desync issues * set data_version to 0 * make Kokiri Sword shuffle off by default * reenable "Random Choice" for various cosmetic options * kill Ruto's Letter turnin if open fountain also fix for shopsanity * place Buy Goron/Zora Tunic first in shop shuffle * make ice traps appear as other items instead of breaking generation * managed to break ice traps on non-major-only * only handle ice traps if they are on * fix shopsanity for non-oot games, and write player name instead of player number * light arrows hint uses player name instead of player number * Reenable "skip child zelda" option * fix entrances_based_rules * fix ganondorf hint if starting with light arrows * fix dungeonitem shuffle and shopsanity interaction * remove has_all_of, has_any_of, count_of in BaseClasses, replace usage with has_all, has_any, has_group * force local giveable item on ZL if skip_child_zelda and shuffle_song_items is any * keep bosses and bombchu bowling chus out of data package * revert workaround for infinite recursion and fix it properly * fix shared shop id caches during patching process * fix shop text box overflows, as much as possible * add default oot host.yaml option * add .apz5, .n64, .z64 to gitignore * Properly document and name all (functioning) OOT options * clean up some imports * remove unnecessary files from oot's data * fix typo in gitignore * readd the Compress and Decompress utilities, since they are needed for generation * cleanup of imports and some minor optimizations * increase shop offset for item IDs to 0xCB * remove shop item AP ids entirely * prevent triforce pieces for other players from being received by yourself * add "excluded" property to Location * Hint system adapted and reenabled; hints still unseeded * make hints deterministic with lists instead of sets * do not allow hints to point to Light Arrows on non-vanilla bridge * foreign locations hint as their full name in OoT rather than their region * checkedLocations now stores hint names by player ID, so that the same location in different worlds can have hints associated * consolidate versioning in Utils * ice traps appear as major items rather than any progression item * set prescription and claim check as defaults for adult trade item settings * add oot options to playerSettings * allow case-insensitive logic tricks in yaml * fix oot shopsanity option formatting * Write OoT override info even if local item, enabling local checks to show up immediately in the client * implement CollectionState.can_live_dmg for oot glitched logic * filter item names for invalid characters when patching shops * make ice traps appear according to the settings of the world they are shuffled into, rather than the original world * set hidden-spoiler items and locations with Shop items to events * make GF carpenters, Gerudo Card, Malon, ZL, and Impa events if the relevant settings are enabled, preventing them from appearing in the client on game start * Fix oot Glitched and No Logic generation * fix indenting * Greatly reduce displayed cosmetic options * Change oot data version to 1 * add apz5 distribution to webhost * print player name if an ALttP dungeon contains a good item for OoT world * delete unneeded commented code * remove OcarinaSongs import to satisfy lint
		
			
				
	
	
		
			783 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import typing
 | 
						|
from Options import Option, DefaultOnToggle, Toggle, Choice, Range, OptionList
 | 
						|
from .Colors import *
 | 
						|
import worlds.oot.Sounds as sfx
 | 
						|
 | 
						|
 | 
						|
class Logic(Choice): 
 | 
						|
    """Set the logic used for the generator."""
 | 
						|
    displayname = "Logic Rules"
 | 
						|
    option_glitchless = 0
 | 
						|
    option_glitched = 1
 | 
						|
    option_no_logic = 2
 | 
						|
 | 
						|
 | 
						|
class NightTokens(Toggle):
 | 
						|
    """Nighttime skulltulas will logically require Sun's Song."""
 | 
						|
    displayname = "Nighttime Skulltulas Expect Sun's Song"
 | 
						|
 | 
						|
 | 
						|
class Forest(Choice): 
 | 
						|
    """Set the state of Kokiri Forest and the path to Deku Tree."""
 | 
						|
    displayname = "Forest"
 | 
						|
    option_open = 0
 | 
						|
    option_closed_deku = 1
 | 
						|
    option_closed = 2
 | 
						|
    alias_open_forest = 0
 | 
						|
    alias_closed_forest = 2
 | 
						|
 | 
						|
 | 
						|
class Gate(Choice): 
 | 
						|
    """Set the state of the Kakariko Village gate."""
 | 
						|
    displayname = "Kakariko Gate"
 | 
						|
    option_open = 0
 | 
						|
    option_zelda = 1
 | 
						|
    option_closed = 2
 | 
						|
 | 
						|
 | 
						|
class DoorOfTime(DefaultOnToggle):
 | 
						|
    """Open the Door of Time by default, without the Song of Time."""
 | 
						|
    displayname = "Open Door of Time"
 | 
						|
 | 
						|
 | 
						|
class Fountain(Choice): 
 | 
						|
    """Set the state of King Zora, blocking the way to Zora's Fountain."""
 | 
						|
    displayname = "Zora's Fountain"
 | 
						|
    option_open = 0
 | 
						|
    option_adult = 1
 | 
						|
    option_closed = 2
 | 
						|
    default = 2
 | 
						|
 | 
						|
 | 
						|
class Fortress(Choice): 
 | 
						|
    """Set the requirements for access to Gerudo Fortress."""
 | 
						|
    displayname = "Gerudo Fortress"
 | 
						|
    option_normal = 0
 | 
						|
    option_fast = 1
 | 
						|
    option_open = 2
 | 
						|
    default = 1
 | 
						|
 | 
						|
 | 
						|
class Bridge(Choice): 
 | 
						|
    """Set the requirements for the Rainbow Bridge."""
 | 
						|
    displayname = "Rainbow Bridge Requirement"
 | 
						|
    option_open = 0
 | 
						|
    option_vanilla = 1
 | 
						|
    option_stones = 2
 | 
						|
    option_medallions = 3
 | 
						|
    option_dungeons = 4
 | 
						|
    option_tokens = 5
 | 
						|
    default = 3
 | 
						|
 | 
						|
 | 
						|
class Trials(Range):
 | 
						|
    """Set the number of required trials in Ganon's Castle."""
 | 
						|
    displayname = "Ganon's Trials Count"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 6
 | 
						|
 | 
						|
 | 
						|
open_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "open_forest": Forest,
 | 
						|
    "open_kakariko": Gate,
 | 
						|
    "open_door_of_time": DoorOfTime,
 | 
						|
    "zora_fountain": Fountain,
 | 
						|
    "gerudo_fortress": Fortress, 
 | 
						|
    "bridge": Bridge,
 | 
						|
    "trials": Trials,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class StartingAge(Choice): 
 | 
						|
    """Choose which age Link will start as."""
 | 
						|
    displayname = "Starting Age"
 | 
						|
    option_child = 0
 | 
						|
    option_adult = 1
 | 
						|
 | 
						|
 | 
						|
# TODO: document and name ER options
 | 
						|
class InteriorEntrances(Choice): 
 | 
						|
    option_off = 0
 | 
						|
    option_simple = 1
 | 
						|
    option_all = 2
 | 
						|
    alias_false = 0
 | 
						|
 | 
						|
 | 
						|
class TriforceHunt(Toggle):
 | 
						|
    """Gather pieces of the Triforce scattered around the world to complete the game."""
 | 
						|
    displayname = "Triforce Hunt"
 | 
						|
 | 
						|
 | 
						|
class TriforceGoal(Range):
 | 
						|
    """Number of Triforce pieces required to complete the game. Total number placed determined by the Item Pool setting."""
 | 
						|
    displayname = "Required Triforce Pieces"
 | 
						|
    range_start = 1
 | 
						|
    range_end = 50
 | 
						|
    default = 20
 | 
						|
 | 
						|
 | 
						|
class LogicalChus(Toggle):
 | 
						|
    """Bombchus are properly considered in logic. The first found pack will have 20 chus; Kokiri Shop and Bazaar sell refills; bombchus open Bombchu Bowling."""
 | 
						|
    displayname = "Bombchus Considered in Logic"
 | 
						|
 | 
						|
 | 
						|
world_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "starting_age": StartingAge,
 | 
						|
    # "shuffle_interior_entrances": InteriorEntrances,
 | 
						|
    # "shuffle_grotto_entrances": Toggle,
 | 
						|
    # "shuffle_dungeon_entrances": Toggle,
 | 
						|
    # "shuffle_overworld_entrances": Toggle,
 | 
						|
    # "owl_drops": Toggle,
 | 
						|
    # "warp_songs": Toggle,
 | 
						|
    # "spawn_positions": Toggle,
 | 
						|
    "triforce_hunt": TriforceHunt, 
 | 
						|
    "triforce_goal": TriforceGoal,
 | 
						|
    "bombchus_in_logic": LogicalChus,
 | 
						|
    # "mq_dungeons": make_range(0, 12),
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class LacsCondition(Choice): 
 | 
						|
    """Set the requirements for the Light Arrow Cutscene in the Temple of Time."""
 | 
						|
    displayname = "Light Arrow Cutscene Requirement"
 | 
						|
    option_vanilla = 0
 | 
						|
    option_stones = 1
 | 
						|
    option_medallions = 2
 | 
						|
    option_dungeons = 3
 | 
						|
    option_tokens = 4
 | 
						|
 | 
						|
 | 
						|
class LacsStones(Range):
 | 
						|
    """Set the number of Spiritual Stones required for LACS."""
 | 
						|
    displayname = "Spiritual Stones Required for LACS"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 3
 | 
						|
    default = 3
 | 
						|
 | 
						|
 | 
						|
class LacsMedallions(Range):
 | 
						|
    """Set the number of medallions required for LACS."""
 | 
						|
    displayname = "Medallions Required for LACS"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 6
 | 
						|
    default = 6
 | 
						|
 | 
						|
 | 
						|
class LacsRewards(Range):
 | 
						|
    """Set the number of dungeon rewards required for LACS."""
 | 
						|
    displayname = "Dungeon Rewards Required for LACS"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 9
 | 
						|
    default = 9
 | 
						|
 | 
						|
 | 
						|
class LacsTokens(Range):
 | 
						|
    """Set the number of Gold Skulltula Tokens required for LACS."""
 | 
						|
    displayname = "Tokens Required for LACS"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 100
 | 
						|
    default = 100
 | 
						|
 | 
						|
 | 
						|
lacs_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "lacs_condition": LacsCondition,
 | 
						|
    "lacs_stones": LacsStones, 
 | 
						|
    "lacs_medallions": LacsMedallions, 
 | 
						|
    "lacs_rewards": LacsRewards, 
 | 
						|
    "lacs_tokens": LacsTokens,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class BridgeStones(Range):
 | 
						|
    """Set the number of Spiritual Stones required for the rainbow bridge."""
 | 
						|
    displayname = "Spiritual Stones Required for Bridge"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 3
 | 
						|
    default = 3
 | 
						|
 | 
						|
 | 
						|
class BridgeMedallions(Range):
 | 
						|
    """Set the number of medallions required for the rainbow bridge."""
 | 
						|
    displayname = "Medallions Required for Bridge"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 6
 | 
						|
    default = 6
 | 
						|
 | 
						|
 | 
						|
class BridgeRewards(Range):
 | 
						|
    """Set the number of dungeon rewards required for the rainbow bridge."""
 | 
						|
    displayname = "Dungeon Rewards Required for Bridge"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 9
 | 
						|
    default = 9
 | 
						|
 | 
						|
 | 
						|
class BridgeTokens(Range):
 | 
						|
    """Set the number of Gold Skulltula Tokens required for the rainbow bridge."""
 | 
						|
    displayname = "Tokens Required for Bridge"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 100
 | 
						|
    default = 100
 | 
						|
 | 
						|
 | 
						|
bridge_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "bridge_stones": BridgeStones,
 | 
						|
    "bridge_medallions": BridgeMedallions,
 | 
						|
    "bridge_rewards": BridgeRewards, 
 | 
						|
    "bridge_tokens": BridgeTokens,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class SongShuffle(Choice): 
 | 
						|
    """Set where songs can appear."""
 | 
						|
    displayname = "Shuffle Songs"
 | 
						|
    option_song = 0
 | 
						|
    option_dungeon = 1
 | 
						|
    option_any = 2
 | 
						|
 | 
						|
 | 
						|
class ShopShuffle(Choice): 
 | 
						|
    """Randomizes shop contents. Set to "off" to not shuffle shops; "0" shuffles shops but does not allow multiworld items in shops."""
 | 
						|
    displayname = "Shopsanity"
 | 
						|
    option_0 = 0
 | 
						|
    option_1 = 1
 | 
						|
    option_2 = 2
 | 
						|
    option_3 = 3
 | 
						|
    option_4 = 4
 | 
						|
    option_random_value = 5
 | 
						|
    option_off = 6
 | 
						|
    default = 6
 | 
						|
    alias_false = 6
 | 
						|
 | 
						|
 | 
						|
class TokenShuffle(Choice): 
 | 
						|
    """Token rewards from Gold Skulltulas are shuffled into the pool."""
 | 
						|
    displayname = "Tokensanity"
 | 
						|
    option_off = 0
 | 
						|
    option_dungeons = 1
 | 
						|
    option_overworld = 2
 | 
						|
    option_all = 3
 | 
						|
    alias_false = 0
 | 
						|
 | 
						|
 | 
						|
class ScrubShuffle(Choice): 
 | 
						|
    """Shuffle the items sold by Business Scrubs, and set the prices."""
 | 
						|
    displayname = "Scrub Shuffle"
 | 
						|
    option_off = 0
 | 
						|
    option_low = 1
 | 
						|
    option_regular = 2
 | 
						|
    option_random_prices = 3
 | 
						|
    alias_false = 0
 | 
						|
    alias_affordable = 1
 | 
						|
    alias_expensive = 2
 | 
						|
 | 
						|
 | 
						|
class ShuffleCows(Toggle):
 | 
						|
    """Cows give items when Epona's Song is played."""
 | 
						|
    displayname = "Shuffle Cows"
 | 
						|
 | 
						|
 | 
						|
class ShuffleSword(Toggle):
 | 
						|
    """Shuffle Kokiri Sword into the item pool."""
 | 
						|
    displayname = "Shuffle Kokiri Sword"
 | 
						|
 | 
						|
 | 
						|
class ShuffleOcarinas(Toggle):
 | 
						|
    """Shuffle the Fairy Ocarina and Ocarina of Time into the item pool."""
 | 
						|
    displayname = "Shuffle Ocarinas"
 | 
						|
 | 
						|
 | 
						|
class ShuffleEgg(Toggle):
 | 
						|
    """Shuffle the Weird Egg from Malon at Hyrule Castle."""
 | 
						|
    displayname = "Shuffle Weird Egg"
 | 
						|
 | 
						|
 | 
						|
class ShuffleCard(Toggle):
 | 
						|
    """Shuffle the Gerudo Membership Card into the item pool."""
 | 
						|
    displayname = "Shuffle Gerudo Card"
 | 
						|
 | 
						|
 | 
						|
class ShuffleBeans(Toggle):
 | 
						|
    """Adds a pack of 10 beans to the item pool and changes the bean salesman to sell one item for 60 rupees."""
 | 
						|
    displayname = "Shuffle Magic Beans"
 | 
						|
 | 
						|
 | 
						|
class ShuffleMedigoronCarpet(Toggle):
 | 
						|
    """Shuffle the items sold by Medigoron and the Haunted Wasteland Carpet Salesman."""
 | 
						|
    displayname = "Shuffle Medigoron & Carpet Salesman"
 | 
						|
 | 
						|
 | 
						|
shuffle_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "shuffle_song_items": SongShuffle,
 | 
						|
    "shopsanity": ShopShuffle, 
 | 
						|
    "tokensanity": TokenShuffle, 
 | 
						|
    "shuffle_scrubs": ScrubShuffle,
 | 
						|
    "shuffle_cows": ShuffleCows, 
 | 
						|
    "shuffle_kokiri_sword": ShuffleSword,
 | 
						|
    "shuffle_ocarinas": ShuffleOcarinas,
 | 
						|
    "shuffle_weird_egg": ShuffleEgg,
 | 
						|
    "shuffle_gerudo_card": ShuffleCard,
 | 
						|
    "shuffle_beans": ShuffleBeans, 
 | 
						|
    "shuffle_medigoron_carpet_salesman": ShuffleMedigoronCarpet,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class ShuffleMapCompass(Choice): 
 | 
						|
    """Control where to shuffle dungeon maps and compasses."""
 | 
						|
    displayname = "Maps & Compasses"
 | 
						|
    option_remove = 0
 | 
						|
    option_startwith = 1
 | 
						|
    option_vanilla = 2
 | 
						|
    option_dungeon = 3
 | 
						|
    option_overworld = 4
 | 
						|
    option_any_dungeon = 5
 | 
						|
    option_keysanity = 6
 | 
						|
    default = 1
 | 
						|
    alias_anywhere = 6
 | 
						|
 | 
						|
 | 
						|
class ShuffleKeys(Choice): 
 | 
						|
    """Control where to shuffle dungeon small keys."""
 | 
						|
    displayname = "Small Keys"
 | 
						|
    option_remove = 0
 | 
						|
    option_vanilla = 2
 | 
						|
    option_dungeon = 3
 | 
						|
    option_overworld = 4
 | 
						|
    option_any_dungeon = 5
 | 
						|
    option_keysanity = 6
 | 
						|
    default = 3
 | 
						|
    alias_keysy = 0
 | 
						|
    alias_anywhere = 6
 | 
						|
 | 
						|
 | 
						|
class ShuffleGerudoKeys(Choice): 
 | 
						|
    """Control where to shuffle the Gerudo Fortress small keys."""
 | 
						|
    displayname = "Gerudo Fortress Keys"
 | 
						|
    option_vanilla = 0
 | 
						|
    option_overworld = 1
 | 
						|
    option_any_dungeon = 2
 | 
						|
    option_keysanity = 3
 | 
						|
    alias_anywhere = 3
 | 
						|
 | 
						|
 | 
						|
class ShuffleBossKeys(Choice): 
 | 
						|
    """Control where to shuffle boss keys, except the Ganon's Castle Boss Key."""
 | 
						|
    displayname = "Boss Keys"
 | 
						|
    option_remove = 0
 | 
						|
    option_vanilla = 2
 | 
						|
    option_dungeon = 3
 | 
						|
    option_overworld = 4
 | 
						|
    option_any_dungeon = 5
 | 
						|
    option_keysanity = 6
 | 
						|
    default = 3
 | 
						|
    alias_keysy = 0
 | 
						|
    alias_anywhere = 6
 | 
						|
 | 
						|
 | 
						|
class ShuffleGanonBK(Choice):
 | 
						|
    """Control where to shuffle the Ganon's Castle Boss Key."""
 | 
						|
    displayname = "Ganon's Boss Key"
 | 
						|
    option_remove = 0
 | 
						|
    option_vanilla = 2
 | 
						|
    option_dungeon = 3
 | 
						|
    option_overworld = 4
 | 
						|
    option_any_dungeon = 5
 | 
						|
    option_keysanity = 6
 | 
						|
    option_on_lacs = 7
 | 
						|
    default = 0
 | 
						|
    alias_keysy = 0
 | 
						|
    alias_anywhere = 6
 | 
						|
 | 
						|
 | 
						|
class EnhanceMC(Toggle):
 | 
						|
    """Map tells if a dungeon is vanilla or MQ. Compass tells what the dungeon reward is."""
 | 
						|
    displayname = "Maps and Compasses Give Information"
 | 
						|
 | 
						|
 | 
						|
dungeon_items_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "shuffle_mapcompass": ShuffleMapCompass, 
 | 
						|
    "shuffle_smallkeys": ShuffleKeys, 
 | 
						|
    "shuffle_fortresskeys": ShuffleGerudoKeys, 
 | 
						|
    "shuffle_bosskeys": ShuffleBossKeys,
 | 
						|
    "shuffle_ganon_bosskey": ShuffleGanonBK,
 | 
						|
    "enhance_map_compass": EnhanceMC,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class SkipChildZelda(Toggle):
 | 
						|
    """Game starts with Zelda's Letter, the item at Zelda's Lullaby, and the relevant events already completed."""
 | 
						|
    displayname = "Skip Child Zelda"
 | 
						|
 | 
						|
 | 
						|
class SkipEscape(DefaultOnToggle):
 | 
						|
    """Skips the tower collapse sequence between the Ganondorf and Ganon fights."""
 | 
						|
    displayname = "Skip Tower Escape Sequence"
 | 
						|
 | 
						|
 | 
						|
class SkipStealth(DefaultOnToggle):
 | 
						|
    """The crawlspace into Hyrule Castle skips straight to Zelda."""
 | 
						|
    displayname = "Skip Child Stealth"
 | 
						|
 | 
						|
 | 
						|
class SkipEponaRace(DefaultOnToggle):
 | 
						|
    """Epona can always be summoned with Epona's Song."""
 | 
						|
    displayname = "Skip Epona Race"
 | 
						|
 | 
						|
 | 
						|
class SkipMinigamePhases(DefaultOnToggle):
 | 
						|
    """Dampe Race and Horseback Archery give both rewards if the second condition is met on the first attempt."""
 | 
						|
    displayname = "Skip Some Minigame Phases"
 | 
						|
 | 
						|
 | 
						|
class CompleteMaskQuest(Toggle):
 | 
						|
    """All masks are immediately available to borrow from the Happy Mask Shop."""
 | 
						|
    displayname = "Complete Mask Quest"
 | 
						|
 | 
						|
 | 
						|
class UsefulCutscenes(Toggle):
 | 
						|
    """Reenables the Poe cutscene in Forest Temple, Darunia in Fire Temple, and Twinrova introduction. Mostly useful for glitched."""
 | 
						|
    displayname = "Enable Useful Cutscenes"
 | 
						|
 | 
						|
 | 
						|
class FastChests(DefaultOnToggle):
 | 
						|
    """All chest animations are fast. If disabled, major items have a slow animation."""
 | 
						|
    displayname = "Fast Chest Cutscenes"
 | 
						|
 | 
						|
 | 
						|
class FreeScarecrow(Toggle):
 | 
						|
    """Pulling out the ocarina near a scarecrow spot spawns Pierre without needing the song."""
 | 
						|
    displayname = "Free Scarecrow's Song"
 | 
						|
 | 
						|
 | 
						|
class FastBunny(Toggle):
 | 
						|
    """Bunny Hood lets you move 1.5x faster like in Majora's Mask."""
 | 
						|
    displayname = "Fast Bunny Hood"
 | 
						|
 | 
						|
 | 
						|
class ChickenCount(Range):
 | 
						|
    """Controls the number of Cuccos for Anju to give an item as child."""
 | 
						|
    displayname = "Cucco Count"
 | 
						|
    range_start = 0
 | 
						|
    range_end = 7
 | 
						|
    default = 7
 | 
						|
 | 
						|
 | 
						|
timesavers_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "skip_child_zelda": SkipChildZelda, 
 | 
						|
    "no_escape_sequence": SkipEscape, 
 | 
						|
    "no_guard_stealth": SkipStealth, 
 | 
						|
    "no_epona_race": SkipEponaRace, 
 | 
						|
    "skip_some_minigame_phases": SkipMinigamePhases, 
 | 
						|
    "complete_mask_quest": CompleteMaskQuest, 
 | 
						|
    "useful_cutscenes": UsefulCutscenes, 
 | 
						|
    "fast_chests": FastChests, 
 | 
						|
    "free_scarecrow": FreeScarecrow, 
 | 
						|
    "fast_bunny_hood": FastBunny,
 | 
						|
    "chicken_count": ChickenCount,
 | 
						|
    # "big_poe_count": make_range(1, 10, 1),
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class Hints(Choice): 
 | 
						|
    """Gossip Stones can give hints about item locations."""
 | 
						|
    displayname = "Gossip Stones"
 | 
						|
    option_none = 0
 | 
						|
    option_mask = 1
 | 
						|
    option_agony = 2
 | 
						|
    option_always = 3
 | 
						|
    default = 3
 | 
						|
    alias_false = 0
 | 
						|
 | 
						|
 | 
						|
class HintDistribution(Choice):
 | 
						|
    """Choose the hint distribution to use. Affects the frequency of strong hints, which items are always hinted, etc."""
 | 
						|
    displayname = "Hint Distribution"
 | 
						|
    option_balanced = 0
 | 
						|
    option_ddr = 1
 | 
						|
    option_league = 2
 | 
						|
    option_mw2 = 3
 | 
						|
    option_scrubs = 4
 | 
						|
    option_strong = 5
 | 
						|
    option_tournament = 6
 | 
						|
    option_useless = 7
 | 
						|
    option_very_strong = 8
 | 
						|
 | 
						|
 | 
						|
class TextShuffle(Choice): 
 | 
						|
    """Randomizes text in the game for comedic effect."""
 | 
						|
    displayname = "Text Shuffle"
 | 
						|
    option_none = 0
 | 
						|
    option_except_hints = 1
 | 
						|
    option_complete = 2
 | 
						|
    alias_false = 0
 | 
						|
 | 
						|
 | 
						|
class DamageMultiplier(Choice): 
 | 
						|
    """Controls the amount of damage Link takes."""
 | 
						|
    displayname = "Damage Multiplier"
 | 
						|
    option_half = 0
 | 
						|
    option_normal = 1
 | 
						|
    option_double = 2
 | 
						|
    option_quadruple = 3
 | 
						|
    option_ohko = 4
 | 
						|
    default = 1
 | 
						|
 | 
						|
 | 
						|
class HeroMode(Toggle):
 | 
						|
    """Hearts will not drop from enemies or objects."""
 | 
						|
    displayname = "Hero Mode"
 | 
						|
 | 
						|
 | 
						|
class StartingToD(Choice):
 | 
						|
    """Change the starting time of day."""
 | 
						|
    displayname = "Starting Time of Day"
 | 
						|
    option_default = 0
 | 
						|
    option_sunrise = 1
 | 
						|
    option_morning = 2
 | 
						|
    option_noon = 3
 | 
						|
    option_afternoon = 4
 | 
						|
    option_sunset = 5
 | 
						|
    option_evening = 6
 | 
						|
    option_midnight = 7
 | 
						|
    option_witching_hour = 8
 | 
						|
 | 
						|
 | 
						|
class ConsumableStart(Toggle):
 | 
						|
    """Start the game with full Deku Sticks and Deku Nuts."""
 | 
						|
    displayname = "Start with Consumables"
 | 
						|
 | 
						|
 | 
						|
class RupeeStart(Toggle):
 | 
						|
    """Start with a full wallet. Wallet upgrades will also fill your wallet."""
 | 
						|
    displayname = "Start with Rupees"
 | 
						|
 | 
						|
 | 
						|
misc_options: typing.Dict[str, type(Option)] = {
 | 
						|
    # "clearer_hints": DefaultOnToggle,
 | 
						|
    "hints": Hints,
 | 
						|
    "hint_dist": HintDistribution,
 | 
						|
    "text_shuffle": TextShuffle,
 | 
						|
    "damage_multiplier": DamageMultiplier,
 | 
						|
    "no_collectible_hearts": HeroMode,
 | 
						|
    "starting_tod": StartingToD,
 | 
						|
    "start_with_consumables": ConsumableStart, 
 | 
						|
    "start_with_rupees": RupeeStart,
 | 
						|
}
 | 
						|
 | 
						|
class ItemPoolValue(Choice): 
 | 
						|
    """Changes the number of items available in the game."""
 | 
						|
    displayname = "Item Pool"
 | 
						|
    option_plentiful = 0
 | 
						|
    option_balanced = 1
 | 
						|
    option_scarce = 2
 | 
						|
    option_minimal = 3
 | 
						|
    default = 1
 | 
						|
 | 
						|
 | 
						|
class IceTraps(Choice): 
 | 
						|
    """Adds ice traps to the item pool."""
 | 
						|
    displayname = "Ice Traps"
 | 
						|
    option_off = 0
 | 
						|
    option_normal = 1
 | 
						|
    option_on = 2
 | 
						|
    option_mayhem = 3
 | 
						|
    option_onslaught = 4
 | 
						|
    default = 1
 | 
						|
    alias_false = 0
 | 
						|
    alias_true = 2
 | 
						|
    alias_extra = 2
 | 
						|
 | 
						|
 | 
						|
class IceTrapVisual(Choice): 
 | 
						|
    """Changes the appearance of ice traps as freestanding items."""
 | 
						|
    displayname = "Ice Trap Appearance"
 | 
						|
    option_major_only = 0
 | 
						|
    option_junk_only = 1
 | 
						|
    option_anything = 2
 | 
						|
 | 
						|
 | 
						|
class AdultTradeItem(Choice): 
 | 
						|
    option_pocket_egg = 0
 | 
						|
    option_pocket_cucco = 1
 | 
						|
    option_cojiro = 2
 | 
						|
    option_odd_mushroom = 3
 | 
						|
    option_poachers_saw = 4
 | 
						|
    option_broken_sword = 5
 | 
						|
    option_prescription = 6
 | 
						|
    option_eyeball_frog = 7
 | 
						|
    option_eyedrops = 8
 | 
						|
    option_claim_check = 9
 | 
						|
 | 
						|
 | 
						|
class EarlyTradeItem(AdultTradeItem):
 | 
						|
    """Earliest item that can appear in the adult trade sequence."""
 | 
						|
    displayname = "Adult Trade Sequence Earliest Item"
 | 
						|
    default = 6
 | 
						|
 | 
						|
 | 
						|
class LateTradeItem(AdultTradeItem):
 | 
						|
    """Latest item that can appear in the adult trade sequence."""
 | 
						|
    displayname = "Adult Trade Sequence Latest Item"
 | 
						|
    default = 9
 | 
						|
 | 
						|
 | 
						|
itempool_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "item_pool_value": ItemPoolValue, 
 | 
						|
    "junk_ice_traps": IceTraps,
 | 
						|
    "ice_trap_appearance": IceTrapVisual, 
 | 
						|
    "logic_earliest_adult_trade": EarlyTradeItem, 
 | 
						|
    "logic_latest_adult_trade": LateTradeItem,
 | 
						|
}
 | 
						|
 | 
						|
# Start of cosmetic options
 | 
						|
 | 
						|
def assemble_color_option(func, display_name: str, default_option: str, outer=False): 
 | 
						|
    color_options = func()
 | 
						|
    if outer:
 | 
						|
        color_options.append("Match Inner")
 | 
						|
    format_color = lambda color: color.replace(' ', '_').lower()
 | 
						|
    color_to_id = {format_color(color): index for index, color in enumerate(color_options)}
 | 
						|
    class ColorOption(Choice):
 | 
						|
        """Choose a color. "random_choice" selects a random option. "completely_random" generates a random hex code."""
 | 
						|
        displayname = display_name
 | 
						|
        default = color_options.index(default_option)
 | 
						|
    ColorOption.options.update(color_to_id)
 | 
						|
    ColorOption.name_lookup.update({id: color for (color, id) in color_to_id.items()})
 | 
						|
    return ColorOption
 | 
						|
 | 
						|
 | 
						|
class Targeting(Choice): 
 | 
						|
    """Default targeting option."""
 | 
						|
    displayname = "Default Targeting Option"
 | 
						|
    option_hold = 0
 | 
						|
    option_switch = 1
 | 
						|
 | 
						|
 | 
						|
class DisplayDpad(DefaultOnToggle):
 | 
						|
    """Show dpad icon on HUD for quick actions (ocarina, hover boots, iron boots)."""
 | 
						|
    displayname = "Display D-Pad HUD"
 | 
						|
 | 
						|
 | 
						|
class CorrectColors(DefaultOnToggle):
 | 
						|
    """Makes in-game models match their HUD element colors."""
 | 
						|
    displayname = "Item Model Colors Match Cosmetics"
 | 
						|
 | 
						|
 | 
						|
class Music(Choice): 
 | 
						|
    option_normal = 0
 | 
						|
    option_off = 1
 | 
						|
    option_randomized = 2
 | 
						|
    alias_false = 1
 | 
						|
 | 
						|
 | 
						|
class BackgroundMusic(Music):
 | 
						|
    """Randomize or disable background music."""
 | 
						|
    displayname = "Background Music"
 | 
						|
 | 
						|
 | 
						|
class Fanfares(Music):
 | 
						|
    """Randomize or disable item fanfares."""
 | 
						|
    displayname = "Fanfares"
 | 
						|
 | 
						|
 | 
						|
class OcarinaFanfares(Toggle):
 | 
						|
    """Enable ocarina songs as fanfares. These are longer than usual fanfares. Does nothing without fanfares randomized."""
 | 
						|
    displayname = "Ocarina Songs as Fanfares"
 | 
						|
 | 
						|
 | 
						|
class SwordTrailDuration(Range):
 | 
						|
    """Set the duration for sword trails."""
 | 
						|
    displayname = "Sword Trail Duration"
 | 
						|
    range_start = 4
 | 
						|
    range_end = 20
 | 
						|
    default = 4
 | 
						|
 | 
						|
 | 
						|
cosmetic_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "default_targeting": Targeting,
 | 
						|
    "display_dpad": DisplayDpad,
 | 
						|
    "correct_model_colors": CorrectColors,
 | 
						|
    "background_music": BackgroundMusic,
 | 
						|
    "fanfares": Fanfares,
 | 
						|
    "ocarina_fanfares": OcarinaFanfares,
 | 
						|
    "kokiri_color": assemble_color_option(get_tunic_color_options, "Kokiri Tunic", "Kokiri Green"),
 | 
						|
    "goron_color":  assemble_color_option(get_tunic_color_options, "Goron Tunic", "Goron Red"),
 | 
						|
    "zora_color":   assemble_color_option(get_tunic_color_options, "Zora Tunic", "Zora Blue"),
 | 
						|
    "silver_gauntlets_color":   assemble_color_option(get_gauntlet_color_options, "Silver Gauntlets Color", "Silver"),
 | 
						|
    "golden_gauntlets_color":   assemble_color_option(get_gauntlet_color_options, "Golden Gauntlets Color", "Gold"),
 | 
						|
    "mirror_shield_frame_color": assemble_color_option(get_shield_frame_color_options, "Mirror Shield Frame Color", "Red"),
 | 
						|
    "navi_color_default_inner": assemble_color_option(get_navi_color_options, "Navi Idle Inner", "White"),
 | 
						|
    "navi_color_default_outer": assemble_color_option(get_navi_color_options, "Navi Idle Outer", "Match Inner", outer=True),
 | 
						|
    "navi_color_enemy_inner":   assemble_color_option(get_navi_color_options, "Navi Targeting Enemy Inner", "Yellow"),
 | 
						|
    "navi_color_enemy_outer":   assemble_color_option(get_navi_color_options, "Navi Targeting Enemy Outer", "Match Inner", outer=True),
 | 
						|
    "navi_color_npc_inner":     assemble_color_option(get_navi_color_options, "Navi Targeting NPC Inner", "Light Blue"),
 | 
						|
    "navi_color_npc_outer":     assemble_color_option(get_navi_color_options, "Navi Targeting NPC Outer", "Match Inner", outer=True),
 | 
						|
    "navi_color_prop_inner":    assemble_color_option(get_navi_color_options, "Navi Targeting Prop Inner", "Green"),
 | 
						|
    "navi_color_prop_outer":    assemble_color_option(get_navi_color_options, "Navi Targeting Prop Outer", "Match Inner", outer=True),
 | 
						|
    "sword_trail_duration": SwordTrailDuration,
 | 
						|
    "sword_trail_color_inner": assemble_color_option(get_sword_trail_color_options, "Sword Trail Inner", "White"),
 | 
						|
    "sword_trail_color_outer": assemble_color_option(get_sword_trail_color_options, "Sword Trail Outer", "Match Inner", outer=True),
 | 
						|
    "bombchu_trail_color_inner": assemble_color_option(get_bombchu_trail_color_options, "Bombchu Trail Inner", "Red"),
 | 
						|
    "bombchu_trail_color_outer": assemble_color_option(get_bombchu_trail_color_options, "Bombchu Trail Outer", "Match Inner", outer=True),
 | 
						|
    "boomerang_trail_color_inner": assemble_color_option(get_boomerang_trail_color_options, "Boomerang Trail Inner", "Yellow"),
 | 
						|
    "boomerang_trail_color_outer": assemble_color_option(get_boomerang_trail_color_options, "Boomerang Trail Outer", "Match Inner", outer=True),
 | 
						|
    "heart_color":          assemble_color_option(get_heart_color_options, "Heart Color", "Red"),
 | 
						|
    "magic_color":          assemble_color_option(get_magic_color_options, "Magic Color", "Green"),
 | 
						|
    "a_button_color":       assemble_color_option(get_a_button_color_options, "A Button Color", "N64 Blue"),
 | 
						|
    "b_button_color":       assemble_color_option(get_b_button_color_options, "B Button Color", "N64 Green"),
 | 
						|
    "c_button_color":       assemble_color_option(get_c_button_color_options, "C Button Color", "Yellow"),
 | 
						|
    "start_button_color":   assemble_color_option(get_start_button_color_options, "Start Button Color", "N64 Red"),
 | 
						|
}
 | 
						|
 | 
						|
def assemble_sfx_option(sound_hook: sfx.SoundHooks, display_name: str):
 | 
						|
    options = sfx.get_setting_choices(sound_hook).keys()
 | 
						|
    sfx_to_id = {sfx.replace('-', '_'): index for index, sfx in enumerate(options)}
 | 
						|
    class SfxOption(Choice):
 | 
						|
        """Choose a sound effect. "random_choice" selects a random option. "random_ear_safe" selects a random safe option. "completely_random" selects any random sound."""
 | 
						|
        displayname = display_name
 | 
						|
    SfxOption.options.update(sfx_to_id)
 | 
						|
    SfxOption.name_lookup.update({id: sfx for (sfx, id) in sfx_to_id.items()})
 | 
						|
    return SfxOption
 | 
						|
 | 
						|
class SfxOcarina(Choice):
 | 
						|
    """Change the sound of the ocarina."""
 | 
						|
    displayname = "Ocarina Instrument"
 | 
						|
    option_ocarina = 1
 | 
						|
    option_malon = 2
 | 
						|
    option_whistle = 3
 | 
						|
    option_harp = 4
 | 
						|
    option_grind_organ = 5
 | 
						|
    option_flute = 6
 | 
						|
    default = 1
 | 
						|
 | 
						|
sfx_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "sfx_navi_overworld":   assemble_sfx_option(sfx.SoundHooks.NAVI_OVERWORLD, "Navi Overworld"),
 | 
						|
    "sfx_navi_enemy":       assemble_sfx_option(sfx.SoundHooks.NAVI_ENEMY, "Navi Enemy"),
 | 
						|
    "sfx_low_hp":           assemble_sfx_option(sfx.SoundHooks.HP_LOW, "Low HP"),
 | 
						|
    "sfx_menu_cursor":      assemble_sfx_option(sfx.SoundHooks.MENU_CURSOR, "Menu Cursor"),
 | 
						|
    "sfx_menu_select":      assemble_sfx_option(sfx.SoundHooks.MENU_SELECT, "Menu Select"),
 | 
						|
    "sfx_nightfall":        assemble_sfx_option(sfx.SoundHooks.NIGHTFALL, "Nightfall"),
 | 
						|
    "sfx_horse_neigh":      assemble_sfx_option(sfx.SoundHooks.HORSE_NEIGH, "Horse"),
 | 
						|
    "sfx_hover_boots":      assemble_sfx_option(sfx.SoundHooks.BOOTS_HOVER, "Hover Boots"),
 | 
						|
    "sfx_ocarina":          SfxOcarina,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# All options assembled into a single dict
 | 
						|
oot_options: typing.Dict[str, type(Option)] = {
 | 
						|
    "logic_rules": Logic, 
 | 
						|
    "logic_no_night_tokens_without_suns_song": NightTokens, 
 | 
						|
    **open_options, 
 | 
						|
    **world_options, 
 | 
						|
    **bridge_options,
 | 
						|
    **dungeon_items_options,
 | 
						|
    **lacs_options,
 | 
						|
    **shuffle_options,
 | 
						|
    **timesavers_options,
 | 
						|
    **misc_options, 
 | 
						|
    **itempool_options,
 | 
						|
    **cosmetic_options,
 | 
						|
    **sfx_options,
 | 
						|
    "logic_tricks": OptionList,
 | 
						|
}
 |