Remove temporary solution "OptionSets" in favor of AutoWorld's Options

This commit is contained in:
Fabian Dill 2021-07-04 16:18:21 +02:00
parent 2530d28c9d
commit 7d5b20ccfc
13 changed files with 145 additions and 156 deletions

View File

@ -142,17 +142,13 @@ class MultiWorld():
def set_options(self, args):
import Options
from worlds import AutoWorld
for option_set in Options.option_sets:
for option in option_set:
setattr(self, option, getattr(args, option, {}))
for world in AutoWorld.AutoWorldRegister.world_types.values():
for option in world.options:
setattr(self, option, getattr(args, option, {}))
for player in self.player_ids:
self.custom_data[player] = {}
self.worlds[player] = AutoWorld.AutoWorldRegister.world_types[self.game[player]](self, player)
world_type = AutoWorld.AutoWorldRegister.world_types[self.game[player]]
for option in world_type.options:
setattr(self, option, getattr(args, option, {}))
self.worlds[player] = world_type(self, player)
def secure(self):
self.random = secrets.SystemRandom()

View File

@ -9,6 +9,7 @@ from collections import Counter
import string
import ModuleUpdate
from worlds.alttp import Options as LttPOptions
from worlds.generic import PlandoItem, PlandoConnection
ModuleUpdate.update()
@ -546,9 +547,7 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
ret.startinventory = startitems
ret.start_hints = set(game_weights.get('start_hints', []))
if ret.game == "A Link to the Past":
roll_alttp_settings(ret, game_weights, plando_options)
elif ret.game in AutoWorldRegister.world_types:
if ret.game in AutoWorldRegister.world_types:
for option_name, option in AutoWorldRegister.world_types[ret.game].options.items():
if option_name in game_weights:
if issubclass(option, Options.OptionDict):
@ -569,18 +568,14 @@ def roll_settings(weights: dict, plando_options: typing.Set[str] = frozenset(("b
get_choice("exit", placement),
get_choice("direction", placement, "both")
))
elif ret.game == "A Link to the Past":
roll_alttp_settings(ret, game_weights, plando_options)
else:
raise Exception(f"Unsupported game {ret.game}")
return ret
def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
for option_name, option in Options.alttp_options.items():
if option_name in weights:
setattr(ret, option_name, option.from_any(get_choice(option_name, weights)))
else:
setattr(ret, option_name, option(option.default))
glitches_required = get_choice('glitches_required', weights)
if glitches_required not in [None, 'none', 'no_logic', 'overworld_glitches', 'hybrid_major_glitches', 'minor_glitches']:
logging.warning("Only NMG, OWG, HMG and No Logic supported")
@ -631,7 +626,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
extra_pieces = get_choice('triforce_pieces_mode', weights, 'available')
ret.triforce_pieces_required = Options.TriforcePieces.from_any(get_choice('triforce_pieces_required', weights, 20))
ret.triforce_pieces_required = LttPOptions.TriforcePieces.from_any(get_choice('triforce_pieces_required', weights, 20))
# sum a percentage to required
if extra_pieces == 'percentage':
@ -639,7 +634,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
ret.triforce_pieces_available = int(round(ret.triforce_pieces_required * percentage, 0))
# vanilla mode (specify how many pieces are)
elif extra_pieces == 'available':
ret.triforce_pieces_available = Options.TriforcePieces.from_any(
ret.triforce_pieces_available = LttPOptions.TriforcePieces.from_any(
get_choice('triforce_pieces_available', weights, 30))
# required pieces + fixed extra
elif extra_pieces == 'extra':

View File

@ -21,38 +21,6 @@ class AssembleOptions(type):
name.startswith("alias_")})
return super(AssembleOptions, mcs).__new__(mcs, name, bases, attrs)
class AssembleCategoryPath(type):
def __new__(mcs, name, bases, attrs):
path = []
for base in bases:
if hasattr(base, "segment"):
path += base.segment
path += attrs["segment"]
attrs["path"] = path
return super(AssembleCategoryPath, mcs).__new__(mcs, name, bases, attrs)
class RootCategory(metaclass=AssembleCategoryPath):
segment = []
class LttPCategory(RootCategory):
segment = ["A Link to the Past"]
class LttPRomCategory(LttPCategory):
segment = ["rom"]
class FactorioCategory(RootCategory):
segment = ["Factorio"]
class MinecraftCategory(RootCategory):
segment = ["Minecraft"]
class Option(metaclass=AssembleOptions):
value: int
name_lookup: typing.Dict[int, str]
@ -216,98 +184,18 @@ class OptionDict(Option):
return str(self.value)
class Logic(Choice):
option_no_glitches = 0
option_minor_glitches = 1
option_overworld_glitches = 2
option_hybrid_major_glitches = 3
option_no_logic = 4
alias_owg = 2
alias_hmg = 3
class Objective(Choice):
option_crystals = 0
# option_pendants = 1
option_triforce_pieces = 2
option_pedestal = 3
option_bingo = 4
local_objective = Toggle # local triforce pieces, local dungeon prizes etc.
class Goal(Choice):
option_kill_ganon = 0
option_kill_ganon_and_gt_agahnim = 1
option_hand_in = 2
class Accessibility(Choice):
option_locations = 0
option_items = 1
option_beatable = 2
class Crystals(Range):
range_start = 0
range_end = 7
class CrystalsTower(Crystals):
default = 7
class CrystalsGanon(Crystals):
default = 7
class TriforcePieces(Range):
default = 30
range_start = 1
range_end = 90
class ShopItemSlots(Range):
range_start = 0
range_end = 30
class WorldState(Choice):
option_standard = 1
option_open = 0
option_inverted = 2
class Bosses(Choice):
option_vanilla = 0
option_simple = 1
option_full = 2
option_chaos = 3
option_singularity = 4
class Enemies(Choice):
option_vanilla = 0
option_shuffled = 1
option_chaos = 2
alttp_options: typing.Dict[str, type(Option)] = {
"crystals_needed_for_gt": CrystalsTower,
"crystals_needed_for_ganon": CrystalsGanon,
"shop_item_slots": ShopItemSlots,
}
# replace with World.options
option_sets = (
# minecraft_options,
# factorio_options,
alttp_options,
# hollow_knight_options
)
if __name__ == "__main__":
from worlds.alttp.Options import Logic
import argparse
mapshuffle = Toggle
compassshuffle = Toggle

View File

@ -1,4 +1,5 @@
import unittest
from argparse import Namespace
from BaseClasses import MultiWorld, CollectionState
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
@ -8,14 +9,16 @@ from worlds.alttp.Items import ItemFactory
from worlds.alttp.Regions import create_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from Options import alttp_options
from worlds import AutoWorld
class TestDungeon(unittest.TestCase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.starting_regions = [] # Where to start exploring
self.remove_exits = [] # Block dungeon exits
self.world.difficulty_requirements[1] = difficulties['normal']

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_inverted_entrances
@ -8,13 +10,16 @@ from worlds.alttp.Regions import mark_light_world_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestInverted(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.difficulty_requirements[1] = difficulties['normal']
self.world.mode[1] = "inverted"
create_inverted_regions(self.world, 1)

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_inverted_entrances
@ -8,13 +10,16 @@ from worlds.alttp.Regions import mark_light_world_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestInvertedMinor(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.mode[1] = "inverted"
self.world.logic[1] = "minorglitches"
self.world.difficulty_requirements[1] = difficulties['normal']

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_inverted_entrances
@ -8,14 +10,17 @@ from worlds.alttp.Regions import mark_light_world_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestInvertedOWG(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.logic[1] = "owglitches"
self.world.mode[1] = "inverted"
self.world.difficulty_requirements[1] = difficulties['normal']

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_entrances
@ -8,13 +10,16 @@ from worlds.alttp.Regions import create_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestMinor(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.logic[1] = "minorglitches"
self.world.difficulty_requirements[1] = difficulties['normal']
create_regions(self.world, 1)

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_entrances
@ -8,14 +10,17 @@ from worlds.alttp.Regions import create_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestVanillaOWG(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.difficulty_requirements[1] = difficulties['normal']
self.world.logic[1] = "owglitches"
create_regions(self.world, 1)

View File

@ -1,3 +1,5 @@
from argparse import Namespace
from BaseClasses import MultiWorld
from worlds.alttp.Dungeons import create_dungeons, get_dungeon_item_pool
from worlds.alttp.EntranceShuffle import link_entrances
@ -8,13 +10,15 @@ from worlds.alttp.Regions import create_regions
from worlds.alttp.Shops import create_shops
from worlds.alttp.Rules import set_rules
from test.TestBase import TestBase
from Options import alttp_options
from worlds import AutoWorld
class TestVanilla(TestBase):
def setUp(self):
self.world = MultiWorld(1)
for option_name, option in alttp_options.items():
setattr(self.world, option_name, {1: option.default})
args = Namespace()
for name, option in AutoWorld.AutoWorldRegister.world_types["A Link to the Past"].options.items():
setattr(args, name, {1: option.from_any(option.default)})
self.world.set_options(args)
self.world.logic[1] = "noglitches"
self.world.difficulty_requirements[1] = difficulties['normal']
create_regions(self.world, 1)

View File

@ -50,7 +50,7 @@ class World(metaclass=AutoWorldRegister):
"""Collect an item into state"""
if item.advancement:
state.prog_items[item.name, item.player] += 1
return True # indicate that a logical state change has occured
return True # indicate that a logical state change has occured
return False
def get_required_client_version(self) -> tuple:

77
worlds/alttp/Options.py Normal file
View File

@ -0,0 +1,77 @@
import typing
from Options import Choice, Range, Option
class Logic(Choice):
option_no_glitches = 0
option_minor_glitches = 1
option_overworld_glitches = 2
option_hybrid_major_glitches = 3
option_no_logic = 4
alias_owg = 2
alias_hmg = 3
class Objective(Choice):
option_crystals = 0
# option_pendants = 1
option_triforce_pieces = 2
option_pedestal = 3
option_bingo = 4
class Goal(Choice):
option_kill_ganon = 0
option_kill_ganon_and_gt_agahnim = 1
option_hand_in = 2
class Crystals(Range):
range_start = 0
range_end = 7
class CrystalsTower(Crystals):
default = 7
class CrystalsGanon(Crystals):
default = 7
class TriforcePieces(Range):
default = 30
range_start = 1
range_end = 90
class ShopItemSlots(Range):
range_start = 0
range_end = 30
class WorldState(Choice):
option_standard = 1
option_open = 0
option_inverted = 2
class Bosses(Choice):
option_vanilla = 0
option_simple = 1
option_full = 2
option_chaos = 3
option_singularity = 4
class Enemies(Choice):
option_vanilla = 0
option_shuffled = 1
option_chaos = 2
alttp_options: typing.Dict[str, type(Option)] = {
"crystals_needed_for_gt": CrystalsTower,
"crystals_needed_for_ganon": CrystalsGanon,
"shop_item_slots": ShopItemSlots,
}

View File

@ -2,10 +2,11 @@ from typing import Optional
from BaseClasses import Location, Item, CollectionState
from ..AutoWorld import World
from .Options import alttp_options
class ALTTPWorld(World):
game: str = "A Link to the Past"
options = alttp_options
def collect(self, state: CollectionState, item: Item) -> bool:
if item.name.startswith('Progressive '):
if 'Sword' in item.name: