89 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import typing
 | |
| from itertools import chain
 | |
| from typing import Callable, Set
 | |
| 
 | |
| from . import pyevermizer
 | |
| from .options import EnergyCore, OutOfBounds, SequenceBreaks, SoEOptions
 | |
| 
 | |
| if typing.TYPE_CHECKING:
 | |
|     from BaseClasses import CollectionState
 | |
| 
 | |
| # TODO: Options may preset certain progress steps (i.e. P_ROCK_SKIP), set in generate_early?
 | |
| 
 | |
| # TODO: resolve/flatten/expand rules to get rid of recursion below where possible
 | |
| # Logic.rules are all rules including locations, excluding those with no progress (i.e. locations that only drop items)
 | |
| rules = pyevermizer.get_logic()
 | |
| # Logic.items are all items and extra items excluding non-progression items and duplicates
 | |
| # NOTE: we are skipping sniff items here because none of them is supposed to provide progression
 | |
| item_names: Set[str] = set()
 | |
| items = [item for item in filter(lambda item: item.progression,  # type: ignore[arg-type]
 | |
|                                  chain(pyevermizer.get_items(), pyevermizer.get_extra_items()))
 | |
|          if item.name not in item_names and not item_names.add(item.name)]  # type: ignore[func-returns-value]
 | |
| 
 | |
| 
 | |
| class SoEPlayerLogic:
 | |
|     __slots__ = "player", "out_of_bounds", "sequence_breaks", "has"
 | |
|     player: int
 | |
|     out_of_bounds: bool
 | |
|     sequence_breaks: bool
 | |
| 
 | |
|     has: Callable[..., bool]
 | |
|     """
 | |
|     Returns True if count of one of evermizer's progress steps is reached based on collected items. i.e. 2 * P_DE
 | |
|     """
 | |
| 
 | |
|     def __init__(self, player: int, options: "SoEOptions"):
 | |
|         self.player = player
 | |
|         self.out_of_bounds = options.out_of_bounds == OutOfBounds.option_logic
 | |
|         self.sequence_breaks = options.sequence_breaks == SequenceBreaks.option_logic
 | |
| 
 | |
|         if options.energy_core == EnergyCore.option_fragments:
 | |
|             # override logic for energy core fragments
 | |
|             required_fragments = options.required_fragments.value
 | |
| 
 | |
|             def fragmented_has(state: "CollectionState", progress: int, count: int = 1) -> bool:
 | |
|                 if progress == pyevermizer.P_ENERGY_CORE:
 | |
|                     progress = pyevermizer.P_CORE_FRAGMENT
 | |
|                     count = required_fragments
 | |
|                 return self._has(state, progress, count)
 | |
| 
 | |
|             self.has = fragmented_has
 | |
|         else:
 | |
|             # default (energy core) logic
 | |
|             self.has = self._has
 | |
| 
 | |
|     def _count(self, state: "CollectionState", progress: int, max_count: int = 0) -> int:
 | |
|         """
 | |
|         Returns reached count of one of evermizer's progress steps based on collected items.
 | |
|         i.e. returns 0-3 for P_DE based on items providing CHECK_BOSS,DIAMOND_EYE_DROP
 | |
|         """
 | |
|         n = 0
 | |
|         for item in items:
 | |
|             for pvd in item.provides:
 | |
|                 if pvd[1] == progress:
 | |
|                     if state.has(item.name, self.player):
 | |
|                         n += state.count(item.name, self.player) * pvd[0]
 | |
|                         if n >= max_count > 0:
 | |
|                             return n
 | |
|         for rule in rules:
 | |
|             for pvd in rule.provides:
 | |
|                 if pvd[1] == progress and pvd[0] > 0:
 | |
|                     has = True
 | |
|                     for req in rule.requires:
 | |
|                         if not self.has(state, req[1], req[0]):
 | |
|                             has = False
 | |
|                             break
 | |
|                     if has:
 | |
|                         n += pvd[0]
 | |
|                         if n >= max_count > 0:
 | |
|                             return n
 | |
|         return n
 | |
| 
 | |
|     def _has(self, state: "CollectionState", progress: int, count: int = 1) -> bool:
 | |
|         """Default implementation of has"""
 | |
|         if self.out_of_bounds is True and progress == pyevermizer.P_ALLOW_OOB:
 | |
|             return True
 | |
|         if self.sequence_breaks is True and progress == pyevermizer.P_ALLOW_SEQUENCE_BREAKS:
 | |
|             return True
 | |
|         return self._count(state, progress, count) >= count
 | 
