Add LogicMixin

This commit is contained in:
Fabian Dill 2021-07-15 13:31:33 +02:00
parent 01f0f309d1
commit 69a5bf0159
3 changed files with 43 additions and 31 deletions

View File

@ -569,32 +569,6 @@ class CollectionState(object):
def has_any(self, items: Set[str], player:int): def has_any(self, items: Set[str], player:int):
return any(self.prog_items[item, player] for item in items) return any(self.prog_items[item, player] for item in items)
def has_essence(self, player: int, count: int):
return self.prog_items["Dream_Nail", player]
# return self.prog_items["Essence", player] >= count
def has_grubs(self, player: int, count: int):
from worlds.hk import Items as HKItems
found = 0
for item_name in HKItems.lookup_type_to_names["Grub"]:
found += self.prog_items[item_name, player]
if found >= count:
return True
return False
def has_flames(self, player: int, count: int):
from worlds.hk import Items as HKItems
found = 0
for item_name in HKItems.lookup_type_to_names["Flame"]:
found += self.prog_items[item_name, player]
if found >= count:
return True
return False
def has_key(self, item, player, count: int = 1): def has_key(self, item, player, count: int = 1):
if self.world.logic[player] == 'nologic': if self.world.logic[player] == 'nologic':
return True return True

View File

@ -21,6 +21,15 @@ class AutoWorldRegister(type):
AutoWorldRegister.world_types[dct["game"]] = new_class AutoWorldRegister.world_types[dct["game"]] = new_class
return new_class return new_class
class AutoLogicRegister(type):
def __new__(cls, name, bases, dct):
new_class = super().__new__(cls, name, bases, dct)
for function_name, function in dct.items():
if hasattr(function, "__call__"): # callable
if hasattr(CollectionState, function_name):
raise Exception(f"Name conflict on Logic Mixin {name} trying to overwrite {function_name}")
setattr(CollectionState, function_name, function)
return new_class
def call_single(world: MultiWorld, method_name: str, player: int): def call_single(world: MultiWorld, method_name: str, player: int):
method = getattr(world.worlds[player], method_name) method = getattr(world.worlds[player], method_name)
@ -36,9 +45,8 @@ class World(metaclass=AutoWorldRegister):
"""A World object encompasses a game's Items, Locations, Rules and additional data or functionality required. """A World object encompasses a game's Items, Locations, Rules and additional data or functionality required.
A Game should have its own subclass of World in which it defines the required data structures.""" A Game should have its own subclass of World in which it defines the required data structures."""
world: MultiWorld options: dict = {} # link your Options mapping
player: int game: str # name the game
options: dict = {}
topology_present: bool = False # indicate if world type has any meaningful layout/pathing topology_present: bool = False # indicate if world type has any meaningful layout/pathing
item_names: Set[str] = frozenset() # set of all potential item names item_names: Set[str] = frozenset() # set of all potential item names
# maps item group names to sets of items. Example: "Weapons" -> {"Sword", "Bow"} # maps item group names to sets of items. Example: "Weapons" -> {"Sword", "Bow"}
@ -64,6 +72,10 @@ class World(metaclass=AutoWorldRegister):
# the client finds its own items in its own world. # the client finds its own items in its own world.
remote_items: bool = True remote_items: bool = True
# autoset on creation:
world: MultiWorld
player: int
def __init__(self, world: MultiWorld, player: int): def __init__(self, world: MultiWorld, player: int):
self.world = world self.world = world
self.player = player self.player = player
@ -102,3 +114,8 @@ class World(metaclass=AutoWorldRegister):
"""Create an item for this world type and player. """Create an item for this world type and player.
Warning: this may be called with self.world = None, for example by MultiServer""" Warning: this may be called with self.world = None, for example by MultiServer"""
raise NotImplementedError raise NotImplementedError
# any methods attached to this can be used as part of CollectionState,
# please use a prefix as all of them get clobbered together
class LogicMixin(metaclass=AutoLogicRegister):
pass

View File

@ -4,13 +4,13 @@ from typing import Set
logger = logging.getLogger("Hollow Knight") logger = logging.getLogger("Hollow Knight")
from .Locations import lookup_name_to_id from .Locations import lookup_name_to_id
from .Items import item_table from .Items import item_table, lookup_type_to_names
from .Regions import create_regions from .Regions import create_regions
from .Rules import set_rules from .Rules import set_rules
from .Options import hollow_knight_options from .Options import hollow_knight_options
from BaseClasses import Region, Entrance, Location, MultiWorld, Item from BaseClasses import Region, Entrance, Location, MultiWorld, Item
from ..AutoWorld import World from ..AutoWorld import World, LogicMixin
class HKWorld(World): class HKWorld(World):
game: str = "Hollow Knight" game: str = "Hollow Knight"
@ -145,5 +145,26 @@ option_to_type_lookup = {
} }
class HKLogic(LogicMixin):
# these are all wip
def _hk_has_essence(self, player: int, count: int):
return self.prog_items["Dream_Nail", player]
# return self.prog_items["Essence", player] >= count
def _hk_has_grubs(self, player: int, count: int):
found = 0
for item_name in lookup_type_to_names["Grub"]:
found += self.prog_items[item_name, player]
if found >= count:
return True
return False
def _hk_has_flames(self, player: int, count: int):
found = 0
for item_name in lookup_type_to_names["Flame"]:
found += self.prog_items[item_name, player]
if found >= count:
return True
return False