LTTP: sort of use new options system (#3764)

* LttP: switch to dataclass options definition

* LttP: write old options onto multiworld
LttP: use World.random
This commit is contained in:
Fabian Dill 2024-11-29 05:02:26 +01:00 committed by GitHub
parent ce210cd4ee
commit 30b414429f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 109 additions and 101 deletions

View File

@ -1,7 +1,7 @@
import typing from dataclasses import dataclass
from BaseClasses import MultiWorld from BaseClasses import MultiWorld
from Options import Choice, Range, DeathLink, DefaultOnToggle, FreeText, ItemsAccessibility, Option, \ from Options import Choice, Range, DeathLink, DefaultOnToggle, FreeText, ItemsAccessibility, PerGameCommonOptions, \
PlandoBosses, PlandoConnections, PlandoTexts, Removed, StartInventoryPool, Toggle PlandoBosses, PlandoConnections, PlandoTexts, Removed, StartInventoryPool, Toggle
from .EntranceShuffle import default_connections, default_dungeon_connections, \ from .EntranceShuffle import default_connections, default_dungeon_connections, \
inverted_default_connections, inverted_default_dungeon_connections inverted_default_connections, inverted_default_dungeon_connections
@ -742,86 +742,86 @@ class ALttPPlandoTexts(PlandoTexts):
valid_keys = TextTable.valid_keys valid_keys = TextTable.valid_keys
alttp_options: typing.Dict[str, type(Option)] = { @dataclass
"accessibility": ItemsAccessibility, class ALTTPOptions(PerGameCommonOptions):
"plando_connections": ALttPPlandoConnections, accessibility: ItemsAccessibility
"plando_texts": ALttPPlandoTexts, plando_connections: ALttPPlandoConnections
"start_inventory_from_pool": StartInventoryPool, plando_texts: ALttPPlandoTexts
"goal": Goal, start_inventory_from_pool: StartInventoryPool
"mode": Mode, goal: Goal
"glitches_required": GlitchesRequired, mode: Mode
"dark_room_logic": DarkRoomLogic, glitches_required: GlitchesRequired
"open_pyramid": OpenPyramid, dark_room_logic: DarkRoomLogic
"crystals_needed_for_gt": CrystalsTower, open_pyramid: OpenPyramid
"crystals_needed_for_ganon": CrystalsGanon, crystals_needed_for_gt: CrystalsTower
"triforce_pieces_mode": TriforcePiecesMode, crystals_needed_for_ganon: CrystalsGanon
"triforce_pieces_percentage": TriforcePiecesPercentage, triforce_pieces_mode: TriforcePiecesMode
"triforce_pieces_required": TriforcePiecesRequired, triforce_pieces_percentage: TriforcePiecesPercentage
"triforce_pieces_available": TriforcePiecesAvailable, triforce_pieces_required: TriforcePiecesRequired
"triforce_pieces_extra": TriforcePiecesExtra, triforce_pieces_available: TriforcePiecesAvailable
"entrance_shuffle": EntranceShuffle, triforce_pieces_extra: TriforcePiecesExtra
"entrance_shuffle_seed": EntranceShuffleSeed, entrance_shuffle: EntranceShuffle
"big_key_shuffle": big_key_shuffle, entrance_shuffle_seed: EntranceShuffleSeed
"small_key_shuffle": small_key_shuffle, big_key_shuffle: big_key_shuffle
"key_drop_shuffle": key_drop_shuffle, small_key_shuffle: small_key_shuffle
"compass_shuffle": compass_shuffle, key_drop_shuffle: key_drop_shuffle
"map_shuffle": map_shuffle, compass_shuffle: compass_shuffle
"restrict_dungeon_item_on_boss": RestrictBossItem, map_shuffle: map_shuffle
"item_pool": ItemPool, restrict_dungeon_item_on_boss: RestrictBossItem
"item_functionality": ItemFunctionality, item_pool: ItemPool
"enemy_health": EnemyHealth, item_functionality: ItemFunctionality
"enemy_damage": EnemyDamage, enemy_health: EnemyHealth
"progressive": Progressive, enemy_damage: EnemyDamage
"swordless": Swordless, progressive: Progressive
"dungeon_counters": DungeonCounters, swordless: Swordless
"retro_bow": RetroBow, dungeon_counters: DungeonCounters
"retro_caves": RetroCaves, retro_bow: RetroBow
"hints": Hints, retro_caves: RetroCaves
"scams": Scams, hints: Hints
"boss_shuffle": LTTPBosses, scams: Scams
"pot_shuffle": PotShuffle, boss_shuffle: LTTPBosses
"enemy_shuffle": EnemyShuffle, pot_shuffle: PotShuffle
"killable_thieves": KillableThieves, enemy_shuffle: EnemyShuffle
"bush_shuffle": BushShuffle, killable_thieves: KillableThieves
"shop_item_slots": ShopItemSlots, bush_shuffle: BushShuffle
"randomize_shop_inventories": RandomizeShopInventories, shop_item_slots: ShopItemSlots
"shuffle_shop_inventories": ShuffleShopInventories, randomize_shop_inventories: RandomizeShopInventories
"include_witch_hut": IncludeWitchHut, shuffle_shop_inventories: ShuffleShopInventories
"randomize_shop_prices": RandomizeShopPrices, include_witch_hut: IncludeWitchHut
"randomize_cost_types": RandomizeCostTypes, randomize_shop_prices: RandomizeShopPrices
"shop_price_modifier": ShopPriceModifier, randomize_cost_types: RandomizeCostTypes
"shuffle_capacity_upgrades": ShuffleCapacityUpgrades, shop_price_modifier: ShopPriceModifier
"bombless_start": BomblessStart, shuffle_capacity_upgrades: ShuffleCapacityUpgrades
"shuffle_prizes": ShufflePrizes, bombless_start: BomblessStart
"tile_shuffle": TileShuffle, shuffle_prizes: ShufflePrizes
"misery_mire_medallion": MiseryMireMedallion, tile_shuffle: TileShuffle
"turtle_rock_medallion": TurtleRockMedallion, misery_mire_medallion: MiseryMireMedallion
"glitch_boots": GlitchBoots, turtle_rock_medallion: TurtleRockMedallion
"beemizer_total_chance": BeemizerTotalChance, glitch_boots: GlitchBoots
"beemizer_trap_chance": BeemizerTrapChance, beemizer_total_chance: BeemizerTotalChance
"timer": Timer, beemizer_trap_chance: BeemizerTrapChance
"countdown_start_time": CountdownStartTime, timer: Timer
"red_clock_time": RedClockTime, countdown_start_time: CountdownStartTime
"blue_clock_time": BlueClockTime, red_clock_time: RedClockTime
"green_clock_time": GreenClockTime, blue_clock_time: BlueClockTime
"death_link": DeathLink, green_clock_time: GreenClockTime
"allow_collect": AllowCollect, death_link: DeathLink
"ow_palettes": OWPalette, allow_collect: AllowCollect
"uw_palettes": UWPalette, ow_palettes: OWPalette
"hud_palettes": HUDPalette, uw_palettes: UWPalette
"sword_palettes": SwordPalette, hud_palettes: HUDPalette
"shield_palettes": ShieldPalette, sword_palettes: SwordPalette
# "link_palettes": LinkPalette, shield_palettes: ShieldPalette
"heartbeep": HeartBeep, # link_palettes: LinkPalette
"heartcolor": HeartColor, heartbeep: HeartBeep
"quickswap": QuickSwap, heartcolor: HeartColor
"menuspeed": MenuSpeed, quickswap: QuickSwap
"music": Music, menuspeed: MenuSpeed
"reduceflashing": ReduceFlashing, music: Music
"triforcehud": TriforceHud, reduceflashing: ReduceFlashing
triforcehud: TriforceHud
# removed: # removed:
"goals": Removed, goals: Removed
"smallkey_shuffle": Removed, smallkey_shuffle: Removed
"bigkey_shuffle": Removed, bigkey_shuffle: Removed
}

View File

@ -782,8 +782,8 @@ def get_nonnative_item_sprite(code: int) -> int:
def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool): def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
local_random = world.per_slot_randoms[player]
local_world = world.worlds[player] local_world = world.worlds[player]
local_random = local_world.random
# patch items # patch items
@ -1867,7 +1867,7 @@ def apply_oof_sfx(rom, oof: str):
def apply_rom_settings(rom, beep, color, quickswap, menuspeed, music: bool, sprite: str, oof: str, palettes_options, def apply_rom_settings(rom, beep, color, quickswap, menuspeed, music: bool, sprite: str, oof: str, palettes_options,
world=None, player=1, allow_random_on_event=False, reduceflashing=False, world=None, player=1, allow_random_on_event=False, reduceflashing=False,
triforcehud: str = None, deathlink: bool = False, allowcollect: bool = False): triforcehud: str = None, deathlink: bool = False, allowcollect: bool = False):
local_random = random if not world else world.per_slot_randoms[player] local_random = random if not world else world.worlds[player].random
disable_music: bool = not music disable_music: bool = not music
# enable instant item menu # enable instant item menu
if menuspeed == 'instant': if menuspeed == 'instant':
@ -2197,8 +2197,9 @@ def write_string_to_rom(rom, target, string):
def write_strings(rom, world, player): def write_strings(rom, world, player):
from . import ALTTPWorld from . import ALTTPWorld
local_random = world.per_slot_randoms[player]
w: ALTTPWorld = world.worlds[player] w: ALTTPWorld = world.worlds[player]
local_random = w.random
tt = TextTable() tt = TextTable()
tt.removeUnwantedText() tt.removeUnwantedText()
@ -2425,7 +2426,7 @@ def write_strings(rom, world, player):
if world.worlds[player].has_progressive_bows and (w.difficulty_requirements.progressive_bow_limit >= 2 or ( if world.worlds[player].has_progressive_bows and (w.difficulty_requirements.progressive_bow_limit >= 2 or (
world.swordless[player] or world.glitches_required[player] == 'no_glitches')): world.swordless[player] or world.glitches_required[player] == 'no_glitches')):
prog_bow_locs = world.find_item_locations('Progressive Bow', player, True) prog_bow_locs = world.find_item_locations('Progressive Bow', player, True)
world.per_slot_randoms[player].shuffle(prog_bow_locs) local_random.shuffle(prog_bow_locs)
found_bow = False found_bow = False
found_bow_alt = False found_bow_alt = False
while prog_bow_locs and not (found_bow and found_bow_alt): while prog_bow_locs and not (found_bow and found_bow_alt):

View File

@ -1,28 +1,27 @@
import logging import logging
import os import os
import random import random
import settings
import threading import threading
import typing import typing
import Utils import settings
from BaseClasses import Item, CollectionState, Tutorial, MultiWorld from BaseClasses import Item, CollectionState, Tutorial, MultiWorld
from worlds.AutoWorld import World, WebWorld, LogicMixin
from .Client import ALTTPSNIClient
from .Dungeons import create_dungeons, Dungeon from .Dungeons import create_dungeons, Dungeon
from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect from .EntranceShuffle import link_entrances, link_inverted_entrances, plando_connect
from .InvertedRegions import create_inverted_regions, mark_dark_world_regions from .InvertedRegions import create_inverted_regions, mark_dark_world_regions
from .ItemPool import generate_itempool, difficulties from .ItemPool import generate_itempool, difficulties
from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem from .Items import item_init_table, item_name_groups, item_table, GetBeemizerItem
from .Options import alttp_options, small_key_shuffle from .Options import ALTTPOptions, small_key_shuffle
from .Regions import lookup_name_to_id, create_regions, mark_light_world_regions, lookup_vanilla_location_to_entrance, \ from .Regions import lookup_name_to_id, create_regions, mark_light_world_regions, lookup_vanilla_location_to_entrance, \
is_main_entrance, key_drop_data is_main_entrance, key_drop_data
from .Client import ALTTPSNIClient
from .Rom import LocalRom, patch_rom, patch_race_rom, check_enemizer, patch_enemizer, apply_rom_settings, \ from .Rom import LocalRom, patch_rom, patch_race_rom, check_enemizer, patch_enemizer, apply_rom_settings, \
get_hash_string, get_base_rom_path, LttPDeltaPatch get_hash_string, get_base_rom_path, LttPDeltaPatch
from .Rules import set_rules from .Rules import set_rules
from .Shops import create_shops, Shop, push_shop_inventories, ShopType, price_rate_display, price_type_display_name from .Shops import create_shops, Shop, push_shop_inventories, ShopType, price_rate_display, price_type_display_name
from .SubClasses import ALttPItem, LTTPRegionType
from worlds.AutoWorld import World, WebWorld, LogicMixin
from .StateHelpers import can_buy_unlimited from .StateHelpers import can_buy_unlimited
from .SubClasses import ALttPItem, LTTPRegionType
lttp_logger = logging.getLogger("A Link to the Past") lttp_logger = logging.getLogger("A Link to the Past")
@ -132,7 +131,8 @@ class ALTTPWorld(World):
Ganon! Ganon!
""" """
game = "A Link to the Past" game = "A Link to the Past"
option_definitions = alttp_options options_dataclass = ALTTPOptions
options: ALTTPOptions
settings_key = "lttp_options" settings_key = "lttp_options"
settings: typing.ClassVar[ALTTPSettings] settings: typing.ClassVar[ALTTPSettings]
topology_present = True topology_present = True
@ -286,13 +286,22 @@ class ALTTPWorld(World):
if not os.path.exists(rom_file): if not os.path.exists(rom_file):
raise FileNotFoundError(rom_file) raise FileNotFoundError(rom_file)
if multiworld.is_race: if multiworld.is_race:
import xxtea import xxtea # noqa
for player in multiworld.get_game_players(cls.game): for player in multiworld.get_game_players(cls.game):
if multiworld.worlds[player].use_enemizer: if multiworld.worlds[player].use_enemizer:
check_enemizer(multiworld.worlds[player].enemizer_path) check_enemizer(multiworld.worlds[player].enemizer_path)
break break
def generate_early(self): def generate_early(self):
# write old options
import dataclasses
is_first = self.player == min(self.multiworld.get_game_players(self.game))
for field in dataclasses.fields(self.options_dataclass):
if is_first:
setattr(self.multiworld, field.name, {})
getattr(self.multiworld, field.name)[self.player] = getattr(self.options, field.name)
# end of old options re-establisher
player = self.player player = self.player
multiworld = self.multiworld multiworld = self.multiworld
@ -536,12 +545,10 @@ class ALTTPWorld(World):
@property @property
def use_enemizer(self) -> bool: def use_enemizer(self) -> bool:
world = self.multiworld return bool(self.options.boss_shuffle or self.options.enemy_shuffle
player = self.player or self.options.enemy_health != 'default' or self.options.enemy_damage != 'default'
return bool(world.boss_shuffle[player] or world.enemy_shuffle[player] or self.options.pot_shuffle or self.options.bush_shuffle
or world.enemy_health[player] != 'default' or world.enemy_damage[player] != 'default' or self.options.killable_thieves)
or world.pot_shuffle[player] or world.bush_shuffle[player]
or world.killable_thieves[player])
def generate_output(self, output_directory: str): def generate_output(self, output_directory: str):
multiworld = self.multiworld multiworld = self.multiworld