bastd.activity.coopjoin

Functionality related to the co-op join screen.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Functionality related to the co-op join screen."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8
  9import _ba
 10import ba
 11from ba.internal import JoinActivity
 12
 13if TYPE_CHECKING:
 14    from typing import Any, Sequence
 15
 16
 17class CoopJoinActivity(JoinActivity):
 18    """Join-screen for co-op mode."""
 19
 20    # We can assume our session is a CoopSession.
 21    session: ba.CoopSession
 22
 23    def __init__(self, settings: dict):
 24        super().__init__(settings)
 25        session = self.session
 26        assert isinstance(session, ba.CoopSession)
 27
 28        # Let's show a list of scores-to-beat for 1 player at least.
 29        assert session.campaign is not None
 30        level_name_full = (session.campaign.name + ':' +
 31                           session.campaign_level_name)
 32        config_str = ('1p' + session.campaign.getlevel(
 33            session.campaign_level_name).get_score_version_string().replace(
 34                ' ', '_'))
 35        _ba.get_scores_to_beat(level_name_full, config_str,
 36                               ba.WeakCall(self._on_got_scores_to_beat))
 37
 38    def on_transition_in(self) -> None:
 39        from bastd.actor.controlsguide import ControlsGuide
 40        from bastd.actor.text import Text
 41        super().on_transition_in()
 42        assert isinstance(self.session, ba.CoopSession)
 43        assert self.session.campaign
 44        Text(self.session.campaign.getlevel(
 45            self.session.campaign_level_name).displayname,
 46             scale=1.3,
 47             h_attach=Text.HAttach.CENTER,
 48             h_align=Text.HAlign.CENTER,
 49             v_attach=Text.VAttach.TOP,
 50             transition=Text.Transition.FADE_IN,
 51             transition_delay=4.0,
 52             color=(1, 1, 1, 0.6),
 53             position=(0, -95)).autoretain()
 54        ControlsGuide(delay=1.0).autoretain()
 55
 56    def _on_got_scores_to_beat(self,
 57                               scores: list[dict[str, Any]] | None) -> None:
 58        # pylint: disable=too-many-locals
 59        # pylint: disable=too-many-statements
 60        from efro.util import asserttype
 61        from bastd.actor.text import Text
 62
 63        # Sort by originating date so that the most recent is first.
 64        if scores is not None:
 65            scores.sort(reverse=True,
 66                        key=lambda score: asserttype(score['time'], int))
 67
 68        # We only show achievements and challenges for CoopGameActivities.
 69        session = self.session
 70        assert isinstance(session, ba.CoopSession)
 71        gameinstance = session.get_current_game_instance()
 72        if isinstance(gameinstance, ba.CoopGameActivity):
 73            score_type = gameinstance.get_score_type()
 74            if scores is not None:
 75                achievement_challenges = [
 76                    a for a in scores if a['type'] == 'achievement_challenge'
 77                ]
 78                score_challenges = [
 79                    a for a in scores if a['type'] == 'score_challenge'
 80                ]
 81            else:
 82                achievement_challenges = score_challenges = []
 83
 84            delay = 1.0
 85            vpos = -140.0
 86            spacing = 25
 87            delay_inc = 0.1
 88
 89            def _add_t(
 90                text: str | ba.Lstr,
 91                h_offs: float = 0.0,
 92                scale: float = 1.0,
 93                color: Sequence[float] = (1.0, 1.0, 1.0, 0.46)
 94            ) -> None:
 95                Text(text,
 96                     scale=scale * 0.76,
 97                     h_align=Text.HAlign.LEFT,
 98                     h_attach=Text.HAttach.LEFT,
 99                     v_attach=Text.VAttach.TOP,
100                     transition=Text.Transition.FADE_IN,
101                     transition_delay=delay,
102                     color=color,
103                     position=(60 + h_offs, vpos)).autoretain()
104
105            if score_challenges:
106                _add_t(ba.Lstr(value='${A}:',
107                               subs=[('${A}',
108                                      ba.Lstr(resource='scoreChallengesText'))
109                                     ]),
110                       scale=1.1)
111                delay += delay_inc
112                vpos -= spacing
113                for chal in score_challenges:
114                    _add_t(str(chal['value'] if score_type == 'points' else ba.
115                               timestring(int(chal['value']) * 10,
116                                          timeformat=ba.TimeFormat.MILLISECONDS
117                                          ).evaluate()) + '  (1 player)',
118                           h_offs=30,
119                           color=(0.9, 0.7, 1.0, 0.8))
120                    delay += delay_inc
121                    vpos -= 0.6 * spacing
122                    _add_t(chal['player'],
123                           h_offs=40,
124                           color=(0.8, 1, 0.8, 0.6),
125                           scale=0.8)
126                    delay += delay_inc
127                    vpos -= 1.2 * spacing
128                vpos -= 0.5 * spacing
129
130            if achievement_challenges:
131                _add_t(ba.Lstr(
132                    value='${A}:',
133                    subs=[('${A}',
134                           ba.Lstr(resource='achievementChallengesText'))]),
135                       scale=1.1)
136                delay += delay_inc
137                vpos -= spacing
138                for chal in achievement_challenges:
139                    _add_t(str(chal['value']),
140                           h_offs=30,
141                           color=(0.9, 0.7, 1.0, 0.8))
142                    delay += delay_inc
143                    vpos -= 0.6 * spacing
144                    _add_t(chal['player'],
145                           h_offs=40,
146                           color=(0.8, 1, 0.8, 0.6),
147                           scale=0.8)
148                    delay += delay_inc
149                    vpos -= 1.2 * spacing
150                vpos -= 0.5 * spacing
151
152            # Now list our remaining achievements for this level.
153            assert self.session.campaign is not None
154            assert isinstance(self.session, ba.CoopSession)
155            levelname = (self.session.campaign.name + ':' +
156                         self.session.campaign_level_name)
157            ts_h_offs = 60
158
159            if not (ba.app.demo_mode or ba.app.arcade_mode):
160                achievements = [
161                    a
162                    for a in ba.app.ach.achievements_for_coop_level(levelname)
163                    if not a.complete
164                ]
165                have_achievements = bool(achievements)
166                achievements = [a for a in achievements if not a.complete]
167                vrmode = ba.app.vr_mode
168                if have_achievements:
169                    Text(ba.Lstr(resource='achievementsRemainingText'),
170                         host_only=True,
171                         position=(ts_h_offs - 10, vpos),
172                         transition=Text.Transition.FADE_IN,
173                         scale=1.1 * 0.76,
174                         h_attach=Text.HAttach.LEFT,
175                         v_attach=Text.VAttach.TOP,
176                         color=(1, 1, 1.2, 1) if vrmode else (0.8, 0.8, 1, 1),
177                         shadow=1.0,
178                         flatness=1.0 if vrmode else 0.6,
179                         transition_delay=delay).autoretain()
180                    hval = ts_h_offs + 50
181                    vpos -= 35
182                    for ach in achievements:
183                        delay += 0.05
184                        ach.create_display(hval, vpos, delay, style='in_game')
185                        vpos -= 55
186                    if not achievements:
187                        Text(ba.Lstr(resource='noAchievementsRemainingText'),
188                             host_only=True,
189                             position=(ts_h_offs + 15, vpos + 10),
190                             transition=Text.Transition.FADE_IN,
191                             scale=0.7,
192                             h_attach=Text.HAttach.LEFT,
193                             v_attach=Text.VAttach.TOP,
194                             color=(1, 1, 1, 0.5),
195                             transition_delay=delay + 0.5).autoretain()
class CoopJoinActivity(ba._activity.Activity[ba._player.EmptyPlayer, ba._team.EmptyTeam]):
 18class CoopJoinActivity(JoinActivity):
 19    """Join-screen for co-op mode."""
 20
 21    # We can assume our session is a CoopSession.
 22    session: ba.CoopSession
 23
 24    def __init__(self, settings: dict):
 25        super().__init__(settings)
 26        session = self.session
 27        assert isinstance(session, ba.CoopSession)
 28
 29        # Let's show a list of scores-to-beat for 1 player at least.
 30        assert session.campaign is not None
 31        level_name_full = (session.campaign.name + ':' +
 32                           session.campaign_level_name)
 33        config_str = ('1p' + session.campaign.getlevel(
 34            session.campaign_level_name).get_score_version_string().replace(
 35                ' ', '_'))
 36        _ba.get_scores_to_beat(level_name_full, config_str,
 37                               ba.WeakCall(self._on_got_scores_to_beat))
 38
 39    def on_transition_in(self) -> None:
 40        from bastd.actor.controlsguide import ControlsGuide
 41        from bastd.actor.text import Text
 42        super().on_transition_in()
 43        assert isinstance(self.session, ba.CoopSession)
 44        assert self.session.campaign
 45        Text(self.session.campaign.getlevel(
 46            self.session.campaign_level_name).displayname,
 47             scale=1.3,
 48             h_attach=Text.HAttach.CENTER,
 49             h_align=Text.HAlign.CENTER,
 50             v_attach=Text.VAttach.TOP,
 51             transition=Text.Transition.FADE_IN,
 52             transition_delay=4.0,
 53             color=(1, 1, 1, 0.6),
 54             position=(0, -95)).autoretain()
 55        ControlsGuide(delay=1.0).autoretain()
 56
 57    def _on_got_scores_to_beat(self,
 58                               scores: list[dict[str, Any]] | None) -> None:
 59        # pylint: disable=too-many-locals
 60        # pylint: disable=too-many-statements
 61        from efro.util import asserttype
 62        from bastd.actor.text import Text
 63
 64        # Sort by originating date so that the most recent is first.
 65        if scores is not None:
 66            scores.sort(reverse=True,
 67                        key=lambda score: asserttype(score['time'], int))
 68
 69        # We only show achievements and challenges for CoopGameActivities.
 70        session = self.session
 71        assert isinstance(session, ba.CoopSession)
 72        gameinstance = session.get_current_game_instance()
 73        if isinstance(gameinstance, ba.CoopGameActivity):
 74            score_type = gameinstance.get_score_type()
 75            if scores is not None:
 76                achievement_challenges = [
 77                    a for a in scores if a['type'] == 'achievement_challenge'
 78                ]
 79                score_challenges = [
 80                    a for a in scores if a['type'] == 'score_challenge'
 81                ]
 82            else:
 83                achievement_challenges = score_challenges = []
 84
 85            delay = 1.0
 86            vpos = -140.0
 87            spacing = 25
 88            delay_inc = 0.1
 89
 90            def _add_t(
 91                text: str | ba.Lstr,
 92                h_offs: float = 0.0,
 93                scale: float = 1.0,
 94                color: Sequence[float] = (1.0, 1.0, 1.0, 0.46)
 95            ) -> None:
 96                Text(text,
 97                     scale=scale * 0.76,
 98                     h_align=Text.HAlign.LEFT,
 99                     h_attach=Text.HAttach.LEFT,
100                     v_attach=Text.VAttach.TOP,
101                     transition=Text.Transition.FADE_IN,
102                     transition_delay=delay,
103                     color=color,
104                     position=(60 + h_offs, vpos)).autoretain()
105
106            if score_challenges:
107                _add_t(ba.Lstr(value='${A}:',
108                               subs=[('${A}',
109                                      ba.Lstr(resource='scoreChallengesText'))
110                                     ]),
111                       scale=1.1)
112                delay += delay_inc
113                vpos -= spacing
114                for chal in score_challenges:
115                    _add_t(str(chal['value'] if score_type == 'points' else ba.
116                               timestring(int(chal['value']) * 10,
117                                          timeformat=ba.TimeFormat.MILLISECONDS
118                                          ).evaluate()) + '  (1 player)',
119                           h_offs=30,
120                           color=(0.9, 0.7, 1.0, 0.8))
121                    delay += delay_inc
122                    vpos -= 0.6 * spacing
123                    _add_t(chal['player'],
124                           h_offs=40,
125                           color=(0.8, 1, 0.8, 0.6),
126                           scale=0.8)
127                    delay += delay_inc
128                    vpos -= 1.2 * spacing
129                vpos -= 0.5 * spacing
130
131            if achievement_challenges:
132                _add_t(ba.Lstr(
133                    value='${A}:',
134                    subs=[('${A}',
135                           ba.Lstr(resource='achievementChallengesText'))]),
136                       scale=1.1)
137                delay += delay_inc
138                vpos -= spacing
139                for chal in achievement_challenges:
140                    _add_t(str(chal['value']),
141                           h_offs=30,
142                           color=(0.9, 0.7, 1.0, 0.8))
143                    delay += delay_inc
144                    vpos -= 0.6 * spacing
145                    _add_t(chal['player'],
146                           h_offs=40,
147                           color=(0.8, 1, 0.8, 0.6),
148                           scale=0.8)
149                    delay += delay_inc
150                    vpos -= 1.2 * spacing
151                vpos -= 0.5 * spacing
152
153            # Now list our remaining achievements for this level.
154            assert self.session.campaign is not None
155            assert isinstance(self.session, ba.CoopSession)
156            levelname = (self.session.campaign.name + ':' +
157                         self.session.campaign_level_name)
158            ts_h_offs = 60
159
160            if not (ba.app.demo_mode or ba.app.arcade_mode):
161                achievements = [
162                    a
163                    for a in ba.app.ach.achievements_for_coop_level(levelname)
164                    if not a.complete
165                ]
166                have_achievements = bool(achievements)
167                achievements = [a for a in achievements if not a.complete]
168                vrmode = ba.app.vr_mode
169                if have_achievements:
170                    Text(ba.Lstr(resource='achievementsRemainingText'),
171                         host_only=True,
172                         position=(ts_h_offs - 10, vpos),
173                         transition=Text.Transition.FADE_IN,
174                         scale=1.1 * 0.76,
175                         h_attach=Text.HAttach.LEFT,
176                         v_attach=Text.VAttach.TOP,
177                         color=(1, 1, 1.2, 1) if vrmode else (0.8, 0.8, 1, 1),
178                         shadow=1.0,
179                         flatness=1.0 if vrmode else 0.6,
180                         transition_delay=delay).autoretain()
181                    hval = ts_h_offs + 50
182                    vpos -= 35
183                    for ach in achievements:
184                        delay += 0.05
185                        ach.create_display(hval, vpos, delay, style='in_game')
186                        vpos -= 55
187                    if not achievements:
188                        Text(ba.Lstr(resource='noAchievementsRemainingText'),
189                             host_only=True,
190                             position=(ts_h_offs + 15, vpos + 10),
191                             transition=Text.Transition.FADE_IN,
192                             scale=0.7,
193                             h_attach=Text.HAttach.LEFT,
194                             v_attach=Text.VAttach.TOP,
195                             color=(1, 1, 1, 0.5),
196                             transition_delay=delay + 0.5).autoretain()

Join-screen for co-op mode.

CoopJoinActivity(settings: dict)
24    def __init__(self, settings: dict):
25        super().__init__(settings)
26        session = self.session
27        assert isinstance(session, ba.CoopSession)
28
29        # Let's show a list of scores-to-beat for 1 player at least.
30        assert session.campaign is not None
31        level_name_full = (session.campaign.name + ':' +
32                           session.campaign_level_name)
33        config_str = ('1p' + session.campaign.getlevel(
34            session.campaign_level_name).get_score_version_string().replace(
35                ' ', '_'))
36        _ba.get_scores_to_beat(level_name_full, config_str,
37                               ba.WeakCall(self._on_got_scores_to_beat))

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.

session: ba._session.Session

The ba.Session this ba.Activity belongs go.

Raises a ba.SessionNotFoundError if the Session no longer exists.

def on_transition_in(self) -> None:
39    def on_transition_in(self) -> None:
40        from bastd.actor.controlsguide import ControlsGuide
41        from bastd.actor.text import Text
42        super().on_transition_in()
43        assert isinstance(self.session, ba.CoopSession)
44        assert self.session.campaign
45        Text(self.session.campaign.getlevel(
46            self.session.campaign_level_name).displayname,
47             scale=1.3,
48             h_attach=Text.HAttach.CENTER,
49             h_align=Text.HAlign.CENTER,
50             v_attach=Text.VAttach.TOP,
51             transition=Text.Transition.FADE_IN,
52             transition_delay=4.0,
53             color=(1, 1, 1, 0.6),
54             position=(0, -95)).autoretain()
55        ControlsGuide(delay=1.0).autoretain()

Called when the Activity is first becoming visible.

Upon this call, the Activity should fade in backgrounds, start playing music, etc. It does not yet have access to players or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

Inherited Members
ba._activity.Activity
is_joining_activity
allow_kick_idle_players
use_fixed_vr_overlay
settings_raw
teams
players
announce_player_deaths
allow_pausing
slow_motion
inherits_slow_motion
inherits_music
inherits_vr_camera_offset
inherits_vr_overlay_center
inherits_tint
allow_mid_activity_joins
transition_time
can_show_ad_on_death
globalsnode
stats
on_expire
customdata
expired
playertype
teamtype
retain_actor
add_actor_weak_ref
on_player_join
on_player_leave
on_team_join
on_team_leave
on_transition_out
on_begin
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