Source code for scripts.engine.internal.event

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 ExitMenuEvent(Event):
[docs] def __init__(self, menu: UIElement): super().__init__(EventType.GAME) self.menu: UIElement = menu
[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 ShrineMenuEvent(Event): # blessing_options is actually of type List[SkillModifier], but I'm trying to avoid circular imports
[docs] def __init__(self, blessing_options: List[Any]): super().__init__(EventType.GAME) self.blessing_options: List[Any] = blessing_options
[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