bascenev1lib.activity.freeforallvictory
Functionality related to the final screen in free-for-all games.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Functionality related to the final screen in free-for-all games.""" 4 5from __future__ import annotations 6 7from typing import TYPE_CHECKING, override 8 9import bascenev1 as bs 10 11from bascenev1lib.activity.multiteamscore import MultiTeamScoreScreenActivity 12 13if TYPE_CHECKING: 14 from typing import Any 15 16 17class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): 18 """Score screen shown at after free-for-all rounds.""" 19 20 def __init__(self, settings: dict): 21 super().__init__(settings=settings) 22 23 # Keep prev activity alive while we fade in. 24 self.transition_time = 0.5 25 self._cymbal_sound = bs.getsound('cymbal') 26 27 @override 28 def on_begin(self) -> None: 29 # pylint: disable=too-many-locals 30 # pylint: disable=too-many-statements 31 from bascenev1lib.actor.text import Text 32 from bascenev1lib.actor.image import Image 33 34 bs.set_analytics_screen('FreeForAll Score Screen') 35 super().on_begin() 36 37 y_base = 100.0 38 ts_h_offs = -305.0 39 tdelay = 1.0 40 scale = 1.2 41 spacing = 37.0 42 43 # We include name and previous score in the sort to reduce the amount 44 # of random jumping around the list we do in cases of ties. 45 player_order_prev = list(self.players) 46 player_order_prev.sort( 47 reverse=True, 48 key=lambda p: ( 49 p.team.sessionteam.customdata['previous_score'], 50 p.getname(full=True), 51 ), 52 ) 53 player_order = list(self.players) 54 player_order.sort( 55 reverse=True, 56 key=lambda p: ( 57 p.team.sessionteam.customdata['score'], 58 p.team.sessionteam.customdata['score'], 59 p.getname(full=True), 60 ), 61 ) 62 63 v_offs = -74.0 + spacing * len(player_order_prev) * 0.5 64 delay1 = 1.3 + 0.1 65 delay2 = 2.9 + 0.1 66 delay3 = 2.9 + 0.1 67 order_change = player_order != player_order_prev 68 69 if order_change: 70 delay3 += 1.5 71 72 bs.timer(0.3, self._score_display_sound.play) 73 results = self.settings_raw['results'] 74 assert isinstance(results, bs.GameResults) 75 self.show_player_scores( 76 delay=0.001, results=results, scale=1.2, x_offset=-110.0 77 ) 78 79 sound_times: set[float] = set() 80 81 def _scoretxt( 82 text: str, 83 x_offs: float, 84 y_offs: float, 85 highlight: bool, 86 delay: float, 87 extrascale: float, 88 flash: bool = False, 89 ) -> Text: 90 return Text( 91 text, 92 position=( 93 ts_h_offs + x_offs * scale, 94 y_base + (y_offs + v_offs + 2.0) * scale, 95 ), 96 scale=scale * extrascale, 97 color=( 98 (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7) 99 ), 100 h_align=Text.HAlign.RIGHT, 101 transition=Text.Transition.IN_LEFT, 102 transition_delay=tdelay + delay, 103 flash=flash, 104 ).autoretain() 105 106 v_offs -= spacing 107 slide_amt = 0.0 108 transtime = 0.250 109 transtime2 = 0.250 110 111 session = self.session 112 assert isinstance(session, bs.FreeForAllSession) 113 title = Text( 114 bs.Lstr( 115 resource='firstToSeriesText', 116 subs=[('${COUNT}', str(session.get_ffa_series_length()))], 117 ), 118 scale=1.05 * scale, 119 position=( 120 ts_h_offs - 0.0 * scale, 121 y_base + (v_offs + 50.0) * scale, 122 ), 123 h_align=Text.HAlign.CENTER, 124 color=(0.5, 0.5, 0.5, 0.5), 125 transition=Text.Transition.IN_LEFT, 126 transition_delay=tdelay, 127 ).autoretain() 128 129 v_offs -= 25 130 v_offs_start = v_offs 131 132 bs.timer( 133 tdelay + delay3, 134 bs.WeakCall( 135 self._safe_animate, 136 title.position_combine, 137 'input0', 138 { 139 0.0: ts_h_offs - 0.0 * scale, 140 transtime2: ts_h_offs - (0.0 + slide_amt) * scale, 141 }, 142 ), 143 ) 144 145 for i, player in enumerate(player_order_prev): 146 v_offs_2 = v_offs_start - spacing * (player_order.index(player)) 147 bs.timer(tdelay + 0.3, self._score_display_sound_small.play) 148 if order_change: 149 bs.timer(tdelay + delay2 + 0.1, self._cymbal_sound.play) 150 img = Image( 151 player.get_icon(), 152 position=( 153 ts_h_offs - 72.0 * scale, 154 y_base + (v_offs + 15.0) * scale, 155 ), 156 scale=(30.0 * scale, 30.0 * scale), 157 transition=Image.Transition.IN_LEFT, 158 transition_delay=tdelay, 159 ).autoretain() 160 bs.timer( 161 tdelay + delay2, 162 bs.WeakCall( 163 self._safe_animate, 164 img.position_combine, 165 'input1', 166 { 167 0: y_base + (v_offs + 15.0) * scale, 168 transtime: y_base + (v_offs_2 + 15.0) * scale, 169 }, 170 ), 171 ) 172 bs.timer( 173 tdelay + delay3, 174 bs.WeakCall( 175 self._safe_animate, 176 img.position_combine, 177 'input0', 178 { 179 0: ts_h_offs - 72.0 * scale, 180 transtime2: ts_h_offs - (72.0 + slide_amt) * scale, 181 }, 182 ), 183 ) 184 txt = Text( 185 bs.Lstr(value=player.getname(full=True)), 186 maxwidth=130.0, 187 scale=0.75 * scale, 188 position=( 189 ts_h_offs - 50.0 * scale, 190 y_base + (v_offs + 15.0) * scale, 191 ), 192 h_align=Text.HAlign.LEFT, 193 v_align=Text.VAlign.CENTER, 194 color=bs.safecolor(player.team.color + (1,)), 195 transition=Text.Transition.IN_LEFT, 196 transition_delay=tdelay, 197 ).autoretain() 198 bs.timer( 199 tdelay + delay2, 200 bs.WeakCall( 201 self._safe_animate, 202 txt.position_combine, 203 'input1', 204 { 205 0: y_base + (v_offs + 15.0) * scale, 206 transtime: y_base + (v_offs_2 + 15.0) * scale, 207 }, 208 ), 209 ) 210 bs.timer( 211 tdelay + delay3, 212 bs.WeakCall( 213 self._safe_animate, 214 txt.position_combine, 215 'input0', 216 { 217 0: ts_h_offs - 50.0 * scale, 218 transtime2: ts_h_offs - (50.0 + slide_amt) * scale, 219 }, 220 ), 221 ) 222 223 txt_num = Text( 224 '#' + str(i + 1), 225 scale=0.55 * scale, 226 position=( 227 ts_h_offs - 95.0 * scale, 228 y_base + (v_offs + 8.0) * scale, 229 ), 230 h_align=Text.HAlign.RIGHT, 231 color=(0.6, 0.6, 0.6, 0.6), 232 transition=Text.Transition.IN_LEFT, 233 transition_delay=tdelay, 234 ).autoretain() 235 bs.timer( 236 tdelay + delay3, 237 bs.WeakCall( 238 self._safe_animate, 239 txt_num.position_combine, 240 'input0', 241 { 242 0: ts_h_offs - 95.0 * scale, 243 transtime2: ts_h_offs - (95.0 + slide_amt) * scale, 244 }, 245 ), 246 ) 247 248 s_txt = _scoretxt( 249 str(player.team.sessionteam.customdata['previous_score']), 250 80, 251 0, 252 False, 253 0, 254 1.0, 255 ) 256 bs.timer( 257 tdelay + delay2, 258 bs.WeakCall( 259 self._safe_animate, 260 s_txt.position_combine, 261 'input1', 262 { 263 0: y_base + (v_offs + 2.0) * scale, 264 transtime: y_base + (v_offs_2 + 2.0) * scale, 265 }, 266 ), 267 ) 268 bs.timer( 269 tdelay + delay3, 270 bs.WeakCall( 271 self._safe_animate, 272 s_txt.position_combine, 273 'input0', 274 { 275 0: ts_h_offs + 80.0 * scale, 276 transtime2: ts_h_offs + (80.0 - slide_amt) * scale, 277 }, 278 ), 279 ) 280 281 score_change = ( 282 player.team.sessionteam.customdata['score'] 283 - player.team.sessionteam.customdata['previous_score'] 284 ) 285 if score_change > 0: 286 xval = 113 287 yval = 3.0 288 s_txt_2 = _scoretxt( 289 '+' + str(score_change), 290 xval, 291 yval, 292 True, 293 0, 294 0.7, 295 flash=True, 296 ) 297 bs.timer( 298 tdelay + delay2, 299 bs.WeakCall( 300 self._safe_animate, 301 s_txt_2.position_combine, 302 'input1', 303 { 304 0: y_base + (v_offs + yval + 2.0) * scale, 305 transtime: y_base + (v_offs_2 + yval + 2.0) * scale, 306 }, 307 ), 308 ) 309 bs.timer( 310 tdelay + delay3, 311 bs.WeakCall( 312 self._safe_animate, 313 s_txt_2.position_combine, 314 'input0', 315 { 316 0: ts_h_offs + xval * scale, 317 transtime2: ts_h_offs + (xval - slide_amt) * scale, 318 }, 319 ), 320 ) 321 322 def _safesetattr( 323 node: bs.Node | None, attr: str, value: Any 324 ) -> None: 325 if node: 326 setattr(node, attr, value) 327 328 bs.timer( 329 tdelay + delay1, 330 bs.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)), 331 ) 332 for j in range(score_change): 333 bs.timer( 334 (tdelay + delay1 + 0.15 * j), 335 bs.Call( 336 _safesetattr, 337 s_txt.node, 338 'text', 339 str( 340 player.team.sessionteam.customdata[ 341 'previous_score' 342 ] 343 + j 344 + 1 345 ), 346 ), 347 ) 348 tfin = tdelay + delay1 + 0.15 * j 349 if tfin not in sound_times: 350 sound_times.add(tfin) 351 bs.timer(tfin, self._score_display_sound_small.play) 352 v_offs -= spacing 353 354 def _safe_animate( 355 self, node: bs.Node | None, attr: str, keys: dict[float, float] 356 ) -> None: 357 """Run an animation on a node if the node still exists.""" 358 if node: 359 bs.animate(node, attr, keys)
18class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): 19 """Score screen shown at after free-for-all rounds.""" 20 21 def __init__(self, settings: dict): 22 super().__init__(settings=settings) 23 24 # Keep prev activity alive while we fade in. 25 self.transition_time = 0.5 26 self._cymbal_sound = bs.getsound('cymbal') 27 28 @override 29 def on_begin(self) -> None: 30 # pylint: disable=too-many-locals 31 # pylint: disable=too-many-statements 32 from bascenev1lib.actor.text import Text 33 from bascenev1lib.actor.image import Image 34 35 bs.set_analytics_screen('FreeForAll Score Screen') 36 super().on_begin() 37 38 y_base = 100.0 39 ts_h_offs = -305.0 40 tdelay = 1.0 41 scale = 1.2 42 spacing = 37.0 43 44 # We include name and previous score in the sort to reduce the amount 45 # of random jumping around the list we do in cases of ties. 46 player_order_prev = list(self.players) 47 player_order_prev.sort( 48 reverse=True, 49 key=lambda p: ( 50 p.team.sessionteam.customdata['previous_score'], 51 p.getname(full=True), 52 ), 53 ) 54 player_order = list(self.players) 55 player_order.sort( 56 reverse=True, 57 key=lambda p: ( 58 p.team.sessionteam.customdata['score'], 59 p.team.sessionteam.customdata['score'], 60 p.getname(full=True), 61 ), 62 ) 63 64 v_offs = -74.0 + spacing * len(player_order_prev) * 0.5 65 delay1 = 1.3 + 0.1 66 delay2 = 2.9 + 0.1 67 delay3 = 2.9 + 0.1 68 order_change = player_order != player_order_prev 69 70 if order_change: 71 delay3 += 1.5 72 73 bs.timer(0.3, self._score_display_sound.play) 74 results = self.settings_raw['results'] 75 assert isinstance(results, bs.GameResults) 76 self.show_player_scores( 77 delay=0.001, results=results, scale=1.2, x_offset=-110.0 78 ) 79 80 sound_times: set[float] = set() 81 82 def _scoretxt( 83 text: str, 84 x_offs: float, 85 y_offs: float, 86 highlight: bool, 87 delay: float, 88 extrascale: float, 89 flash: bool = False, 90 ) -> Text: 91 return Text( 92 text, 93 position=( 94 ts_h_offs + x_offs * scale, 95 y_base + (y_offs + v_offs + 2.0) * scale, 96 ), 97 scale=scale * extrascale, 98 color=( 99 (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7) 100 ), 101 h_align=Text.HAlign.RIGHT, 102 transition=Text.Transition.IN_LEFT, 103 transition_delay=tdelay + delay, 104 flash=flash, 105 ).autoretain() 106 107 v_offs -= spacing 108 slide_amt = 0.0 109 transtime = 0.250 110 transtime2 = 0.250 111 112 session = self.session 113 assert isinstance(session, bs.FreeForAllSession) 114 title = Text( 115 bs.Lstr( 116 resource='firstToSeriesText', 117 subs=[('${COUNT}', str(session.get_ffa_series_length()))], 118 ), 119 scale=1.05 * scale, 120 position=( 121 ts_h_offs - 0.0 * scale, 122 y_base + (v_offs + 50.0) * scale, 123 ), 124 h_align=Text.HAlign.CENTER, 125 color=(0.5, 0.5, 0.5, 0.5), 126 transition=Text.Transition.IN_LEFT, 127 transition_delay=tdelay, 128 ).autoretain() 129 130 v_offs -= 25 131 v_offs_start = v_offs 132 133 bs.timer( 134 tdelay + delay3, 135 bs.WeakCall( 136 self._safe_animate, 137 title.position_combine, 138 'input0', 139 { 140 0.0: ts_h_offs - 0.0 * scale, 141 transtime2: ts_h_offs - (0.0 + slide_amt) * scale, 142 }, 143 ), 144 ) 145 146 for i, player in enumerate(player_order_prev): 147 v_offs_2 = v_offs_start - spacing * (player_order.index(player)) 148 bs.timer(tdelay + 0.3, self._score_display_sound_small.play) 149 if order_change: 150 bs.timer(tdelay + delay2 + 0.1, self._cymbal_sound.play) 151 img = Image( 152 player.get_icon(), 153 position=( 154 ts_h_offs - 72.0 * scale, 155 y_base + (v_offs + 15.0) * scale, 156 ), 157 scale=(30.0 * scale, 30.0 * scale), 158 transition=Image.Transition.IN_LEFT, 159 transition_delay=tdelay, 160 ).autoretain() 161 bs.timer( 162 tdelay + delay2, 163 bs.WeakCall( 164 self._safe_animate, 165 img.position_combine, 166 'input1', 167 { 168 0: y_base + (v_offs + 15.0) * scale, 169 transtime: y_base + (v_offs_2 + 15.0) * scale, 170 }, 171 ), 172 ) 173 bs.timer( 174 tdelay + delay3, 175 bs.WeakCall( 176 self._safe_animate, 177 img.position_combine, 178 'input0', 179 { 180 0: ts_h_offs - 72.0 * scale, 181 transtime2: ts_h_offs - (72.0 + slide_amt) * scale, 182 }, 183 ), 184 ) 185 txt = Text( 186 bs.Lstr(value=player.getname(full=True)), 187 maxwidth=130.0, 188 scale=0.75 * scale, 189 position=( 190 ts_h_offs - 50.0 * scale, 191 y_base + (v_offs + 15.0) * scale, 192 ), 193 h_align=Text.HAlign.LEFT, 194 v_align=Text.VAlign.CENTER, 195 color=bs.safecolor(player.team.color + (1,)), 196 transition=Text.Transition.IN_LEFT, 197 transition_delay=tdelay, 198 ).autoretain() 199 bs.timer( 200 tdelay + delay2, 201 bs.WeakCall( 202 self._safe_animate, 203 txt.position_combine, 204 'input1', 205 { 206 0: y_base + (v_offs + 15.0) * scale, 207 transtime: y_base + (v_offs_2 + 15.0) * scale, 208 }, 209 ), 210 ) 211 bs.timer( 212 tdelay + delay3, 213 bs.WeakCall( 214 self._safe_animate, 215 txt.position_combine, 216 'input0', 217 { 218 0: ts_h_offs - 50.0 * scale, 219 transtime2: ts_h_offs - (50.0 + slide_amt) * scale, 220 }, 221 ), 222 ) 223 224 txt_num = Text( 225 '#' + str(i + 1), 226 scale=0.55 * scale, 227 position=( 228 ts_h_offs - 95.0 * scale, 229 y_base + (v_offs + 8.0) * scale, 230 ), 231 h_align=Text.HAlign.RIGHT, 232 color=(0.6, 0.6, 0.6, 0.6), 233 transition=Text.Transition.IN_LEFT, 234 transition_delay=tdelay, 235 ).autoretain() 236 bs.timer( 237 tdelay + delay3, 238 bs.WeakCall( 239 self._safe_animate, 240 txt_num.position_combine, 241 'input0', 242 { 243 0: ts_h_offs - 95.0 * scale, 244 transtime2: ts_h_offs - (95.0 + slide_amt) * scale, 245 }, 246 ), 247 ) 248 249 s_txt = _scoretxt( 250 str(player.team.sessionteam.customdata['previous_score']), 251 80, 252 0, 253 False, 254 0, 255 1.0, 256 ) 257 bs.timer( 258 tdelay + delay2, 259 bs.WeakCall( 260 self._safe_animate, 261 s_txt.position_combine, 262 'input1', 263 { 264 0: y_base + (v_offs + 2.0) * scale, 265 transtime: y_base + (v_offs_2 + 2.0) * scale, 266 }, 267 ), 268 ) 269 bs.timer( 270 tdelay + delay3, 271 bs.WeakCall( 272 self._safe_animate, 273 s_txt.position_combine, 274 'input0', 275 { 276 0: ts_h_offs + 80.0 * scale, 277 transtime2: ts_h_offs + (80.0 - slide_amt) * scale, 278 }, 279 ), 280 ) 281 282 score_change = ( 283 player.team.sessionteam.customdata['score'] 284 - player.team.sessionteam.customdata['previous_score'] 285 ) 286 if score_change > 0: 287 xval = 113 288 yval = 3.0 289 s_txt_2 = _scoretxt( 290 '+' + str(score_change), 291 xval, 292 yval, 293 True, 294 0, 295 0.7, 296 flash=True, 297 ) 298 bs.timer( 299 tdelay + delay2, 300 bs.WeakCall( 301 self._safe_animate, 302 s_txt_2.position_combine, 303 'input1', 304 { 305 0: y_base + (v_offs + yval + 2.0) * scale, 306 transtime: y_base + (v_offs_2 + yval + 2.0) * scale, 307 }, 308 ), 309 ) 310 bs.timer( 311 tdelay + delay3, 312 bs.WeakCall( 313 self._safe_animate, 314 s_txt_2.position_combine, 315 'input0', 316 { 317 0: ts_h_offs + xval * scale, 318 transtime2: ts_h_offs + (xval - slide_amt) * scale, 319 }, 320 ), 321 ) 322 323 def _safesetattr( 324 node: bs.Node | None, attr: str, value: Any 325 ) -> None: 326 if node: 327 setattr(node, attr, value) 328 329 bs.timer( 330 tdelay + delay1, 331 bs.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)), 332 ) 333 for j in range(score_change): 334 bs.timer( 335 (tdelay + delay1 + 0.15 * j), 336 bs.Call( 337 _safesetattr, 338 s_txt.node, 339 'text', 340 str( 341 player.team.sessionteam.customdata[ 342 'previous_score' 343 ] 344 + j 345 + 1 346 ), 347 ), 348 ) 349 tfin = tdelay + delay1 + 0.15 * j 350 if tfin not in sound_times: 351 sound_times.add(tfin) 352 bs.timer(tfin, self._score_display_sound_small.play) 353 v_offs -= spacing 354 355 def _safe_animate( 356 self, node: bs.Node | None, attr: str, keys: dict[float, float] 357 ) -> None: 358 """Run an animation on a node if the node still exists.""" 359 if node: 360 bs.animate(node, attr, keys)
Score screen shown at after free-for-all rounds.
21 def __init__(self, settings: dict): 22 super().__init__(settings=settings) 23 24 # Keep prev activity alive while we fade in. 25 self.transition_time = 0.5 26 self._cymbal_sound = bs.getsound('cymbal')
Creates an Activity in the current bascenev1.Session.
The activity will not be actually run until bascenev1.Session.setactivity is called. 'settings' should be a dict of key/value pairs specific to the activity.
Activities should preload as much of their media/etc as possible in their constructor, but none of it should actually be used until they are transitioned in.
If the activity fades or transitions in, it should set the length of time here so that previous activities will be kept alive for that long (avoiding 'holes' in the screen) This value is given in real-time seconds.
28 @override 29 def on_begin(self) -> None: 30 # pylint: disable=too-many-locals 31 # pylint: disable=too-many-statements 32 from bascenev1lib.actor.text import Text 33 from bascenev1lib.actor.image import Image 34 35 bs.set_analytics_screen('FreeForAll Score Screen') 36 super().on_begin() 37 38 y_base = 100.0 39 ts_h_offs = -305.0 40 tdelay = 1.0 41 scale = 1.2 42 spacing = 37.0 43 44 # We include name and previous score in the sort to reduce the amount 45 # of random jumping around the list we do in cases of ties. 46 player_order_prev = list(self.players) 47 player_order_prev.sort( 48 reverse=True, 49 key=lambda p: ( 50 p.team.sessionteam.customdata['previous_score'], 51 p.getname(full=True), 52 ), 53 ) 54 player_order = list(self.players) 55 player_order.sort( 56 reverse=True, 57 key=lambda p: ( 58 p.team.sessionteam.customdata['score'], 59 p.team.sessionteam.customdata['score'], 60 p.getname(full=True), 61 ), 62 ) 63 64 v_offs = -74.0 + spacing * len(player_order_prev) * 0.5 65 delay1 = 1.3 + 0.1 66 delay2 = 2.9 + 0.1 67 delay3 = 2.9 + 0.1 68 order_change = player_order != player_order_prev 69 70 if order_change: 71 delay3 += 1.5 72 73 bs.timer(0.3, self._score_display_sound.play) 74 results = self.settings_raw['results'] 75 assert isinstance(results, bs.GameResults) 76 self.show_player_scores( 77 delay=0.001, results=results, scale=1.2, x_offset=-110.0 78 ) 79 80 sound_times: set[float] = set() 81 82 def _scoretxt( 83 text: str, 84 x_offs: float, 85 y_offs: float, 86 highlight: bool, 87 delay: float, 88 extrascale: float, 89 flash: bool = False, 90 ) -> Text: 91 return Text( 92 text, 93 position=( 94 ts_h_offs + x_offs * scale, 95 y_base + (y_offs + v_offs + 2.0) * scale, 96 ), 97 scale=scale * extrascale, 98 color=( 99 (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7) 100 ), 101 h_align=Text.HAlign.RIGHT, 102 transition=Text.Transition.IN_LEFT, 103 transition_delay=tdelay + delay, 104 flash=flash, 105 ).autoretain() 106 107 v_offs -= spacing 108 slide_amt = 0.0 109 transtime = 0.250 110 transtime2 = 0.250 111 112 session = self.session 113 assert isinstance(session, bs.FreeForAllSession) 114 title = Text( 115 bs.Lstr( 116 resource='firstToSeriesText', 117 subs=[('${COUNT}', str(session.get_ffa_series_length()))], 118 ), 119 scale=1.05 * scale, 120 position=( 121 ts_h_offs - 0.0 * scale, 122 y_base + (v_offs + 50.0) * scale, 123 ), 124 h_align=Text.HAlign.CENTER, 125 color=(0.5, 0.5, 0.5, 0.5), 126 transition=Text.Transition.IN_LEFT, 127 transition_delay=tdelay, 128 ).autoretain() 129 130 v_offs -= 25 131 v_offs_start = v_offs 132 133 bs.timer( 134 tdelay + delay3, 135 bs.WeakCall( 136 self._safe_animate, 137 title.position_combine, 138 'input0', 139 { 140 0.0: ts_h_offs - 0.0 * scale, 141 transtime2: ts_h_offs - (0.0 + slide_amt) * scale, 142 }, 143 ), 144 ) 145 146 for i, player in enumerate(player_order_prev): 147 v_offs_2 = v_offs_start - spacing * (player_order.index(player)) 148 bs.timer(tdelay + 0.3, self._score_display_sound_small.play) 149 if order_change: 150 bs.timer(tdelay + delay2 + 0.1, self._cymbal_sound.play) 151 img = Image( 152 player.get_icon(), 153 position=( 154 ts_h_offs - 72.0 * scale, 155 y_base + (v_offs + 15.0) * scale, 156 ), 157 scale=(30.0 * scale, 30.0 * scale), 158 transition=Image.Transition.IN_LEFT, 159 transition_delay=tdelay, 160 ).autoretain() 161 bs.timer( 162 tdelay + delay2, 163 bs.WeakCall( 164 self._safe_animate, 165 img.position_combine, 166 'input1', 167 { 168 0: y_base + (v_offs + 15.0) * scale, 169 transtime: y_base + (v_offs_2 + 15.0) * scale, 170 }, 171 ), 172 ) 173 bs.timer( 174 tdelay + delay3, 175 bs.WeakCall( 176 self._safe_animate, 177 img.position_combine, 178 'input0', 179 { 180 0: ts_h_offs - 72.0 * scale, 181 transtime2: ts_h_offs - (72.0 + slide_amt) * scale, 182 }, 183 ), 184 ) 185 txt = Text( 186 bs.Lstr(value=player.getname(full=True)), 187 maxwidth=130.0, 188 scale=0.75 * scale, 189 position=( 190 ts_h_offs - 50.0 * scale, 191 y_base + (v_offs + 15.0) * scale, 192 ), 193 h_align=Text.HAlign.LEFT, 194 v_align=Text.VAlign.CENTER, 195 color=bs.safecolor(player.team.color + (1,)), 196 transition=Text.Transition.IN_LEFT, 197 transition_delay=tdelay, 198 ).autoretain() 199 bs.timer( 200 tdelay + delay2, 201 bs.WeakCall( 202 self._safe_animate, 203 txt.position_combine, 204 'input1', 205 { 206 0: y_base + (v_offs + 15.0) * scale, 207 transtime: y_base + (v_offs_2 + 15.0) * scale, 208 }, 209 ), 210 ) 211 bs.timer( 212 tdelay + delay3, 213 bs.WeakCall( 214 self._safe_animate, 215 txt.position_combine, 216 'input0', 217 { 218 0: ts_h_offs - 50.0 * scale, 219 transtime2: ts_h_offs - (50.0 + slide_amt) * scale, 220 }, 221 ), 222 ) 223 224 txt_num = Text( 225 '#' + str(i + 1), 226 scale=0.55 * scale, 227 position=( 228 ts_h_offs - 95.0 * scale, 229 y_base + (v_offs + 8.0) * scale, 230 ), 231 h_align=Text.HAlign.RIGHT, 232 color=(0.6, 0.6, 0.6, 0.6), 233 transition=Text.Transition.IN_LEFT, 234 transition_delay=tdelay, 235 ).autoretain() 236 bs.timer( 237 tdelay + delay3, 238 bs.WeakCall( 239 self._safe_animate, 240 txt_num.position_combine, 241 'input0', 242 { 243 0: ts_h_offs - 95.0 * scale, 244 transtime2: ts_h_offs - (95.0 + slide_amt) * scale, 245 }, 246 ), 247 ) 248 249 s_txt = _scoretxt( 250 str(player.team.sessionteam.customdata['previous_score']), 251 80, 252 0, 253 False, 254 0, 255 1.0, 256 ) 257 bs.timer( 258 tdelay + delay2, 259 bs.WeakCall( 260 self._safe_animate, 261 s_txt.position_combine, 262 'input1', 263 { 264 0: y_base + (v_offs + 2.0) * scale, 265 transtime: y_base + (v_offs_2 + 2.0) * scale, 266 }, 267 ), 268 ) 269 bs.timer( 270 tdelay + delay3, 271 bs.WeakCall( 272 self._safe_animate, 273 s_txt.position_combine, 274 'input0', 275 { 276 0: ts_h_offs + 80.0 * scale, 277 transtime2: ts_h_offs + (80.0 - slide_amt) * scale, 278 }, 279 ), 280 ) 281 282 score_change = ( 283 player.team.sessionteam.customdata['score'] 284 - player.team.sessionteam.customdata['previous_score'] 285 ) 286 if score_change > 0: 287 xval = 113 288 yval = 3.0 289 s_txt_2 = _scoretxt( 290 '+' + str(score_change), 291 xval, 292 yval, 293 True, 294 0, 295 0.7, 296 flash=True, 297 ) 298 bs.timer( 299 tdelay + delay2, 300 bs.WeakCall( 301 self._safe_animate, 302 s_txt_2.position_combine, 303 'input1', 304 { 305 0: y_base + (v_offs + yval + 2.0) * scale, 306 transtime: y_base + (v_offs_2 + yval + 2.0) * scale, 307 }, 308 ), 309 ) 310 bs.timer( 311 tdelay + delay3, 312 bs.WeakCall( 313 self._safe_animate, 314 s_txt_2.position_combine, 315 'input0', 316 { 317 0: ts_h_offs + xval * scale, 318 transtime2: ts_h_offs + (xval - slide_amt) * scale, 319 }, 320 ), 321 ) 322 323 def _safesetattr( 324 node: bs.Node | None, attr: str, value: Any 325 ) -> None: 326 if node: 327 setattr(node, attr, value) 328 329 bs.timer( 330 tdelay + delay1, 331 bs.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)), 332 ) 333 for j in range(score_change): 334 bs.timer( 335 (tdelay + delay1 + 0.15 * j), 336 bs.Call( 337 _safesetattr, 338 s_txt.node, 339 'text', 340 str( 341 player.team.sessionteam.customdata[ 342 'previous_score' 343 ] 344 + j 345 + 1 346 ), 347 ), 348 ) 349 tfin = tdelay + delay1 + 0.15 * j 350 if tfin not in sound_times: 351 sound_times.add(tfin) 352 bs.timer(tfin, self._score_display_sound_small.play) 353 v_offs -= spacing
Called once the previous Activity has finished transitioning out.
At this point the activity's initial players and teams are filled in and it should begin its actual game logic.
Inherited Members
- bascenev1._activitytypes.ScoreScreenActivity
- inherits_tint
- inherits_vr_camera_offset
- use_fixed_vr_overlay
- default_music
- on_player_join
- on_transition_in
- bascenev1._activity.Activity
- settings_raw
- teams
- players
- announce_player_deaths
- is_joining_activity
- allow_pausing
- allow_kick_idle_players
- slow_motion
- inherits_slow_motion
- inherits_music
- inherits_vr_overlay_center
- allow_mid_activity_joins
- can_show_ad_on_death
- paused_text
- preloads
- lobby
- context
- globalsnode
- stats
- on_expire
- customdata
- expired
- playertype
- teamtype
- retain_actor
- add_actor_weak_ref
- session
- on_player_leave
- on_team_join
- on_team_leave
- on_transition_out
- handlemessage
- has_transitioned_in
- has_begun
- has_ended
- is_transitioning_out
- transition_out
- end
- create_player
- create_team
- bascenev1._dependency.DependencyComponent
- dep_is_present
- get_dynamic_deps