bastd.game.kingofthehill
Defines the King of the Hill game.
1# Released under the MIT License. See LICENSE for details. 2# 3"""Defines the King of the Hill game.""" 4 5# ba_meta require api 7 6# (see https://ballistica.net/wiki/meta-tag-system) 7 8from __future__ import annotations 9 10import weakref 11from enum import Enum 12from typing import TYPE_CHECKING 13 14import ba 15from bastd.actor.flag import Flag 16from bastd.actor.playerspaz import PlayerSpaz 17from bastd.actor.scoreboard import Scoreboard 18from bastd.gameutils import SharedObjects 19 20if TYPE_CHECKING: 21 from typing import Any, Sequence 22 23 24class FlagState(Enum): 25 """States our single flag can be in.""" 26 NEW = 0 27 UNCONTESTED = 1 28 CONTESTED = 2 29 HELD = 3 30 31 32class Player(ba.Player['Team']): 33 """Our player type for this game.""" 34 35 def __init__(self) -> None: 36 self.time_at_flag = 0 37 38 39class Team(ba.Team[Player]): 40 """Our team type for this game.""" 41 42 def __init__(self, time_remaining: int) -> None: 43 self.time_remaining = time_remaining 44 45 46# ba_meta export game 47class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): 48 """Game where a team wins by holding a 'hill' for a set amount of time.""" 49 50 name = 'King of the Hill' 51 description = 'Secure the flag for a set length of time.' 52 available_settings = [ 53 ba.IntSetting( 54 'Hold Time', 55 min_value=10, 56 default=30, 57 increment=10, 58 ), 59 ba.IntChoiceSetting( 60 'Time Limit', 61 choices=[ 62 ('None', 0), 63 ('1 Minute', 60), 64 ('2 Minutes', 120), 65 ('5 Minutes', 300), 66 ('10 Minutes', 600), 67 ('20 Minutes', 1200), 68 ], 69 default=0, 70 ), 71 ba.FloatChoiceSetting( 72 'Respawn Times', 73 choices=[ 74 ('Shorter', 0.25), 75 ('Short', 0.5), 76 ('Normal', 1.0), 77 ('Long', 2.0), 78 ('Longer', 4.0), 79 ], 80 default=1.0, 81 ), 82 ] 83 scoreconfig = ba.ScoreConfig(label='Time Held') 84 85 @classmethod 86 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 87 return issubclass(sessiontype, ba.MultiTeamSession) 88 89 @classmethod 90 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 91 return ba.getmaps('king_of_the_hill') 92 93 def __init__(self, settings: dict): 94 super().__init__(settings) 95 shared = SharedObjects.get() 96 self._scoreboard = Scoreboard() 97 self._swipsound = ba.getsound('swip') 98 self._tick_sound = ba.getsound('tick') 99 self._countdownsounds = { 100 10: ba.getsound('announceTen'), 101 9: ba.getsound('announceNine'), 102 8: ba.getsound('announceEight'), 103 7: ba.getsound('announceSeven'), 104 6: ba.getsound('announceSix'), 105 5: ba.getsound('announceFive'), 106 4: ba.getsound('announceFour'), 107 3: ba.getsound('announceThree'), 108 2: ba.getsound('announceTwo'), 109 1: ba.getsound('announceOne') 110 } 111 self._flag_pos: Sequence[float] | None = None 112 self._flag_state: FlagState | None = None 113 self._flag: Flag | None = None 114 self._flag_light: ba.Node | None = None 115 self._scoring_team: weakref.ref[Team] | None = None 116 self._hold_time = int(settings['Hold Time']) 117 self._time_limit = float(settings['Time Limit']) 118 self._flag_region_material = ba.Material() 119 self._flag_region_material.add_actions( 120 conditions=('they_have_material', shared.player_material), 121 actions=( 122 ('modify_part_collision', 'collide', True), 123 ('modify_part_collision', 'physical', False), 124 ('call', 'at_connect', 125 ba.Call(self._handle_player_flag_region_collide, True)), 126 ('call', 'at_disconnect', 127 ba.Call(self._handle_player_flag_region_collide, False)), 128 )) 129 130 # Base class overrides. 131 self.default_music = ba.MusicType.SCARY 132 133 def get_instance_description(self) -> str | Sequence: 134 return 'Secure the flag for ${ARG1} seconds.', self._hold_time 135 136 def get_instance_description_short(self) -> str | Sequence: 137 return 'secure the flag for ${ARG1} seconds', self._hold_time 138 139 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 140 return Team(time_remaining=self._hold_time) 141 142 def on_begin(self) -> None: 143 super().on_begin() 144 shared = SharedObjects.get() 145 self.setup_standard_time_limit(self._time_limit) 146 self.setup_standard_powerup_drops() 147 self._flag_pos = self.map.get_flag_position(None) 148 ba.timer(1.0, self._tick, repeat=True) 149 self._flag_state = FlagState.NEW 150 Flag.project_stand(self._flag_pos) 151 self._flag = Flag(position=self._flag_pos, 152 touchable=False, 153 color=(1, 1, 1)) 154 self._flag_light = ba.newnode('light', 155 attrs={ 156 'position': self._flag_pos, 157 'intensity': 0.2, 158 'height_attenuated': False, 159 'radius': 0.4, 160 'color': (0.2, 0.2, 0.2) 161 }) 162 # Flag region. 163 flagmats = [self._flag_region_material, shared.region_material] 164 ba.newnode('region', 165 attrs={ 166 'position': self._flag_pos, 167 'scale': (1.8, 1.8, 1.8), 168 'type': 'sphere', 169 'materials': flagmats 170 }) 171 self._update_flag_state() 172 173 def _tick(self) -> None: 174 self._update_flag_state() 175 176 # Give holding players points. 177 for player in self.players: 178 if player.time_at_flag > 0: 179 self.stats.player_scored(player, 180 3, 181 screenmessage=False, 182 display=False) 183 if self._scoring_team is None: 184 scoring_team = None 185 else: 186 scoring_team = self._scoring_team() 187 if scoring_team: 188 189 if scoring_team.time_remaining > 0: 190 ba.playsound(self._tick_sound) 191 192 scoring_team.time_remaining = max(0, 193 scoring_team.time_remaining - 1) 194 self._update_scoreboard() 195 if scoring_team.time_remaining > 0: 196 assert self._flag is not None 197 self._flag.set_score_text(str(scoring_team.time_remaining)) 198 199 # Announce numbers we have sounds for. 200 numsound = self._countdownsounds.get(scoring_team.time_remaining) 201 if numsound is not None: 202 ba.playsound(numsound) 203 204 # winner 205 if scoring_team.time_remaining <= 0: 206 self.end_game() 207 208 def end_game(self) -> None: 209 results = ba.GameResults() 210 for team in self.teams: 211 results.set_team_score(team, self._hold_time - team.time_remaining) 212 self.end(results=results, announce_delay=0) 213 214 def _update_flag_state(self) -> None: 215 holding_teams = set(player.team for player in self.players 216 if player.time_at_flag) 217 prev_state = self._flag_state 218 assert self._flag_light 219 assert self._flag is not None 220 assert self._flag.node 221 if len(holding_teams) > 1: 222 self._flag_state = FlagState.CONTESTED 223 self._scoring_team = None 224 self._flag_light.color = (0.6, 0.6, 0.1) 225 self._flag.node.color = (1.0, 1.0, 0.4) 226 elif len(holding_teams) == 1: 227 holding_team = list(holding_teams)[0] 228 self._flag_state = FlagState.HELD 229 self._scoring_team = weakref.ref(holding_team) 230 self._flag_light.color = ba.normalized_color(holding_team.color) 231 self._flag.node.color = holding_team.color 232 else: 233 self._flag_state = FlagState.UNCONTESTED 234 self._scoring_team = None 235 self._flag_light.color = (0.2, 0.2, 0.2) 236 self._flag.node.color = (1, 1, 1) 237 if self._flag_state != prev_state: 238 ba.playsound(self._swipsound) 239 240 def _handle_player_flag_region_collide(self, colliding: bool) -> None: 241 try: 242 spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) 243 except ba.NotFoundError: 244 return 245 246 if not spaz.is_alive(): 247 return 248 249 player = spaz.getplayer(Player, True) 250 251 # Different parts of us can collide so a single value isn't enough 252 # also don't count it if we're dead (flying heads shouldn't be able to 253 # win the game :-) 254 if colliding and player.is_alive(): 255 player.time_at_flag += 1 256 else: 257 player.time_at_flag = max(0, player.time_at_flag - 1) 258 259 self._update_flag_state() 260 261 def _update_scoreboard(self) -> None: 262 for team in self.teams: 263 self._scoreboard.set_team_value(team, 264 team.time_remaining, 265 self._hold_time, 266 countdown=True) 267 268 def handlemessage(self, msg: Any) -> Any: 269 if isinstance(msg, ba.PlayerDiedMessage): 270 super().handlemessage(msg) # Augment default. 271 272 # No longer can count as time_at_flag once dead. 273 player = msg.getplayer(Player) 274 player.time_at_flag = 0 275 self._update_flag_state() 276 self.respawn_player(player)
25class FlagState(Enum): 26 """States our single flag can be in.""" 27 NEW = 0 28 UNCONTESTED = 1 29 CONTESTED = 2 30 HELD = 3
States our single flag can be in.
Inherited Members
- enum.Enum
- name
- value
33class Player(ba.Player['Team']): 34 """Our player type for this game.""" 35 36 def __init__(self) -> None: 37 self.time_at_flag = 0
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
40class Team(ba.Team[Player]): 41 """Our team type for this game.""" 42 43 def __init__(self, time_remaining: int) -> None: 44 self.time_remaining = time_remaining
Our team type for this game.
Inherited Members
48class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): 49 """Game where a team wins by holding a 'hill' for a set amount of time.""" 50 51 name = 'King of the Hill' 52 description = 'Secure the flag for a set length of time.' 53 available_settings = [ 54 ba.IntSetting( 55 'Hold Time', 56 min_value=10, 57 default=30, 58 increment=10, 59 ), 60 ba.IntChoiceSetting( 61 'Time Limit', 62 choices=[ 63 ('None', 0), 64 ('1 Minute', 60), 65 ('2 Minutes', 120), 66 ('5 Minutes', 300), 67 ('10 Minutes', 600), 68 ('20 Minutes', 1200), 69 ], 70 default=0, 71 ), 72 ba.FloatChoiceSetting( 73 'Respawn Times', 74 choices=[ 75 ('Shorter', 0.25), 76 ('Short', 0.5), 77 ('Normal', 1.0), 78 ('Long', 2.0), 79 ('Longer', 4.0), 80 ], 81 default=1.0, 82 ), 83 ] 84 scoreconfig = ba.ScoreConfig(label='Time Held') 85 86 @classmethod 87 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 88 return issubclass(sessiontype, ba.MultiTeamSession) 89 90 @classmethod 91 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 92 return ba.getmaps('king_of_the_hill') 93 94 def __init__(self, settings: dict): 95 super().__init__(settings) 96 shared = SharedObjects.get() 97 self._scoreboard = Scoreboard() 98 self._swipsound = ba.getsound('swip') 99 self._tick_sound = ba.getsound('tick') 100 self._countdownsounds = { 101 10: ba.getsound('announceTen'), 102 9: ba.getsound('announceNine'), 103 8: ba.getsound('announceEight'), 104 7: ba.getsound('announceSeven'), 105 6: ba.getsound('announceSix'), 106 5: ba.getsound('announceFive'), 107 4: ba.getsound('announceFour'), 108 3: ba.getsound('announceThree'), 109 2: ba.getsound('announceTwo'), 110 1: ba.getsound('announceOne') 111 } 112 self._flag_pos: Sequence[float] | None = None 113 self._flag_state: FlagState | None = None 114 self._flag: Flag | None = None 115 self._flag_light: ba.Node | None = None 116 self._scoring_team: weakref.ref[Team] | None = None 117 self._hold_time = int(settings['Hold Time']) 118 self._time_limit = float(settings['Time Limit']) 119 self._flag_region_material = ba.Material() 120 self._flag_region_material.add_actions( 121 conditions=('they_have_material', shared.player_material), 122 actions=( 123 ('modify_part_collision', 'collide', True), 124 ('modify_part_collision', 'physical', False), 125 ('call', 'at_connect', 126 ba.Call(self._handle_player_flag_region_collide, True)), 127 ('call', 'at_disconnect', 128 ba.Call(self._handle_player_flag_region_collide, False)), 129 )) 130 131 # Base class overrides. 132 self.default_music = ba.MusicType.SCARY 133 134 def get_instance_description(self) -> str | Sequence: 135 return 'Secure the flag for ${ARG1} seconds.', self._hold_time 136 137 def get_instance_description_short(self) -> str | Sequence: 138 return 'secure the flag for ${ARG1} seconds', self._hold_time 139 140 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 141 return Team(time_remaining=self._hold_time) 142 143 def on_begin(self) -> None: 144 super().on_begin() 145 shared = SharedObjects.get() 146 self.setup_standard_time_limit(self._time_limit) 147 self.setup_standard_powerup_drops() 148 self._flag_pos = self.map.get_flag_position(None) 149 ba.timer(1.0, self._tick, repeat=True) 150 self._flag_state = FlagState.NEW 151 Flag.project_stand(self._flag_pos) 152 self._flag = Flag(position=self._flag_pos, 153 touchable=False, 154 color=(1, 1, 1)) 155 self._flag_light = ba.newnode('light', 156 attrs={ 157 'position': self._flag_pos, 158 'intensity': 0.2, 159 'height_attenuated': False, 160 'radius': 0.4, 161 'color': (0.2, 0.2, 0.2) 162 }) 163 # Flag region. 164 flagmats = [self._flag_region_material, shared.region_material] 165 ba.newnode('region', 166 attrs={ 167 'position': self._flag_pos, 168 'scale': (1.8, 1.8, 1.8), 169 'type': 'sphere', 170 'materials': flagmats 171 }) 172 self._update_flag_state() 173 174 def _tick(self) -> None: 175 self._update_flag_state() 176 177 # Give holding players points. 178 for player in self.players: 179 if player.time_at_flag > 0: 180 self.stats.player_scored(player, 181 3, 182 screenmessage=False, 183 display=False) 184 if self._scoring_team is None: 185 scoring_team = None 186 else: 187 scoring_team = self._scoring_team() 188 if scoring_team: 189 190 if scoring_team.time_remaining > 0: 191 ba.playsound(self._tick_sound) 192 193 scoring_team.time_remaining = max(0, 194 scoring_team.time_remaining - 1) 195 self._update_scoreboard() 196 if scoring_team.time_remaining > 0: 197 assert self._flag is not None 198 self._flag.set_score_text(str(scoring_team.time_remaining)) 199 200 # Announce numbers we have sounds for. 201 numsound = self._countdownsounds.get(scoring_team.time_remaining) 202 if numsound is not None: 203 ba.playsound(numsound) 204 205 # winner 206 if scoring_team.time_remaining <= 0: 207 self.end_game() 208 209 def end_game(self) -> None: 210 results = ba.GameResults() 211 for team in self.teams: 212 results.set_team_score(team, self._hold_time - team.time_remaining) 213 self.end(results=results, announce_delay=0) 214 215 def _update_flag_state(self) -> None: 216 holding_teams = set(player.team for player in self.players 217 if player.time_at_flag) 218 prev_state = self._flag_state 219 assert self._flag_light 220 assert self._flag is not None 221 assert self._flag.node 222 if len(holding_teams) > 1: 223 self._flag_state = FlagState.CONTESTED 224 self._scoring_team = None 225 self._flag_light.color = (0.6, 0.6, 0.1) 226 self._flag.node.color = (1.0, 1.0, 0.4) 227 elif len(holding_teams) == 1: 228 holding_team = list(holding_teams)[0] 229 self._flag_state = FlagState.HELD 230 self._scoring_team = weakref.ref(holding_team) 231 self._flag_light.color = ba.normalized_color(holding_team.color) 232 self._flag.node.color = holding_team.color 233 else: 234 self._flag_state = FlagState.UNCONTESTED 235 self._scoring_team = None 236 self._flag_light.color = (0.2, 0.2, 0.2) 237 self._flag.node.color = (1, 1, 1) 238 if self._flag_state != prev_state: 239 ba.playsound(self._swipsound) 240 241 def _handle_player_flag_region_collide(self, colliding: bool) -> None: 242 try: 243 spaz = ba.getcollision().opposingnode.getdelegate(PlayerSpaz, True) 244 except ba.NotFoundError: 245 return 246 247 if not spaz.is_alive(): 248 return 249 250 player = spaz.getplayer(Player, True) 251 252 # Different parts of us can collide so a single value isn't enough 253 # also don't count it if we're dead (flying heads shouldn't be able to 254 # win the game :-) 255 if colliding and player.is_alive(): 256 player.time_at_flag += 1 257 else: 258 player.time_at_flag = max(0, player.time_at_flag - 1) 259 260 self._update_flag_state() 261 262 def _update_scoreboard(self) -> None: 263 for team in self.teams: 264 self._scoreboard.set_team_value(team, 265 team.time_remaining, 266 self._hold_time, 267 countdown=True) 268 269 def handlemessage(self, msg: Any) -> Any: 270 if isinstance(msg, ba.PlayerDiedMessage): 271 super().handlemessage(msg) # Augment default. 272 273 # No longer can count as time_at_flag once dead. 274 player = msg.getplayer(Player) 275 player.time_at_flag = 0 276 self._update_flag_state() 277 self.respawn_player(player)
Game where a team wins by holding a 'hill' for a set amount of time.
94 def __init__(self, settings: dict): 95 super().__init__(settings) 96 shared = SharedObjects.get() 97 self._scoreboard = Scoreboard() 98 self._swipsound = ba.getsound('swip') 99 self._tick_sound = ba.getsound('tick') 100 self._countdownsounds = { 101 10: ba.getsound('announceTen'), 102 9: ba.getsound('announceNine'), 103 8: ba.getsound('announceEight'), 104 7: ba.getsound('announceSeven'), 105 6: ba.getsound('announceSix'), 106 5: ba.getsound('announceFive'), 107 4: ba.getsound('announceFour'), 108 3: ba.getsound('announceThree'), 109 2: ba.getsound('announceTwo'), 110 1: ba.getsound('announceOne') 111 } 112 self._flag_pos: Sequence[float] | None = None 113 self._flag_state: FlagState | None = None 114 self._flag: Flag | None = None 115 self._flag_light: ba.Node | None = None 116 self._scoring_team: weakref.ref[Team] | None = None 117 self._hold_time = int(settings['Hold Time']) 118 self._time_limit = float(settings['Time Limit']) 119 self._flag_region_material = ba.Material() 120 self._flag_region_material.add_actions( 121 conditions=('they_have_material', shared.player_material), 122 actions=( 123 ('modify_part_collision', 'collide', True), 124 ('modify_part_collision', 'physical', False), 125 ('call', 'at_connect', 126 ba.Call(self._handle_player_flag_region_collide, True)), 127 ('call', 'at_disconnect', 128 ba.Call(self._handle_player_flag_region_collide, False)), 129 )) 130 131 # Base class overrides. 132 self.default_music = ba.MusicType.SCARY
Instantiate the Activity.
86 @classmethod 87 def supports_session_type(cls, sessiontype: type[ba.Session]) -> bool: 88 return issubclass(sessiontype, ba.MultiTeamSession)
Class method override; returns True for ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.
90 @classmethod 91 def get_supported_maps(cls, sessiontype: type[ba.Session]) -> list[str]: 92 return ba.getmaps('king_of_the_hill')
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.
134 def get_instance_description(self) -> str | Sequence: 135 return 'Secure 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.
137 def get_instance_description_short(self) -> str | Sequence: 138 return 'secure 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.
140 def create_team(self, sessionteam: ba.SessionTeam) -> Team: 141 return Team(time_remaining=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.
143 def on_begin(self) -> None: 144 super().on_begin() 145 shared = SharedObjects.get() 146 self.setup_standard_time_limit(self._time_limit) 147 self.setup_standard_powerup_drops() 148 self._flag_pos = self.map.get_flag_position(None) 149 ba.timer(1.0, self._tick, repeat=True) 150 self._flag_state = FlagState.NEW 151 Flag.project_stand(self._flag_pos) 152 self._flag = Flag(position=self._flag_pos, 153 touchable=False, 154 color=(1, 1, 1)) 155 self._flag_light = ba.newnode('light', 156 attrs={ 157 'position': self._flag_pos, 158 'intensity': 0.2, 159 'height_attenuated': False, 160 'radius': 0.4, 161 'color': (0.2, 0.2, 0.2) 162 }) 163 # Flag region. 164 flagmats = [self._flag_region_material, shared.region_material] 165 ba.newnode('region', 166 attrs={ 167 'position': self._flag_pos, 168 'scale': (1.8, 1.8, 1.8), 169 'type': 'sphere', 170 'materials': flagmats 171 }) 172 self._update_flag_state()
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.
209 def end_game(self) -> None: 210 results = ba.GameResults() 211 for team in self.teams: 212 results.set_team_score(team, self._hold_time - team.time_remaining) 213 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.
269 def handlemessage(self, msg: Any) -> Any: 270 if isinstance(msg, ba.PlayerDiedMessage): 271 super().handlemessage(msg) # Augment default. 272 273 # No longer can count as time_at_flag once dead. 274 player = msg.getplayer(Player) 275 player.time_at_flag = 0 276 self._update_flag_state() 277 self.respawn_player(player)
General message handling; can be passed any message object.
Inherited Members
- ba._gameactivity.GameActivity
- default_music
- tips
- 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._activity.Activity
- settings_raw
- teams
- players
- announce_player_deaths
- is_joining_activity
- use_fixed_vr_overlay
- 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
- session
- on_player_leave
- on_team_join
- 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