64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
from __future__ import annotations
|
|
import threading, time
|
|
from dataclasses import asdict
|
|
from typing import Any, Dict, List
|
|
from .models import Actor, KNOWN_CONDITIONS, CONDITION_EMOJI, CONDITION_ICON_FILES
|
|
|
|
def now_ms() -> int:
|
|
return int(time.time() * 1000)
|
|
|
|
class CombatState:
|
|
def __init__(self) -> None:
|
|
self.actors: List[Actor] = []
|
|
self.turn_idx: int = 0
|
|
self.round: int = 1
|
|
self.visible: bool = True
|
|
self.dead_mode: str = 'normal' # 'normal' | 'shrink' | 'hide'
|
|
self.updated_at: int = now_ms()
|
|
self.version: int = 1
|
|
self._cv = threading.Condition()
|
|
|
|
def touch(self) -> None:
|
|
self.updated_at = now_ms()
|
|
self.version += 1
|
|
|
|
def sorted_actors(self) -> List[Actor]:
|
|
return sorted(self.actors, key=lambda a: a.init, reverse=True)
|
|
|
|
def normalize(self) -> None:
|
|
self.actors = self.sorted_actors()
|
|
if self.turn_idx >= len(self.actors):
|
|
self.turn_idx = 0
|
|
|
|
def to_public(self) -> Dict[str, Any]:
|
|
return {
|
|
'actors': [asdict(a) for a in self.sorted_actors()],
|
|
'turn_idx': self.turn_idx,
|
|
'round': self.round,
|
|
'visible': self.visible,
|
|
'dead_mode': self.dead_mode,
|
|
'updated_at': self.updated_at,
|
|
'version': self.version,
|
|
'condition_icons': CONDITION_ICON_FILES,
|
|
'condition_emoji': CONDITION_EMOJI,
|
|
'known_conditions': KNOWN_CONDITIONS,
|
|
}
|
|
|
|
def broadcast(self) -> None:
|
|
with self._cv:
|
|
self.touch()
|
|
self._cv.notify_all()
|
|
|
|
def wait_for(self, since: int, timeout: float = 25.0) -> Dict[str, Any]:
|
|
end = time.time() + timeout
|
|
with self._cv:
|
|
while self.version <= since:
|
|
remaining = end - time.time()
|
|
if remaining <= 0:
|
|
break
|
|
self._cv.wait(timeout=remaining)
|
|
return self.to_public()
|
|
|
|
# Singleton
|
|
STATE = CombatState()
|