Source code for scripts.engine.core.state

from __future__ import annotations

import datetime
import json
import logging
import os
from typing import Tuple

import scripts.engine.core.matter
from scripts.engine.core import utility, world
from scripts.engine.internal import library
from scripts.engine.internal.constant import GameState, MAX_SAVES, SAVE_PATH, VERSION
from scripts.engine.internal.data import store

__all__ = [
    "get_previous",
    "get_internal_clock",
    "get_active_skill",
    "get_current",
    "set_active_skill",
    "update_clock",
    "set_new",
    "save_game",
    "dump_save_game",
    "load_game",
]

_save = {}

################### GET ##############################


[docs]def get_previous() -> GameState: """ Get the previous game state """ return store.previous_game_state
[docs]def get_internal_clock(): """ Get the internal clock """ return store.internal_clock
[docs]def get_active_skill() -> str: """ Get the active skill. Used for targeting mode. """ return store.active_skill
[docs]def get_active_skill_target() -> Tuple[int, int]: """ Get the active skill target. Used for targeting mode. """ return store.active_skill_target
[docs]def get_skill_target_valid() -> bool: """ Get the validity of the current target. Used for targeting mode. """ return store.skill_target_valid
[docs]def get_current() -> GameState: """ Get the current game state """ return store.current_game_state
################### MANAGING STATE ###################
[docs]def initialise_engine(): """ Initialise engine resources. N.B. Must be called before using the rest of the engine. """ # load modules that have module level instances the engine needs import scripts.engine.core.system import scripts.engine.core.ui import scripts.engine.internal.data import scripts.engine.internal.debug import scripts.engine.internal.library # register any Actions that exist within the engine from scripts.engine.internal.action import DelayedSkill, Projectile, register_action register_action(Projectile) register_action(DelayedSkill)
[docs]def update_clock() -> float: """ Tick the internal clock. Manages the frame rate. Returns delta time. """ return store.internal_clock.tick(library.VIDEO_CONFIG.fps_limit) / 1000.0
[docs]def set_new(new_game_state: GameState): """ Set the current game state """ store.previous_game_state = store.current_game_state store.current_game_state = new_game_state prev_name = utility.value_to_member(store.previous_game_state, GameState) curr_name = utility.value_to_member(store.current_game_state, GameState) log_string = f"game_state updated from {prev_name} to {curr_name}" logging.info(log_string)
[docs]def set_active_skill(skill_name: str): """ Set the active skill. Used for targeting mode. """ store.active_skill = skill_name
[docs]def set_active_skill_target(skill_target: Tuple[int, int]): """ Set the active skill target. Used for targeting mode. """ store.active_skill_target = skill_target
[docs]def set_skill_target_valid(skill_target_valid: bool): """ Set the validity of the current target. Used for targeting mode. """ store.skill_target_valid = skill_target_valid
##################### SAVE AND LOAD #######################
[docs]def save_game(): """ Serialise the game data to an internal container """ global _save # clear existing save data _save = {} # get the info needed full_save_path = SAVE_PATH save = {} # Prevent FileNotFoundError if not os.path.isdir(full_save_path): os.makedirs(full_save_path) # add data to dict save["version"] = VERSION save["world"] = world.serialise() save["store"] = store.serialise() # prep filename player = scripts.engine.core.matter.get_player() name = scripts.engine.core.matter.get_name(player) name = name.replace(" ", "_") # clean name date_and_time = datetime.datetime.utcnow().strftime("%Y%m%d@%H%M%S") save_name_prefix = f"{name}" new_save_name = f"{save_name_prefix}_{date_and_time}" # clear old saves existing_saves = [] # get existing save files and check if they match for save_name in os.listdir(str(full_save_path)): if save_name_prefix in save_name: existing_saves.append(save_name) existing_saves = sorted(existing_saves) while len(existing_saves) > MAX_SAVES - 1: # -1 to handle the offset save_name = existing_saves.pop(0) os.remove(str(full_save_path / save_name)) # update save data _save[new_save_name] = save
[docs]def dump_save_game(): """ Export the save game data, if it exists, to an external json file """ global _save for save_name, save_values in _save.items(): # write to json str_path = str(SAVE_PATH / save_name) + ".json" with open(str_path, "w") as file: json.dump(save_values, file, indent=4) logging.info("Save file dumped.")
[docs]def load_game(filename: str): """ Deserialise the game data from a file. Filename does not include path to save folder. """ # read from json str_path = str(SAVE_PATH / filename) + ".json" with open(str_path, "r") as file: save = json.load(file) # check the version if save["version"] != VERSION: logging.warning(f"Loading data from a previous version, {save['version']}.") # deserialise data store.deserialise(save["store"]) new_world = world.deserialise(save["world"]) # set the data as the default world world.move_world(new_world) logging.info(f"Game loaded from {filename}.")