Core: auto alias (#1022)
* Test: check that default templates can be parsed into Option objects
This commit is contained in:
parent
156e9e0e43
commit
af11fa5150
|
@ -26,13 +26,18 @@ class AssembleOptions(abc.ABCMeta):
|
||||||
|
|
||||||
attrs["name_lookup"].update({option_id: name for name, option_id in new_options.items()})
|
attrs["name_lookup"].update({option_id: name for name, option_id in new_options.items()})
|
||||||
options.update(new_options)
|
options.update(new_options)
|
||||||
|
|
||||||
# apply aliases, without name_lookup
|
# apply aliases, without name_lookup
|
||||||
aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if
|
aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if
|
||||||
name.startswith("alias_")}
|
name.startswith("alias_")}
|
||||||
|
|
||||||
assert "random" not in aliases, "Choice option 'random' cannot be manually assigned."
|
assert "random" not in aliases, "Choice option 'random' cannot be manually assigned."
|
||||||
|
|
||||||
|
# auto-alias Off and On being parsed as True and False
|
||||||
|
if "off" in options:
|
||||||
|
options["false"] = options["off"]
|
||||||
|
if "on" in options:
|
||||||
|
options["true"] = options["on"]
|
||||||
|
|
||||||
options.update(aliases)
|
options.update(aliases)
|
||||||
|
|
||||||
# auto-validate schema on __init__
|
# auto-validate schema on __init__
|
||||||
|
|
|
@ -274,14 +274,12 @@ Define a property `option_<name> = <number>` per selectable value and
|
||||||
`default = <number>` to set the default selection. Aliases can be set by
|
`default = <number>` to set the default selection. Aliases can be set by
|
||||||
defining a property `alias_<name> = <same number>`.
|
defining a property `alias_<name> = <same number>`.
|
||||||
|
|
||||||
One special case where aliases are required is when option name is `yes`, `no`,
|
|
||||||
`on` or `off` because they parse to `True` or `False`:
|
|
||||||
```python
|
```python
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_on = 1
|
option_on = 1
|
||||||
option_some = 2
|
option_some = 2
|
||||||
alias_false = 0
|
alias_disabled = 0
|
||||||
alias_true = 1
|
alias_enabled = 1
|
||||||
default = 0
|
default = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,20 @@ class TestFileGeneration(unittest.TestCase):
|
||||||
|
|
||||||
def testOptions(self):
|
def testOptions(self):
|
||||||
WebHost.create_options_files()
|
WebHost.create_options_files()
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.correct_path, "static", "generated", "configs")))
|
target = os.path.join(self.correct_path, "static", "generated", "configs")
|
||||||
|
self.assertTrue(os.path.exists(target))
|
||||||
self.assertFalse(os.path.exists(os.path.join(self.incorrect_path, "static", "generated", "configs")))
|
self.assertFalse(os.path.exists(os.path.join(self.incorrect_path, "static", "generated", "configs")))
|
||||||
|
|
||||||
|
# folder seems fine, so now we try to generate Options based on the default file
|
||||||
|
from WebHostLib.check import roll_options
|
||||||
|
file: os.DirEntry
|
||||||
|
for file in os.scandir(target):
|
||||||
|
if file.is_file() and file.name.endswith(".yaml"):
|
||||||
|
with self.subTest(file=file.name):
|
||||||
|
with open(file) as f:
|
||||||
|
for value in roll_options({file.name: f.read()})[0].values():
|
||||||
|
self.assertTrue(value is True, f"Default Options for template {file.name} cannot be run.")
|
||||||
|
|
||||||
def testTutorial(self):
|
def testTutorial(self):
|
||||||
WebHost.create_ordered_tutorials_file()
|
WebHost.create_ordered_tutorials_file()
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.correct_path, "static", "generated", "tutorials.json")))
|
self.assertTrue(os.path.exists(os.path.join(self.correct_path, "static", "generated", "tutorials.json")))
|
||||||
|
|
|
@ -39,8 +39,6 @@ class OpenPyramid(Choice):
|
||||||
option_auto = 3
|
option_auto = 3
|
||||||
default = option_goal
|
default = option_goal
|
||||||
|
|
||||||
alias_true = option_open
|
|
||||||
alias_false = option_closed
|
|
||||||
alias_yes = option_open
|
alias_yes = option_open
|
||||||
alias_no = option_closed
|
alias_no = option_closed
|
||||||
|
|
||||||
|
@ -159,8 +157,6 @@ class Progressive(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_grouped_random = 1
|
option_grouped_random = 1
|
||||||
option_on = 2
|
option_on = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
|
||||||
default = 2
|
default = 2
|
||||||
|
|
||||||
def want_progressives(self, random):
|
def want_progressives(self, random):
|
||||||
|
@ -202,8 +198,6 @@ class Hints(Choice):
|
||||||
option_on = 2
|
option_on = 2
|
||||||
option_full = 3
|
option_full = 3
|
||||||
default = 2
|
default = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
|
||||||
|
|
||||||
|
|
||||||
class Scams(Choice):
|
class Scams(Choice):
|
||||||
|
@ -213,7 +207,6 @@ class Scams(Choice):
|
||||||
option_king_zora = 1
|
option_king_zora = 1
|
||||||
option_bottle_merchant = 2
|
option_bottle_merchant = 2
|
||||||
option_all = 3
|
option_all = 3
|
||||||
alias_false = 0
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gives_king_zora_hint(self):
|
def gives_king_zora_hint(self):
|
||||||
|
@ -293,7 +286,6 @@ class HeartBeep(Choice):
|
||||||
option_half = 2
|
option_half = 2
|
||||||
option_quarter = 3
|
option_quarter = 3
|
||||||
option_off = 4
|
option_off = 4
|
||||||
alias_false = 4
|
|
||||||
|
|
||||||
|
|
||||||
class HeartColor(Choice):
|
class HeartColor(Choice):
|
||||||
|
|
|
@ -137,8 +137,6 @@ class Progressive(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_grouped_random = 1
|
option_grouped_random = 1
|
||||||
option_on = 2
|
option_on = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
|
||||||
default = 2
|
default = 2
|
||||||
|
|
||||||
def want_progressives(self, random):
|
def want_progressives(self, random):
|
||||||
|
|
|
@ -409,7 +409,6 @@ class DeathLink(Choice):
|
||||||
shade: DeathLink functions like a normal death if you do not already have a shade, shadeless otherwise.
|
shade: DeathLink functions like a normal death if you do not already have a shade, shadeless otherwise.
|
||||||
"""
|
"""
|
||||||
option_off = 0
|
option_off = 0
|
||||||
alias_false = 0
|
|
||||||
alias_no = 0
|
alias_no = 0
|
||||||
alias_true = 1
|
alias_true = 1
|
||||||
alias_on = 1
|
alias_on = 1
|
||||||
|
@ -435,10 +434,8 @@ class CostSanity(Choice):
|
||||||
These costs can be in Geo (except Grubfather, Seer and Eggshop), Grubs, Charms, Essence and/or Rancid Eggs
|
These costs can be in Geo (except Grubfather, Seer and Eggshop), Grubs, Charms, Essence and/or Rancid Eggs
|
||||||
"""
|
"""
|
||||||
option_off = 0
|
option_off = 0
|
||||||
alias_false = 0
|
|
||||||
alias_no = 0
|
alias_no = 0
|
||||||
option_on = 1
|
option_on = 1
|
||||||
alias_true = 1
|
|
||||||
alias_yes = 1
|
alias_yes = 1
|
||||||
option_shopsonly = 2
|
option_shopsonly = 2
|
||||||
option_notshops = 3
|
option_notshops = 3
|
||||||
|
|
|
@ -101,7 +101,6 @@ class InteriorEntrances(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_simple = 1
|
option_simple = 1
|
||||||
option_all = 2
|
option_all = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
alias_true = 2
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,7 +140,6 @@ class MixEntrancePools(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_indoor = 1
|
option_indoor = 1
|
||||||
option_all = 2
|
option_all = 2
|
||||||
alias_false = 0
|
|
||||||
|
|
||||||
|
|
||||||
class DecoupleEntrances(Toggle):
|
class DecoupleEntrances(Toggle):
|
||||||
|
@ -308,7 +306,6 @@ class ShopShuffle(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_fixed_number = 1
|
option_fixed_number = 1
|
||||||
option_random_number = 2
|
option_random_number = 2
|
||||||
alias_false = 0
|
|
||||||
|
|
||||||
|
|
||||||
class ShopSlots(Range):
|
class ShopSlots(Range):
|
||||||
|
@ -326,7 +323,6 @@ class TokenShuffle(Choice):
|
||||||
option_dungeons = 1
|
option_dungeons = 1
|
||||||
option_overworld = 2
|
option_overworld = 2
|
||||||
option_all = 3
|
option_all = 3
|
||||||
alias_false = 0
|
|
||||||
|
|
||||||
|
|
||||||
class ScrubShuffle(Choice):
|
class ScrubShuffle(Choice):
|
||||||
|
@ -336,7 +332,6 @@ class ScrubShuffle(Choice):
|
||||||
option_low = 1
|
option_low = 1
|
||||||
option_regular = 2
|
option_regular = 2
|
||||||
option_random_prices = 3
|
option_random_prices = 3
|
||||||
alias_false = 0
|
|
||||||
alias_affordable = 1
|
alias_affordable = 1
|
||||||
alias_expensive = 2
|
alias_expensive = 2
|
||||||
|
|
||||||
|
@ -569,7 +564,6 @@ class Hints(Choice):
|
||||||
option_agony = 2
|
option_agony = 2
|
||||||
option_always = 3
|
option_always = 3
|
||||||
default = 3
|
default = 3
|
||||||
alias_false = 0
|
|
||||||
|
|
||||||
|
|
||||||
class MiscHints(DefaultOnToggle):
|
class MiscHints(DefaultOnToggle):
|
||||||
|
@ -673,8 +667,6 @@ class IceTraps(Choice):
|
||||||
option_mayhem = 3
|
option_mayhem = 3
|
||||||
option_onslaught = 4
|
option_onslaught = 4
|
||||||
default = 1
|
default = 1
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
|
||||||
alias_extra = 2
|
alias_extra = 2
|
||||||
|
|
||||||
|
|
||||||
|
@ -742,7 +734,6 @@ class Music(Choice):
|
||||||
option_normal = 0
|
option_normal = 0
|
||||||
option_off = 1
|
option_off = 1
|
||||||
option_randomized = 2
|
option_randomized = 2
|
||||||
alias_false = 1
|
|
||||||
|
|
||||||
|
|
||||||
class BackgroundMusic(Music):
|
class BackgroundMusic(Music):
|
||||||
|
|
|
@ -122,8 +122,6 @@ class AreaRandomization(Choice):
|
||||||
option_off = 0
|
option_off = 0
|
||||||
option_light = 1
|
option_light = 1
|
||||||
option_on = 2
|
option_on = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
|
||||||
default = 0
|
default = 0
|
||||||
|
|
||||||
class AreaLayout(Toggle):
|
class AreaLayout(Toggle):
|
||||||
|
|
|
@ -1,48 +1,57 @@
|
||||||
import typing
|
import typing
|
||||||
from Options import Option, DefaultOnToggle, Range, Toggle, DeathLink, Choice
|
from Options import Option, DefaultOnToggle, Range, Toggle, DeathLink, Choice
|
||||||
|
|
||||||
|
|
||||||
class EnableCoinStars(DefaultOnToggle):
|
class EnableCoinStars(DefaultOnToggle):
|
||||||
"""Disable to Ignore 100 Coin Stars. You can still collect them, but they don't do anything"""
|
"""Disable to Ignore 100 Coin Stars. You can still collect them, but they don't do anything"""
|
||||||
display_name = "Enable 100 Coin Stars"
|
display_name = "Enable 100 Coin Stars"
|
||||||
|
|
||||||
|
|
||||||
class StrictCapRequirements(DefaultOnToggle):
|
class StrictCapRequirements(DefaultOnToggle):
|
||||||
"""If disabled, Stars that expect special caps may have to be acquired without the caps"""
|
"""If disabled, Stars that expect special caps may have to be acquired without the caps"""
|
||||||
display_name = "Strict Cap Requirements"
|
display_name = "Strict Cap Requirements"
|
||||||
|
|
||||||
|
|
||||||
class StrictCannonRequirements(DefaultOnToggle):
|
class StrictCannonRequirements(DefaultOnToggle):
|
||||||
"""If disabled, Stars that expect cannons may have to be acquired without them. Only makes a difference if Buddy Checks are enabled"""
|
"""If disabled, Stars that expect cannons may have to be acquired without them. Only makes a difference if Buddy Checks are enabled"""
|
||||||
display_name = "Strict Cannon Requirements"
|
display_name = "Strict Cannon Requirements"
|
||||||
|
|
||||||
|
|
||||||
class FirstBowserStarDoorCost(Range):
|
class FirstBowserStarDoorCost(Range):
|
||||||
"""How many stars are required at the Star Door to Bowser in the Dark World"""
|
"""How many stars are required at the Star Door to Bowser in the Dark World"""
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 50
|
range_end = 50
|
||||||
default = 8
|
default = 8
|
||||||
|
|
||||||
|
|
||||||
class BasementStarDoorCost(Range):
|
class BasementStarDoorCost(Range):
|
||||||
"""How many stars are required at the Star Door in the Basement"""
|
"""How many stars are required at the Star Door in the Basement"""
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 70
|
range_end = 70
|
||||||
default = 30
|
default = 30
|
||||||
|
|
||||||
|
|
||||||
class SecondFloorStarDoorCost(Range):
|
class SecondFloorStarDoorCost(Range):
|
||||||
"""How many stars are required to access the third floor"""
|
"""How many stars are required to access the third floor"""
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 90
|
range_end = 90
|
||||||
default = 50
|
default = 50
|
||||||
|
|
||||||
|
|
||||||
class MIPS1Cost(Range):
|
class MIPS1Cost(Range):
|
||||||
"""How many stars are required to spawn MIPS the first time"""
|
"""How many stars are required to spawn MIPS the first time"""
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 40
|
range_end = 40
|
||||||
default = 15
|
default = 15
|
||||||
|
|
||||||
|
|
||||||
class MIPS2Cost(Range):
|
class MIPS2Cost(Range):
|
||||||
"""How many stars are required to spawn MIPS the secound time. Must be bigger or equal MIPS1Cost"""
|
"""How many stars are required to spawn MIPS the secound time. Must be bigger or equal MIPS1Cost"""
|
||||||
range_start = 0
|
range_start = 0
|
||||||
range_end = 80
|
range_end = 80
|
||||||
default = 50
|
default = 50
|
||||||
|
|
||||||
|
|
||||||
class StarsToFinish(Range):
|
class StarsToFinish(Range):
|
||||||
"""How many stars are required at the infinite stairs"""
|
"""How many stars are required at the infinite stairs"""
|
||||||
display_name = "Endless Stairs Stars"
|
display_name = "Endless Stairs Stars"
|
||||||
|
@ -50,35 +59,40 @@ class StarsToFinish(Range):
|
||||||
range_end = 100
|
range_end = 100
|
||||||
default = 70
|
default = 70
|
||||||
|
|
||||||
|
|
||||||
class AmountOfStars(Range):
|
class AmountOfStars(Range):
|
||||||
"""How many stars exist. Disabling 100 Coin Stars removes 15 from the Pool. At least max of any Cost set"""
|
"""How many stars exist. Disabling 100 Coin Stars removes 15 from the Pool. At least max of any Cost set"""
|
||||||
range_start = 35
|
range_start = 35
|
||||||
range_end = 120
|
range_end = 120
|
||||||
default = 120
|
default = 120
|
||||||
|
|
||||||
|
|
||||||
class AreaRandomizer(Choice):
|
class AreaRandomizer(Choice):
|
||||||
"""Randomize Entrances"""
|
"""Randomize Entrances"""
|
||||||
display_name = "Entrance Randomizer"
|
display_name = "Entrance Randomizer"
|
||||||
alias_false = 0
|
|
||||||
option_Off = 0
|
option_Off = 0
|
||||||
option_Courses_Only = 1
|
option_Courses_Only = 1
|
||||||
option_Courses_and_Secrets = 2
|
option_Courses_and_Secrets = 2
|
||||||
|
|
||||||
|
|
||||||
class BuddyChecks(Toggle):
|
class BuddyChecks(Toggle):
|
||||||
"""Bob-omb Buddies are checks, Cannon Unlocks are items"""
|
"""Bob-omb Buddies are checks, Cannon Unlocks are items"""
|
||||||
display_name = "Bob-omb Buddy Checks"
|
display_name = "Bob-omb Buddy Checks"
|
||||||
|
|
||||||
|
|
||||||
class ExclamationBoxes(Choice):
|
class ExclamationBoxes(Choice):
|
||||||
"""Include 1Up Exclamation Boxes during randomization"""
|
"""Include 1Up Exclamation Boxes during randomization"""
|
||||||
display_name = "Randomize 1Up !-Blocks"
|
display_name = "Randomize 1Up !-Blocks"
|
||||||
option_Off = 0
|
option_Off = 0
|
||||||
option_1Ups_Only = 1
|
option_1Ups_Only = 1
|
||||||
|
|
||||||
|
|
||||||
class ProgressiveKeys(DefaultOnToggle):
|
class ProgressiveKeys(DefaultOnToggle):
|
||||||
"""Keys will first grant you access to the Basement, then to the Secound Floor"""
|
"""Keys will first grant you access to the Basement, then to the Secound Floor"""
|
||||||
display_name = "Progressive Keys"
|
display_name = "Progressive Keys"
|
||||||
|
|
||||||
sm64_options: typing.Dict[str,type(Option)] = {
|
|
||||||
|
sm64_options: typing.Dict[str, type(Option)] = {
|
||||||
"AreaRandomizer": AreaRandomizer,
|
"AreaRandomizer": AreaRandomizer,
|
||||||
"ProgressiveKeys": ProgressiveKeys,
|
"ProgressiveKeys": ProgressiveKeys,
|
||||||
"EnableCoinStars": EnableCoinStars,
|
"EnableCoinStars": EnableCoinStars,
|
||||||
|
@ -93,5 +107,5 @@ sm64_options: typing.Dict[str,type(Option)] = {
|
||||||
"StarsToFinish": StarsToFinish,
|
"StarsToFinish": StarsToFinish,
|
||||||
"death_link": DeathLink,
|
"death_link": DeathLink,
|
||||||
"BuddyChecks": BuddyChecks,
|
"BuddyChecks": BuddyChecks,
|
||||||
"ExclamationBoxes": ExclamationBoxes
|
"ExclamationBoxes": ExclamationBoxes,
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .Regions import create_regions, sm64courses, sm64entrances_s, sm64_internal
|
||||||
from BaseClasses import Item, Tutorial, ItemClassification
|
from BaseClasses import Item, Tutorial, ItemClassification
|
||||||
from ..AutoWorld import World, WebWorld
|
from ..AutoWorld import World, WebWorld
|
||||||
|
|
||||||
|
|
||||||
class SM64Web(WebWorld):
|
class SM64Web(WebWorld):
|
||||||
tutorials = [Tutorial(
|
tutorials = [Tutorial(
|
||||||
"Multiworld Setup Guide",
|
"Multiworld Setup Guide",
|
||||||
|
|
|
@ -107,7 +107,6 @@ class HeartBeepSpeed(Choice):
|
||||||
option_Half = 2
|
option_Half = 2
|
||||||
option_Normal = 3
|
option_Normal = 3
|
||||||
option_Double = 4
|
option_Double = 4
|
||||||
alias_false = 0
|
|
||||||
default = 3
|
default = 3
|
||||||
|
|
||||||
class HeartColor(Choice):
|
class HeartColor(Choice):
|
||||||
|
|
|
@ -21,8 +21,6 @@ class OffOnFullChoice(Choice):
|
||||||
option_on = 1
|
option_on = 1
|
||||||
option_full = 2
|
option_full = 2
|
||||||
alias_chaos = 2
|
alias_chaos = 2
|
||||||
alias_false = 0
|
|
||||||
alias_true = 1
|
|
||||||
|
|
||||||
|
|
||||||
class Difficulty(EvermizerFlags, Choice):
|
class Difficulty(EvermizerFlags, Choice):
|
||||||
|
|
|
@ -3,66 +3,82 @@ from BaseClasses import MultiWorld
|
||||||
from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, Option, OptionDict
|
from Options import Toggle, DefaultOnToggle, DeathLink, Choice, Range, Option, OptionDict
|
||||||
from schema import Schema, And, Optional
|
from schema import Schema, And, Optional
|
||||||
|
|
||||||
|
|
||||||
class StartWithJewelryBox(Toggle):
|
class StartWithJewelryBox(Toggle):
|
||||||
"Start with Jewelry Box unlocked"
|
"Start with Jewelry Box unlocked"
|
||||||
display_name = "Start with Jewelry Box"
|
display_name = "Start with Jewelry Box"
|
||||||
|
|
||||||
|
|
||||||
#class ProgressiveVerticalMovement(Toggle):
|
#class ProgressiveVerticalMovement(Toggle):
|
||||||
# "Always find vertical movement in the following order Succubus Hairpin -> Light Wall -> Celestial Sash"
|
# "Always find vertical movement in the following order Succubus Hairpin -> Light Wall -> Celestial Sash"
|
||||||
# display_name = "Progressive vertical movement"
|
# display_name = "Progressive vertical movement"
|
||||||
|
|
||||||
|
|
||||||
#class ProgressiveKeycards(Toggle):
|
#class ProgressiveKeycards(Toggle):
|
||||||
# "Always find Security Keycard's in the following order D -> C -> B -> A"
|
# "Always find Security Keycard's in the following order D -> C -> B -> A"
|
||||||
# display_name = "Progressive keycards"
|
# display_name = "Progressive keycards"
|
||||||
|
|
||||||
|
|
||||||
class DownloadableItems(DefaultOnToggle):
|
class DownloadableItems(DefaultOnToggle):
|
||||||
"With the tablet you will be able to download items at terminals"
|
"With the tablet you will be able to download items at terminals"
|
||||||
display_name = "Downloadable items"
|
display_name = "Downloadable items"
|
||||||
|
|
||||||
|
|
||||||
class EyeSpy(Toggle):
|
class EyeSpy(Toggle):
|
||||||
"Requires Oculus Ring in inventory to be able to break hidden walls."
|
"Requires Oculus Ring in inventory to be able to break hidden walls."
|
||||||
display_name = "Eye Spy"
|
display_name = "Eye Spy"
|
||||||
|
|
||||||
|
|
||||||
class StartWithMeyef(Toggle):
|
class StartWithMeyef(Toggle):
|
||||||
"Start with Meyef, ideal for when you want to play multiplayer."
|
"Start with Meyef, ideal for when you want to play multiplayer."
|
||||||
display_name = "Start with Meyef"
|
display_name = "Start with Meyef"
|
||||||
|
|
||||||
|
|
||||||
class QuickSeed(Toggle):
|
class QuickSeed(Toggle):
|
||||||
"Start with Talaria Attachment, Nyoom!"
|
"Start with Talaria Attachment, Nyoom!"
|
||||||
display_name = "Quick seed"
|
display_name = "Quick seed"
|
||||||
|
|
||||||
|
|
||||||
class SpecificKeycards(Toggle):
|
class SpecificKeycards(Toggle):
|
||||||
"Keycards can only open corresponding doors"
|
"Keycards can only open corresponding doors"
|
||||||
display_name = "Specific Keycards"
|
display_name = "Specific Keycards"
|
||||||
|
|
||||||
|
|
||||||
class Inverted(Toggle):
|
class Inverted(Toggle):
|
||||||
"Start in the past"
|
"Start in the past"
|
||||||
display_name = "Inverted"
|
display_name = "Inverted"
|
||||||
|
|
||||||
|
|
||||||
#class StinkyMaw(Toggle):
|
#class StinkyMaw(Toggle):
|
||||||
# "Require gasmask for Maw"
|
# "Require gasmask for Maw"
|
||||||
# display_name = "Stinky Maw"
|
# display_name = "Stinky Maw"
|
||||||
|
|
||||||
|
|
||||||
class GyreArchives(Toggle):
|
class GyreArchives(Toggle):
|
||||||
"Gyre locations are in logic. New warps are gated by Merchant Crow and Kobo"
|
"Gyre locations are in logic. New warps are gated by Merchant Crow and Kobo"
|
||||||
display_name = "Gyre Archives"
|
display_name = "Gyre Archives"
|
||||||
|
|
||||||
|
|
||||||
class Cantoran(Toggle):
|
class Cantoran(Toggle):
|
||||||
"Cantoran's fight and check are available upon revisiting his room"
|
"Cantoran's fight and check are available upon revisiting his room"
|
||||||
display_name = "Cantoran"
|
display_name = "Cantoran"
|
||||||
|
|
||||||
|
|
||||||
class LoreChecks(Toggle):
|
class LoreChecks(Toggle):
|
||||||
"Memories and journal entries contain items."
|
"Memories and journal entries contain items."
|
||||||
display_name = "Lore Checks"
|
display_name = "Lore Checks"
|
||||||
|
|
||||||
|
|
||||||
class BossRando(Toggle):
|
class BossRando(Toggle):
|
||||||
"Shuffles the positions of all bosses."
|
"Shuffles the positions of all bosses."
|
||||||
display_name = "Boss Randomization"
|
display_name = "Boss Randomization"
|
||||||
|
|
||||||
|
|
||||||
class BossScaling(DefaultOnToggle):
|
class BossScaling(DefaultOnToggle):
|
||||||
"When Boss Rando is enabled, scales the bosses' HP, XP, and ATK to the stats of the location they replace (Reccomended)"
|
"When Boss Rando is enabled, scales the bosses' HP, XP, and ATK to the stats of the location they replace (Reccomended)"
|
||||||
display_name = "Scale Random Boss Stats"
|
display_name = "Scale Random Boss Stats"
|
||||||
|
|
||||||
|
|
||||||
class DamageRando(Choice):
|
class DamageRando(Choice):
|
||||||
"Randomly nerfs and buffs some orbs and their associated spells as well as some associated rings."
|
"Randomly nerfs and buffs some orbs and their associated spells as well as some associated rings."
|
||||||
display_name = "Damage Rando"
|
display_name = "Damage Rando"
|
||||||
|
@ -73,9 +89,9 @@ class DamageRando(Choice):
|
||||||
option_mostlybuffs = 4
|
option_mostlybuffs = 4
|
||||||
option_allbuffs = 5
|
option_allbuffs = 5
|
||||||
option_manual = 6
|
option_manual = 6
|
||||||
alias_false = 0
|
|
||||||
alias_true = 2
|
alias_true = 2
|
||||||
|
|
||||||
|
|
||||||
class DamageRandoOverrides(OptionDict):
|
class DamageRandoOverrides(OptionDict):
|
||||||
"Manual +/-/normal odds for an orb. Put 0 if you don't want a certain nerf or buff to be a possibility. Orbs that you don't specify will roll with 1/1/1 as odds"
|
"Manual +/-/normal odds for an orb. Put 0 if you don't want a certain nerf or buff to be a possibility. Orbs that you don't specify will roll with 1/1/1 as odds"
|
||||||
schema = Schema({
|
schema = Schema({
|
||||||
|
@ -180,6 +196,7 @@ class DamageRandoOverrides(OptionDict):
|
||||||
"Radiant": { "MinusOdds": 1, "NormalOdds": 1, "PlusOdds": 1 },
|
"Radiant": { "MinusOdds": 1, "NormalOdds": 1, "PlusOdds": 1 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class HpCap(Range):
|
class HpCap(Range):
|
||||||
"Sets the number that Lunais's HP maxes out at."
|
"Sets the number that Lunais's HP maxes out at."
|
||||||
display_name = "HP Cap"
|
display_name = "HP Cap"
|
||||||
|
@ -187,10 +204,12 @@ class HpCap(Range):
|
||||||
range_end = 999
|
range_end = 999
|
||||||
default = 999
|
default = 999
|
||||||
|
|
||||||
|
|
||||||
class BossHealing(DefaultOnToggle):
|
class BossHealing(DefaultOnToggle):
|
||||||
"Enables/disables healing after boss fights. NOTE: Currently only applicable when Boss Rando is enabled."
|
"Enables/disables healing after boss fights. NOTE: Currently only applicable when Boss Rando is enabled."
|
||||||
display_name = "Heal After Bosses"
|
display_name = "Heal After Bosses"
|
||||||
|
|
||||||
|
|
||||||
class ShopFill(Choice):
|
class ShopFill(Choice):
|
||||||
"""Sets the items for sale in Merchant Crow's shops.
|
"""Sets the items for sale in Merchant Crow's shops.
|
||||||
Default: No sunglasses or trendy jacket, but sand vials for sale.
|
Default: No sunglasses or trendy jacket, but sand vials for sale.
|
||||||
|
@ -203,10 +222,12 @@ class ShopFill(Choice):
|
||||||
option_vanilla = 2
|
option_vanilla = 2
|
||||||
option_empty = 3
|
option_empty = 3
|
||||||
|
|
||||||
|
|
||||||
class ShopWarpShards(DefaultOnToggle):
|
class ShopWarpShards(DefaultOnToggle):
|
||||||
"Shops always sell warp shards (when keys possessed), ignoring inventory setting."
|
"Shops always sell warp shards (when keys possessed), ignoring inventory setting."
|
||||||
display_name = "Always Sell Warp Shards"
|
display_name = "Always Sell Warp Shards"
|
||||||
|
|
||||||
|
|
||||||
class ShopMultiplier(Range):
|
class ShopMultiplier(Range):
|
||||||
"Multiplier for the cost of items in the shop. Set to 0 for free shops."
|
"Multiplier for the cost of items in the shop. Set to 0 for free shops."
|
||||||
display_name = "Shop Price Multiplier"
|
display_name = "Shop Price Multiplier"
|
||||||
|
@ -214,6 +235,7 @@ class ShopMultiplier(Range):
|
||||||
range_end = 10
|
range_end = 10
|
||||||
default = 1
|
default = 1
|
||||||
|
|
||||||
|
|
||||||
class LootPool(Choice):
|
class LootPool(Choice):
|
||||||
"""Sets the items that drop from enemies (does not apply to boss reward checks)
|
"""Sets the items that drop from enemies (does not apply to boss reward checks)
|
||||||
Vanilla: Drops are the same as the base game
|
Vanilla: Drops are the same as the base game
|
||||||
|
@ -224,6 +246,7 @@ class LootPool(Choice):
|
||||||
option_randomized = 1
|
option_randomized = 1
|
||||||
option_empty = 2
|
option_empty = 2
|
||||||
|
|
||||||
|
|
||||||
class DropRateCategory(Choice):
|
class DropRateCategory(Choice):
|
||||||
"""Sets the drop rate when 'Loot Pool' is set to 'Random'
|
"""Sets the drop rate when 'Loot Pool' is set to 'Random'
|
||||||
Tiered: Based on item rarity/value
|
Tiered: Based on item rarity/value
|
||||||
|
@ -237,6 +260,7 @@ class DropRateCategory(Choice):
|
||||||
option_randomized = 2
|
option_randomized = 2
|
||||||
option_fixed = 3
|
option_fixed = 3
|
||||||
|
|
||||||
|
|
||||||
class FixedDropRate(Range):
|
class FixedDropRate(Range):
|
||||||
"Base drop rate percentage when 'Drop Rate Category' is set to 'Fixed'"
|
"Base drop rate percentage when 'Drop Rate Category' is set to 'Fixed'"
|
||||||
display_name = "Fixed Drop Rate"
|
display_name = "Fixed Drop Rate"
|
||||||
|
@ -244,6 +268,7 @@ class FixedDropRate(Range):
|
||||||
range_end = 100
|
range_end = 100
|
||||||
default = 5
|
default = 5
|
||||||
|
|
||||||
|
|
||||||
class LootTierDistro(Choice):
|
class LootTierDistro(Choice):
|
||||||
"""Sets how often items of each rarity tier are placed when 'Loot Pool' is set to 'Random'
|
"""Sets how often items of each rarity tier are placed when 'Loot Pool' is set to 'Random'
|
||||||
Default Weight: Rarer items will be assigned to enemy drop slots less frequently than common items
|
Default Weight: Rarer items will be assigned to enemy drop slots less frequently than common items
|
||||||
|
@ -255,14 +280,17 @@ class LootTierDistro(Choice):
|
||||||
option_full_random = 1
|
option_full_random = 1
|
||||||
option_inverted_weight = 2
|
option_inverted_weight = 2
|
||||||
|
|
||||||
|
|
||||||
class ShowBestiary(Toggle):
|
class ShowBestiary(Toggle):
|
||||||
"All entries in the bestiary are visible, without needing to kill one of a given enemy first"
|
"All entries in the bestiary are visible, without needing to kill one of a given enemy first"
|
||||||
display_name = "Show Bestiary Entries"
|
display_name = "Show Bestiary Entries"
|
||||||
|
|
||||||
|
|
||||||
class ShowDrops(Toggle):
|
class ShowDrops(Toggle):
|
||||||
"All item drops in the bestiary are visible, without needing an enemy to drop one of a given item first"
|
"All item drops in the bestiary are visible, without needing an enemy to drop one of a given item first"
|
||||||
display_name = "Show Bestiary Item Drops"
|
display_name = "Show Bestiary Item Drops"
|
||||||
|
|
||||||
|
|
||||||
# Some options that are available in the timespinner randomizer arent currently implemented
|
# Some options that are available in the timespinner randomizer arent currently implemented
|
||||||
timespinner_options: Dict[str, Option] = {
|
timespinner_options: Dict[str, Option] = {
|
||||||
"StartWithJewelryBox": StartWithJewelryBox,
|
"StartWithJewelryBox": StartWithJewelryBox,
|
||||||
|
@ -296,9 +324,11 @@ timespinner_options: Dict[str, Option] = {
|
||||||
"DeathLink": DeathLink,
|
"DeathLink": DeathLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def is_option_enabled(world: MultiWorld, player: int, name: str) -> bool:
|
def is_option_enabled(world: MultiWorld, player: int, name: str) -> bool:
|
||||||
return get_option_value(world, player, name) > 0
|
return get_option_value(world, player, name) > 0
|
||||||
|
|
||||||
|
|
||||||
def get_option_value(world: MultiWorld, player: int, name: str) -> Union[int, dict]:
|
def get_option_value(world: MultiWorld, player: int, name: str) -> Union[int, dict]:
|
||||||
option = getattr(world, name, None)
|
option = getattr(world, name, None)
|
||||||
if option == None:
|
if option == None:
|
||||||
|
|
Loading…
Reference in New Issue