Source code for scripts.engine.core.hourglass

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from snecs.typedefs import EntityID

import scripts.engine.core.matter
from scripts.engine.core import query
from scripts.engine.core.component import Tracked
from scripts.engine.internal import library
from scripts.engine.internal.data import store
from scripts.engine.internal.event import EndRoundEvent, EndTurnEvent, event_hub, NewRoundEvent, NewTurnEvent

if TYPE_CHECKING:
    from typing import Dict, List, Optional, Tuple


############ ACTIONS ##################


[docs]def rebuild_turn_queue(entity_to_exclude: Optional[EntityID] = None): """ Build a new turn queue that includes all timed entities. entity_to_exclude is one that should not be added to the queue. Usually used in relation to deletion. """ logging.debug(f"Building a new turn queue...") # create a turn queue from the entities list new_queue = {} for entity, ( is_active, tracked, ) in query.active_and_tracked: if entity != entity_to_exclude: assert isinstance(tracked, Tracked) new_queue[entity] = tracked.time_spent # did we actually allocate to anyone? if not new_queue: # add player to queue new_queue[scripts.engine.core.matter.get_player()] = get_time() set_turn_queue(new_queue) # get the next entity in the queue and set as new turn holder set_previous_turn_holder(get_turn_holder()) set_turn_holder(_get_next_entity_in_queue()) # log result logging.debug(f"-> New queue built: {_get_pretty_queue()}")
[docs]def next_turn(entity_to_exclude: Optional[EntityID] = None): """ Proceed to the next turn, setting the next entity to act as the turn holder and updating the passage of time. Posts NEW_TURN event. """ logging.info(f"Moving to the next turn...") # update the queue rebuild_turn_queue(entity_to_exclude) # get next entity in queue turn_holder = get_turn_holder() # whats the difference between current time and when they last acted? tracked = scripts.engine.core.matter.get_entitys_component(turn_holder, Tracked) if tracked: next_entity_time = tracked.time_spent else: next_entity_time = get_time_of_last_turn() # turn holder should always have Tracked but handle if they dont time_progressed = next_entity_time - get_time_of_last_turn() # add the difference to the time _add_time(time_progressed) set_time_of_last_turn(get_time()) # check if we need to set new round time_per_round = library.GAME_CONFIG.default_values.time_per_round if get_time_in_round() + time_progressed >= time_per_round: end_round() # add progressed time and minus time_in_round to keep the remaining time set_time_in_round((get_time_in_round() + time_progressed) - time_per_round) else: set_time_in_round(get_time_in_round() + time_progressed) # post game event event_hub.post(NewTurnEvent()) # log new turn holder name = scripts.engine.core.matter.get_name(turn_holder) logging.debug(f"-> Current time is {get_time()}. We are {get_time_in_round()} TU`s into round {get_round()}.") logging.debug(f"-> '{name}' is now the turn holder.")
[docs]def end_turn(entity: EntityID, time_spent: int): """ Spend an entities time, progress time, move to next acting entity in queue. Posts END_TURN event. N.B. If entity given is NOT the turn holder then nothing happens. """ if entity == get_turn_holder(): scripts.engine.core.matter.spend_time(entity, time_spent) # post game event event_hub.post(EndTurnEvent()) else: logging.warning( f"Tried to end {scripts.engine.core.matter.get_name(entity)}'s turn but they're not turn holder." )
[docs]def next_round(): """ Move to the next round. Posts NEW_ROUND event. """ # post game event event_hub.post(NewRoundEvent()) # increment rounds _increment_round_number() logging.info(f"It is now round {get_round()}.")
[docs]def end_round(): """ Posts END_ROUND event. """ # post game event event_hub.post(EndRoundEvent())
def _increment_round_number(): """ Increment the round by 1 """ store.round += 1 def _add_time(time_to_add: int): """ Add to the current time """ store.time += time_to_add ############# GET ###################
[docs]def get_turn_holder() -> EntityID: """ Get the entity who has the current turn """ return store.turn_holder
[docs]def get_previous_turn_holder() -> EntityID: """ Get the entity who had the last turn """ return store.previous_turn_holder
[docs]def get_turn_queue() -> Dict[EntityID, int]: """ Get the turn queue """ return store.turn_queue
[docs]def get_time_in_round() -> int: """ Get current time in the current round """ return store.round_time
[docs]def get_time() -> int: """ Get the current time """ return store.time
[docs]def get_time_of_last_turn() -> int: """ Get the time of the last turn """ return store.time_of_last_turn
[docs]def get_time_left_in_round() -> int: """ Get the amount of time left in the current round """ return library.GAME_CONFIG.default_values.time_per_round - get_time_in_round()
[docs]def get_round() -> int: """ Get the current round """ return store.round
def _get_pretty_queue() -> List[Tuple[str, int]]: queue = [] for entity, time in get_turn_queue().items(): name = scripts.engine.core.matter.get_name(entity) queue.append((name, time)) return queue def _get_next_entity_in_queue() -> EntityID: queue = get_turn_queue() next_entity = min(queue, key=queue.get) # type: ignore return next_entity ############# SET ###################
[docs]def set_turn_holder(active_entity: EntityID): """ Set the entity who has the current turn """ store.turn_holder = active_entity
[docs]def set_previous_turn_holder(entity: EntityID): """ Set the entity who had the last turn """ store.previous_turn_holder = entity
[docs]def set_time_in_round(time: int): """ Set current time in the current round """ store.round_time = time
[docs]def set_turn_queue(queue: Dict[EntityID, int]): """ Set the turn queue """ store.turn_queue = queue
[docs]def set_time_of_last_turn(time: int): """ Set the time of the last turn """ store.time_of_last_turn = time