from __future__ import annotations
from abc import ABC, abstractmethod
from typing import Dict, List, Tuple, Any
from snecs.typedefs import EntityID
from scripts.engine.internal.constant import DamageTypeType, DirectionType, EventType, PrimaryStatType, UIElement
from scripts.engine.internal.definition import ActorData
__all__ = [
"event_hub",
"Subscriber",
"MoveEvent",
"DamageEvent",
"AffectStatEvent",
"AffectCooldownEvent",
"AfflictionEvent",
"AlterTerrainEvent",
"ExitGameEvent",
"ExitMenuEvent",
"NewGameEvent",
"NewTurnEvent",
"NewRoundEvent",
"EndRoundEvent",
"EndTurnEvent",
"StartGameEvent",
"LoadGameEvent",
"WinConditionMetEvent",
"LoseConditionMetEvent",
"ChangeMapEvent",
"MessageEvent",
]
[docs]class EventHub:
"""
Event hub to handle the interactions between events and subscribers
"""
[docs] def __init__(self):
self.events: List[Event] = []
self.subscribers: Dict = {}
[docs] def post(self, event: Event):
"""
Log an event ready for notifying subscribers.
"""
self.events.append(event)
[docs] def subscribe(self, event_type: EventType, subscriber: Subscriber):
"""
Register a subscriber with an EventType
"""
self.subscribers.setdefault(event_type, []).append(subscriber)
[docs] def unsubscribe(self, event_type: EventType, subscriber: Subscriber):
"""
Remove a subscribers registration to an EventType
"""
self.subscribers[event_type].remove(subscriber)
[docs] def peek(self, event):
"""
Check if an event exists in the queue.
Return None if nothing is found so the result can be used as a bool.
"""
found_events = []
for e in self.events:
if isinstance(e, event): # type: ignore
found_events.append(e)
if found_events != []:
return found_events
return None
[docs] def update(self):
"""
Notify subscribers of their registered event.
"""
# loop every event and notify every subscriber
while self.events:
event = self.events.pop(0)
for sub in self.subscribers.get(event.event_type, []):
sub.process_event(event)
event_hub = EventHub()
[docs]class Subscriber(ABC):
"""
Class to set default behaviour for handlers listening for events
"""
[docs] def __init__(self, name: str):
self.name: str = name
self.event_hub: EventHub = event_hub
[docs] def subscribe(self, event_type: EventType):
self.event_hub.subscribe(event_type, self)
[docs] def unsubscribe(self, event_type: EventType):
self.event_hub.unsubscribe(event_type, self)
[docs] @abstractmethod
def process_event(self, event: Event):
"""
Process game events.
"""
pass
[docs]class Event(ABC):
"""
Events to cause top level actions to take place
"""
[docs] def __init__(self, event_type: EventType):
"""
Base class for events
"""
self.event_type = event_type
######################### INTERACTION EVENTS #########################
[docs]class MoveEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, direction: DirectionType, new_pos: Tuple[int, int]):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.direction: DirectionType = direction
self.new_pos: Tuple[int, int] = new_pos
[docs]class DamageEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, amount: int, damage_type: DamageTypeType, remaining_hp: int):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.amount: int = amount
self.damage_type: DamageTypeType = damage_type
self.remaining_hp: int = remaining_hp
[docs]class AffectStatEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, stat_to_target: PrimaryStatType, amount: int):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.stat_to_target: PrimaryStatType = stat_to_target
self.amount: int = amount
[docs]class AffectCooldownEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, amount: int):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.amount: int = amount
[docs]class AfflictionEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, affliction_name: str):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.affliction_name: str = affliction_name
[docs]class AlterTerrainEvent(Event):
[docs] def __init__(self, origin: EntityID, target: EntityID, terrain_name: str, duration: int):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.target: EntityID = target
self.terrain_name: str = terrain_name
self.duration: int = duration
[docs]class UseSkillEvent(Event):
[docs] def __init__(self, origin: EntityID, skill_name: str):
super().__init__(EventType.INTERACTION)
self.origin: EntityID = origin
self.skill_name = skill_name
######################### GAME EVENTS #########################
[docs]class NewGameEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class StartGameEvent(Event):
[docs] def __init__(self, player_data: ActorData):
super().__init__(EventType.GAME)
self.player_data: ActorData = player_data
[docs]class LoadGameEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class ExitGameEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class WinConditionMetEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class LoseConditionMetEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class ChangeMapEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class ShrineEvent(Event):
[docs] def __init__(self, entity_id: int):
super().__init__(EventType.GAME)
self.target_shrine: int = entity_id
[docs]class NewTurnEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class EndTurnEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class NewRoundEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class EndRoundEvent(Event):
[docs] def __init__(self):
super().__init__(EventType.GAME)
[docs]class MessageEvent(Event):
[docs] def __init__(self, message: str):
super().__init__(EventType.GAME)
self.message = message