mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Core: move option results to the World class instead of MultiWorld (#993)
🤞 * map option objects to a `World.options` dict * convert RoR2 to options dict system for testing * add temp behavior for lttp with notes * copy/paste bad * convert `set_default_common_options` to a namespace property * reorganize test call order * have fill_restrictive use the new options system * update world api * update soe tests * fix world api * core: auto initialize a dataclass on the World class with the option results * core: auto initialize a dataclass on the World class with the option results: small tying improvement * add `as_dict` method to the options dataclass * fix namespace issues with tests * have current option updates use `.value` instead of changing the option * update ror2 to use the new options system again * revert the junk pool dict since it's cased differently * fix begin_with_loop typo * write new and old options to spoiler * change factorio option behavior back * fix comparisons * move common and per_game_common options to new system * core: automatically create missing options_dataclass from legacy option_definitions * remove spoiler special casing and add back the Factorio option changing but in new system * give ArchipIDLE the default options_dataclass so its options get generated and spoilered properly * reimplement `inspect.get_annotations` * move option info generation for webhost to new system * need to include Common and PerGame common since __annotations__ doesn't include super * use get_type_hints for the options dictionary * typing.get_type_hints returns the bases too. * forgot to sweep through generate * sweep through all the tests * swap to a metaclass property * move remaining usages from get_type_hints to metaclass property * move remaining usages from __annotations__ to metaclass property * move remaining usages from legacy dictionaries to metaclass property * remove legacy dictionaries * cache the metaclass property * clarify inheritance in world api * move the messenger to new options system * add an assert for my dumb * update the doc * rename o to options * missed a spot * update new messenger options * comment spacing Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com> * fix tests * fix missing import * make the documentation definition more accurate * use options system for loc creation * type cast MessengerWorld * fix typo and use quotes for cast * LTTP: set random seed in tests * ArchipIdle: remove change here as it's default on AutoWorld * Stardew: Need to set state because `set_default_common_options` used to * The Messenger: update shop rando and helpers to new system; optimize imports * Add a kwarg to `as_dict` to do the casing for you * RoR2: use new kwarg for less code * RoR2: revert some accidental reverts * The Messenger: remove an unnecessary variable * remove TypeVar that isn't used * CommonOptions not abstract * Docs: fix mistake in options api.md Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com> * create options for item link worlds * revert accidental doc removals * Item Links: set default options on group * change Zillion to new options dataclass * remove unused parameter to function * use TypeGuard for Literal narrowing * move dlc quest to new api * move overcooked 2 to new api * fixed some missed code in oc2 * - Tried to be compliant with 993 (WIP?) * - I think it all works now * - Removed last trace of me touching core * typo * It now passes all tests! * Improve options, fix all issues I hope * - Fixed init options * dlcquest: fix bad imports * missed a file * - Reduce code duplication * add as_dict documentation * - Use .items(), get option name more directly, fix slot data content * - Remove generic options from the slot data * improve slot data documentation * remove `CommonOptions.get_value` (#21) * better slot data description Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> --------- Co-authored-by: el-u <109771707+el-u@users.noreply.github.com> Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com> Co-authored-by: Doug Hoskisson <beauxq@yahoo.com> Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com> Co-authored-by: Alex Gilbert <alexgilbert@yahoo.com>
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
from collections import Counter
|
||||
# import logging
|
||||
from typing import TYPE_CHECKING, Any, Dict, Tuple, cast
|
||||
from Options import AssembleOptions, DefaultOnToggle, Range, SpecialRange, Toggle, Choice
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Tuple
|
||||
from typing_extensions import TypeGuard # remove when Python >= 3.10
|
||||
|
||||
from Options import DefaultOnToggle, PerGameCommonOptions, Range, SpecialRange, Toggle, Choice
|
||||
|
||||
from zilliandomizer.options import \
|
||||
Options as ZzOptions, char_to_gun, char_to_jump, ID, \
|
||||
VBLR as ZzVBLR, chars, Chars, ItemCounts as ZzItemCounts
|
||||
from zilliandomizer.options.parsing import validate as zz_validate
|
||||
if TYPE_CHECKING:
|
||||
from BaseClasses import MultiWorld
|
||||
|
||||
|
||||
class ZillionContinues(SpecialRange):
|
||||
@@ -41,6 +42,19 @@ class VBLR(Choice):
|
||||
option_restrictive = 3
|
||||
default = 1
|
||||
|
||||
def to_zz_vblr(self) -> ZzVBLR:
|
||||
def is_vblr(o: str) -> TypeGuard[ZzVBLR]:
|
||||
"""
|
||||
This function is because mypy doesn't support narrowing with `in`,
|
||||
https://github.com/python/mypy/issues/12535
|
||||
so this is the only way I see to get type narrowing to `Literal`.
|
||||
"""
|
||||
return o in ("vanilla", "balanced", "low", "restrictive")
|
||||
|
||||
key = self.current_key
|
||||
assert is_vblr(key), f"{key=}"
|
||||
return key
|
||||
|
||||
|
||||
class ZillionGunLevels(VBLR):
|
||||
"""
|
||||
@@ -225,27 +239,27 @@ class ZillionRoomGen(Toggle):
|
||||
display_name = "room generation"
|
||||
|
||||
|
||||
zillion_options: Dict[str, AssembleOptions] = {
|
||||
"continues": ZillionContinues,
|
||||
"floppy_req": ZillionFloppyReq,
|
||||
"gun_levels": ZillionGunLevels,
|
||||
"jump_levels": ZillionJumpLevels,
|
||||
"randomize_alarms": ZillionRandomizeAlarms,
|
||||
"max_level": ZillionMaxLevel,
|
||||
"start_char": ZillionStartChar,
|
||||
"opas_per_level": ZillionOpasPerLevel,
|
||||
"id_card_count": ZillionIDCardCount,
|
||||
"bread_count": ZillionBreadCount,
|
||||
"opa_opa_count": ZillionOpaOpaCount,
|
||||
"zillion_count": ZillionZillionCount,
|
||||
"floppy_disk_count": ZillionFloppyDiskCount,
|
||||
"scope_count": ZillionScopeCount,
|
||||
"red_id_card_count": ZillionRedIDCardCount,
|
||||
"early_scope": ZillionEarlyScope,
|
||||
"skill": ZillionSkill,
|
||||
"starting_cards": ZillionStartingCards,
|
||||
"room_gen": ZillionRoomGen,
|
||||
}
|
||||
@dataclass
|
||||
class ZillionOptions(PerGameCommonOptions):
|
||||
continues: ZillionContinues
|
||||
floppy_req: ZillionFloppyReq
|
||||
gun_levels: ZillionGunLevels
|
||||
jump_levels: ZillionJumpLevels
|
||||
randomize_alarms: ZillionRandomizeAlarms
|
||||
max_level: ZillionMaxLevel
|
||||
start_char: ZillionStartChar
|
||||
opas_per_level: ZillionOpasPerLevel
|
||||
id_card_count: ZillionIDCardCount
|
||||
bread_count: ZillionBreadCount
|
||||
opa_opa_count: ZillionOpaOpaCount
|
||||
zillion_count: ZillionZillionCount
|
||||
floppy_disk_count: ZillionFloppyDiskCount
|
||||
scope_count: ZillionScopeCount
|
||||
red_id_card_count: ZillionRedIDCardCount
|
||||
early_scope: ZillionEarlyScope
|
||||
skill: ZillionSkill
|
||||
starting_cards: ZillionStartingCards
|
||||
room_gen: ZillionRoomGen
|
||||
|
||||
|
||||
def convert_item_counts(ic: "Counter[str]") -> ZzItemCounts:
|
||||
@@ -262,47 +276,34 @@ def convert_item_counts(ic: "Counter[str]") -> ZzItemCounts:
|
||||
return tr
|
||||
|
||||
|
||||
def validate(world: "MultiWorld", p: int) -> "Tuple[ZzOptions, Counter[str]]":
|
||||
def validate(options: ZillionOptions) -> "Tuple[ZzOptions, Counter[str]]":
|
||||
"""
|
||||
adjusts options to make game completion possible
|
||||
|
||||
`world` parameter is MultiWorld object that has my options on it
|
||||
`p` is my player id
|
||||
`options` parameter is ZillionOptions object that was put on my world by the core
|
||||
"""
|
||||
for option_name in zillion_options:
|
||||
assert hasattr(world, option_name), f"Zillion option {option_name} didn't get put in world object"
|
||||
wo = cast(Any, world) # so I don't need getattr on all the options
|
||||
|
||||
skill = wo.skill[p].value
|
||||
skill = options.skill.value
|
||||
|
||||
jump_levels = cast(ZillionJumpLevels, wo.jump_levels[p])
|
||||
jump_option = jump_levels.current_key
|
||||
required_level = char_to_jump["Apple"][cast(ZzVBLR, jump_option)].index(3) + 1
|
||||
jump_option = options.jump_levels.to_zz_vblr()
|
||||
required_level = char_to_jump["Apple"][jump_option].index(3) + 1
|
||||
if skill == 0:
|
||||
# because of hp logic on final boss
|
||||
required_level = 8
|
||||
|
||||
gun_levels = cast(ZillionGunLevels, wo.gun_levels[p])
|
||||
gun_option = gun_levels.current_key
|
||||
guns_required = char_to_gun["Champ"][cast(ZzVBLR, gun_option)].index(3)
|
||||
gun_option = options.gun_levels.to_zz_vblr()
|
||||
guns_required = char_to_gun["Champ"][gun_option].index(3)
|
||||
|
||||
floppy_req = cast(ZillionFloppyReq, wo.floppy_req[p])
|
||||
floppy_req = options.floppy_req
|
||||
|
||||
card = cast(ZillionIDCardCount, wo.id_card_count[p])
|
||||
bread = cast(ZillionBreadCount, wo.bread_count[p])
|
||||
opa = cast(ZillionOpaOpaCount, wo.opa_opa_count[p])
|
||||
gun = cast(ZillionZillionCount, wo.zillion_count[p])
|
||||
floppy = cast(ZillionFloppyDiskCount, wo.floppy_disk_count[p])
|
||||
scope = cast(ZillionScopeCount, wo.scope_count[p])
|
||||
red = cast(ZillionRedIDCardCount, wo.red_id_card_count[p])
|
||||
item_counts = Counter({
|
||||
"ID Card": card,
|
||||
"Bread": bread,
|
||||
"Opa-Opa": opa,
|
||||
"Zillion": gun,
|
||||
"Floppy Disk": floppy,
|
||||
"Scope": scope,
|
||||
"Red ID Card": red
|
||||
"ID Card": options.id_card_count,
|
||||
"Bread": options.bread_count,
|
||||
"Opa-Opa": options.opa_opa_count,
|
||||
"Zillion": options.zillion_count,
|
||||
"Floppy Disk": options.floppy_disk_count,
|
||||
"Scope": options.scope_count,
|
||||
"Red ID Card": options.red_id_card_count
|
||||
})
|
||||
minimums = Counter({
|
||||
"ID Card": 0,
|
||||
@@ -335,10 +336,10 @@ def validate(world: "MultiWorld", p: int) -> "Tuple[ZzOptions, Counter[str]]":
|
||||
item_counts["Empty"] += diff
|
||||
assert sum(item_counts.values()) == 144
|
||||
|
||||
max_level = cast(ZillionMaxLevel, wo.max_level[p])
|
||||
max_level = options.max_level
|
||||
max_level.value = max(required_level, max_level.value)
|
||||
|
||||
opas_per_level = cast(ZillionOpasPerLevel, wo.opas_per_level[p])
|
||||
opas_per_level = options.opas_per_level
|
||||
while (opas_per_level.value > 1) and (1 + item_counts["Opa-Opa"] // opas_per_level.value < max_level.value):
|
||||
# logging.warning(
|
||||
# "zillion options validate: option opas_per_level incompatible with options max_level and opa_opa_count"
|
||||
@@ -347,39 +348,34 @@ def validate(world: "MultiWorld", p: int) -> "Tuple[ZzOptions, Counter[str]]":
|
||||
|
||||
# that should be all of the level requirements met
|
||||
|
||||
name_capitalization = {
|
||||
name_capitalization: Dict[str, Chars] = {
|
||||
"jj": "JJ",
|
||||
"apple": "Apple",
|
||||
"champ": "Champ",
|
||||
}
|
||||
|
||||
start_char = cast(ZillionStartChar, wo.start_char[p])
|
||||
start_char = options.start_char
|
||||
start_char_name = name_capitalization[start_char.current_key]
|
||||
assert start_char_name in chars
|
||||
start_char_name = cast(Chars, start_char_name)
|
||||
|
||||
starting_cards = cast(ZillionStartingCards, wo.starting_cards[p])
|
||||
starting_cards = options.starting_cards
|
||||
|
||||
room_gen = cast(ZillionRoomGen, wo.room_gen[p])
|
||||
|
||||
early_scope = cast(ZillionEarlyScope, wo.early_scope[p])
|
||||
if early_scope:
|
||||
world.early_items[p]["Scope"] = 1
|
||||
room_gen = options.room_gen
|
||||
|
||||
zz_item_counts = convert_item_counts(item_counts)
|
||||
zz_op = ZzOptions(
|
||||
zz_item_counts,
|
||||
cast(ZzVBLR, jump_option),
|
||||
cast(ZzVBLR, gun_option),
|
||||
jump_option,
|
||||
gun_option,
|
||||
opas_per_level.value,
|
||||
max_level.value,
|
||||
False, # tutorial
|
||||
skill,
|
||||
start_char_name,
|
||||
floppy_req.value,
|
||||
wo.continues[p].value,
|
||||
wo.randomize_alarms[p].value,
|
||||
False, # early scope is done with AP early_items API
|
||||
options.continues.value,
|
||||
bool(options.randomize_alarms.value),
|
||||
bool(options.early_scope.value),
|
||||
True, # balance defense
|
||||
starting_cards.value,
|
||||
bool(room_gen.value)
|
||||
|
Reference in New Issue
Block a user