|
|
|
|
@ -1,9 +1,13 @@
|
|
|
|
|
from .events import Timeout
|
|
|
|
|
from .anim import AnimatedObject
|
|
|
|
|
import NoPELib
|
|
|
|
|
import tomllib
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
import NoPELib
|
|
|
|
|
import pygame
|
|
|
|
|
|
|
|
|
|
from .events import Timeout
|
|
|
|
|
from .anim import AnimatedObject
|
|
|
|
|
from .utils import centre
|
|
|
|
|
|
|
|
|
|
class Game:
|
|
|
|
|
def __init__(self, surface):
|
|
|
|
|
"""
|
|
|
|
|
@ -16,27 +20,88 @@ class Game:
|
|
|
|
|
with open('./game.toml', 'r') as f:
|
|
|
|
|
self.cfg = tomllib.loads(f.read())
|
|
|
|
|
|
|
|
|
|
self.surf = surface
|
|
|
|
|
# The surface that gets drawn by the launcher.
|
|
|
|
|
# Contains the game surface, and overlays.
|
|
|
|
|
self._surf = surface
|
|
|
|
|
# The games serface
|
|
|
|
|
self.surf = pygame.Surface(self._surf.size)
|
|
|
|
|
self.size = self.surf.size
|
|
|
|
|
# Used for time delta, stores when the last frame was drawn
|
|
|
|
|
self._lastFrame = time.perf_counter()
|
|
|
|
|
# How many seconds it's been between frames
|
|
|
|
|
self.timeDelta = 0
|
|
|
|
|
# Pre-render semi-transparent black surface
|
|
|
|
|
self._dimSurf = pygame.Surface(self._surf.size)
|
|
|
|
|
self._dimSurf.set_alpha(128)
|
|
|
|
|
pygame.draw.rect(self._dimSurf, (50, 50, 50), (0, 0, self.size[0], self.size[1]))
|
|
|
|
|
|
|
|
|
|
self.pm = NoPELib.PlayersManager(self.cfg['name'], playersPath='../players.json')
|
|
|
|
|
# Holds all the timeouts that haven't been fired yet
|
|
|
|
|
self._timeouts = []
|
|
|
|
|
# The following are used by self.popup() to halt some events
|
|
|
|
|
self._haltUpdate = False
|
|
|
|
|
self._haltEvents = False
|
|
|
|
|
# Will become a pygame.Surface with the popup contents
|
|
|
|
|
self._popupMenu = None
|
|
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
|
"""
|
|
|
|
|
Updates some core things in the background.
|
|
|
|
|
Intended to be overridden by the game developer.
|
|
|
|
|
See BaseGame for documentation.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def _update(self):
|
|
|
|
|
"""
|
|
|
|
|
Updates some core things in the background, and calls update()
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Handle timeouts
|
|
|
|
|
for timeout in self._timeouts.copy():
|
|
|
|
|
if timeout.fireOn <= time.perf_counter():
|
|
|
|
|
self.onEvent(timeout)
|
|
|
|
|
self._timeouts.remove(timeout)
|
|
|
|
|
|
|
|
|
|
# Game update
|
|
|
|
|
if not self._haltUpdate:
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
|
|
# Draw the game surface onto the main surface
|
|
|
|
|
self._surf.blit(self.surf, (0, 0))
|
|
|
|
|
|
|
|
|
|
# If there's a popup
|
|
|
|
|
if self._popupMenu is not None:
|
|
|
|
|
# Dim the screen
|
|
|
|
|
self._surf.blit(self._dimSurf, (0, 0))
|
|
|
|
|
self._surf.blit(centre(self._popupMenu, self.size), (0, 0))
|
|
|
|
|
|
|
|
|
|
self.timeDelta = time.perf_counter() - self._lastFrame
|
|
|
|
|
self._lastFrame = time.perf_counter()
|
|
|
|
|
|
|
|
|
|
def onEvent(self, event):
|
|
|
|
|
pass
|
|
|
|
|
"""
|
|
|
|
|
Intended to be overridden by the game developer.
|
|
|
|
|
See BaseGame for documentation.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def _onEvent(self, event):
|
|
|
|
|
"""
|
|
|
|
|
Updates some core things in the background, and calls onEvent()
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
if not self._haltEvents:
|
|
|
|
|
self.onEvent(event)
|
|
|
|
|
|
|
|
|
|
if event.type == pygame.KEYDOWN and self._popupMenu is not None:
|
|
|
|
|
if event.key == 13 and event.mod & 0b10000000: # R-CTRL + ENTER
|
|
|
|
|
self._popupMenu = None
|
|
|
|
|
self._haltUpdate = False
|
|
|
|
|
self._haltEvents = False
|
|
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
|
pass
|
|
|
|
|
"""
|
|
|
|
|
Intended to be overridden by the game developer.
|
|
|
|
|
See BaseGame for documentation.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def createAnimObj(self, *args, **kwargs):
|
|
|
|
|
"""
|
|
|
|
|
@ -62,20 +127,59 @@ class Game:
|
|
|
|
|
|
|
|
|
|
self._timeouts.append(Timeout(id, time.perf_counter()+delay))
|
|
|
|
|
|
|
|
|
|
def awaitingTimeout(self, id: str):
|
|
|
|
|
def awaitingTimeout(self, timeoutID: str):
|
|
|
|
|
"""
|
|
|
|
|
Tells you if a timeout ID is on the timeout stack.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
id (str): The timeout ID.
|
|
|
|
|
timeoutID (str): The timeout ID.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
bool: True if there is a timeout with that ID
|
|
|
|
|
ID on the stack, False otherwise.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
return any([timeout.timeoutID == id for timeout in self._timeouts])
|
|
|
|
|
return any(timeout.timeoutID == timeoutID for timeout in self._timeouts)
|
|
|
|
|
|
|
|
|
|
# TODO: Add popup method
|
|
|
|
|
def popup(self, title: str, message: str, haltUpdate: bool=False, haltEvents: bool=True):
|
|
|
|
|
"""
|
|
|
|
|
Pops up a dialogue box.
|
|
|
|
|
|
|
|
|
|
# TODO: add punish(player, intensity)
|
|
|
|
|
Args:
|
|
|
|
|
title (str): The big "title" text to be displayed.
|
|
|
|
|
message (str): The main body text to be displayed.
|
|
|
|
|
haltUpdate (bool): If True, the games update() method will not be called until
|
|
|
|
|
the popup is dismissed. Default: False.
|
|
|
|
|
haltEvents (bool): If True, the games onEvent() method will not be called until
|
|
|
|
|
the popup is dismissed. Default: True.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
POPUP_MARGINS = 10
|
|
|
|
|
FONT_BIG = pygame.font.SysFont('', 50)
|
|
|
|
|
FONT_NORM = pygame.font.SysFont('', 32)
|
|
|
|
|
|
|
|
|
|
titleSurf = FONT_BIG.render(title, True, (128, 128, 128))
|
|
|
|
|
messageSurf = FONT_NORM.render(message, True, (128, 128, 128))
|
|
|
|
|
|
|
|
|
|
w = max(titleSurf.get_width(), messageSurf.get_width())
|
|
|
|
|
w += POPUP_MARGINS*2
|
|
|
|
|
h = titleSurf.get_height() + messageSurf.get_height()
|
|
|
|
|
h += POPUP_MARGINS*3
|
|
|
|
|
|
|
|
|
|
self._haltUpdate = haltUpdate
|
|
|
|
|
self._haltEvents = haltEvents
|
|
|
|
|
self._popupMenu = pygame.Surface((w, h))
|
|
|
|
|
self._popupMenu.fill((0, 0, 0))
|
|
|
|
|
self._popupMenu.blit(centre(titleSurf, (w, titleSurf.get_height())), (0, POPUP_MARGINS))
|
|
|
|
|
self._popupMenu.blit(centre(messageSurf, (w, messageSurf.get_height())), (0, titleSurf.get_height()+POPUP_MARGINS*2))
|
|
|
|
|
|
|
|
|
|
def punish(self, player, intensity: float):
|
|
|
|
|
"""
|
|
|
|
|
Handles punishing players for most games.
|
|
|
|
|
Handles games preferences on PDO order?
|
|
|
|
|
Handles auto popups for messaged events.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
player (NoPELib.Player): The player to punish.
|
|
|
|
|
intensity (float): The intensity to punish the player.
|
|
|
|
|
"""
|
|
|
|
|
|