Files
Grinch-AP/worlds/ladx/Options.py
2025-10-13 19:32:49 +02:00

672 lines
18 KiB
Python

from dataclasses import dataclass
import os.path
import typing
import logging
from Options import Choice, Toggle, DefaultOnToggle, Range, FreeText, PerGameCommonOptions, OptionGroup, Removed, StartInventoryPool
from collections import defaultdict
import Utils
DefaultOffToggle = Toggle
logger = logging.getLogger("Link's Awakening Logger")
class LADXROption:
def to_ladxr_option(self, all_options):
if not self.ladxr_name:
return None, None
return (self.ladxr_name, self.name_lookup[self.value].replace("_", ""))
class Logic(Choice, LADXROption):
"""
Affects where items are allowed to be placed.
**Normal:** Playable without using any tricks or glitches. Can require
knowledge from a vanilla playthrough, such as how to open Color Dungeon.
**Hard:** More advanced techniques may be required, but glitches are not.
Examples include tricky jumps, killing enemies with only pots.
**Glitched:** Advanced glitches and techniques may be required, but
extremely difficult or tedious tricks are not required. Examples include
Bomb Triggers, Super Jumps and Jesus Jumps.
**Hell:** Obscure knowledge and hard techniques may be required. Examples
include featherless jumping with boots and/or hookshot, sequential pit
buffers and unclipped superjumps. Things in here can be extremely hard to do
or very time consuming.
"""
display_name = "Logic"
rich_text_doc = True
ladxr_name = "logic"
# option_casual = 0
option_normal = 1
option_hard = 2
option_glitched = 3
option_hell = 4
default = option_normal
class TradeQuest(DefaultOffToggle, LADXROption):
"""
Trade quest items are randomized. Each NPC takes its normal trade quest
item and gives a randomized item in return.
"""
display_name = "Trade Quest"
ladxr_name = "tradequest"
class TextShuffle(DefaultOffToggle):
"""
Shuffles all text in the game.
"""
display_name = "Text Shuffle"
class Rooster(DefaultOnToggle, LADXROption):
"""
Adds the rooster to the item pool. If disabled, the overworld will be
modified so that any location requiring the rooster is accessible by other
means.
"""
display_name = "Rooster"
ladxr_name = "rooster"
class EntranceShuffle(Choice, LADXROption):
"""
Randomizes where overworld entrances lead.
**Simple:** Single-entrance caves/houses that have items are shuffled
amongst each other.
If *Dungeon Shuffle* is enabled, then dungeons will be shuffled with all the
non-connector entrances in the pool. Note, some entrances can lead into water, use
the warp-to-home from the save&quit menu to escape this.
"""
# [Advanced] Simple, but two-way connector caves are shuffled in their own pool as well.
# [Expert] Advanced, but caves/houses without items are also shuffled into the Simple entrance pool.
# [Insanity] Expert, but the Raft Minigame hut and Mamu's cave are added to the non-connector pool.
option_none = 0
option_simple = 1
# option_advanced = 2
# option_expert = 3
# option_insanity = 4
default = option_none
display_name = "Entrance Shuffle"
ladxr_name = "entranceshuffle"
rich_text_doc = True
class DungeonShuffle(DefaultOffToggle, LADXROption):
"""
Randomizes dungeon entrances with each other.
"""
display_name = "Dungeon Shuffle"
ladxr_name = "dungeonshuffle"
class APTitleScreen(DefaultOnToggle):
"""
Enables AP specific title screen and disables the intro cutscene.
"""
display_name = "AP Title Screen"
class BossShuffle(Choice):
display_name = "Boss Shuffle"
none = 0
shuffle = 1
random = 2
default = none
class DungeonItemShuffle(Choice):
display_name = "Dungeon Item Shuffle"
rich_text_doc = True
option_original_dungeon = 0
option_own_dungeons = 1
option_own_world = 2
option_any_world = 3
option_different_world = 4
# option_delete = 5
# option_start_with = 6
alias_true = 3
alias_false = 0
ladxr_item: str
class ShuffleNightmareKeys(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
"""
display_name = "Shuffle Nightmare Keys"
ladxr_item = "NIGHTMARE_KEY"
class ShuffleSmallKeys(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
"""
display_name = "Shuffle Small Keys"
ladxr_item = "KEY"
class ShuffleMaps(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
"""
display_name = "Shuffle Maps"
ladxr_item = "MAP"
class ShuffleCompasses(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
"""
display_name = "Shuffle Compasses"
ladxr_item = "COMPASS"
class ShuffleStoneBeaks(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
"""
display_name = "Shuffle Stone Beaks"
ladxr_item = "STONE_BEAK"
class ShuffleInstruments(DungeonItemShuffle):
"""
**Original Dungeon:** The item will be within its original dungeon.
**Own Dungeons:** The item will be within a dungeon in your world.
**Own World:** The item will be somewhere in your world.
**Any World:** The item could be anywhere.
**Different World:** The item will be somewhere in another world.
**Vanilla:** The item will be in its vanilla location in your world.
"""
display_name = "Shuffle Instruments"
ladxr_item = "INSTRUMENT"
default = 100
option_vanilla = 100
alias_false = 100
class Goal(Choice, LADXROption):
"""
The Goal of the game.
**Instruments:** The Wind Fish's Egg will only open if you have the required
number of Instruments of the Sirens, and play the Ballad of the Wind Fish.
**Seashells:** The Egg will open when you bring 20 seashells. The Ballad and
Ocarina are not needed.
**Open:** The Egg will start pre-opened.
"""
display_name = "Goal"
rich_text_doc = True
ladxr_name = "goal"
option_instruments = 1
option_seashells = 2
option_open = 3
default = option_instruments
def to_ladxr_option(self, all_options):
if self.value == self.option_instruments:
return ("goal", all_options["instrument_count"])
else:
return LADXROption.to_ladxr_option(self, all_options)
class InstrumentCount(Range, LADXROption):
"""
Sets the number of instruments required to open the Egg.
"""
display_name = "Instrument Count"
ladxr_name = None
range_start = 0
range_end = 8
default = 8
class NagMessages(DefaultOffToggle, LADXROption):
"""
Controls if nag messages are shown when rocks and crystals are touched.
Useful for glitches, annoying for everything else.
"""
display_name = "Nag Messages"
ladxr_name = "nagmessages"
class MusicChangeCondition(Choice):
"""
Controls how the music changes.
**Sword:** When you pick up a sword, the music changes.
**Always:** You always have the post-sword music.
"""
display_name = "Music Change Condition"
rich_text_doc = True
option_sword = 0
option_always = 1
default = option_always
class HardMode(Choice, LADXROption):
"""
**Oracle:** Less iframes and health from drops. Bombs damage yourself. Water
damages you without flippers. No pieces of power or acorns.
**Hero:** Switch version hero mode, double damage, no heart/fairy drops.
**OHKO:** You die on a single hit, always.
"""
display_name = "Hard Mode"
ladxr_name = "hardmode"
rich_text_doc = True
option_none = 0
option_oracle = 1
option_hero = 2
option_ohko = 3
default = option_none
class Overworld(Choice, LADXROption):
"""
**Open Mabe:** Replaces rock on the east side of Mabe Village with bushes,
allowing access to Ukuku Prairie without Power Bracelet.
"""
display_name = "Overworld"
ladxr_name = "overworld"
rich_text_doc = True
option_normal = 0
option_open_mabe = 1
default = option_normal
class Quickswap(Choice, LADXROption):
"""
Instead of opening the map, the *SELECT* button swaps the top item of your inventory on to your *A* or *B* button.
"""
display_name = "Quickswap"
ladxr_name = "quickswap"
rich_text_doc = True
option_none = 0
option_a = 1
option_b = 2
default = option_none
class TextMode(Choice, LADXROption):
"""
**Fast:** Makes text appear twice as fast.
"""
display_name = "Text Mode"
ladxr_name = "textmode"
rich_text_doc = True
option_normal = 0
option_fast = 1
default = option_fast
class LowHpBeep(Choice, LADXROption):
"""
Slows or disables the low health beeping sound.
"""
display_name = "Low HP Beep"
ladxr_name = "lowhpbeep"
option_default = 0
option_slow = 1
option_none = 2
default = option_default
class NoFlash(DefaultOnToggle, LADXROption):
"""
Remove the flashing light effects from Mamu, shopkeeper and MadBatter.
Useful for capture cards and people that are sensitive to these things.
"""
display_name = "No Flash"
ladxr_name = "noflash"
class BootsControls(Choice):
"""
Adds an additional button to activate Pegasus Boots (does nothing if you
haven't picked up your boots!)
**Vanilla:** Nothing changes, you have to equip the boots to use them.
**Bracelet:** Holding down the button for the bracelet also activates boots
(somewhat like Link to the Past).
**Press A:** Holding down A activates boots.
**Press B:** Holding down B activates boots.
"""
display_name = "Boots Controls"
rich_text_doc = True
option_vanilla = 0
option_bracelet = 1
option_press_a = 2
alias_a = 2
option_press_b = 3
alias_b = 3
class LinkPalette(Choice, LADXROption):
"""
Sets Link's palette.
A-D are color palettes usually used during the damage animation and can
change based on where you are.
"""
display_name = "Link's Palette"
ladxr_name = "linkspalette"
option_normal = -1
option_green = 0
option_yellow = 1
option_red = 2
option_blue = 3
option_invert_a = 4
option_invert_b = 5
option_invert_c = 6
option_invert_d = 7
default = option_normal
def to_ladxr_option(self, all_options):
return self.ladxr_name, str(self.value)
class TrendyGame(Choice):
"""
**Easy:** All of the items hold still for you.
**Normal:** The vanilla behavior.
**Hard:** The trade item also moves.
**Harder:** The items move faster.
**Hardest:** The items move diagonally.
**Impossible:** The items move impossibly fast, may scroll on and off the
screen.
"""
display_name = "Trendy Game"
rich_text_doc = True
option_easy = 0
option_normal = 1
option_hard = 2
option_harder = 3
option_hardest = 4
option_impossible = 5
default = option_normal
class GfxMod(DefaultOffToggle):
"""
If enabled, the patcher will prompt the user for a modification file to change sprites in the game and optionally some text.
"""
display_name = "GFX Modification"
class Palette(Choice):
"""
Sets the palette for the game.
Note: A few places aren't patched, such as the menu and a few color dungeon
tiles.
**Normal:** The vanilla palette.
**1-Bit:** One bit of color per channel.
**2-Bit:** Two bits of color per channel.
**Greyscale:** Shades of grey.
**Pink:** Aesthetic.
**Inverted:** Inverted.
"""
display_name = "Palette"
rich_text_doc = True
option_normal = 0
option_1bit = 1
option_2bit = 2
option_greyscale = 3
option_pink = 4
option_inverted = 5
class Music(Choice, LADXROption):
"""
**Vanilla:** Regular Music
**Shuffled:** Shuffled Music
**Off:** No music
"""
display_name = "Music"
ladxr_name = "music"
rich_text_doc = True
option_vanilla = 0
option_shuffled = 1
option_off = 2
def to_ladxr_option(self, all_options):
s = ""
if self.value == self.option_shuffled:
s = "random"
elif self.value == self.option_off:
s = "off"
return self.ladxr_name, s
class Warps(Choice):
"""
**Improved:** Adds remake style warp screen to the game. Choose your warp
destination on the map after jumping in a portal and press *B* to select.
**Improved Additional:** Improved warps, and adds a warp point at Crazy
Tracy's house (the Mambo teleport spot) and Eagle's Tower.
"""
display_name = "Warps"
rich_text_doc = True
option_vanilla = 0
option_improved = 1
option_improved_additional = 2
default = option_vanilla
class InGameHints(DefaultOnToggle):
"""
When enabled, owl statues and library books may indicate the location of
your items in the multiworld.
"""
display_name = "In-game Hints"
class TarinsGift(Choice):
"""
**Local Progression:** Forces Tarin's gift to be an item that immediately
opens up local checks. Has little effect in single player games, and isn't
always necessary with randomized entrances.
**Bush Breaker:** Forces Tarin's gift to be an item that can destroy bushes.
**Any Item:** Tarin's gift can be any item for any world
"""
display_name = "Tarin's Gift"
rich_text_doc = True
option_local_progression = 0
option_bush_breaker = 1
option_any_item = 2
default = option_local_progression
class StabilizeItemPool(DefaultOffToggle):
"""
By default, some rupees in the item pool are randomly swapped with bombs,
arrows, powders, or capacity upgrades. This set of items is also used as
filler. This option disables that swapping and makes *Nothing* the filler
item.
"""
display_name = "Stabilize Item Pool"
rich_text_doc = True
class ForeignItemIcons(Choice):
"""
Choose how to display foreign items.
**Guess By Name:** Foreign items can look like any Link's Awakening item.
**Indicate Progression:** Foreign items are either a Piece of Power
(progression) or Guardian Acorn (non-progression).
"""
display_name = "Foreign Item Icons"
rich_text_doc = True
option_guess_by_name = 0
option_indicate_progression = 1
default = option_guess_by_name
ladx_option_groups = [
OptionGroup("Gameplay Adjustments", [
InGameHints,
TarinsGift,
HardMode,
TrendyGame,
]),
OptionGroup("World Layout", [
Overworld,
Warps,
DungeonShuffle,
EntranceShuffle,
]),
OptionGroup("Item Pool", [
ShuffleInstruments,
ShuffleNightmareKeys,
ShuffleSmallKeys,
ShuffleMaps,
ShuffleCompasses,
ShuffleStoneBeaks,
TradeQuest,
Rooster,
StabilizeItemPool,
]),
OptionGroup("Quality of Life & Aesthetic", [
NagMessages,
Quickswap,
BootsControls,
ForeignItemIcons,
GfxMod,
LinkPalette,
Palette,
APTitleScreen,
TextShuffle,
TextMode,
Music,
MusicChangeCondition,
LowHpBeep,
NoFlash,
])
]
@dataclass
class LinksAwakeningOptions(PerGameCommonOptions):
logic: Logic
tradequest: TradeQuest
rooster: Rooster
experimental_dungeon_shuffle: DungeonShuffle
experimental_entrance_shuffle: EntranceShuffle
goal: Goal
instrument_count: InstrumentCount
link_palette: LinkPalette
warps: Warps
trendy_game: TrendyGame
gfxmod: GfxMod
palette: Palette
text_shuffle: TextShuffle
foreign_item_icons: ForeignItemIcons
shuffle_nightmare_keys: ShuffleNightmareKeys
shuffle_small_keys: ShuffleSmallKeys
shuffle_maps: ShuffleMaps
shuffle_compasses: ShuffleCompasses
shuffle_stone_beaks: ShuffleStoneBeaks
music: Music
shuffle_instruments: ShuffleInstruments
music_change_condition: MusicChangeCondition
nag_messages: NagMessages
ap_title_screen: APTitleScreen
boots_controls: BootsControls
quickswap: Quickswap
hard_mode: HardMode
low_hp_beep: LowHpBeep
text_mode: TextMode
no_flash: NoFlash
in_game_hints: InGameHints
tarins_gift: TarinsGift
overworld: Overworld
stabilize_item_pool: StabilizeItemPool
start_inventory_from_pool: StartInventoryPool
warp_improvements: Removed
additional_warp_points: Removed