mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00
Core: Add "OptionCounter", use it for generic "StartInventory" and Witness "TrapWeights" (#3756)
* CounterOption * bring back the negative exception for ItemDict * Backwards compatibility * ruff on witness * fix in calls * move the contains * comment * comment * Add option min and max values for CounterOption * Use min 0 for TrapWeights * This is safe now * ruff * This fits on one line again now * OptionCounter * Update Options.py * Couple more typing things * Update Options.py * Make StartInventory work again, also make LocationCounter theoretically work * Docs * more forceful wording * forced line break * Fix unit test (that wasn't breaking?) * Add trapweights to witness option presets to 'prove' that the unit test passes * Make it so you can order stuff * Update macros.html
This commit is contained in:
47
Options.py
47
Options.py
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import abc
|
||||
import collections
|
||||
import functools
|
||||
import logging
|
||||
import math
|
||||
@@ -866,15 +867,49 @@ class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mappin
|
||||
def __len__(self) -> int:
|
||||
return self.value.__len__()
|
||||
|
||||
# __getitem__ fallback fails for Counters, so we define this explicitly
|
||||
def __contains__(self, item) -> bool:
|
||||
return item in self.value
|
||||
|
||||
class ItemDict(OptionDict):
|
||||
|
||||
class OptionCounter(OptionDict):
|
||||
min: int | None = None
|
||||
max: int | None = None
|
||||
|
||||
def __init__(self, value: dict[str, int]) -> None:
|
||||
super(OptionCounter, self).__init__(collections.Counter(value))
|
||||
|
||||
def verify(self, world: type[World], player_name: str, plando_options: PlandoOptions) -> None:
|
||||
super(OptionCounter, self).verify(world, player_name, plando_options)
|
||||
|
||||
range_errors = []
|
||||
|
||||
if self.max is not None:
|
||||
range_errors += [
|
||||
f"\"{key}: {value}\" is higher than maximum allowed value {self.max}."
|
||||
for key, value in self.value.items() if value > self.max
|
||||
]
|
||||
|
||||
if self.min is not None:
|
||||
range_errors += [
|
||||
f"\"{key}: {value}\" is lower than minimum allowed value {self.min}."
|
||||
for key, value in self.value.items() if value < self.min
|
||||
]
|
||||
|
||||
if range_errors:
|
||||
range_errors = [f"For option {getattr(self, 'display_name', self)}:"] + range_errors
|
||||
raise OptionError("\n".join(range_errors))
|
||||
|
||||
|
||||
class ItemDict(OptionCounter):
|
||||
verify_item_name = True
|
||||
|
||||
def __init__(self, value: typing.Dict[str, int]):
|
||||
if any(item_count is None for item_count in value.values()):
|
||||
raise Exception("Items must have counts associated with them. Please provide positive integer values in the format \"item\": count .")
|
||||
if any(item_count < 1 for item_count in value.values()):
|
||||
raise Exception("Cannot have non-positive item counts.")
|
||||
min = 0
|
||||
|
||||
def __init__(self, value: dict[str, int]) -> None:
|
||||
# Backwards compatibility: Cull 0s to make "in" checks behave the same as when this wasn't a OptionCounter
|
||||
value = {item_name: amount for item_name, amount in value.items() if amount != 0}
|
||||
|
||||
super(ItemDict, self).__init__(value)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user