implement Range option type

This commit is contained in:
Fabian Dill 2021-06-08 14:15:23 +02:00
parent 4b5ac3f926
commit adda0eff4a
4 changed files with 42 additions and 30 deletions

View File

@ -94,12 +94,8 @@ def main(args, seed=None):
world.compassshuffle = args.compassshuffle.copy()
world.keyshuffle = args.keyshuffle.copy()
world.bigkeyshuffle = args.bigkeyshuffle.copy()
world.crystals_needed_for_ganon = {
player: world.random.randint(0, 7) if args.crystals_ganon[player] == 'random' else int(
args.crystals_ganon[player]) for player in range(1, world.players + 1)}
world.crystals_needed_for_gt = {
player: world.random.randint(0, 7) if args.crystals_gt[player] == 'random' else int(args.crystals_gt[player])
for player in range(1, world.players + 1)}
world.crystals_needed_for_ganon = args.crystals_ganon.copy()
world.crystals_needed_for_gt = args.crystals_gt.copy()
world.open_pyramid = args.open_pyramid.copy()
world.boss_shuffle = args.shufflebosses.copy()
world.enemy_shuffle = args.enemy_shuffle.copy()

View File

@ -632,14 +632,12 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
# fast ganon + ganon at hole
ret.open_pyramid = get_choice('open_pyramid', weights, 'goal')
ret.crystals_gt = prefer_int(get_choice('tower_open', weights))
ret.crystals_ganon = prefer_int(get_choice('ganon_open', weights))
ret.crystals_gt = Options.Crystals.from_any(get_choice('tower_open', weights)).value
ret.crystals_ganon = Options.Crystals.from_any(get_choice('ganon_open', weights)).value
extra_pieces = get_choice('triforce_pieces_mode', weights, 'available')
ret.triforce_pieces_required = int(get_choice('triforce_pieces_required', weights, 20))
ret.triforce_pieces_required = min(max(1, int(ret.triforce_pieces_required)), 90)
ret.triforce_pieces_required = Options.TriforcePieces.from_any(get_choice('triforce_pieces_required', weights)).value
# sum a percentage to required
if extra_pieces == 'percentage':
@ -647,7 +645,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 = int(get_choice('triforce_pieces_available', weights, 30))
ret.triforce_pieces_available = Options.TriforcePieces.from_any(get_choice('triforce_pieces_available', weights)).value
# required pieces + fixed extra
elif extra_pieces == 'extra':
extra_pieces = max(0, int(get_choice('triforce_pieces_extra', weights, 10)))
@ -655,11 +653,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
# change minimum to required pieces to avoid problems
ret.triforce_pieces_available = min(max(ret.triforce_pieces_required, int(ret.triforce_pieces_available)), 90)
shuffle_slots = get_choice('shop_shuffle_slots', weights, '0')
if str(shuffle_slots).lower() == "random":
ret.shop_shuffle_slots = random.randint(0, 30)
else:
ret.shop_shuffle_slots = int(shuffle_slots)
ret.shop_shuffle_slots = Options.TriforcePieces.from_any(get_choice('shop_shuffle_slots', weights)).value
ret.shop_shuffle = get_choice('shop_shuffle', weights, '')
if not ret.shop_shuffle:

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import typing
import random
class AssembleOptions(type):
@ -108,6 +109,29 @@ class Choice(Option):
return cls(data)
return cls.from_text(str(data))
class Range(Option):
range_start = 0
range_end = 1
def __init__(self, value: typing.Union[str, int]):
self.value: typing.Union[str, int] = value
@classmethod
def from_text(cls, text: str) -> Range:
if text.lower() == "random":
return cls(random.randint(cls.range_start, cls.range_end))
number = int(text)
if number < cls.range_start:
raise Exception(f"{number} is lower than minimum {cls.range_start} for option {cls.__name__}")
elif number > cls.range_end:
raise Exception(f"{number} is higher than maximum {cls.range_end} for option {cls.__name__}")
else:
return cls(number)
@classmethod
def from_any(cls, data: typing.Any) -> Range:
if type(data) == int:
return cls(data)
return cls.from_text(str(data))
class OptionNameSet(Option):
default = frozenset()
@ -173,18 +197,17 @@ class Accessibility(Choice):
option_beatable = 2
class Crystals(Choice):
# can't use IntEnum since there's also random
option_0 = 0
option_1 = 1
option_2 = 2
option_3 = 3
option_4 = 4
option_5 = 5
option_6 = 6
option_7 = 7
option_random = -1
class Crystals(Range):
range_start = 0
range_end = 7
class TriforcePieces(Range):
range_start = 1
range_end = 90
class ShopShuffleSlots(Range):
range_start = 0
range_end = 30
class WorldState(Choice):
option_standard = 1

View File

@ -206,11 +206,10 @@ def parse_arguments(argv, no_defaults=False):
0-7: Number of crystals needed
''')
parser.add_argument('--crystals_gt', default=defval('7'), const='7', nargs='?',
choices=['random', '0', '1', '2', '3', '4', '5', '6', '7'],
choices=['0', '1', '2', '3', '4', '5', '6', '7'],
help='''\
How many crystals are needed to open GT. For inverted mode
this applies to the castle tower door instead. (default: %(default)s)
Random: Picks a random value between 0 and 7 (inclusive).
0-7: Number of crystals needed
''')
parser.add_argument('--open_pyramid', default=defval('auto'), help='''\