vh-bombsquad-modded-server-.../dist/ba_data/python/bastd/actor/onscreentimer.py
2024-02-19 18:29:19 +05:30

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()