bastd.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
  8
  9import ba
 10from bastd.activity.multiteamscore import MultiTeamScoreScreenActivity
 11
 12if TYPE_CHECKING:
 13    from typing import Any
 14
 15
 16class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
 17    """Score screen shown at after free-for-all rounds."""
 18
 19    def __init__(self, settings: dict):
 20        super().__init__(settings=settings)
 21
 22        # Keep prev activity alive while we fade in.
 23        self.transition_time = 0.5
 24        self._cymbal_sound = ba.getsound('cymbal')
 25
 26    def on_begin(self) -> None:
 27        # pylint: disable=too-many-locals
 28        # pylint: disable=too-many-statements
 29        from bastd.actor.text import Text
 30        from bastd.actor.image import Image
 31
 32        ba.set_analytics_screen('FreeForAll Score Screen')
 33        super().on_begin()
 34
 35        y_base = 100.0
 36        ts_h_offs = -305.0
 37        tdelay = 1.0
 38        scale = 1.2
 39        spacing = 37.0
 40
 41        # We include name and previous score in the sort to reduce the amount
 42        # of random jumping around the list we do in cases of ties.
 43        player_order_prev = list(self.players)
 44        player_order_prev.sort(
 45            reverse=True,
 46            key=lambda p: (
 47                p.team.sessionteam.customdata['previous_score'],
 48                p.getname(full=True),
 49            ),
 50        )
 51        player_order = list(self.players)
 52        player_order.sort(
 53            reverse=True,
 54            key=lambda p: (
 55                p.team.sessionteam.customdata['score'],
 56                p.team.sessionteam.customdata['score'],
 57                p.getname(full=True),
 58            ),
 59        )
 60
 61        v_offs = -74.0 + spacing * len(player_order_prev) * 0.5
 62        delay1 = 1.3 + 0.1
 63        delay2 = 2.9 + 0.1
 64        delay3 = 2.9 + 0.1
 65        order_change = player_order != player_order_prev
 66
 67        if order_change:
 68            delay3 += 1.5
 69
 70        ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound))
 71        results = self.settings_raw['results']
 72        assert isinstance(results, ba.GameResults)
 73        self.show_player_scores(
 74            delay=0.001, results=results, scale=1.2, x_offset=-110.0
 75        )
 76
 77        sound_times: set[float] = set()
 78
 79        def _scoretxt(
 80            text: str,
 81            x_offs: float,
 82            y_offs: float,
 83            highlight: bool,
 84            delay: float,
 85            extrascale: float,
 86            flash: bool = False,
 87        ) -> Text:
 88            return Text(
 89                text,
 90                position=(
 91                    ts_h_offs + x_offs * scale,
 92                    y_base + (y_offs + v_offs + 2.0) * scale,
 93                ),
 94                scale=scale * extrascale,
 95                color=(
 96                    (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7)
 97                ),
 98                h_align=Text.HAlign.RIGHT,
 99                transition=Text.Transition.IN_LEFT,
100                transition_delay=tdelay + delay,
101                flash=flash,
102            ).autoretain()
103
104        v_offs -= spacing
105        slide_amt = 0.0
106        transtime = 0.250
107        transtime2 = 0.250
108
109        session = self.session
110        assert isinstance(session, ba.FreeForAllSession)
111        title = Text(
112            ba.Lstr(
113                resource='firstToSeriesText',
114                subs=[('${COUNT}', str(session.get_ffa_series_length()))],
115            ),
116            scale=1.05 * scale,
117            position=(
118                ts_h_offs - 0.0 * scale,
119                y_base + (v_offs + 50.0) * scale,
120            ),
121            h_align=Text.HAlign.CENTER,
122            color=(0.5, 0.5, 0.5, 0.5),
123            transition=Text.Transition.IN_LEFT,
124            transition_delay=tdelay,
125        ).autoretain()
126
127        v_offs -= 25
128        v_offs_start = v_offs
129
130        ba.timer(
131            tdelay + delay3,
132            ba.WeakCall(
133                self._safe_animate,
134                title.position_combine,
135                'input0',
136                {
137                    0.0: ts_h_offs - 0.0 * scale,
138                    transtime2: ts_h_offs - (0.0 + slide_amt) * scale,
139                },
140            ),
141        )
142
143        for i, player in enumerate(player_order_prev):
144            v_offs_2 = v_offs_start - spacing * (player_order.index(player))
145            ba.timer(
146                tdelay + 0.3,
147                ba.Call(ba.playsound, self._score_display_sound_small),
148            )
149            if order_change:
150                ba.timer(
151                    tdelay + delay2 + 0.1,
152                    ba.Call(ba.playsound, self._cymbal_sound),
153                )
154            img = Image(
155                player.get_icon(),
156                position=(
157                    ts_h_offs - 72.0 * scale,
158                    y_base + (v_offs + 15.0) * scale,
159                ),
160                scale=(30.0 * scale, 30.0 * scale),
161                transition=Image.Transition.IN_LEFT,
162                transition_delay=tdelay,
163            ).autoretain()
164            ba.timer(
165                tdelay + delay2,
166                ba.WeakCall(
167                    self._safe_animate,
168                    img.position_combine,
169                    'input1',
170                    {
171                        0: y_base + (v_offs + 15.0) * scale,
172                        transtime: y_base + (v_offs_2 + 15.0) * scale,
173                    },
174                ),
175            )
176            ba.timer(
177                tdelay + delay3,
178                ba.WeakCall(
179                    self._safe_animate,
180                    img.position_combine,
181                    'input0',
182                    {
183                        0: ts_h_offs - 72.0 * scale,
184                        transtime2: ts_h_offs - (72.0 + slide_amt) * scale,
185                    },
186                ),
187            )
188            txt = Text(
189                ba.Lstr(value=player.getname(full=True)),
190                maxwidth=130.0,
191                scale=0.75 * scale,
192                position=(
193                    ts_h_offs - 50.0 * scale,
194                    y_base + (v_offs + 15.0) * scale,
195                ),
196                h_align=Text.HAlign.LEFT,
197                v_align=Text.VAlign.CENTER,
198                color=ba.safecolor(player.team.color + (1,)),
199                transition=Text.Transition.IN_LEFT,
200                transition_delay=tdelay,
201            ).autoretain()
202            ba.timer(
203                tdelay + delay2,
204                ba.WeakCall(
205                    self._safe_animate,
206                    txt.position_combine,
207                    'input1',
208                    {
209                        0: y_base + (v_offs + 15.0) * scale,
210                        transtime: y_base + (v_offs_2 + 15.0) * scale,
211                    },
212                ),
213            )
214            ba.timer(
215                tdelay + delay3,
216                ba.WeakCall(
217                    self._safe_animate,
218                    txt.position_combine,
219                    'input0',
220                    {
221                        0: ts_h_offs - 50.0 * scale,
222                        transtime2: ts_h_offs - (50.0 + slide_amt) * scale,
223                    },
224                ),
225            )
226
227            txt_num = Text(
228                '#' + str(i + 1),
229                scale=0.55 * scale,
230                position=(
231                    ts_h_offs - 95.0 * scale,
232                    y_base + (v_offs + 8.0) * scale,
233                ),
234                h_align=Text.HAlign.RIGHT,
235                color=(0.6, 0.6, 0.6, 0.6),
236                transition=Text.Transition.IN_LEFT,
237                transition_delay=tdelay,
238            ).autoretain()
239            ba.timer(
240                tdelay + delay3,
241                ba.WeakCall(
242                    self._safe_animate,
243                    txt_num.position_combine,
244                    'input0',
245                    {
246                        0: ts_h_offs - 95.0 * scale,
247                        transtime2: ts_h_offs - (95.0 + slide_amt) * scale,
248                    },
249                ),
250            )
251
252            s_txt = _scoretxt(
253                str(player.team.sessionteam.customdata['previous_score']),
254                80,
255                0,
256                False,
257                0,
258                1.0,
259            )
260            ba.timer(
261                tdelay + delay2,
262                ba.WeakCall(
263                    self._safe_animate,
264                    s_txt.position_combine,
265                    'input1',
266                    {
267                        0: y_base + (v_offs + 2.0) * scale,
268                        transtime: y_base + (v_offs_2 + 2.0) * scale,
269                    },
270                ),
271            )
272            ba.timer(
273                tdelay + delay3,
274                ba.WeakCall(
275                    self._safe_animate,
276                    s_txt.position_combine,
277                    'input0',
278                    {
279                        0: ts_h_offs + 80.0 * scale,
280                        transtime2: ts_h_offs + (80.0 - slide_amt) * scale,
281                    },
282                ),
283            )
284
285            score_change = (
286                player.team.sessionteam.customdata['score']
287                - player.team.sessionteam.customdata['previous_score']
288            )
289            if score_change > 0:
290                xval = 113
291                yval = 3.0
292                s_txt_2 = _scoretxt(
293                    '+' + str(score_change),
294                    xval,
295                    yval,
296                    True,
297                    0,
298                    0.7,
299                    flash=True,
300                )
301                ba.timer(
302                    tdelay + delay2,
303                    ba.WeakCall(
304                        self._safe_animate,
305                        s_txt_2.position_combine,
306                        'input1',
307                        {
308                            0: y_base + (v_offs + yval + 2.0) * scale,
309                            transtime: y_base + (v_offs_2 + yval + 2.0) * scale,
310                        },
311                    ),
312                )
313                ba.timer(
314                    tdelay + delay3,
315                    ba.WeakCall(
316                        self._safe_animate,
317                        s_txt_2.position_combine,
318                        'input0',
319                        {
320                            0: ts_h_offs + xval * scale,
321                            transtime2: ts_h_offs + (xval - slide_amt) * scale,
322                        },
323                    ),
324                )
325
326                def _safesetattr(
327                    node: ba.Node | None, attr: str, value: Any
328                ) -> None:
329                    if node:
330                        setattr(node, attr, value)
331
332                ba.timer(
333                    tdelay + delay1,
334                    ba.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)),
335                )
336                for j in range(score_change):
337                    ba.timer(
338                        (tdelay + delay1 + 0.15 * j),
339                        ba.Call(
340                            _safesetattr,
341                            s_txt.node,
342                            'text',
343                            str(
344                                player.team.sessionteam.customdata[
345                                    'previous_score'
346                                ]
347                                + j
348                                + 1
349                            ),
350                        ),
351                    )
352                    tfin = tdelay + delay1 + 0.15 * j
353                    if tfin not in sound_times:
354                        sound_times.add(tfin)
355                        ba.timer(
356                            tfin,
357                            ba.Call(
358                                ba.playsound, self._score_display_sound_small
359                            ),
360                        )
361            v_offs -= spacing
362
363    def _safe_animate(
364        self, node: ba.Node | None, attr: str, keys: dict[float, float]
365    ) -> None:
366        """Run an animation on a node if the node still exists."""
367        if node:
368            ba.animate(node, attr, keys)
class FreeForAllVictoryScoreScreenActivity(ba._activity.Activity[ba._player.EmptyPlayer, ba._team.EmptyTeam]):
 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 = ba.getsound('cymbal')
 26
 27    def on_begin(self) -> None:
 28        # pylint: disable=too-many-locals
 29        # pylint: disable=too-many-statements
 30        from bastd.actor.text import Text
 31        from bastd.actor.image import Image
 32
 33        ba.set_analytics_screen('FreeForAll Score Screen')
 34        super().on_begin()
 35
 36        y_base = 100.0
 37        ts_h_offs = -305.0
 38        tdelay = 1.0
 39        scale = 1.2
 40        spacing = 37.0
 41
 42        # We include name and previous score in the sort to reduce the amount
 43        # of random jumping around the list we do in cases of ties.
 44        player_order_prev = list(self.players)
 45        player_order_prev.sort(
 46            reverse=True,
 47            key=lambda p: (
 48                p.team.sessionteam.customdata['previous_score'],
 49                p.getname(full=True),
 50            ),
 51        )
 52        player_order = list(self.players)
 53        player_order.sort(
 54            reverse=True,
 55            key=lambda p: (
 56                p.team.sessionteam.customdata['score'],
 57                p.team.sessionteam.customdata['score'],
 58                p.getname(full=True),
 59            ),
 60        )
 61
 62        v_offs = -74.0 + spacing * len(player_order_prev) * 0.5
 63        delay1 = 1.3 + 0.1
 64        delay2 = 2.9 + 0.1
 65        delay3 = 2.9 + 0.1
 66        order_change = player_order != player_order_prev
 67
 68        if order_change:
 69            delay3 += 1.5
 70
 71        ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound))
 72        results = self.settings_raw['results']
 73        assert isinstance(results, ba.GameResults)
 74        self.show_player_scores(
 75            delay=0.001, results=results, scale=1.2, x_offset=-110.0
 76        )
 77
 78        sound_times: set[float] = set()
 79
 80        def _scoretxt(
 81            text: str,
 82            x_offs: float,
 83            y_offs: float,
 84            highlight: bool,
 85            delay: float,
 86            extrascale: float,
 87            flash: bool = False,
 88        ) -> Text:
 89            return Text(
 90                text,
 91                position=(
 92                    ts_h_offs + x_offs * scale,
 93                    y_base + (y_offs + v_offs + 2.0) * scale,
 94                ),
 95                scale=scale * extrascale,
 96                color=(
 97                    (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7)
 98                ),
 99                h_align=Text.HAlign.RIGHT,
100                transition=Text.Transition.IN_LEFT,
101                transition_delay=tdelay + delay,
102                flash=flash,
103            ).autoretain()
104
105        v_offs -= spacing
106        slide_amt = 0.0
107        transtime = 0.250
108        transtime2 = 0.250
109
110        session = self.session
111        assert isinstance(session, ba.FreeForAllSession)
112        title = Text(
113            ba.Lstr(
114                resource='firstToSeriesText',
115                subs=[('${COUNT}', str(session.get_ffa_series_length()))],
116            ),
117            scale=1.05 * scale,
118            position=(
119                ts_h_offs - 0.0 * scale,
120                y_base + (v_offs + 50.0) * scale,
121            ),
122            h_align=Text.HAlign.CENTER,
123            color=(0.5, 0.5, 0.5, 0.5),
124            transition=Text.Transition.IN_LEFT,
125            transition_delay=tdelay,
126        ).autoretain()
127
128        v_offs -= 25
129        v_offs_start = v_offs
130
131        ba.timer(
132            tdelay + delay3,
133            ba.WeakCall(
134                self._safe_animate,
135                title.position_combine,
136                'input0',
137                {
138                    0.0: ts_h_offs - 0.0 * scale,
139                    transtime2: ts_h_offs - (0.0 + slide_amt) * scale,
140                },
141            ),
142        )
143
144        for i, player in enumerate(player_order_prev):
145            v_offs_2 = v_offs_start - spacing * (player_order.index(player))
146            ba.timer(
147                tdelay + 0.3,
148                ba.Call(ba.playsound, self._score_display_sound_small),
149            )
150            if order_change:
151                ba.timer(
152                    tdelay + delay2 + 0.1,
153                    ba.Call(ba.playsound, self._cymbal_sound),
154                )
155            img = Image(
156                player.get_icon(),
157                position=(
158                    ts_h_offs - 72.0 * scale,
159                    y_base + (v_offs + 15.0) * scale,
160                ),
161                scale=(30.0 * scale, 30.0 * scale),
162                transition=Image.Transition.IN_LEFT,
163                transition_delay=tdelay,
164            ).autoretain()
165            ba.timer(
166                tdelay + delay2,
167                ba.WeakCall(
168                    self._safe_animate,
169                    img.position_combine,
170                    'input1',
171                    {
172                        0: y_base + (v_offs + 15.0) * scale,
173                        transtime: y_base + (v_offs_2 + 15.0) * scale,
174                    },
175                ),
176            )
177            ba.timer(
178                tdelay + delay3,
179                ba.WeakCall(
180                    self._safe_animate,
181                    img.position_combine,
182                    'input0',
183                    {
184                        0: ts_h_offs - 72.0 * scale,
185                        transtime2: ts_h_offs - (72.0 + slide_amt) * scale,
186                    },
187                ),
188            )
189            txt = Text(
190                ba.Lstr(value=player.getname(full=True)),
191                maxwidth=130.0,
192                scale=0.75 * scale,
193                position=(
194                    ts_h_offs - 50.0 * scale,
195                    y_base + (v_offs + 15.0) * scale,
196                ),
197                h_align=Text.HAlign.LEFT,
198                v_align=Text.VAlign.CENTER,
199                color=ba.safecolor(player.team.color + (1,)),
200                transition=Text.Transition.IN_LEFT,
201                transition_delay=tdelay,
202            ).autoretain()
203            ba.timer(
204                tdelay + delay2,
205                ba.WeakCall(
206                    self._safe_animate,
207                    txt.position_combine,
208                    'input1',
209                    {
210                        0: y_base + (v_offs + 15.0) * scale,
211                        transtime: y_base + (v_offs_2 + 15.0) * scale,
212                    },
213                ),
214            )
215            ba.timer(
216                tdelay + delay3,
217                ba.WeakCall(
218                    self._safe_animate,
219                    txt.position_combine,
220                    'input0',
221                    {
222                        0: ts_h_offs - 50.0 * scale,
223                        transtime2: ts_h_offs - (50.0 + slide_amt) * scale,
224                    },
225                ),
226            )
227
228            txt_num = Text(
229                '#' + str(i + 1),
230                scale=0.55 * scale,
231                position=(
232                    ts_h_offs - 95.0 * scale,
233                    y_base + (v_offs + 8.0) * scale,
234                ),
235                h_align=Text.HAlign.RIGHT,
236                color=(0.6, 0.6, 0.6, 0.6),
237                transition=Text.Transition.IN_LEFT,
238                transition_delay=tdelay,
239            ).autoretain()
240            ba.timer(
241                tdelay + delay3,
242                ba.WeakCall(
243                    self._safe_animate,
244                    txt_num.position_combine,
245                    'input0',
246                    {
247                        0: ts_h_offs - 95.0 * scale,
248                        transtime2: ts_h_offs - (95.0 + slide_amt) * scale,
249                    },
250                ),
251            )
252
253            s_txt = _scoretxt(
254                str(player.team.sessionteam.customdata['previous_score']),
255                80,
256                0,
257                False,
258                0,
259                1.0,
260            )
261            ba.timer(
262                tdelay + delay2,
263                ba.WeakCall(
264                    self._safe_animate,
265                    s_txt.position_combine,
266                    'input1',
267                    {
268                        0: y_base + (v_offs + 2.0) * scale,
269                        transtime: y_base + (v_offs_2 + 2.0) * scale,
270                    },
271                ),
272            )
273            ba.timer(
274                tdelay + delay3,
275                ba.WeakCall(
276                    self._safe_animate,
277                    s_txt.position_combine,
278                    'input0',
279                    {
280                        0: ts_h_offs + 80.0 * scale,
281                        transtime2: ts_h_offs + (80.0 - slide_amt) * scale,
282                    },
283                ),
284            )
285
286            score_change = (
287                player.team.sessionteam.customdata['score']
288                - player.team.sessionteam.customdata['previous_score']
289            )
290            if score_change > 0:
291                xval = 113
292                yval = 3.0
293                s_txt_2 = _scoretxt(
294                    '+' + str(score_change),
295                    xval,
296                    yval,
297                    True,
298                    0,
299                    0.7,
300                    flash=True,
301                )
302                ba.timer(
303                    tdelay + delay2,
304                    ba.WeakCall(
305                        self._safe_animate,
306                        s_txt_2.position_combine,
307                        'input1',
308                        {
309                            0: y_base + (v_offs + yval + 2.0) * scale,
310                            transtime: y_base + (v_offs_2 + yval + 2.0) * scale,
311                        },
312                    ),
313                )
314                ba.timer(
315                    tdelay + delay3,
316                    ba.WeakCall(
317                        self._safe_animate,
318                        s_txt_2.position_combine,
319                        'input0',
320                        {
321                            0: ts_h_offs + xval * scale,
322                            transtime2: ts_h_offs + (xval - slide_amt) * scale,
323                        },
324                    ),
325                )
326
327                def _safesetattr(
328                    node: ba.Node | None, attr: str, value: Any
329                ) -> None:
330                    if node:
331                        setattr(node, attr, value)
332
333                ba.timer(
334                    tdelay + delay1,
335                    ba.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)),
336                )
337                for j in range(score_change):
338                    ba.timer(
339                        (tdelay + delay1 + 0.15 * j),
340                        ba.Call(
341                            _safesetattr,
342                            s_txt.node,
343                            'text',
344                            str(
345                                player.team.sessionteam.customdata[
346                                    'previous_score'
347                                ]
348                                + j
349                                + 1
350                            ),
351                        ),
352                    )
353                    tfin = tdelay + delay1 + 0.15 * j
354                    if tfin not in sound_times:
355                        sound_times.add(tfin)
356                        ba.timer(
357                            tfin,
358                            ba.Call(
359                                ba.playsound, self._score_display_sound_small
360                            ),
361                        )
362            v_offs -= spacing
363
364    def _safe_animate(
365        self, node: ba.Node | None, attr: str, keys: dict[float, float]
366    ) -> None:
367        """Run an animation on a node if the node still exists."""
368        if node:
369            ba.animate(node, attr, keys)

Score screen shown at after free-for-all rounds.

FreeForAllVictoryScoreScreenActivity(settings: dict)
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 = ba.getsound('cymbal')

Creates an Activity in the current ba.Session.

The activity will not be actually run until ba.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.

transition_time = 0.5

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.

def on_begin(self) -> None:
 27    def on_begin(self) -> None:
 28        # pylint: disable=too-many-locals
 29        # pylint: disable=too-many-statements
 30        from bastd.actor.text import Text
 31        from bastd.actor.image import Image
 32
 33        ba.set_analytics_screen('FreeForAll Score Screen')
 34        super().on_begin()
 35
 36        y_base = 100.0
 37        ts_h_offs = -305.0
 38        tdelay = 1.0
 39        scale = 1.2
 40        spacing = 37.0
 41
 42        # We include name and previous score in the sort to reduce the amount
 43        # of random jumping around the list we do in cases of ties.
 44        player_order_prev = list(self.players)
 45        player_order_prev.sort(
 46            reverse=True,
 47            key=lambda p: (
 48                p.team.sessionteam.customdata['previous_score'],
 49                p.getname(full=True),
 50            ),
 51        )
 52        player_order = list(self.players)
 53        player_order.sort(
 54            reverse=True,
 55            key=lambda p: (
 56                p.team.sessionteam.customdata['score'],
 57                p.team.sessionteam.customdata['score'],
 58                p.getname(full=True),
 59            ),
 60        )
 61
 62        v_offs = -74.0 + spacing * len(player_order_prev) * 0.5
 63        delay1 = 1.3 + 0.1
 64        delay2 = 2.9 + 0.1
 65        delay3 = 2.9 + 0.1
 66        order_change = player_order != player_order_prev
 67
 68        if order_change:
 69            delay3 += 1.5
 70
 71        ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound))
 72        results = self.settings_raw['results']
 73        assert isinstance(results, ba.GameResults)
 74        self.show_player_scores(
 75            delay=0.001, results=results, scale=1.2, x_offset=-110.0
 76        )
 77
 78        sound_times: set[float] = set()
 79
 80        def _scoretxt(
 81            text: str,
 82            x_offs: float,
 83            y_offs: float,
 84            highlight: bool,
 85            delay: float,
 86            extrascale: float,
 87            flash: bool = False,
 88        ) -> Text:
 89            return Text(
 90                text,
 91                position=(
 92                    ts_h_offs + x_offs * scale,
 93                    y_base + (y_offs + v_offs + 2.0) * scale,
 94                ),
 95                scale=scale * extrascale,
 96                color=(
 97                    (1.0, 0.7, 0.3, 1.0) if highlight else (0.7, 0.7, 0.7, 0.7)
 98                ),
 99                h_align=Text.HAlign.RIGHT,
100                transition=Text.Transition.IN_LEFT,
101                transition_delay=tdelay + delay,
102                flash=flash,
103            ).autoretain()
104
105        v_offs -= spacing
106        slide_amt = 0.0
107        transtime = 0.250
108        transtime2 = 0.250
109
110        session = self.session
111        assert isinstance(session, ba.FreeForAllSession)
112        title = Text(
113            ba.Lstr(
114                resource='firstToSeriesText',
115                subs=[('${COUNT}', str(session.get_ffa_series_length()))],
116            ),
117            scale=1.05 * scale,
118            position=(
119                ts_h_offs - 0.0 * scale,
120                y_base + (v_offs + 50.0) * scale,
121            ),
122            h_align=Text.HAlign.CENTER,
123            color=(0.5, 0.5, 0.5, 0.5),
124            transition=Text.Transition.IN_LEFT,
125            transition_delay=tdelay,
126        ).autoretain()
127
128        v_offs -= 25
129        v_offs_start = v_offs
130
131        ba.timer(
132            tdelay + delay3,
133            ba.WeakCall(
134                self._safe_animate,
135                title.position_combine,
136                'input0',
137                {
138                    0.0: ts_h_offs - 0.0 * scale,
139                    transtime2: ts_h_offs - (0.0 + slide_amt) * scale,
140                },
141            ),
142        )
143
144        for i, player in enumerate(player_order_prev):
145            v_offs_2 = v_offs_start - spacing * (player_order.index(player))
146            ba.timer(
147                tdelay + 0.3,
148                ba.Call(ba.playsound, self._score_display_sound_small),
149            )
150            if order_change:
151                ba.timer(
152                    tdelay + delay2 + 0.1,
153                    ba.Call(ba.playsound, self._cymbal_sound),
154                )
155            img = Image(
156                player.get_icon(),
157                position=(
158                    ts_h_offs - 72.0 * scale,
159                    y_base + (v_offs + 15.0) * scale,
160                ),
161                scale=(30.0 * scale, 30.0 * scale),
162                transition=Image.Transition.IN_LEFT,
163                transition_delay=tdelay,
164            ).autoretain()
165            ba.timer(
166                tdelay + delay2,
167                ba.WeakCall(
168                    self._safe_animate,
169                    img.position_combine,
170                    'input1',
171                    {
172                        0: y_base + (v_offs + 15.0) * scale,
173                        transtime: y_base + (v_offs_2 + 15.0) * scale,
174                    },
175                ),
176            )
177            ba.timer(
178                tdelay + delay3,
179                ba.WeakCall(
180                    self._safe_animate,
181                    img.position_combine,
182                    'input0',
183                    {
184                        0: ts_h_offs - 72.0 * scale,
185                        transtime2: ts_h_offs - (72.0 + slide_amt) * scale,
186                    },
187                ),
188            )
189            txt = Text(
190                ba.Lstr(value=player.getname(full=True)),
191                maxwidth=130.0,
192                scale=0.75 * scale,
193                position=(
194                    ts_h_offs - 50.0 * scale,
195                    y_base + (v_offs + 15.0) * scale,
196                ),
197                h_align=Text.HAlign.LEFT,
198                v_align=Text.VAlign.CENTER,
199                color=ba.safecolor(player.team.color + (1,)),
200                transition=Text.Transition.IN_LEFT,
201                transition_delay=tdelay,
202            ).autoretain()
203            ba.timer(
204                tdelay + delay2,
205                ba.WeakCall(
206                    self._safe_animate,
207                    txt.position_combine,
208                    'input1',
209                    {
210                        0: y_base + (v_offs + 15.0) * scale,
211                        transtime: y_base + (v_offs_2 + 15.0) * scale,
212                    },
213                ),
214            )
215            ba.timer(
216                tdelay + delay3,
217                ba.WeakCall(
218                    self._safe_animate,
219                    txt.position_combine,
220                    'input0',
221                    {
222                        0: ts_h_offs - 50.0 * scale,
223                        transtime2: ts_h_offs - (50.0 + slide_amt) * scale,
224                    },
225                ),
226            )
227
228            txt_num = Text(
229                '#' + str(i + 1),
230                scale=0.55 * scale,
231                position=(
232                    ts_h_offs - 95.0 * scale,
233                    y_base + (v_offs + 8.0) * scale,
234                ),
235                h_align=Text.HAlign.RIGHT,
236                color=(0.6, 0.6, 0.6, 0.6),
237                transition=Text.Transition.IN_LEFT,
238                transition_delay=tdelay,
239            ).autoretain()
240            ba.timer(
241                tdelay + delay3,
242                ba.WeakCall(
243                    self._safe_animate,
244                    txt_num.position_combine,
245                    'input0',
246                    {
247                        0: ts_h_offs - 95.0 * scale,
248                        transtime2: ts_h_offs - (95.0 + slide_amt) * scale,
249                    },
250                ),
251            )
252
253            s_txt = _scoretxt(
254                str(player.team.sessionteam.customdata['previous_score']),
255                80,
256                0,
257                False,
258                0,
259                1.0,
260            )
261            ba.timer(
262                tdelay + delay2,
263                ba.WeakCall(
264                    self._safe_animate,
265                    s_txt.position_combine,
266                    'input1',
267                    {
268                        0: y_base + (v_offs + 2.0) * scale,
269                        transtime: y_base + (v_offs_2 + 2.0) * scale,
270                    },
271                ),
272            )
273            ba.timer(
274                tdelay + delay3,
275                ba.WeakCall(
276                    self._safe_animate,
277                    s_txt.position_combine,
278                    'input0',
279                    {
280                        0: ts_h_offs + 80.0 * scale,
281                        transtime2: ts_h_offs + (80.0 - slide_amt) * scale,
282                    },
283                ),
284            )
285
286            score_change = (
287                player.team.sessionteam.customdata['score']
288                - player.team.sessionteam.customdata['previous_score']
289            )
290            if score_change > 0:
291                xval = 113
292                yval = 3.0
293                s_txt_2 = _scoretxt(
294                    '+' + str(score_change),
295                    xval,
296                    yval,
297                    True,
298                    0,
299                    0.7,
300                    flash=True,
301                )
302                ba.timer(
303                    tdelay + delay2,
304                    ba.WeakCall(
305                        self._safe_animate,
306                        s_txt_2.position_combine,
307                        'input1',
308                        {
309                            0: y_base + (v_offs + yval + 2.0) * scale,
310                            transtime: y_base + (v_offs_2 + yval + 2.0) * scale,
311                        },
312                    ),
313                )
314                ba.timer(
315                    tdelay + delay3,
316                    ba.WeakCall(
317                        self._safe_animate,
318                        s_txt_2.position_combine,
319                        'input0',
320                        {
321                            0: ts_h_offs + xval * scale,
322                            transtime2: ts_h_offs + (xval - slide_amt) * scale,
323                        },
324                    ),
325                )
326
327                def _safesetattr(
328                    node: ba.Node | None, attr: str, value: Any
329                ) -> None:
330                    if node:
331                        setattr(node, attr, value)
332
333                ba.timer(
334                    tdelay + delay1,
335                    ba.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)),
336                )
337                for j in range(score_change):
338                    ba.timer(
339                        (tdelay + delay1 + 0.15 * j),
340                        ba.Call(
341                            _safesetattr,
342                            s_txt.node,
343                            'text',
344                            str(
345                                player.team.sessionteam.customdata[
346                                    'previous_score'
347                                ]
348                                + j
349                                + 1
350                            ),
351                        ),
352                    )
353                    tfin = tdelay + delay1 + 0.15 * j
354                    if tfin not in sound_times:
355                        sound_times.add(tfin)
356                        ba.timer(
357                            tfin,
358                            ba.Call(
359                                ba.playsound, self._score_display_sound_small
360                            ),
361                        )
362            v_offs -= spacing

Called once the previous ba.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
bastd.activity.multiteamscore.MultiTeamScoreScreenActivity
show_player_scores
ba._activitytypes.ScoreScreenActivity
inherits_tint
inherits_vr_camera_offset
use_fixed_vr_overlay
default_music
on_player_join
on_transition_in
ba._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
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
ba._dependency.DependencyComponent
dep_is_present
get_dynamic_deps