diff --git a/src/assets/ba_data/python/bascenev1lib/activity/multiteamvictory.py b/src/assets/ba_data/python/bascenev1lib/activity/multiteamvictory.py index a8ecc289..a024da7d 100644 --- a/src/assets/ba_data/python/bascenev1lib/activity/multiteamvictory.py +++ b/src/assets/ba_data/python/bascenev1lib/activity/multiteamvictory.py @@ -24,6 +24,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): self._allow_server_transition = True self._tips_text = None self._default_show_tips = False + self._topscored_player: list[object] | None = None @override def on_begin(self) -> None: @@ -70,6 +71,10 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): ) ) player_entries.sort(reverse=True, key=lambda x: x[0]) + if len(player_entries) > 0: + self._topscored_player = list(player_entries[0]) + self._topscored_player[1] = self._topscored_player[2].getname() + self._topscored_player[2] = self._topscored_player[2].get_icon() else: for _pkey, prec in self.stats.get_records().items(): player_entries.append((prec.score, prec.name_full, prec)) @@ -372,39 +377,40 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): v_offs = 0.0 tdelay += len(player_entries) * 8 * t_incr for _score, name, prec in player_entries: - tdelay -= 4 * t_incr - v_offs -= 40 - Text( - ( - str(prec.team.customdata['score']) - if self._is_ffa - else str(prec.score) - ), - color=(0.5, 0.5, 0.5, 1.0), - position=(ts_h_offs + 230, ts_height / 2 + v_offs), - h_align=Text.HAlign.RIGHT, - transition=Text.Transition.IN_RIGHT, - transition_delay=tdelay, - ).autoretain() - tdelay -= 4 * t_incr + if prec.player.in_game: + tdelay -= 4 * t_incr + v_offs -= 40 + Text( + ( + str(prec.team.customdata['score']) + if self._is_ffa + else str(prec.score) + ), + color=(0.5, 0.5, 0.5, 1.0), + position=(ts_h_offs + 230, ts_height / 2 + v_offs), + h_align=Text.HAlign.RIGHT, + transition=Text.Transition.IN_RIGHT, + transition_delay=tdelay, + ).autoretain() + tdelay -= 4 * t_incr - Image( - prec.get_icon(), - position=(ts_h_offs - 72, ts_height / 2 + v_offs + 15), - scale=(30, 30), - transition=Image.Transition.IN_LEFT, - transition_delay=tdelay, - ).autoretain() - Text( - bs.Lstr(value=name), - position=(ts_h_offs - 50, ts_height / 2 + v_offs + 15), - h_align=Text.HAlign.LEFT, - v_align=Text.VAlign.CENTER, - maxwidth=180, - color=bs.safecolor(prec.team.color + (1,)), - transition=Text.Transition.IN_RIGHT, - transition_delay=tdelay, - ).autoretain() + Image( + prec.get_icon(), + position=(ts_h_offs - 72, ts_height / 2 + v_offs + 15), + scale=(30, 30), + transition=Image.Transition.IN_LEFT, + transition_delay=tdelay, + ).autoretain() + Text( + bs.Lstr(value=name), + position=(ts_h_offs - 50, ts_height / 2 + v_offs + 15), + h_align=Text.HAlign.LEFT, + v_align=Text.VAlign.CENTER, + maxwidth=180, + color=bs.safecolor(prec.team.color + (1,)), + transition=Text.Transition.IN_RIGHT, + transition_delay=tdelay, + ).autoretain() bs.timer(15.0, bs.WeakCall(self._show_tips)) @@ -433,25 +439,38 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): maxwidth=250, ).autoretain() else: - offs_v = -80.0 + offs_v = -80 + series_length = self.session.get_ffa_series_length() if len(team.players) == 1: + icon = team.players[0].get_icon() + player_name = team.players[0].getname(full=True, icon=False) + elif ( + self._topscored_player is not None and + self._topscored_player[0] >= series_length + ): + icon = self._topscored_player[2] + player_name = self._topscored_player[1] + else: + icon = None + player_name = 'Player Not Found' + + if icon is not None: i = Image( - team.players[0].get_icon(), + icon, position=(0, 143), scale=(100, 100), ).autoretain() assert i.node bs.animate(i.node, 'opacity', {0.0: 0.0, 0.25: 1.0}) - ZoomText( - bs.Lstr( - value=team.players[0].getname(full=True, icon=False) - ), - position=(0, 97 + offs_v), - color=team.color, - scale=1.15, - jitter=1.0, - maxwidth=250, - ).autoretain() + + ZoomText( + bs.Lstr(value=player_name), + position=(0, 97 + offs_v + (0 if icon is not None else 60)), + color=team.color, + scale=1.15, + jitter=1.0, + maxwidth=250, + ).autoretain() s_extra = 1.0 if self._is_ffa else 1.0 diff --git a/src/assets/ba_data/python/bascenev1lib/actor/scoreboard.py b/src/assets/ba_data/python/bascenev1lib/actor/scoreboard.py index f5e30583..46660468 100644 --- a/src/assets/ba_data/python/bascenev1lib/actor/scoreboard.py +++ b/src/assets/ba_data/python/bascenev1lib/actor/scoreboard.py @@ -22,15 +22,18 @@ class _Entry: scale: float, label: bs.Lstr | None, flash_length: float, + width: float | None = None, + height: float | None = None, ): + # pylint: disable=too-many-locals # pylint: disable=too-many-statements # pylint: disable=too-many-positional-arguments self._scoreboard = weakref.ref(scoreboard) self._do_cover = do_cover self._scale = scale self._flash_length = flash_length - self._width = 140.0 * self._scale - self._height = 32.0 * self._scale + self._width = (140.0 if width is None else width) * self._scale + self._height = (32.0 if height is None else height) * self._scale self._bar_width = 2.0 * self._scale self._bar_height = 32.0 * self._scale self._bar_tex = self._backing_tex = bs.gettexture('bar') @@ -370,16 +373,26 @@ class Scoreboard: _ENTRYSTORENAME = bs.storagename('entry') - def __init__(self, label: bs.Lstr | None = None, score_split: float = 0.7): + def __init__( + self, + label: bs.Lstr | None = None, + score_split: float = 0.7, + pos: Sequence[float] | None = None, + width: float | None = None, + height: float | None = None + ): """Instantiate a scoreboard. Label can be something like 'points' and will show up on boards if provided. """ + # pylint: disable=too-many-positional-arguments self._flat_tex = bs.gettexture('null') self._entries: dict[int, _Entry] = {} self._label = label self.score_split = score_split + self._width = width + self._height = height # For free-for-all we go simpler since we have one per player. self._pos: Sequence[float] @@ -395,6 +408,7 @@ class Scoreboard: self._pos = (20.0, -70.0) self._scale = 1.0 self._flash_length = 1.0 + self._pos = self._pos if pos is None else pos def set_team_value( self, @@ -433,6 +447,8 @@ class Scoreboard: do_cover=self._do_cover, scale=self._scale, label=self._label, + width=self._width, + height=self._height, flash_length=self._flash_length, ) self._update_teams() diff --git a/src/assets/ba_data/python/bauiv1lib/settings/benchmarks.py b/src/assets/ba_data/python/bauiv1lib/settings/benchmarks.py index 1f841057..cdc2ab25 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/benchmarks.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/benchmarks.py @@ -8,7 +8,7 @@ import logging from typing import cast, override import bauiv1 as bui - +import bascenev1 as bs class BenchmarksAndStressTestsWindow(bui.MainWindow): """Window for launching benchmarks or stress tests.""" @@ -372,16 +372,26 @@ class BenchmarksAndStressTestsWindow(bui.MainWindow): bui.app.classic.run_media_reload_benchmark() def _stress_test_pressed(self) -> None: + from bascenev1lib.mainmenu import MainMenuActivity + if bui.app.classic is None: logging.warning('stress-test requires classic') return - bui.app.classic.run_stress_test( - playlist_type=self._stress_test_game_type, - playlist_name=cast( - str, bui.textwidget(query=self._stress_test_playlist_name_field) - ), - player_count=self._stress_test_player_count, - round_duration=self._stress_test_round_duration, - ) - bui.containerwidget(edit=self._root_widget, transition='out_right') + activity = bs.get_foreground_host_activity() + if isinstance(activity, MainMenuActivity): + bui.app.classic.run_stress_test( + playlist_type=self._stress_test_game_type, + playlist_name=cast( + str, bui.textwidget( + query=self._stress_test_playlist_name_field + ) + ), + player_count=self._stress_test_player_count, + round_duration=self._stress_test_round_duration, + ) + bui.containerwidget(edit=self._root_widget, transition='out_right') + else: + bui.screenmessage( + bui.Lstr(value='Already present in another activity.') + )