bastd.game.keepaway
Defines a keep-away game type.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines a keep-away game type.""" 4 5# ba_meta require api 7 6# (see https://ballistica.net/wiki/meta-tag-system) 7 8from __future__ import annotations 9 10from enum import Enum 11from typing import TYPE_CHECKING 12 13import ba 14from bastd.actor.playerspaz import PlayerSpaz 15from bastd.actor.scoreboard import Scoreboard 16from bastd.actor.flag import ( 17 Flag, 18 FlagDroppedMessage, 19 FlagDiedMessage, 20 FlagPickedUpMessage, 21) 22 23if TYPE_CHECKING: 24 from typing import Any, Sequence 25 26 27class FlagState(Enum): 28 """States our single flag can be in.""" 29 30 NEW = 0 31 UNCONTESTED = 1 32 CONTESTED = 2 33 HELD = 3 34 35 36class Player(ba.Player['Team']): 37 """Our player type for this game.""" 38 39 40class Team(ba.Team[Player]): 41 """Our team type for this game.""" 42 43 def __init__(self, timeremaining: int) -> None: 44 self.timeremaining = timeremaining 45 self.holdingflag = False 46 47 48# ba_meta export game 49class KeepAwayGame(ba.TeamGameActivity[Player, Team]): 50 """Game where you try to keep the flag away from your enemies.""" 51 52 name = 'Keep Away' 53 description = 'Carry the flag for a set length of time.' 54 available_settings = [ 55 ba.IntSetting( 56 'Hold Time', 57 min_value=10, 58 default=30, 59 increment=10, 60 ), 61 ba.IntChoiceSetting( 62 'Time Limit', 63 choices=[ 64 ('None', 0), 65 ('1 Minute', 60), 66 ('2 Minutes', 120), 67 ('5 Minutes', 300), 68 ('10 Minutes', 600), 69 ('20 Minutes', 1200), 70 ], 71 default=0, 72 ), 73 ba.FloatChoiceSetting( 74 'Respawn Times', 75 choices=[ 76 ('Shorter', 0.25), 77 ('Short', 0.5), 78 ('Normal', 1.0), 79 ('Long', 2.0), 80 ('Longer', 4.0), 81 ], 82 default=1.0, 83 ), 84 ba.BoolSetting('Epic Mode', default=False), 85 ] 86 scoreconfig = ba.ScoreConfig(label='Time Held') 87 88 @classmethod 89 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 90 return issubclass(sessiontype, ba.DualTeamSession) or issubclass( 91 sessiontype, ba.FreeForAllSession 92 ) 93 94 @classmethod 95 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 96 return ba.getmaps('keep_away') 97 98 def __init__(self, settings: dict): 99 super().__init__(settings) 100 self._scoreboard = Scoreboard() 101 self._swipsound = ba.getsound('swip') 102 self._tick_sound = ba.getsound('tick') 103 self._countdownsounds = { 104 10: ba.getsound('announceTen'), 105 9: ba.getsound('announceNine'), 106 8: ba.getsound('announceEight'), 107 7: ba.getsound('announceSeven'), 108 6: ba.getsound('announceSix'), 109 5: ba.getsound('announceFive'), 110 4: ba.getsound('announceFour'), 111 3: ba.getsound('announceThree'), 112 2: ba.getsound('announceTwo'), 113 1: ba.getsound('announceOne'), 114 } 115 self._flag_spawn_pos: Sequence[float] | None = None 116 self._update_timer: ba.Timer | None = None 117 self._holding_players: list[Player] = [] 118 self._flag_state: FlagState | None = None 119 self._flag_light: ba.Node | None = None 120 self._scoring_team: Team | None = None 121 self._flag: Flag | None = None 122 self._hold_time = int(settings['Hold Time']) 123 self._time_limit = float(settings['Time Limit']) 124 self._epic_mode = bool(settings['Epic Mode']) 125 self.slow_motion = self._epic_mode 126 self.default_music = ( 127 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.KEEP_AWAY 128 ) 129 130 def get_instance_description(self) -> str | Sequence: 131 return 'Carry the flag for ${ARG1} seconds.', self._hold_time 132 133 def get_instance_description_short(self) -> str | Sequence: 134 return 'carry the flag for ${ARG1} seconds', self._hold_time 135 136 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 137 return Team(timeremaining=self._hold_time) 138 139 def on_team_join(self, team: Team) -> None: 140 self._update_scoreboard() 141 142 def on_begin(self) -> None: 143 super().on_begin() 144 self.setup_standard_time_limit(self._time_limit) 145 self.setup_standard_powerup_drops() 146 self._flag_spawn_pos = self.map.get_flag_position(None) 147 self._spawn_flag() 148 self._update_timer = ba.Timer(1.0, call=self._tick, repeat=True) 149 self._update_flag_state() 150 Flag.project_stand(self._flag_spawn_pos) 151 152 def _tick(self) -> None: 153 self._update_flag_state() 154 155 # Award points to all living players holding the flag. 156 for player in self._holding_players: 157 if player: 158 assert self.stats 159 self.stats.player_scored( 160 player, 3, screenmessage=False, display=False 161 ) 162 163 scoreteam = self._scoring_team 164 165 if scoreteam is not None: 166 167 if scoreteam.timeremaining > 0: 168 ba.playsound(self._tick_sound) 169 170 scoreteam.timeremaining = max(0, scoreteam.timeremaining - 1) 171 self._update_scoreboard() 172 if scoreteam.timeremaining > 0: 173 assert self._flag is not None 174 self._flag.set_score_text(str(scoreteam.timeremaining)) 175 176 # Announce numbers we have sounds for. 177 if scoreteam.timeremaining in self._countdownsounds: 178 ba.playsound(self._countdownsounds[scoreteam.timeremaining]) 179 180 # Winner. 181 if scoreteam.timeremaining <= 0: 182 self.end_game() 183 184 def end_game(self) -> None: 185 results = ba.GameResults() 186 for team in self.teams: 187 results.set_team_score(team, self._hold_time - team.timeremaining) 188 self.end(results=results, announce_delay=0) 189 190 def _update_flag_state(self) -> None: 191 for team in self.teams: 192 team.holdingflag = False 193 self._holding_players = [] 194 for player in self.players: 195 holdingflag = False 196 try: 197 assert isinstance(player.actor, (PlayerSpaz, type(None))) 198 if ( 199 player.actor 200 and player.actor.node 201 and player.actor.node.hold_node 202 ): 203 holdingflag = ( 204 player.actor.node.hold_node.getnodetype() == 'flag' 205 ) 206 except Exception: 207 ba.print_exception('Error checking hold flag.') 208 if holdingflag: 209 self._holding_players.append(player) 210 player.team.holdingflag = True 211 212 holdingteams = set(t for t in self.teams if t.holdingflag) 213 prevstate = self._flag_state 214 assert self._flag is not None 215 assert self._flag_light 216 assert self._flag.node 217 if len(holdingteams) > 1: 218 self._flag_state = FlagState.CONTESTED 219 self._scoring_team = None 220 self._flag_light.color = (0.6, 0.6, 0.1) 221 self._flag.node.color = (1.0, 1.0, 0.4) 222 elif len(holdingteams) == 1: 223 holdingteam = list(holdingteams)[0] 224 self._flag_state = FlagState.HELD 225 self._scoring_team = holdingteam 226 self._flag_light.color = ba.normalized_color(holdingteam.color) 227 self._flag.node.color = holdingteam.color 228 else: 229 self._flag_state = FlagState.UNCONTESTED 230 self._scoring_team = None 231 self._flag_light.color = (0.2, 0.2, 0.2) 232 self._flag.node.color = (1, 1, 1) 233 234 if self._flag_state != prevstate: 235 ba.playsound(self._swipsound) 236 237 def _spawn_flag(self) -> None: 238 ba.playsound(self._swipsound) 239 self._flash_flag_spawn() 240 assert self._flag_spawn_pos is not None 241 self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos) 242 self._flag_state = FlagState.NEW 243 self._flag_light = ba.newnode( 244 'light', 245 owner=self._flag.node, 246 attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)}, 247 ) 248 assert self._flag.node 249 self._flag.node.connectattr('position', self._flag_light, 'position') 250 self._update_flag_state() 251 252 def _flash_flag_spawn(self) -> None: 253 light = ba.newnode( 254 'light', 255 attrs={ 256 'position': self._flag_spawn_pos, 257 'color': (1, 1, 1), 258 'radius': 0.3, 259 'height_attenuated': False, 260 }, 261 ) 262 ba.animate(light, 'intensity', {0.0: 0, 0.25: 0.5, 0.5: 0}, loop=True) 263 ba.timer(1.0, light.delete) 264 265 def _update_scoreboard(self) -> None: 266 for team in self.teams: 267 self._scoreboard.set_team_value( 268 team, team.timeremaining, self._hold_time, countdown=True 269 ) 270 271 def handlemessage(self, msg: Any) -> Any: 272 if isinstance(msg, ba.PlayerDiedMessage): 273 # Augment standard behavior. 274 super().handlemessage(msg) 275 self.respawn_player(msg.getplayer(Player)) 276 elif isinstance(msg, FlagDiedMessage): 277 self._spawn_flag() 278 elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): 279 self._update_flag_state() 280 else: 281 super().handlemessage(msg)
28class FlagState(Enum): 29 """States our single flag can be in.""" 30 31 NEW = 0 32 UNCONTESTED = 1 33 CONTESTED = 2 34 HELD = 3
States our single flag can be in.
Inherited Members
- enum.Enum
- name
- value
Our player type for this game.
Inherited Members
- ba._player.Player
- actor
- on_expire
- team
- customdata
- sessionplayer
- node
- position
- exists
- getname
- is_alive
- get_icon
- assigninput
- resetinput
41class Team(ba.Team[Player]): 42 """Our team type for this game.""" 43 44 def __init__(self, timeremaining: int) -> None: 45 self.timeremaining = timeremaining 46 self.holdingflag = False
Our team type for this game.
Inherited Members
- ba._team.Team
- manual_init
- customdata
- on_expire
- sessionteam
50class KeepAwayGame(ba.TeamGameActivity[Player, Team]): 51 """Game where you try to keep the flag away from your enemies.""" 52 53 name = 'Keep Away' 54 description = 'Carry the flag for a set length of time.' 55 available_settings = [ 56 ba.IntSetting( 57 'Hold Time', 58 min_value=10, 59 default=30, 60 increment=10, 61 ), 62 ba.IntChoiceSetting( 63 'Time Limit', 64 choices=[ 65 ('None', 0), 66 ('1 Minute', 60), 67 ('2 Minutes', 120), 68 ('5 Minutes', 300), 69 ('10 Minutes', 600), 70 ('20 Minutes', 1200), 71 ], 72 default=0, 73 ), 74 ba.FloatChoiceSetting( 75 'Respawn Times', 76 choices=[ 77 ('Shorter', 0.25), 78 ('Short', 0.5), 79 ('Normal', 1.0), 80 ('Long', 2.0), 81 ('Longer', 4.0), 82 ], 83 default=1.0, 84 ), 85 ba.BoolSetting('Epic Mode', default=False), 86 ] 87 scoreconfig = ba.ScoreConfig(label='Time Held') 88 89 @classmethod 90 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 91 return issubclass(sessiontype, ba.DualTeamSession) or issubclass( 92 sessiontype, ba.FreeForAllSession 93 ) 94 95 @classmethod 96 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 97 return ba.getmaps('keep_away') 98 99 def __init__(self, settings: dict): 100 super().__init__(settings) 101 self._scoreboard = Scoreboard() 102 self._swipsound = ba.getsound('swip') 103 self._tick_sound = ba.getsound('tick') 104 self._countdownsounds = { 105 10: ba.getsound('announceTen'), 106 9: ba.getsound('announceNine'), 107 8: ba.getsound('announceEight'), 108 7: ba.getsound('announceSeven'), 109 6: ba.getsound('announceSix'), 110 5: ba.getsound('announceFive'), 111 4: ba.getsound('announceFour'), 112 3: ba.getsound('announceThree'), 113 2: ba.getsound('announceTwo'), 114 1: ba.getsound('announceOne'), 115 } 116 self._flag_spawn_pos: Sequence[float] | None = None 117 self._update_timer: ba.Timer | None = None 118 self._holding_players: list[Player] = [] 119 self._flag_state: FlagState | None = None 120 self._flag_light: ba.Node | None = None 121 self._scoring_team: Team | None = None 122 self._flag: Flag | None = None 123 self._hold_time = int(settings['Hold Time']) 124 self._time_limit = float(settings['Time Limit']) 125 self._epic_mode = bool(settings['Epic Mode']) 126 self.slow_motion = self._epic_mode 127 self.default_music = ( 128 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.KEEP_AWAY 129 ) 130 131 def get_instance_description(self) -> str | Sequence: 132 return 'Carry the flag for ${ARG1} seconds.', self._hold_time 133 134 def get_instance_description_short(self) -> str | Sequence: 135 return 'carry the flag for ${ARG1} seconds', self._hold_time 136 137 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 138 return Team(timeremaining=self._hold_time) 139 140 def on_team_join(self, team: Team) -> None: 141 self._update_scoreboard() 142 143 def on_begin(self) -> None: 144 super().on_begin() 145 self.setup_standard_time_limit(self._time_limit) 146 self.setup_standard_powerup_drops() 147 self._flag_spawn_pos = self.map.get_flag_position(None) 148 self._spawn_flag() 149 self._update_timer = ba.Timer(1.0, call=self._tick, repeat=True) 150 self._update_flag_state() 151 Flag.project_stand(self._flag_spawn_pos) 152 153 def _tick(self) -> None: 154 self._update_flag_state() 155 156 # Award points to all living players holding the flag. 157 for player in self._holding_players: 158 if player: 159 assert self.stats 160 self.stats.player_scored( 161 player, 3, screenmessage=False, display=False 162 ) 163 164 scoreteam = self._scoring_team 165 166 if scoreteam is not None: 167 168 if scoreteam.timeremaining > 0: 169 ba.playsound(self._tick_sound) 170 171 scoreteam.timeremaining = max(0, scoreteam.timeremaining - 1) 172 self._update_scoreboard() 173 if scoreteam.timeremaining > 0: 174 assert self._flag is not None 175 self._flag.set_score_text(str(scoreteam.timeremaining)) 176 177 # Announce numbers we have sounds for. 178 if scoreteam.timeremaining in self._countdownsounds: 179 ba.playsound(self._countdownsounds[scoreteam.timeremaining]) 180 181 # Winner. 182 if scoreteam.timeremaining <= 0: 183 self.end_game() 184 185 def end_game(self) -> None: 186 results = ba.GameResults() 187 for team in self.teams: 188 results.set_team_score(team, self._hold_time - team.timeremaining) 189 self.end(results=results, announce_delay=0) 190 191 def _update_flag_state(self) -> None: 192 for team in self.teams: 193 team.holdingflag = False 194 self._holding_players = [] 195 for player in self.players: 196 holdingflag = False 197 try: 198 assert isinstance(player.actor, (PlayerSpaz, type(None))) 199 if ( 200 player.actor 201 and player.actor.node 202 and player.actor.node.hold_node 203 ): 204 holdingflag = ( 205 player.actor.node.hold_node.getnodetype() == 'flag' 206 ) 207 except Exception: 208 ba.print_exception('Error checking hold flag.') 209 if holdingflag: 210 self._holding_players.append(player) 211 player.team.holdingflag = True 212 213 holdingteams = set(t for t in self.teams if t.holdingflag) 214 prevstate = self._flag_state 215 assert self._flag is not None 216 assert self._flag_light 217 assert self._flag.node 218 if len(holdingteams) > 1: 219 self._flag_state = FlagState.CONTESTED 220 self._scoring_team = None 221 self._flag_light.color = (0.6, 0.6, 0.1) 222 self._flag.node.color = (1.0, 1.0, 0.4) 223 elif len(holdingteams) == 1: 224 holdingteam = list(holdingteams)[0] 225 self._flag_state = FlagState.HELD 226 self._scoring_team = holdingteam 227 self._flag_light.color = ba.normalized_color(holdingteam.color) 228 self._flag.node.color = holdingteam.color 229 else: 230 self._flag_state = FlagState.UNCONTESTED 231 self._scoring_team = None 232 self._flag_light.color = (0.2, 0.2, 0.2) 233 self._flag.node.color = (1, 1, 1) 234 235 if self._flag_state != prevstate: 236 ba.playsound(self._swipsound) 237 238 def _spawn_flag(self) -> None: 239 ba.playsound(self._swipsound) 240 self._flash_flag_spawn() 241 assert self._flag_spawn_pos is not None 242 self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos) 243 self._flag_state = FlagState.NEW 244 self._flag_light = ba.newnode( 245 'light', 246 owner=self._flag.node, 247 attrs={'intensity': 0.2, 'radius': 0.3, 'color': (0.2, 0.2, 0.2)}, 248 ) 249 assert self._flag.node 250 self._flag.node.connectattr('position', self._flag_light, 'position') 251 self._update_flag_state() 252 253 def _flash_flag_spawn(self) -> None: 254 light = ba.newnode( 255 'light', 256 attrs={ 257 'position': self._flag_spawn_pos, 258 'color': (1, 1, 1), 259 'radius': 0.3, 260 'height_attenuated': False, 261 }, 262 ) 263 ba.animate(light, 'intensity', {0.0: 0, 0.25: 0.5, 0.5: 0}, loop=True) 264 ba.timer(1.0, light.delete) 265 266 def _update_scoreboard(self) -> None: 267 for team in self.teams: 268 self._scoreboard.set_team_value( 269 team, team.timeremaining, self._hold_time, countdown=True 270 ) 271 272 def handlemessage(self, msg: Any) -> Any: 273 if isinstance(msg, ba.PlayerDiedMessage): 274 # Augment standard behavior. 275 super().handlemessage(msg) 276 self.respawn_player(msg.getplayer(Player)) 277 elif isinstance(msg, FlagDiedMessage): 278 self._spawn_flag() 279 elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): 280 self._update_flag_state() 281 else: 282 super().handlemessage(msg)
Game where you try to keep the flag away from your enemies.
99 def __init__(self, settings: dict): 100 super().__init__(settings) 101 self._scoreboard = Scoreboard() 102 self._swipsound = ba.getsound('swip') 103 self._tick_sound = ba.getsound('tick') 104 self._countdownsounds = { 105 10: ba.getsound('announceTen'), 106 9: ba.getsound('announceNine'), 107 8: ba.getsound('announceEight'), 108 7: ba.getsound('announceSeven'), 109 6: ba.getsound('announceSix'), 110 5: ba.getsound('announceFive'), 111 4: ba.getsound('announceFour'), 112 3: ba.getsound('announceThree'), 113 2: ba.getsound('announceTwo'), 114 1: ba.getsound('announceOne'), 115 } 116 self._flag_spawn_pos: Sequence[float] | None = None 117 self._update_timer: ba.Timer | None = None 118 self._holding_players: list[Player] = [] 119 self._flag_state: FlagState | None = None 120 self._flag_light: ba.Node | None = None 121 self._scoring_team: Team | None = None 122 self._flag: Flag | None = None 123 self._hold_time = int(settings['Hold Time']) 124 self._time_limit = float(settings['Time Limit']) 125 self._epic_mode = bool(settings['Epic Mode']) 126 self.slow_motion = self._epic_mode 127 self.default_music = ( 128 ba.MusicType.EPIC if self._epic_mode else ba.MusicType.KEEP_AWAY 129 )
Instantiate the Activity.
89 @classmethod 90 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 91 return issubclass(sessiontype, ba.DualTeamSession) or issubclass( 92 sessiontype, ba.FreeForAllSession 93 )
Class method override; returns True for ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.
95 @classmethod 96 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 97 return ba.getmaps('keep_away')
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.
131 def get_instance_description(self) -> str | Sequence: 132 return 'Carry the flag for ${ARG1} seconds.', self._hold_time
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.
134 def get_instance_description_short(self) -> str | Sequence: 135 return 'carry the flag for ${ARG1} seconds', self._hold_time
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.
137 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 138 return Team(timeremaining=self._hold_time)
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.
Called when a new ba.Team joins the Activity.
(including the initial set of Teams)
143 def on_begin(self) -> None: 144 super().on_begin() 145 self.setup_standard_time_limit(self._time_limit) 146 self.setup_standard_powerup_drops() 147 self._flag_spawn_pos = self.map.get_flag_position(None) 148 self._spawn_flag() 149 self._update_timer = ba.Timer(1.0, call=self._tick, repeat=True) 150 self._update_flag_state() 151 Flag.project_stand(self._flag_spawn_pos)
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.
185 def end_game(self) -> None: 186 results = ba.GameResults() 187 for team in self.teams: 188 results.set_team_score(team, self._hold_time - team.timeremaining) 189 self.end(results=results, announce_delay=0)
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.
272 def handlemessage(self, msg: Any) -> Any: 273 if isinstance(msg, ba.PlayerDiedMessage): 274 # Augment standard behavior. 275 super().handlemessage(msg) 276 self.respawn_player(msg.getplayer(Player)) 277 elif isinstance(msg, FlagDiedMessage): 278 self._spawn_flag() 279 elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): 280 self._update_flag_state() 281 else: 282 super().handlemessage(msg)
General message handling; can be passed any message object.
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
- 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._activity.Activity
- 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._dependency.DependencyComponent
- dep_is_present
- get_dynamic_deps