bastd.game.meteorshower

Defines a bomb-dodging mini-game.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines a bomb-dodging mini-game."""
  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.bomb import Bomb
 15from bastd.actor.onscreentimer import OnScreenTimer
 16
 17if TYPE_CHECKING:
 18    from typing import Any, Sequence
 19
 20
 21class Player(ba.Player['Team']):
 22    """Our player type for this game."""
 23
 24    def __init__(self) -> None:
 25        super().__init__()
 26        self.death_time: float | None = None
 27
 28
 29class Team(ba.Team[Player]):
 30    """Our team type for this game."""
 31
 32
 33# ba_meta export game
 34class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
 35    """Minigame involving dodging falling bombs."""
 36
 37    name = 'Meteor Shower'
 38    description = 'Dodge the falling bombs.'
 39    available_settings = [ba.BoolSetting('Epic Mode', default=False)]
 40    scoreconfig = ba.ScoreConfig(
 41        label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B'
 42    )
 43
 44    # Print messages when players die (since its meaningful in this game).
 45    announce_player_deaths = True
 46
 47    # Don't allow joining after we start
 48    # (would enable leave/rejoin tomfoolery).
 49    allow_mid_activity_joins = False
 50
 51    # We're currently hard-coded for one map.
 52    @classmethod
 53    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
 54        return ['Rampage']
 55
 56    # We support teams, free-for-all, and co-op sessions.
 57    @classmethod
 58    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
 59        return (
 60            issubclass(sessiontype, ba.DualTeamSession)
 61            or issubclass(sessiontype, ba.FreeForAllSession)
 62            or issubclass(sessiontype, ba.CoopSession)
 63        )
 64
 65    def __init__(self, settings: dict):
 66        super().__init__(settings)
 67
 68        self._epic_mode = settings.get('Epic Mode', False)
 69        self._last_player_death_time: float | None = None
 70        self._meteor_time = 2.0
 71        self._timer: OnScreenTimer | None = None
 72
 73        # Some base class overrides:
 74        self.default_music = (
 75            ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL
 76        )
 77        if self._epic_mode:
 78            self.slow_motion = True
 79
 80    def on_begin(self) -> None:
 81        super().on_begin()
 82
 83        # Drop a wave every few seconds.. and every so often drop the time
 84        # between waves ..lets have things increase faster if we have fewer
 85        # players.
 86        delay = 5.0 if len(self.players) > 2 else 2.5
 87        if self._epic_mode:
 88            delay *= 0.25
 89        ba.timer(delay, self._decrement_meteor_time, repeat=True)
 90
 91        # Kick off the first wave in a few seconds.
 92        delay = 3.0
 93        if self._epic_mode:
 94            delay *= 0.25
 95        ba.timer(delay, self._set_meteor_timer)
 96
 97        self._timer = OnScreenTimer()
 98        self._timer.start()
 99
100        # Check for immediate end (if we've only got 1 player, etc).
101        ba.timer(5.0, self._check_end_game)
102
103    def on_player_leave(self, player: Player) -> None:
104        # Augment default behavior.
105        super().on_player_leave(player)
106
107        # A departing player may trigger game-over.
108        self._check_end_game()
109
110    # overriding the default character spawning..
111    def spawn_player(self, player: Player) -> ba.Actor:
112        spaz = self.spawn_player_spaz(player)
113
114        # Let's reconnect this player's controls to this
115        # spaz but *without* the ability to attack or pick stuff up.
116        spaz.connect_controls_to_player(
117            enable_punch=False, enable_bomb=False, enable_pickup=False
118        )
119
120        # Also lets have them make some noise when they die.
121        spaz.play_big_death_sound = True
122        return spaz
123
124    # Various high-level game events come through this method.
125    def handlemessage(self, msg: Any) -> Any:
126        if isinstance(msg, ba.PlayerDiedMessage):
127
128            # Augment standard behavior.
129            super().handlemessage(msg)
130
131            curtime = ba.time()
132
133            # Record the player's moment of death.
134            # assert isinstance(msg.spaz.player
135            msg.getplayer(Player).death_time = curtime
136
137            # In co-op mode, end the game the instant everyone dies
138            # (more accurate looking).
139            # In teams/ffa, allow a one-second fudge-factor so we can
140            # get more draws if players die basically at the same time.
141            if isinstance(self.session, ba.CoopSession):
142                # Teams will still show up if we check now.. check in
143                # the next cycle.
144                ba.pushcall(self._check_end_game)
145
146                # Also record this for a final setting of the clock.
147                self._last_player_death_time = curtime
148            else:
149                ba.timer(1.0, self._check_end_game)
150
151        else:
152            # Default handler:
153            return super().handlemessage(msg)
154        return None
155
156    def _check_end_game(self) -> None:
157        living_team_count = 0
158        for team in self.teams:
159            for player in team.players:
160                if player.is_alive():
161                    living_team_count += 1
162                    break
163
164        # In co-op, we go till everyone is dead.. otherwise we go
165        # until one team remains.
166        if isinstance(self.session, ba.CoopSession):
167            if living_team_count <= 0:
168                self.end_game()
169        else:
170            if living_team_count <= 1:
171                self.end_game()
172
173    def _set_meteor_timer(self) -> None:
174        ba.timer(
175            (1.0 + 0.2 * random.random()) * self._meteor_time,
176            self._drop_bomb_cluster,
177        )
178
179    def _drop_bomb_cluster(self) -> None:
180
181        # Random note: code like this is a handy way to plot out extents
182        # and debug things.
183        loc_test = False
184        if loc_test:
185            ba.newnode('locator', attrs={'position': (8, 6, -5.5)})
186            ba.newnode('locator', attrs={'position': (8, 6, -2.3)})
187            ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
188            ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
189
190        # Drop several bombs in series.
191        delay = 0.0
192        for _i in range(random.randrange(1, 3)):
193            # Drop them somewhere within our bounds with velocity pointing
194            # toward the opposite side.
195            pos = (
196                -7.3 + 15.3 * random.random(),
197                11,
198                -5.57 + 2.1 * random.random(),
199            )
200            dropdir = -1.0 if pos[0] > 0 else 1.0
201            vel = (
202                (-5.0 + random.random() * 30.0) * dropdir,
203                random.uniform(-3.066, -4.12),
204                0,
205            )
206            ba.timer(delay, ba.Call(self._drop_bomb, pos, vel))
207            delay += 0.1
208        self._set_meteor_timer()
209
210    def _drop_bomb(
211        self, position: Sequence[float], velocity: Sequence[float]
212    ) -> None:
213        Bomb(position=position, velocity=velocity).autoretain()
214
215    def _decrement_meteor_time(self) -> None:
216        self._meteor_time = max(0.01, self._meteor_time * 0.9)
217
218    def end_game(self) -> None:
219        cur_time = ba.time()
220        assert self._timer is not None
221        start_time = self._timer.getstarttime()
222
223        # Mark death-time as now for any still-living players
224        # and award players points for how long they lasted.
225        # (these per-player scores are only meaningful in team-games)
226        for team in self.teams:
227            for player in team.players:
228                survived = False
229
230                # Throw an extra fudge factor in so teams that
231                # didn't die come out ahead of teams that did.
232                if player.death_time is None:
233                    survived = True
234                    player.death_time = cur_time + 1
235
236                # Award a per-player score depending on how many seconds
237                # they lasted (per-player scores only affect teams mode;
238                # everywhere else just looks at the per-team score).
239                score = int(player.death_time - self._timer.getstarttime())
240                if survived:
241                    score += 50  # A bit extra for survivors.
242                self.stats.player_scored(player, score, screenmessage=False)
243
244        # Stop updating our time text, and set the final time to match
245        # exactly when our last guy died.
246        self._timer.stop(endtime=self._last_player_death_time)
247
248        # Ok now calc game results: set a score for each team and then tell
249        # the game to end.
250        results = ba.GameResults()
251
252        # Remember that 'free-for-all' mode is simply a special form
253        # of 'teams' mode where each player gets their own team, so we can
254        # just always deal in teams and have all cases covered.
255        for team in self.teams:
256
257            # Set the team score to the max time survived by any player on
258            # that team.
259            longest_life = 0.0
260            for player in team.players:
261                assert player.death_time is not None
262                longest_life = max(longest_life, player.death_time - start_time)
263
264            # Submit the score value in milliseconds.
265            results.set_team_score(team, int(1000.0 * longest_life))
266
267        self.end(results=results)
class Player(ba._player.Player[ForwardRef('Team')]):
22class Player(ba.Player['Team']):
23    """Our player type for this game."""
24
25    def __init__(self) -> None:
26        super().__init__()
27        self.death_time: float | None = None

Our player type for this game.

Player()
25    def __init__(self) -> None:
26        super().__init__()
27        self.death_time: float | None = None
Inherited Members
ba._player.Player
actor
on_expire
team
customdata
sessionplayer
node
position
exists
getname
is_alive
get_icon
assigninput
resetinput
class Team(ba._team.Team[bastd.game.meteorshower.Player]):
30class Team(ba.Team[Player]):
31    """Our team type for this game."""

Our team type for this game.

Team()
Inherited Members
ba._team.Team
manual_init
customdata
on_expire
sessionteam
class MeteorShowerGame(ba._teamgame.TeamGameActivity[bastd.game.meteorshower.Player, bastd.game.meteorshower.Team]):
 35class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
 36    """Minigame involving dodging falling bombs."""
 37
 38    name = 'Meteor Shower'
 39    description = 'Dodge the falling bombs.'
 40    available_settings = [ba.BoolSetting('Epic Mode', default=False)]
 41    scoreconfig = ba.ScoreConfig(
 42        label='Survived', scoretype=ba.ScoreType.MILLISECONDS, version='B'
 43    )
 44
 45    # Print messages when players die (since its meaningful in this game).
 46    announce_player_deaths = True
 47
 48    # Don't allow joining after we start
 49    # (would enable leave/rejoin tomfoolery).
 50    allow_mid_activity_joins = False
 51
 52    # We're currently hard-coded for one map.
 53    @classmethod
 54    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
 55        return ['Rampage']
 56
 57    # We support teams, free-for-all, and co-op sessions.
 58    @classmethod
 59    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
 60        return (
 61            issubclass(sessiontype, ba.DualTeamSession)
 62            or issubclass(sessiontype, ba.FreeForAllSession)
 63            or issubclass(sessiontype, ba.CoopSession)
 64        )
 65
 66    def __init__(self, settings: dict):
 67        super().__init__(settings)
 68
 69        self._epic_mode = settings.get('Epic Mode', False)
 70        self._last_player_death_time: float | None = None
 71        self._meteor_time = 2.0
 72        self._timer: OnScreenTimer | None = None
 73
 74        # Some base class overrides:
 75        self.default_music = (
 76            ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL
 77        )
 78        if self._epic_mode:
 79            self.slow_motion = True
 80
 81    def on_begin(self) -> None:
 82        super().on_begin()
 83
 84        # Drop a wave every few seconds.. and every so often drop the time
 85        # between waves ..lets have things increase faster if we have fewer
 86        # players.
 87        delay = 5.0 if len(self.players) > 2 else 2.5
 88        if self._epic_mode:
 89            delay *= 0.25
 90        ba.timer(delay, self._decrement_meteor_time, repeat=True)
 91
 92        # Kick off the first wave in a few seconds.
 93        delay = 3.0
 94        if self._epic_mode:
 95            delay *= 0.25
 96        ba.timer(delay, self._set_meteor_timer)
 97
 98        self._timer = OnScreenTimer()
 99        self._timer.start()
100
101        # Check for immediate end (if we've only got 1 player, etc).
102        ba.timer(5.0, self._check_end_game)
103
104    def on_player_leave(self, player: Player) -> None:
105        # Augment default behavior.
106        super().on_player_leave(player)
107
108        # A departing player may trigger game-over.
109        self._check_end_game()
110
111    # overriding the default character spawning..
112    def spawn_player(self, player: Player) -> ba.Actor:
113        spaz = self.spawn_player_spaz(player)
114
115        # Let's reconnect this player's controls to this
116        # spaz but *without* the ability to attack or pick stuff up.
117        spaz.connect_controls_to_player(
118            enable_punch=False, enable_bomb=False, enable_pickup=False
119        )
120
121        # Also lets have them make some noise when they die.
122        spaz.play_big_death_sound = True
123        return spaz
124
125    # Various high-level game events come through this method.
126    def handlemessage(self, msg: Any) -> Any:
127        if isinstance(msg, ba.PlayerDiedMessage):
128
129            # Augment standard behavior.
130            super().handlemessage(msg)
131
132            curtime = ba.time()
133
134            # Record the player's moment of death.
135            # assert isinstance(msg.spaz.player
136            msg.getplayer(Player).death_time = curtime
137
138            # In co-op mode, end the game the instant everyone dies
139            # (more accurate looking).
140            # In teams/ffa, allow a one-second fudge-factor so we can
141            # get more draws if players die basically at the same time.
142            if isinstance(self.session, ba.CoopSession):
143                # Teams will still show up if we check now.. check in
144                # the next cycle.
145                ba.pushcall(self._check_end_game)
146
147                # Also record this for a final setting of the clock.
148                self._last_player_death_time = curtime
149            else:
150                ba.timer(1.0, self._check_end_game)
151
152        else:
153            # Default handler:
154            return super().handlemessage(msg)
155        return None
156
157    def _check_end_game(self) -> None:
158        living_team_count = 0
159        for team in self.teams:
160            for player in team.players:
161                if player.is_alive():
162                    living_team_count += 1
163                    break
164
165        # In co-op, we go till everyone is dead.. otherwise we go
166        # until one team remains.
167        if isinstance(self.session, ba.CoopSession):
168            if living_team_count <= 0:
169                self.end_game()
170        else:
171            if living_team_count <= 1:
172                self.end_game()
173
174    def _set_meteor_timer(self) -> None:
175        ba.timer(
176            (1.0 + 0.2 * random.random()) * self._meteor_time,
177            self._drop_bomb_cluster,
178        )
179
180    def _drop_bomb_cluster(self) -> None:
181
182        # Random note: code like this is a handy way to plot out extents
183        # and debug things.
184        loc_test = False
185        if loc_test:
186            ba.newnode('locator', attrs={'position': (8, 6, -5.5)})
187            ba.newnode('locator', attrs={'position': (8, 6, -2.3)})
188            ba.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
189            ba.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
190
191        # Drop several bombs in series.
192        delay = 0.0
193        for _i in range(random.randrange(1, 3)):
194            # Drop them somewhere within our bounds with velocity pointing
195            # toward the opposite side.
196            pos = (
197                -7.3 + 15.3 * random.random(),
198                11,
199                -5.57 + 2.1 * random.random(),
200            )
201            dropdir = -1.0 if pos[0] > 0 else 1.0
202            vel = (
203                (-5.0 + random.random() * 30.0) * dropdir,
204                random.uniform(-3.066, -4.12),
205                0,
206            )
207            ba.timer(delay, ba.Call(self._drop_bomb, pos, vel))
208            delay += 0.1
209        self._set_meteor_timer()
210
211    def _drop_bomb(
212        self, position: Sequence[float], velocity: Sequence[float]
213    ) -> None:
214        Bomb(position=position, velocity=velocity).autoretain()
215
216    def _decrement_meteor_time(self) -> None:
217        self._meteor_time = max(0.01, self._meteor_time * 0.9)
218
219    def end_game(self) -> None:
220        cur_time = ba.time()
221        assert self._timer is not None
222        start_time = self._timer.getstarttime()
223
224        # Mark death-time as now for any still-living players
225        # and award players points for how long they lasted.
226        # (these per-player scores are only meaningful in team-games)
227        for team in self.teams:
228            for player in team.players:
229                survived = False
230
231                # Throw an extra fudge factor in so teams that
232                # didn't die come out ahead of teams that did.
233                if player.death_time is None:
234                    survived = True
235                    player.death_time = cur_time + 1
236
237                # Award a per-player score depending on how many seconds
238                # they lasted (per-player scores only affect teams mode;
239                # everywhere else just looks at the per-team score).
240                score = int(player.death_time - self._timer.getstarttime())
241                if survived:
242                    score += 50  # A bit extra for survivors.
243                self.stats.player_scored(player, score, screenmessage=False)
244
245        # Stop updating our time text, and set the final time to match
246        # exactly when our last guy died.
247        self._timer.stop(endtime=self._last_player_death_time)
248
249        # Ok now calc game results: set a score for each team and then tell
250        # the game to end.
251        results = ba.GameResults()
252
253        # Remember that 'free-for-all' mode is simply a special form
254        # of 'teams' mode where each player gets their own team, so we can
255        # just always deal in teams and have all cases covered.
256        for team in self.teams:
257
258            # Set the team score to the max time survived by any player on
259            # that team.
260            longest_life = 0.0
261            for player in team.players:
262                assert player.death_time is not None
263                longest_life = max(longest_life, player.death_time - start_time)
264
265            # Submit the score value in milliseconds.
266            results.set_team_score(team, int(1000.0 * longest_life))
267
268        self.end(results=results)

Minigame involving dodging falling bombs.

MeteorShowerGame(settings: dict)
66    def __init__(self, settings: dict):
67        super().__init__(settings)
68
69        self._epic_mode = settings.get('Epic Mode', False)
70        self._last_player_death_time: float | None = None
71        self._meteor_time = 2.0
72        self._timer: OnScreenTimer | None = None
73
74        # Some base class overrides:
75        self.default_music = (
76            ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL
77        )
78        if self._epic_mode:
79            self.slow_motion = True

Instantiate the Activity.

announce_player_deaths = True

Whether to print every time a player dies. This can be pertinent in games such as Death-Match but can be annoying in games where it doesn't matter.

allow_mid_activity_joins = False

Whether players should be allowed to join in the middle of this activity. Note that Sessions may not allow mid-activity-joins even if the activity says its ok.

@classmethod
def get_supported_maps(cls, sessiontype: type[ba._session.Session]) -> list[str]:
53    @classmethod
54    def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]:
55        return ['Rampage']

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.

@classmethod
def supports_session_type(cls, sessiontype: type[ba._session.Session]) -> bool:
58    @classmethod
59    def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool:
60        return (
61            issubclass(sessiontype, ba.DualTeamSession)
62            or issubclass(sessiontype, ba.FreeForAllSession)
63            or issubclass(sessiontype, ba.CoopSession)
64        )

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

def on_begin(self) -> None:
 81    def on_begin(self) -> None:
 82        super().on_begin()
 83
 84        # Drop a wave every few seconds.. and every so often drop the time
 85        # between waves ..lets have things increase faster if we have fewer
 86        # players.
 87        delay = 5.0 if len(self.players) > 2 else 2.5
 88        if self._epic_mode:
 89            delay *= 0.25
 90        ba.timer(delay, self._decrement_meteor_time, repeat=True)
 91
 92        # Kick off the first wave in a few seconds.
 93        delay = 3.0
 94        if self._epic_mode:
 95            delay *= 0.25
 96        ba.timer(delay, self._set_meteor_timer)
 97
 98        self._timer = OnScreenTimer()
 99        self._timer.start()
100
101        # Check for immediate end (if we've only got 1 player, etc).
102        ba.timer(5.0, self._check_end_game)

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 on_player_leave(self, player: bastd.game.meteorshower.Player) -> None:
104    def on_player_leave(self, player: Player) -> None:
105        # Augment default behavior.
106        super().on_player_leave(player)
107
108        # A departing player may trigger game-over.
109        self._check_end_game()

Called when a ba.Player is leaving the Activity.

def spawn_player(self, player: bastd.game.meteorshower.Player) -> ba._actor.Actor:
112    def spawn_player(self, player: Player) -> ba.Actor:
113        spaz = self.spawn_player_spaz(player)
114
115        # Let's reconnect this player's controls to this
116        # spaz but *without* the ability to attack or pick stuff up.
117        spaz.connect_controls_to_player(
118            enable_punch=False, enable_bomb=False, enable_pickup=False
119        )
120
121        # Also lets have them make some noise when they die.
122        spaz.play_big_death_sound = True
123        return spaz

Spawn something for the provided ba.Player.

The default implementation simply calls spawn_player_spaz().

def handlemessage(self, msg: Any) -> Any:
126    def handlemessage(self, msg: Any) -> Any:
127        if isinstance(msg, ba.PlayerDiedMessage):
128
129            # Augment standard behavior.
130            super().handlemessage(msg)
131
132            curtime = ba.time()
133
134            # Record the player's moment of death.
135            # assert isinstance(msg.spaz.player
136            msg.getplayer(Player).death_time = curtime
137
138            # In co-op mode, end the game the instant everyone dies
139            # (more accurate looking).
140            # In teams/ffa, allow a one-second fudge-factor so we can
141            # get more draws if players die basically at the same time.
142            if isinstance(self.session, ba.CoopSession):
143                # Teams will still show up if we check now.. check in
144                # the next cycle.
145                ba.pushcall(self._check_end_game)
146
147                # Also record this for a final setting of the clock.
148                self._last_player_death_time = curtime
149            else:
150                ba.timer(1.0, self._check_end_game)
151
152        else:
153            # Default handler:
154            return super().handlemessage(msg)
155        return None

General message handling; can be passed any message object.

def end_game(self) -> None:
219    def end_game(self) -> None:
220        cur_time = ba.time()
221        assert self._timer is not None
222        start_time = self._timer.getstarttime()
223
224        # Mark death-time as now for any still-living players
225        # and award players points for how long they lasted.
226        # (these per-player scores are only meaningful in team-games)
227        for team in self.teams:
228            for player in team.players:
229                survived = False
230
231                # Throw an extra fudge factor in so teams that
232                # didn't die come out ahead of teams that did.
233                if player.death_time is None:
234                    survived = True
235                    player.death_time = cur_time + 1
236
237                # Award a per-player score depending on how many seconds
238                # they lasted (per-player scores only affect teams mode;
239                # everywhere else just looks at the per-team score).
240                score = int(player.death_time - self._timer.getstarttime())
241                if survived:
242                    score += 50  # A bit extra for survivors.
243                self.stats.player_scored(player, score, screenmessage=False)
244
245        # Stop updating our time text, and set the final time to match
246        # exactly when our last guy died.
247        self._timer.stop(endtime=self._last_player_death_time)
248
249        # Ok now calc game results: set a score for each team and then tell
250        # the game to end.
251        results = ba.GameResults()
252
253        # Remember that 'free-for-all' mode is simply a special form
254        # of 'teams' mode where each player gets their own team, so we can
255        # just always deal in teams and have all cases covered.
256        for team in self.teams:
257
258            # Set the team score to the max time survived by any player on
259            # that team.
260            longest_life = 0.0
261            for player in team.players:
262                assert player.death_time is not None
263                longest_life = max(longest_life, player.death_time - start_time)
264
265            # Submit the score value in milliseconds.
266            results.set_team_score(team, int(1000.0 * longest_life))
267
268        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._teamgame.TeamGameActivity
on_transition_in
spawn_player_spaz
end
ba._gameactivity.GameActivity
allow_pausing
allow_kick_idle_players
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
get_instance_description
get_instance_description_short
on_continue
is_waiting_for_continue
continue_or_end_game
on_player_join
respawn_player
spawn_player_if_exists
setup_standard_powerup_drops
setup_standard_time_limit
show_zoom_message
ba._activity.Activity
settings_raw
teams
players
is_joining_activity
use_fixed_vr_overlay
slow_motion
inherits_slow_motion
inherits_music
inherits_vr_camera_offset
inherits_vr_overlay_center
inherits_tint
transition_time
can_show_ad_on_death
globalsnode
stats
on_expire
customdata
expired
playertype
teamtype
retain_actor
add_actor_weak_ref
session
on_team_join
on_team_leave
on_transition_out
has_transitioned_in
has_begun
has_ended
is_transitioning_out
transition_out
create_player
create_team
ba._dependency.DependencyComponent
dep_is_present
get_dynamic_deps