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)
class FreeForAllVictoryScoreScreenActivity(bascenev1._activity.Activity[bascenev1._player.EmptyPlayer, bascenev1._team.EmptyTeam]):
 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.

FreeForAllVictoryScoreScreenActivity(settings: dict)
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.

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.

@override
def on_begin(self) -> None:
 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
bascenev1lib.activity.multiteamscore.MultiTeamScoreScreenActivity
show_player_scores
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