bastd.actor.respawnicon
Implements respawn icon actor.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Implements respawn icon actor.""" 4 5from __future__ import annotations 6 7import weakref 8from typing import TYPE_CHECKING 9 10import ba 11 12if TYPE_CHECKING: 13 pass 14 15 16class RespawnIcon: 17 """An icon with a countdown that appears alongside the screen. 18 19 category: Gameplay Classes 20 21 This is used to indicate that a ba.Player is waiting to respawn. 22 """ 23 24 _MASKTEXSTORENAME = ba.storagename('masktex') 25 _ICONSSTORENAME = ba.storagename('icons') 26 27 def __init__(self, player: ba.Player, respawn_time: float): 28 """Instantiate with a ba.Player and respawn_time (in seconds).""" 29 self._visible = True 30 31 on_right, offs_extra, respawn_icons = self._get_context(player) 32 33 # Cache our mask tex on the team for easy access. 34 mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME) 35 if mask_tex is None: 36 mask_tex = ba.gettexture('characterIconMask') 37 player.team.customdata[self._MASKTEXSTORENAME] = mask_tex 38 assert isinstance(mask_tex, ba.Texture) 39 40 # Now find the first unused slot and use that. 41 index = 0 42 while ( 43 index in respawn_icons 44 and respawn_icons[index]() is not None 45 and respawn_icons[index]().visible 46 ): 47 index += 1 48 respawn_icons[index] = weakref.ref(self) 49 50 offs = offs_extra + index * -53 51 icon = player.get_icon() 52 texture = icon['texture'] 53 h_offs = -10 54 ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs) 55 self._image: ba.NodeActor | None = ba.NodeActor( 56 ba.newnode( 57 'image', 58 attrs={ 59 'texture': texture, 60 'tint_texture': icon['tint_texture'], 61 'tint_color': icon['tint_color'], 62 'tint2_color': icon['tint2_color'], 63 'mask_texture': mask_tex, 64 'position': ipos, 65 'scale': (32, 32), 66 'opacity': 1.0, 67 'absolute_scale': True, 68 'attach': 'topRight' if on_right else 'topLeft', 69 }, 70 ) 71 ) 72 73 assert self._image.node 74 ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7}) 75 76 npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs) 77 self._name: ba.NodeActor | None = ba.NodeActor( 78 ba.newnode( 79 'text', 80 attrs={ 81 'v_attach': 'top', 82 'h_attach': 'right' if on_right else 'left', 83 'text': ba.Lstr(value=player.getname()), 84 'maxwidth': 100, 85 'h_align': 'center', 86 'v_align': 'center', 87 'shadow': 1.0, 88 'flatness': 1.0, 89 'color': ba.safecolor(icon['tint_color']), 90 'scale': 0.5, 91 'position': npos, 92 }, 93 ) 94 ) 95 96 assert self._name.node 97 ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5}) 98 99 tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs) 100 self._text: ba.NodeActor | None = ba.NodeActor( 101 ba.newnode( 102 'text', 103 attrs={ 104 'position': tpos, 105 'h_attach': 'right' if on_right else 'left', 106 'h_align': 'right' if on_right else 'left', 107 'scale': 0.9, 108 'shadow': 0.5, 109 'flatness': 0.5, 110 'v_attach': 'top', 111 'color': ba.safecolor(icon['tint_color']), 112 'text': '', 113 }, 114 ) 115 ) 116 117 assert self._text.node 118 ba.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9}) 119 120 self._respawn_time = ba.time() + respawn_time 121 self._update() 122 self._timer: ba.Timer | None = ba.Timer( 123 1.0, ba.WeakCall(self._update), repeat=True 124 ) 125 126 @property 127 def visible(self) -> bool: 128 """Is this icon still visible?""" 129 return self._visible 130 131 def _get_context(self, player: ba.Player) -> tuple[bool, float, dict]: 132 """Return info on where we should be shown and stored.""" 133 activity = ba.getactivity() 134 135 if isinstance(ba.getsession(), ba.DualTeamSession): 136 on_right = player.team.id % 2 == 1 137 138 # Store a list of icons in the team. 139 icons = player.team.customdata.get(self._ICONSSTORENAME) 140 if icons is None: 141 player.team.customdata[self._ICONSSTORENAME] = icons = {} 142 assert isinstance(icons, dict) 143 144 offs_extra = -20 145 else: 146 on_right = False 147 148 # Store a list of icons in the activity. 149 icons = activity.customdata.get(self._ICONSSTORENAME) 150 if icons is None: 151 activity.customdata[self._ICONSSTORENAME] = icons = {} 152 assert isinstance(icons, dict) 153 154 if isinstance(activity.session, ba.FreeForAllSession): 155 offs_extra = -150 156 else: 157 offs_extra = -20 158 return on_right, offs_extra, icons 159 160 def _update(self) -> None: 161 remaining = int(round(self._respawn_time - ba.time())) 162 if remaining > 0: 163 assert self._text is not None 164 if self._text.node: 165 self._text.node.text = str(remaining) 166 else: 167 self._visible = False 168 self._image = self._text = self._timer = self._name = None
class
RespawnIcon:
17class RespawnIcon: 18 """An icon with a countdown that appears alongside the screen. 19 20 category: Gameplay Classes 21 22 This is used to indicate that a ba.Player is waiting to respawn. 23 """ 24 25 _MASKTEXSTORENAME = ba.storagename('masktex') 26 _ICONSSTORENAME = ba.storagename('icons') 27 28 def __init__(self, player: ba.Player, respawn_time: float): 29 """Instantiate with a ba.Player and respawn_time (in seconds).""" 30 self._visible = True 31 32 on_right, offs_extra, respawn_icons = self._get_context(player) 33 34 # Cache our mask tex on the team for easy access. 35 mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME) 36 if mask_tex is None: 37 mask_tex = ba.gettexture('characterIconMask') 38 player.team.customdata[self._MASKTEXSTORENAME] = mask_tex 39 assert isinstance(mask_tex, ba.Texture) 40 41 # Now find the first unused slot and use that. 42 index = 0 43 while ( 44 index in respawn_icons 45 and respawn_icons[index]() is not None 46 and respawn_icons[index]().visible 47 ): 48 index += 1 49 respawn_icons[index] = weakref.ref(self) 50 51 offs = offs_extra + index * -53 52 icon = player.get_icon() 53 texture = icon['texture'] 54 h_offs = -10 55 ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs) 56 self._image: ba.NodeActor | None = ba.NodeActor( 57 ba.newnode( 58 'image', 59 attrs={ 60 'texture': texture, 61 'tint_texture': icon['tint_texture'], 62 'tint_color': icon['tint_color'], 63 'tint2_color': icon['tint2_color'], 64 'mask_texture': mask_tex, 65 'position': ipos, 66 'scale': (32, 32), 67 'opacity': 1.0, 68 'absolute_scale': True, 69 'attach': 'topRight' if on_right else 'topLeft', 70 }, 71 ) 72 ) 73 74 assert self._image.node 75 ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7}) 76 77 npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs) 78 self._name: ba.NodeActor | None = ba.NodeActor( 79 ba.newnode( 80 'text', 81 attrs={ 82 'v_attach': 'top', 83 'h_attach': 'right' if on_right else 'left', 84 'text': ba.Lstr(value=player.getname()), 85 'maxwidth': 100, 86 'h_align': 'center', 87 'v_align': 'center', 88 'shadow': 1.0, 89 'flatness': 1.0, 90 'color': ba.safecolor(icon['tint_color']), 91 'scale': 0.5, 92 'position': npos, 93 }, 94 ) 95 ) 96 97 assert self._name.node 98 ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5}) 99 100 tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs) 101 self._text: ba.NodeActor | None = ba.NodeActor( 102 ba.newnode( 103 'text', 104 attrs={ 105 'position': tpos, 106 'h_attach': 'right' if on_right else 'left', 107 'h_align': 'right' if on_right else 'left', 108 'scale': 0.9, 109 'shadow': 0.5, 110 'flatness': 0.5, 111 'v_attach': 'top', 112 'color': ba.safecolor(icon['tint_color']), 113 'text': '', 114 }, 115 ) 116 ) 117 118 assert self._text.node 119 ba.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9}) 120 121 self._respawn_time = ba.time() + respawn_time 122 self._update() 123 self._timer: ba.Timer | None = ba.Timer( 124 1.0, ba.WeakCall(self._update), repeat=True 125 ) 126 127 @property 128 def visible(self) -> bool: 129 """Is this icon still visible?""" 130 return self._visible 131 132 def _get_context(self, player: ba.Player) -> tuple[bool, float, dict]: 133 """Return info on where we should be shown and stored.""" 134 activity = ba.getactivity() 135 136 if isinstance(ba.getsession(), ba.DualTeamSession): 137 on_right = player.team.id % 2 == 1 138 139 # Store a list of icons in the team. 140 icons = player.team.customdata.get(self._ICONSSTORENAME) 141 if icons is None: 142 player.team.customdata[self._ICONSSTORENAME] = icons = {} 143 assert isinstance(icons, dict) 144 145 offs_extra = -20 146 else: 147 on_right = False 148 149 # Store a list of icons in the activity. 150 icons = activity.customdata.get(self._ICONSSTORENAME) 151 if icons is None: 152 activity.customdata[self._ICONSSTORENAME] = icons = {} 153 assert isinstance(icons, dict) 154 155 if isinstance(activity.session, ba.FreeForAllSession): 156 offs_extra = -150 157 else: 158 offs_extra = -20 159 return on_right, offs_extra, icons 160 161 def _update(self) -> None: 162 remaining = int(round(self._respawn_time - ba.time())) 163 if remaining > 0: 164 assert self._text is not None 165 if self._text.node: 166 self._text.node.text = str(remaining) 167 else: 168 self._visible = False 169 self._image = self._text = self._timer = self._name = None
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.
RespawnIcon(player: ba._player.Player, respawn_time: float)
28 def __init__(self, player: ba.Player, respawn_time: float): 29 """Instantiate with a ba.Player and respawn_time (in seconds).""" 30 self._visible = True 31 32 on_right, offs_extra, respawn_icons = self._get_context(player) 33 34 # Cache our mask tex on the team for easy access. 35 mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME) 36 if mask_tex is None: 37 mask_tex = ba.gettexture('characterIconMask') 38 player.team.customdata[self._MASKTEXSTORENAME] = mask_tex 39 assert isinstance(mask_tex, ba.Texture) 40 41 # Now find the first unused slot and use that. 42 index = 0 43 while ( 44 index in respawn_icons 45 and respawn_icons[index]() is not None 46 and respawn_icons[index]().visible 47 ): 48 index += 1 49 respawn_icons[index] = weakref.ref(self) 50 51 offs = offs_extra + index * -53 52 icon = player.get_icon() 53 texture = icon['texture'] 54 h_offs = -10 55 ipos = (-40 - h_offs if on_right else 40 + h_offs, -180 + offs) 56 self._image: ba.NodeActor | None = ba.NodeActor( 57 ba.newnode( 58 'image', 59 attrs={ 60 'texture': texture, 61 'tint_texture': icon['tint_texture'], 62 'tint_color': icon['tint_color'], 63 'tint2_color': icon['tint2_color'], 64 'mask_texture': mask_tex, 65 'position': ipos, 66 'scale': (32, 32), 67 'opacity': 1.0, 68 'absolute_scale': True, 69 'attach': 'topRight' if on_right else 'topLeft', 70 }, 71 ) 72 ) 73 74 assert self._image.node 75 ba.animate(self._image.node, 'opacity', {0.0: 0, 0.2: 0.7}) 76 77 npos = (-40 - h_offs if on_right else 40 + h_offs, -205 + 49 + offs) 78 self._name: ba.NodeActor | None = ba.NodeActor( 79 ba.newnode( 80 'text', 81 attrs={ 82 'v_attach': 'top', 83 'h_attach': 'right' if on_right else 'left', 84 'text': ba.Lstr(value=player.getname()), 85 'maxwidth': 100, 86 'h_align': 'center', 87 'v_align': 'center', 88 'shadow': 1.0, 89 'flatness': 1.0, 90 'color': ba.safecolor(icon['tint_color']), 91 'scale': 0.5, 92 'position': npos, 93 }, 94 ) 95 ) 96 97 assert self._name.node 98 ba.animate(self._name.node, 'scale', {0: 0, 0.1: 0.5}) 99 100 tpos = (-60 - h_offs if on_right else 60 + h_offs, -192 + offs) 101 self._text: ba.NodeActor | None = ba.NodeActor( 102 ba.newnode( 103 'text', 104 attrs={ 105 'position': tpos, 106 'h_attach': 'right' if on_right else 'left', 107 'h_align': 'right' if on_right else 'left', 108 'scale': 0.9, 109 'shadow': 0.5, 110 'flatness': 0.5, 111 'v_attach': 'top', 112 'color': ba.safecolor(icon['tint_color']), 113 'text': '', 114 }, 115 ) 116 ) 117 118 assert self._text.node 119 ba.animate(self._text.node, 'scale', {0: 0, 0.1: 0.9}) 120 121 self._respawn_time = ba.time() + respawn_time 122 self._update() 123 self._timer: ba.Timer | None = ba.Timer( 124 1.0, ba.WeakCall(self._update), repeat=True 125 )
Instantiate with a ba.Player and respawn_time (in seconds).