Compare commits

...

16 Commits

5 changed files with 167 additions and 16 deletions

2
TODO.md Normal file
View File

@ -0,0 +1,2 @@
# TODO
- Add turn / round based systems

View File

@ -7,4 +7,4 @@ name = "gameUtils"
version = "1.0.0"
description = "A set of utilities to make the game development process less painful (despite the organisation name) and more unified."
authors = [{ name = "Brosef" }]
dependencies = ["pygame-ce"]
dependencies = ["pygame-ce", "pygame_gui"]

View File

@ -5,3 +5,5 @@ from .anim import AnimatedObject
from .events import AnimStart
from .events import AnimFinish
from .events import Timeout
from .turns import BaseTurnHandler
from .turns import RoundTable

View File

@ -1,8 +1,11 @@
from .events import Timeout
from .anim import AnimatedObject
import tomllib
import time
import NoPELib
from .events import Timeout
from .anim import AnimatedObject
class Game:
def __init__(self, surface):
"""
@ -12,30 +15,62 @@ class Game:
surface (pygame.Surface): The surface the game devs draw on.
"""
self.surf = surface
self.size = self.surf.size
self.pm = None
# Holds all the timeouts that haven't been fired yet
self._timeouts = []
with open('./game.toml', 'r') as f:
self.cfg = tomllib.loads(f.read())
self.surf = surface
self.size = self.surf.size
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()
# TODO: Draw things like debug menu, etc.
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)
def close(self):
pass
"""
Intended to be overridden by the game developer.
See BaseGame for documentation.
"""
def createAnimObj(self, *args, **kwargs):
"""
@ -60,3 +95,46 @@ class Game:
"""
self._timeouts.append(Timeout(id, time.perf_counter()+delay))
def awaitingTimeout(self, timeoutID: str):
"""
Tells you if a timeout ID is on the timeout stack.
Args:
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 == timeoutID for timeout in self._timeouts)
def popup(self, title: str, text: str, haltUpdate: bool=False, haltEvents: bool=True):
"""
Pops up a dialogue box.
Args:
title (str): The big "title" text to be displayed.
text (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.
"""
self._haltUpdate = haltUpdate
self._haltEvents = haltEvents
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.
"""

69
src/gameUtils/turns.py Normal file
View File

@ -0,0 +1,69 @@
# TODO: Add a variable for the game developers to see if pain is "avaialbe",
# I.E. has the shocker been passed to the next player.
# Also add a pop-up, probably using pygame-gui, to tell the player
# to pass the shocker to the next person.
# NOTE: Each expansion is assigned multiple players, if an expansion has a tag
# such as "ONE_PERSON_ONLY", it means that when the game developer wants
# to go to the next player, it must self.notify() the players to pass the
# physical object around.
# NOTE: That tag IS NOT a part of NoPE-Lib or PDO-Lib. It simply acts as an
# identifier for games to use.
# TODO: Add player config editor.
class BaseTurnHandler:
def __init__(self, playersManager):
"""
The base turn handler metaclass, used to create round
handlers such as round table.
"""
self._pm = playersManager
# The current turn number (0 based)
self.turn = 0
# The maximum number of turns
self.turns = len(self._pm)
# The current round number (0 based)
self.round = 0
# Which players are playing in this turn
self.playing = []
def next(self):
raise NotImplementedError
class RoundTable(BaseTurnHandler):
"""
A simple "round table" round system.
"""
# TODO: Add some kind of implementation with NoPE
# to determain if we actually need to re-assign PDOs.
def __init__(self, teamSize: int, *args, **kwargs):
"""
"""
super().__init__(*args, **kwargs)
if teamSize > len(self._pm):
raise Exception('Too little players for specified team size.') # TODO: Custom exception
self.teamSize = teamSize
self.turns //= self.teamSize
self.turn -= 1
self.next()
def next(self):
"""
Oh god I hate it.
"""
self.turn += 1
if self.turn >= self.turns:
self.turn -= self.turns
self.round += 1
self.playing = []
playerNames = list(self._pm.keys())
for i in range(self.teamSize):
self.playing.append(self._pm[playerNames[(i+self.turn)%len(playerNames)]])
return self.playing