mirror of
https://github.com/hypervortex/VH-Bombsquad-Modded-Server-Files
synced 2026-08-15 13:04:50 +00:00
131 lines
4.1 KiB
Python
131 lines
4.1 KiB
Python
# Released under the MIT License. See LICENSE for details.
|
|
#
|
|
"""Defines Actor(s)."""
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, overload
|
|
|
|
import ba
|
|
|
|
if TYPE_CHECKING:
|
|
from typing import Any, Literal
|
|
|
|
|
|
class OnScreenTimer(ba.Actor):
|
|
"""A handy on-screen timer.
|
|
|
|
category: Gameplay Classes
|
|
|
|
Useful for time-based games where time increases.
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self._starttime_ms: int | None = None
|
|
self.node = ba.newnode(
|
|
'text',
|
|
attrs={
|
|
'v_attach': 'top',
|
|
'h_attach': 'center',
|
|
'h_align': 'center',
|
|
'color': (1, 1, 0.5, 1),
|
|
'flatness': 0.5,
|
|
'shadow': 0.5,
|
|
'position': (0, -70),
|
|
'scale': 1.4,
|
|
'text': '',
|
|
},
|
|
)
|
|
self.inputnode = ba.newnode(
|
|
'timedisplay', attrs={'timemin': 0, 'showsubseconds': True}
|
|
)
|
|
self.inputnode.connectattr('output', self.node, 'text')
|
|
|
|
def start(self) -> None:
|
|
"""Start the timer."""
|
|
tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
|
assert isinstance(tval, int)
|
|
self._starttime_ms = tval
|
|
self.inputnode.time1 = self._starttime_ms
|
|
ba.getactivity().globalsnode.connectattr(
|
|
'time', self.inputnode, 'time2'
|
|
)
|
|
|
|
def has_started(self) -> bool:
|
|
"""Return whether this timer has started yet."""
|
|
return self._starttime_ms is not None
|
|
|
|
def stop(
|
|
self,
|
|
endtime: int | float | None = None,
|
|
timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS,
|
|
) -> None:
|
|
"""End the timer.
|
|
|
|
If 'endtime' is not None, it is used when calculating
|
|
the final display time; otherwise the current time is used.
|
|
|
|
'timeformat' applies to endtime and can be SECONDS or MILLISECONDS
|
|
"""
|
|
if endtime is None:
|
|
endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
|
timeformat = ba.TimeFormat.MILLISECONDS
|
|
|
|
if self._starttime_ms is None:
|
|
print('Warning: OnScreenTimer.stop() called without start() first')
|
|
else:
|
|
endtime_ms: int
|
|
if timeformat is ba.TimeFormat.SECONDS:
|
|
endtime_ms = int(endtime * 1000)
|
|
elif timeformat is ba.TimeFormat.MILLISECONDS:
|
|
assert isinstance(endtime, int)
|
|
endtime_ms = endtime
|
|
else:
|
|
raise ValueError(f'invalid timeformat: {timeformat}')
|
|
|
|
self.inputnode.timemax = endtime_ms - self._starttime_ms
|
|
|
|
# Overloads so type checker knows our exact return type based in args.
|
|
@overload
|
|
def getstarttime(
|
|
self, timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS
|
|
) -> float:
|
|
...
|
|
|
|
@overload
|
|
def getstarttime(
|
|
self, timeformat: Literal[ba.TimeFormat.MILLISECONDS]
|
|
) -> int:
|
|
...
|
|
|
|
def getstarttime(
|
|
self, timeformat: ba.TimeFormat = ba.TimeFormat.SECONDS
|
|
) -> int | float:
|
|
"""Return the sim-time when start() was called.
|
|
|
|
Time will be returned in seconds if timeformat is SECONDS or
|
|
milliseconds if it is MILLISECONDS.
|
|
"""
|
|
val_ms: Any
|
|
if self._starttime_ms is None:
|
|
print('WARNING: getstarttime() called on un-started timer')
|
|
val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
|
else:
|
|
val_ms = self._starttime_ms
|
|
assert isinstance(val_ms, int)
|
|
if timeformat is ba.TimeFormat.SECONDS:
|
|
return 0.001 * val_ms
|
|
if timeformat is ba.TimeFormat.MILLISECONDS:
|
|
return val_ms
|
|
raise ValueError(f'invalid timeformat: {timeformat}')
|
|
|
|
@property
|
|
def starttime(self) -> float:
|
|
"""Shortcut for start time in seconds."""
|
|
return self.getstarttime()
|
|
|
|
def handlemessage(self, msg: Any) -> Any:
|
|
# if we're asked to die, just kill our node/timer
|
|
if isinstance(msg, ba.DieMessage):
|
|
if self.node:
|
|
self.node.delete()
|