mirror of
https://github.com/hypervortex/VH-Bombsquad-Modded-Server-Files
synced 2025-11-07 17:36:08 +00:00
168 lines
5.6 KiB
Python
168 lines
5.6 KiB
Python
# Released under the MIT License. See LICENSE for details.
|
|
#
|
|
"""Implements respawn icon actor."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import weakref
|
|
from typing import TYPE_CHECKING
|
|
|
|
import ba
|
|
|
|
if TYPE_CHECKING:
|
|
pass
|
|
|
|
|
|
class RespawnIcon:
|
|
"""An icon with a countdown that appears alongside the screen.
|
|
|
|
category: Gameplay Classes
|
|
|
|
This is used to indicate that a ba.Player is waiting to respawn.
|
|
"""
|
|
|
|
_MASKTEXSTORENAME = ba.storagename('masktex')
|
|
_ICONSSTORENAME = ba.storagename('icons')
|
|
|
|
def __init__(self, player: ba.Player, respawn_time: float):
|
|
"""Instantiate with a ba.Player and respawn_time (in seconds)."""
|
|
self._visible = True
|
|
|
|
on_right, offs_extra, respawn_icons = self._get_context(player)
|
|
|
|
# Cache our mask tex on the team for easy access.
|
|
mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME)
|
|
if mask_tex is None:
|
|
mask_tex = ba.gettexture('characterIconMask')
|
|
player.team.customdata[self._MASKTEXSTORENAME] = mask_tex
|
|
assert isinstance(mask_tex, ba.Texture)
|
|
|
|
# Now find the first unused slot and use that.
|
|
index = 0
|
|
while (
|
|
index in respawn_icons
|
|
and respawn_icons[index]() is not None
|
|
and respawn_icons[index]().visible
|
|
):
|
|
index += 1
|
|
respawn_icons[index] = weakref.ref(self)
|
|
|
|
offs = offs_extra + index * -53
|
|
icon = player.get_icon()
|
|
texture = icon['texture']
|
|
h_offs = -10
|
|
ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs)
|
|
self._image: ba.NodeActor | None = ba.NodeActor(
|
|
ba.newnode(
|
|
'image',
|
|
attrs={
|
|
'texture': texture,
|
|
'tint_texture': icon['tint_texture'],
|
|
'tint_color': icon['tint_color'],
|
|
'tint2_color': icon['tint2_color'],
|
|
'mask_texture': mask_tex,
|
|
'position': ipos,
|
|
'scale': (32, 32),
|
|
'opacity': 1.0,
|
|
'absolute_scale': True,
|
|
'attach': 'topRight' if on_right else 'topLeft',
|
|
},
|
|
)
|
|
)
|
|
|
|
assert self._image.node
|
|
ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7})
|
|
|
|
npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs)
|
|
self._name: ba.NodeActor | None = ba.NodeActor(
|
|
ba.newnode(
|
|
'text',
|
|
attrs={
|
|
'v_attach': 'top',
|
|
'h_attach': 'right' if on_right else 'left',
|
|
'text': ba.Lstr(value=player.getname()),
|
|
'maxwidth': 100,
|
|
'h_align': 'center',
|
|
'v_align': 'center',
|
|
'shadow': 1.0,
|
|
'flatness': 1.0,
|
|
'color': ba.safecolor(icon['tint_color']),
|
|
'scale': 0.5,
|
|
'position': npos,
|
|
},
|
|
)
|
|
)
|
|
|
|
assert self._name.node
|
|
ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5})
|
|
|
|
tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs)
|
|
self._text: ba.NodeActor | None = ba.NodeActor(
|
|
ba.newnode(
|
|
'text',
|
|
attrs={
|
|
'position': tpos,
|
|
'h_attach': 'right' if on_right else 'left',
|
|
'h_align': 'right' if on_right else 'left',
|
|
'scale': 0.9,
|
|
'shadow': 0.5,
|
|
'flatness': 0.5,
|
|
'v_attach': 'top',
|
|
'color': ba.safecolor(icon['tint_color']),
|
|
'text': '',
|
|
},
|
|
)
|
|
)
|
|
|
|
assert self._text.node
|
|
ba.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9})
|
|
|
|
self._respawn_time = ba.time() + respawn_time
|
|
self._update()
|
|
self._timer: ba.Timer | None = ba.Timer(
|
|
1.0, ba.WeakCall(self._update), repeat=True
|
|
)
|
|
|
|
@property
|
|
def visible(self) -> bool:
|
|
"""Is this icon still visible?"""
|
|
return self._visible
|
|
|
|
def _get_context(self, player: ba.Player) -> tuple[bool, float, dict]:
|
|
"""Return info on where we should be shown and stored."""
|
|
activity = ba.getactivity()
|
|
|
|
if isinstance(ba.getsession(), ba.DualTeamSession):
|
|
on_right = player.team.id % 2 == 1
|
|
|
|
# Store a list of icons in the team.
|
|
icons = player.team.customdata.get(self._ICONSSTORENAME)
|
|
if icons is None:
|
|
player.team.customdata[self._ICONSSTORENAME] = icons = {}
|
|
assert isinstance(icons, dict)
|
|
|
|
offs_extra = -20
|
|
else:
|
|
on_right = False
|
|
|
|
# Store a list of icons in the activity.
|
|
icons = activity.customdata.get(self._ICONSSTORENAME)
|
|
if icons is None:
|
|
activity.customdata[self._ICONSSTORENAME] = icons = {}
|
|
assert isinstance(icons, dict)
|
|
|
|
if isinstance(activity.session, ba.FreeForAllSession):
|
|
offs_extra = -150
|
|
else:
|
|
offs_extra = -20
|
|
return on_right, offs_extra, icons
|
|
|
|
def _update(self) -> None:
|
|
remaining = int(round(self._respawn_time - ba.time()))
|
|
if remaining > 0:
|
|
assert self._text is not None
|
|
if self._text.node:
|
|
self._text.node.text = str(remaining)
|
|
else:
|
|
self._visible = False
|
|
self._image = self._text = self._timer = self._name = None
|