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