bastd.game.assault

Defines assault minigame.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines assault minigame."""
  4
  5# ba_meta require api 7
  6# (see https://ballistica.net/wiki/meta-tag-system)
  7
  8from __future__ import annotations
  9
 10import random
 11from typing import TYPE_CHECKING
 12
 13import ba
 14from bastd.actor.playerspaz import PlayerSpaz
 15from bastd.actor.flag import Flag
 16from bastd.actor.scoreboard import Scoreboard
 17from bastd.gameutils import SharedObjects
 18
 19if TYPE_CHECKING:
 20    from typing import Any, Sequence
 21
 22
 23class Player(ba.Player['Team']):
 24    """Our player type for this game."""
 25
 26
 27class Team(ba.Team[Player]):
 28    """Our team type for this game."""
 29
 30    def __init__(self, base_pos: Sequence[float], flag: Flag) -> None:
 31        self.base_pos = base_pos
 32        self.flag = flag
 33        self.score = 0
 34
 35
 36# ba_meta export game
 37class AssaultGame(ba.TeamGameActivity[Player, Team]):
 38    """Game where you score by touching the other team's flag."""
 39
 40    name = 'Assault'
 41    description = 'Reach the enemy flag to score.'
 42    available_settings = [
 43        ba.IntSetting(
 44            'Score to Win',
 45            min_value=1,
 46            default=3,
 47        ),
 48        ba.IntChoiceSetting(
 49            'Time Limit',
 50            choices=[
 51                ('None', 0),
 52                ('1 Minute', 60),
 53                ('2 Minutes', 120),
 54                ('5 Minutes', 300),
 55                ('10 Minutes', 600),
 56                ('20 Minutes', 1200),
 57            ],
 58            default=0,
 59        ),
 60        ba.FloatChoiceSetting(
 61            'Respawn Times',
 62            choices=[
 63                ('Shorter', 0.25),
 64                ('Short', 0.5),
 65                ('Normal', 1.0),
 66                ('Long', 2.0),
 67                ('Longer', 4.0),
 68            ],
 69            default=1.0,
 70        ),
 71        ba.BoolSetting('Epic Mode', default=False),
 72    ]
 73
 74    @classmethod
 75    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
 76        return issubclass(sessiontype, ba.DualTeamSession)
 77
 78    @classmethod
 79    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
 80        return ba.getmaps('team_flag')
 81
 82    def __init__(self, settings: dict):
 83        super().__init__(settings)
 84        self._scoreboard = Scoreboard()
 85        self._last_score_time = 0.0
 86        self._score_sound = ba.getsound('score')
 87        self._base_region_materials: dict[int, ba.Material] = {}
 88        self._epic_mode = bool(settings['Epic Mode'])
 89        self._score_to_win = int(settings['Score to Win'])
 90        self._time_limit = float(settings['Time Limit'])
 91
 92        # Base class overrides
 93        self.slow_motion = self._epic_mode
 94        self.default_music = (ba.MusicType.EPIC if self._epic_mode else
 95                              ba.MusicType.FORWARD_MARCH)
 96
 97    def get_instance_description(self) -> str | Sequence:
 98        if self._score_to_win == 1:
 99            return 'Touch the enemy flag.'
100        return 'Touch the enemy flag ${ARG1} times.', self._score_to_win
101
102    def get_instance_description_short(self) -> str | Sequence:
103        if self._score_to_win == 1:
104            return 'touch 1 flag'
105        return 'touch ${ARG1} flags', self._score_to_win
106
107    def create_team(self, sessionteam: ba.SessionTeam) -> Team:
108        shared = SharedObjects.get()
109        base_pos = self.map.get_flag_position(sessionteam.id)
110        ba.newnode('light',
111                   attrs={
112                       'position': base_pos,
113                       'intensity': 0.6,
114                       'height_attenuated': False,
115                       'volume_intensity_scale': 0.1,
116                       'radius': 0.1,
117                       'color': sessionteam.color
118                   })
119        Flag.project_stand(base_pos)
120        flag = Flag(touchable=False,
121                    position=base_pos,
122                    color=sessionteam.color)
123        team = Team(base_pos=base_pos, flag=flag)
124
125        mat = self._base_region_materials[sessionteam.id] = ba.Material()
126        mat.add_actions(
127            conditions=('they_have_material', shared.player_material),
128            actions=(
129                ('modify_part_collision', 'collide', True),
130                ('modify_part_collision', 'physical', False),
131                ('call', 'at_connect', ba.Call(self._handle_base_collide,
132                                               team)),
133            ),
134        )
135
136        ba.newnode(
137            'region',
138            owner=flag.node,
139            attrs={
140                'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]),
141                'scale': (0.5, 0.5, 0.5),
142                'type': 'sphere',
143                'materials': [self._base_region_materials[sessionteam.id]]
144            })
145
146        return team
147
148    def on_team_join(self, team: Team) -> None:
149        # Can't do this in create_team because the team's color/etc. have
150        # not been wired up yet at that point.
151        self._update_scoreboard()
152
153    def on_begin(self) -> None:
154        super().on_begin()
155        self.setup_standard_time_limit(self._time_limit)
156        self.setup_standard_powerup_drops()
157
158    def handlemessage(self, msg: Any) -> Any:
159        if isinstance(msg, ba.PlayerDiedMessage):
160            super().handlemessage(msg)  # Augment standard.
161            self.respawn_player(msg.getplayer(Player))
162        else:
163            super().handlemessage(msg)
164
165    def _flash_base(self, team: Team, length: float = 2.0) -> None:
166        light = ba.newnode('light',
167                           attrs={
168                               'position': team.base_pos,
169                               'height_attenuated': False,
170                               'radius': 0.3,
171                               'color': team.color
172                           })
173        ba.animate(light, 'intensity', {0: 0, 0.25: 2.0, 0.5: 0}, loop=True)
174        ba.timer(length, light.delete)
175
176    def _handle_base_collide(self, team: Team) -> None:
177        try:
178            spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True)
179        except ba.NotFoundError:
180            return
181
182        if not spaz.is_alive():
183            return
184
185        try:
186            player = spaz.getplayer(Player, True)
187        except ba.NotFoundError:
188            return
189
190        # If its another team's player, they scored.
191        player_team = player.team
192        if player_team is not team:
193
194            # Prevent multiple simultaneous scores.
195            if ba.time() != self._last_score_time:
196                self._last_score_time = ba.time()
197                self.stats.player_scored(player, 50, big_message=True)
198                ba.playsound(self._score_sound)
199                self._flash_base(team)
200
201                # Move all players on the scoring team back to their start
202                # and add flashes of light so its noticeable.
203                for player in player_team.players:
204                    if player.is_alive():
205                        pos = player.node.position
206                        light = ba.newnode('light',
207                                           attrs={
208                                               'position': pos,
209                                               'color': player_team.color,
210                                               'height_attenuated': False,
211                                               'radius': 0.4
212                                           })
213                        ba.timer(0.5, light.delete)
214                        ba.animate(light, 'intensity', {
215                            0: 0,
216                            0.1: 1.0,
217                            0.5: 0
218                        })
219
220                        new_pos = (self.map.get_start_position(player_team.id))
221                        light = ba.newnode('light',
222                                           attrs={
223                                               'position': new_pos,
224                                               'color': player_team.color,
225                                               'radius': 0.4,
226                                               'height_attenuated': False
227                                           })
228                        ba.timer(0.5, light.delete)
229                        ba.animate(light, 'intensity', {
230                            0: 0,
231                            0.1: 1.0,
232                            0.5: 0
233                        })
234                        if player.actor:
235                            player.actor.handlemessage(
236                                ba.StandMessage(new_pos,
237                                                random.uniform(0, 360)))
238
239                # Have teammates celebrate.
240                for player in player_team.players:
241                    if player.actor:
242                        player.actor.handlemessage(ba.CelebrateMessage(2.0))
243
244                player_team.score += 1
245                self._update_scoreboard()
246                if player_team.score >= self._score_to_win:
247                    self.end_game()
248
249    def end_game(self) -> None:
250        results = ba.GameResults()
251        for team in self.teams:
252            results.set_team_score(team, team.score)
253        self.end(results=results)
254
255    def _update_scoreboard(self) -> None:
256        for team in self.teams:
257            self._scoreboard.set_team_value(team, team.score,
258                                            self._score_to_win)
class Player(ba._player.Player[ForwardRef('Team')]):
24class Player(ba.Player['Team']):
25    """Our player type for this game."""

Our player type for this game.

Player()
class Team(ba._team.Team[bastd.game.assault.Player]):
28class Team(ba.Team[Player]):
29    """Our team type for this game."""
30
31    def __init__(self, base_pos: Sequence[float], flag: Flag) -> None:
32        self.base_pos = base_pos
33        self.flag = flag
34        self.score = 0

Our team type for this game.

Team(base_pos: Sequence[float], flag: bastd.actor.flag.Flag)
31    def __init__(self, base_pos: Sequence[float], flag: Flag) -> None:
32        self.base_pos = base_pos
33        self.flag = flag
34        self.score = 0
Inherited Members
ba._team.Team
manual_init
customdata
on_expire
sessionteam
class AssaultGame(ba._teamgame.TeamGameActivity[bastd.game.assault.Player, bastd.game.assault.Team]):
 38class AssaultGame(ba.TeamGameActivity[Player, Team]):
 39    """Game where you score by touching the other team's flag."""
 40
 41    name = 'Assault'
 42    description = 'Reach the enemy flag to score.'
 43    available_settings = [
 44        ba.IntSetting(
 45            'Score to Win',
 46            min_value=1,
 47            default=3,
 48        ),
 49        ba.IntChoiceSetting(
 50            'Time Limit',
 51            choices=[
 52                ('None', 0),
 53                ('1 Minute', 60),
 54                ('2 Minutes', 120),
 55                ('5 Minutes', 300),
 56                ('10 Minutes', 600),
 57                ('20 Minutes', 1200),
 58            ],
 59            default=0,
 60        ),
 61        ba.FloatChoiceSetting(
 62            'Respawn Times',
 63            choices=[
 64                ('Shorter', 0.25),
 65                ('Short', 0.5),
 66                ('Normal', 1.0),
 67                ('Long', 2.0),
 68                ('Longer', 4.0),
 69            ],
 70            default=1.0,
 71        ),
 72        ba.BoolSetting('Epic Mode', default=False),
 73    ]
 74
 75    @classmethod
 76    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
 77        return issubclass(sessiontype, ba.DualTeamSession)
 78
 79    @classmethod
 80    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
 81        return ba.getmaps('team_flag')
 82
 83    def __init__(self, settings: dict):
 84        super().__init__(settings)
 85        self._scoreboard = Scoreboard()
 86        self._last_score_time = 0.0
 87        self._score_sound = ba.getsound('score')
 88        self._base_region_materials: dict[int, ba.Material] = {}
 89        self._epic_mode = bool(settings['Epic Mode'])
 90        self._score_to_win = int(settings['Score to Win'])
 91        self._time_limit = float(settings['Time Limit'])
 92
 93        # Base class overrides
 94        self.slow_motion = self._epic_mode
 95        self.default_music = (ba.MusicType.EPIC if self._epic_mode else
 96                              ba.MusicType.FORWARD_MARCH)
 97
 98    def get_instance_description(self) -> str | Sequence:
 99        if self._score_to_win == 1:
100            return 'Touch the enemy flag.'
101        return 'Touch the enemy flag ${ARG1} times.', self._score_to_win
102
103    def get_instance_description_short(self) -> str | Sequence:
104        if self._score_to_win == 1:
105            return 'touch 1 flag'
106        return 'touch ${ARG1} flags', self._score_to_win
107
108    def create_team(self, sessionteam: ba.SessionTeam) -> Team:
109        shared = SharedObjects.get()
110        base_pos = self.map.get_flag_position(sessionteam.id)
111        ba.newnode('light',
112                   attrs={
113                       'position': base_pos,
114                       'intensity': 0.6,
115                       'height_attenuated': False,
116                       'volume_intensity_scale': 0.1,
117                       'radius': 0.1,
118                       'color': sessionteam.color
119                   })
120        Flag.project_stand(base_pos)
121        flag = Flag(touchable=False,
122                    position=base_pos,
123                    color=sessionteam.color)
124        team = Team(base_pos=base_pos, flag=flag)
125
126        mat = self._base_region_materials[sessionteam.id] = ba.Material()
127        mat.add_actions(
128            conditions=('they_have_material', shared.player_material),
129            actions=(
130                ('modify_part_collision', 'collide', True),
131                ('modify_part_collision', 'physical', False),
132                ('call', 'at_connect', ba.Call(self._handle_base_collide,
133                                               team)),
134            ),
135        )
136
137        ba.newnode(
138            'region',
139            owner=flag.node,
140            attrs={
141                'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]),
142                'scale': (0.5, 0.5, 0.5),
143                'type': 'sphere',
144                'materials': [self._base_region_materials[sessionteam.id]]
145            })
146
147        return team
148
149    def on_team_join(self, team: Team) -> None:
150        # Can't do this in create_team because the team's color/etc. have
151        # not been wired up yet at that point.
152        self._update_scoreboard()
153
154    def on_begin(self) -> None:
155        super().on_begin()
156        self.setup_standard_time_limit(self._time_limit)
157        self.setup_standard_powerup_drops()
158
159    def handlemessage(self, msg: Any) -> Any:
160        if isinstance(msg, ba.PlayerDiedMessage):
161            super().handlemessage(msg)  # Augment standard.
162            self.respawn_player(msg.getplayer(Player))
163        else:
164            super().handlemessage(msg)
165
166    def _flash_base(self, team: Team, length: float = 2.0) -> None:
167        light = ba.newnode('light',
168                           attrs={
169                               'position': team.base_pos,
170                               'height_attenuated': False,
171                               'radius': 0.3,
172                               'color': team.color
173                           })
174        ba.animate(light, 'intensity', {0: 0, 0.25: 2.0, 0.5: 0}, loop=True)
175        ba.timer(length, light.delete)
176
177    def _handle_base_collide(self, team: Team) -> None:
178        try:
179            spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True)
180        except ba.NotFoundError:
181            return
182
183        if not spaz.is_alive():
184            return
185
186        try:
187            player = spaz.getplayer(Player, True)
188        except ba.NotFoundError:
189            return
190
191        # If its another team's player, they scored.
192        player_team = player.team
193        if player_team is not team:
194
195            # Prevent multiple simultaneous scores.
196            if ba.time() != self._last_score_time:
197                self._last_score_time = ba.time()
198                self.stats.player_scored(player, 50, big_message=True)
199                ba.playsound(self._score_sound)
200                self._flash_base(team)
201
202                # Move all players on the scoring team back to their start
203                # and add flashes of light so its noticeable.
204                for player in player_team.players:
205                    if player.is_alive():
206                        pos = player.node.position
207                        light = ba.newnode('light',
208                                           attrs={
209                                               'position': pos,
210                                               'color': player_team.color,
211                                               'height_attenuated': False,
212                                               'radius': 0.4
213                                           })
214                        ba.timer(0.5, light.delete)
215                        ba.animate(light, 'intensity', {
216                            0: 0,
217                            0.1: 1.0,
218                            0.5: 0
219                        })
220
221                        new_pos = (self.map.get_start_position(player_team.id))
222                        light = ba.newnode('light',
223                                           attrs={
224                                               'position': new_pos,
225                                               'color': player_team.color,
226                                               'radius': 0.4,
227                                               'height_attenuated': False
228                                           })
229                        ba.timer(0.5, light.delete)
230                        ba.animate(light, 'intensity', {
231                            0: 0,
232                            0.1: 1.0,
233                            0.5: 0
234                        })
235                        if player.actor:
236                            player.actor.handlemessage(
237                                ba.StandMessage(new_pos,
238                                                random.uniform(0, 360)))
239
240                # Have teammates celebrate.
241                for player in player_team.players:
242                    if player.actor:
243                        player.actor.handlemessage(ba.CelebrateMessage(2.0))
244
245                player_team.score += 1
246                self._update_scoreboard()
247                if player_team.score >= self._score_to_win:
248                    self.end_game()
249
250    def end_game(self) -> None:
251        results = ba.GameResults()
252        for team in self.teams:
253            results.set_team_score(team, team.score)
254        self.end(results=results)
255
256    def _update_scoreboard(self) -> None:
257        for team in self.teams:
258            self._scoreboard.set_team_value(team, team.score,
259                                            self._score_to_win)

Game where you score by touching the other team's flag.

AssaultGame(settings: dict)
83    def __init__(self, settings: dict):
84        super().__init__(settings)
85        self._scoreboard = Scoreboard()
86        self._last_score_time = 0.0
87        self._score_sound = ba.getsound('score')
88        self._base_region_materials: dict[int, ba.Material] = {}
89        self._epic_mode = bool(settings['Epic Mode'])
90        self._score_to_win = int(settings['Score to Win'])
91        self._time_limit = float(settings['Time Limit'])
92
93        # Base class overrides
94        self.slow_motion = self._epic_mode
95        self.default_music = (ba.MusicType.EPIC if self._epic_mode else
96                              ba.MusicType.FORWARD_MARCH)

Instantiate the Activity.

name: str | None = 'Assault'
description: str | None = 'Reach the enemy flag to score.'
available_settings: list[ba._settings.Setting] | None = [IntSetting(name='Score to Win', default=3, min_value=1, max_value=9999, increment=1), IntChoiceSetting(name='Time Limit', default=0, choices=[('None', 0), ('1 Minute', 60), ('2 Minutes', 120), ('5 Minutes', 300), ('10 Minutes', 600), ('20 Minutes', 1200)]), FloatChoiceSetting(name='Respawn Times', default=1.0, choices=[('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)]), BoolSetting(name='Epic Mode', default=False)]
@classmethod
def supports_session_type(cls, sessiontype: type[ba._session.Session]) -> bool:
75    @classmethod
76    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
77        return issubclass(sessiontype, ba.DualTeamSession)

Class method override; returns True for ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.

@classmethod
def get_supported_maps(cls, sessiontype: type[ba._session.Session]) -> list[str]:
79    @classmethod
80    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
81        return ba.getmaps('team_flag')

Called by the default ba.GameActivity.create_settings_ui() implementation; should return a list of map names valid for this game-type for the given ba.Session type.

def get_instance_description(self) -> Union[str, Sequence]:
 98    def get_instance_description(self) -> str | Sequence:
 99        if self._score_to_win == 1:
100            return 'Touch the enemy flag.'
101        return 'Touch the enemy flag ${ARG1} times.', self._score_to_win

Return a description for this game instance, in English.

This is shown in the center of the screen below the game name at the start of a game. It should start with a capital letter and end with a period, and can be a bit more verbose than the version returned by get_instance_description_short().

Note that translation is applied by looking up the specific returned value as a key, so the number of returned variations should be limited; ideally just one or two. To include arbitrary values in the description, you can return a sequence of values in the following form instead of just a string:

This will give us something like 'Score 3 goals.' in English

and can properly translate to 'Anota 3 goles.' in Spanish.

If we just returned the string 'Score 3 Goals' here, there would

have to be a translation entry for each specific number. ew.

return ['Score ${ARG1} goals.', self.settings_raw['Score to Win']]

This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced with the first value, ${ARG2} with the second, etc.

def get_instance_description_short(self) -> Union[str, Sequence]:
103    def get_instance_description_short(self) -> str | Sequence:
104        if self._score_to_win == 1:
105            return 'touch 1 flag'
106        return 'touch ${ARG1} flags', self._score_to_win

Return a short description for this game instance in English.

This description is used above the game scoreboard in the corner of the screen, so it should be as concise as possible. It should be lowercase and should not contain periods or other punctuation.

Note that translation is applied by looking up the specific returned value as a key, so the number of returned variations should be limited; ideally just one or two. To include arbitrary values in the description, you can return a sequence of values in the following form instead of just a string:

This will give us something like 'score 3 goals' in English

and can properly translate to 'anota 3 goles' in Spanish.

If we just returned the string 'score 3 goals' here, there would

have to be a translation entry for each specific number. ew.

return ['score ${ARG1} goals', self.settings_raw['Score to Win']]

This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced with the first value, ${ARG2} with the second, etc.

def create_team(self, sessionteam: ba._team.SessionTeam) -> bastd.game.assault.Team:
108    def create_team(self, sessionteam: ba.SessionTeam) -> Team:
109        shared = SharedObjects.get()
110        base_pos = self.map.get_flag_position(sessionteam.id)
111        ba.newnode('light',
112                   attrs={
113                       'position': base_pos,
114                       'intensity': 0.6,
115                       'height_attenuated': False,
116                       'volume_intensity_scale': 0.1,
117                       'radius': 0.1,
118                       'color': sessionteam.color
119                   })
120        Flag.project_stand(base_pos)
121        flag = Flag(touchable=False,
122                    position=base_pos,
123                    color=sessionteam.color)
124        team = Team(base_pos=base_pos, flag=flag)
125
126        mat = self._base_region_materials[sessionteam.id] = ba.Material()
127        mat.add_actions(
128            conditions=('they_have_material', shared.player_material),
129            actions=(
130                ('modify_part_collision', 'collide', True),
131                ('modify_part_collision', 'physical', False),
132                ('call', 'at_connect', ba.Call(self._handle_base_collide,
133                                               team)),
134            ),
135        )
136
137        ba.newnode(
138            'region',
139            owner=flag.node,
140            attrs={
141                'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]),
142                'scale': (0.5, 0.5, 0.5),
143                'type': 'sphere',
144                'materials': [self._base_region_materials[sessionteam.id]]
145            })
146
147        return team

Create the Team instance for this Activity.

Subclasses can override this if the activity's team class requires a custom constructor; otherwise it will be called with no args. Note that the team object should not be used at this point as it is not yet fully wired up; wait for on_team_join() for that.

def on_team_join(self, team: bastd.game.assault.Team) -> None:
149    def on_team_join(self, team: Team) -> None:
150        # Can't do this in create_team because the team's color/etc. have
151        # not been wired up yet at that point.
152        self._update_scoreboard()

Called when a new ba.Team joins the Activity.

(including the initial set of Teams)

def on_begin(self) -> None:
154    def on_begin(self) -> None:
155        super().on_begin()
156        self.setup_standard_time_limit(self._time_limit)
157        self.setup_standard_powerup_drops()

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.

def handlemessage(self, msg: Any) -> Any:
159    def handlemessage(self, msg: Any) -> Any:
160        if isinstance(msg, ba.PlayerDiedMessage):
161            super().handlemessage(msg)  # Augment standard.
162            self.respawn_player(msg.getplayer(Player))
163        else:
164            super().handlemessage(msg)

General message handling; can be passed any message object.

def end_game(self) -> None:
250    def end_game(self) -> None:
251        results = ba.GameResults()
252        for team in self.teams:
253            results.set_team_score(team, team.score)
254        self.end(results=results)

Tell the game to wrap up and call ba.Activity.end() immediately.

This method should be overridden by subclasses. A game should always be prepared to end and deliver results, even if there is no 'winner' yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game.

Inherited Members
ba._activity.Activity
slow_motion
settings_raw
teams
players
announce_player_deaths
is_joining_activity
use_fixed_vr_overlay
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
session
on_player_leave
on_team_leave
on_transition_out
has_transitioned_in
has_begun
has_ended
is_transitioning_out
transition_out
create_player
ba._gameactivity.GameActivity
default_music
tips
scoreconfig
allow_pausing
allow_kick_idle_players
show_kill_points
create_settings_ui
getscoreconfig
getname
get_display_string
get_team_display_string
get_description
get_description_display_string
get_available_settings
get_settings_display_string
map
get_instance_display_string
get_instance_scoreboard_display_string
on_continue
is_waiting_for_continue
continue_or_end_game
on_player_join
respawn_player
spawn_player_if_exists
spawn_player
setup_standard_powerup_drops
setup_standard_time_limit
show_zoom_message
ba._teamgame.TeamGameActivity
on_transition_in
spawn_player_spaz
end
ba._dependency.DependencyComponent
dep_is_present
get_dynamic_deps