bascenev1lib.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 8
  6# (see https://ballistica.net/wiki/meta-tag-system)
  7
  8from __future__ import annotations
  9
 10import random
 11from typing import TYPE_CHECKING
 12
 13from bascenev1lib.actor.bomb import Bomb
 14from bascenev1lib.actor.onscreentimer import OnScreenTimer
 15import bascenev1 as bs
 16
 17if TYPE_CHECKING:
 18    from typing import Any, Sequence
 19
 20
 21class Player(bs.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(bs.Team[Player]):
 30    """Our team type for this game."""
 31
 32
 33# ba_meta export bascenev1.GameActivity
 34class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
 35    """Minigame involving dodging falling bombs."""
 36
 37    name = 'Meteor Shower'
 38    description = 'Dodge the falling bombs.'
 39    available_settings = [bs.BoolSetting('Epic Mode', default=False)]
 40    scoreconfig = bs.ScoreConfig(
 41        label='Survived', scoretype=bs.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[bs.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[bs.Session]) -> bool:
 59        return (
 60            issubclass(sessiontype, bs.DualTeamSession)
 61            or issubclass(sessiontype, bs.FreeForAllSession)
 62            or issubclass(sessiontype, bs.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            bs.MusicType.EPIC if self._epic_mode else bs.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        bs.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        bs.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        bs.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) -> bs.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, bs.PlayerDiedMessage):
127            # Augment standard behavior.
128            super().handlemessage(msg)
129
130            curtime = bs.time()
131
132            # Record the player's moment of death.
133            # assert isinstance(msg.spaz.player
134            msg.getplayer(Player).death_time = curtime
135
136            # In co-op mode, end the game the instant everyone dies
137            # (more accurate looking).
138            # In teams/ffa, allow a one-second fudge-factor so we can
139            # get more draws if players die basically at the same time.
140            if isinstance(self.session, bs.CoopSession):
141                # Teams will still show up if we check now.. check in
142                # the next cycle.
143                bs.pushcall(self._check_end_game)
144
145                # Also record this for a final setting of the clock.
146                self._last_player_death_time = curtime
147            else:
148                bs.timer(1.0, self._check_end_game)
149
150        else:
151            # Default handler:
152            return super().handlemessage(msg)
153        return None
154
155    def _check_end_game(self) -> None:
156        living_team_count = 0
157        for team in self.teams:
158            for player in team.players:
159                if player.is_alive():
160                    living_team_count += 1
161                    break
162
163        # In co-op, we go till everyone is dead.. otherwise we go
164        # until one team remains.
165        if isinstance(self.session, bs.CoopSession):
166            if living_team_count <= 0:
167                self.end_game()
168        else:
169            if living_team_count <= 1:
170                self.end_game()
171
172    def _set_meteor_timer(self) -> None:
173        bs.timer(
174            (1.0 + 0.2 * random.random()) * self._meteor_time,
175            self._drop_bomb_cluster,
176        )
177
178    def _drop_bomb_cluster(self) -> None:
179        # Random note: code like this is a handy way to plot out extents
180        # and debug things.
181        loc_test = False
182        if loc_test:
183            bs.newnode('locator', attrs={'position': (8, 6, -5.5)})
184            bs.newnode('locator', attrs={'position': (8, 6, -2.3)})
185            bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
186            bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
187
188        # Drop several bombs in series.
189        delay = 0.0
190        for _i in range(random.randrange(1, 3)):
191            # Drop them somewhere within our bounds with velocity pointing
192            # toward the opposite side.
193            pos = (
194                -7.3 + 15.3 * random.random(),
195                11,
196                -5.57 + 2.1 * random.random(),
197            )
198            dropdir = -1.0 if pos[0] > 0 else 1.0
199            vel = (
200                (-5.0 + random.random() * 30.0) * dropdir,
201                random.uniform(-3.066, -4.12),
202                0,
203            )
204            bs.timer(delay, bs.Call(self._drop_bomb, pos, vel))
205            delay += 0.1
206        self._set_meteor_timer()
207
208    def _drop_bomb(
209        self, position: Sequence[float], velocity: Sequence[float]
210    ) -> None:
211        Bomb(position=position, velocity=velocity).autoretain()
212
213    def _decrement_meteor_time(self) -> None:
214        self._meteor_time = max(0.01, self._meteor_time * 0.9)
215
216    def end_game(self) -> None:
217        cur_time = bs.time()
218        assert self._timer is not None
219        start_time = self._timer.getstarttime()
220
221        # Mark death-time as now for any still-living players
222        # and award players points for how long they lasted.
223        # (these per-player scores are only meaningful in team-games)
224        for team in self.teams:
225            for player in team.players:
226                survived = False
227
228                # Throw an extra fudge factor in so teams that
229                # didn't die come out ahead of teams that did.
230                if player.death_time is None:
231                    survived = True
232                    player.death_time = cur_time + 1
233
234                # Award a per-player score depending on how many seconds
235                # they lasted (per-player scores only affect teams mode;
236                # everywhere else just looks at the per-team score).
237                score = int(player.death_time - self._timer.getstarttime())
238                if survived:
239                    score += 50  # A bit extra for survivors.
240                self.stats.player_scored(player, score, screenmessage=False)
241
242        # Stop updating our time text, and set the final time to match
243        # exactly when our last guy died.
244        self._timer.stop(endtime=self._last_player_death_time)
245
246        # Ok now calc game results: set a score for each team and then tell
247        # the game to end.
248        results = bs.GameResults()
249
250        # Remember that 'free-for-all' mode is simply a special form
251        # of 'teams' mode where each player gets their own team, so we can
252        # just always deal in teams and have all cases covered.
253        for team in self.teams:
254            # Set the team score to the max time survived by any player on
255            # that team.
256            longest_life = 0.0
257            for player in team.players:
258                assert player.death_time is not None
259                longest_life = max(longest_life, player.death_time - start_time)
260
261            # Submit the score value in milliseconds.
262            results.set_team_score(team, int(1000.0 * longest_life))
263
264        self.end(results=results)
class Player(bascenev1._player.Player[ForwardRef('Team')]):
22class Player(bs.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.

death_time: float | None
Inherited Members
bascenev1._player.Player
character
actor
color
highlight
on_expire
team
customdata
sessionplayer
node
position
exists
getname
is_alive
get_icon
assigninput
resetinput
class Team(bascenev1._team.Team[bascenev1lib.game.meteorshower.Player]):
30class Team(bs.Team[Player]):
31    """Our team type for this game."""

Our team type for this game.

Inherited Members
bascenev1._team.Team
players
id
name
color
manual_init
customdata
on_expire
sessionteam
class MeteorShowerGame(bascenev1._teamgame.TeamGameActivity[bascenev1lib.game.meteorshower.Player, bascenev1lib.game.meteorshower.Team]):
 35class MeteorShowerGame(bs.TeamGameActivity[Player, Team]):
 36    """Minigame involving dodging falling bombs."""
 37
 38    name = 'Meteor Shower'
 39    description = 'Dodge the falling bombs.'
 40    available_settings = [bs.BoolSetting('Epic Mode', default=False)]
 41    scoreconfig = bs.ScoreConfig(
 42        label='Survived', scoretype=bs.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[bs.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[bs.Session]) -> bool:
 60        return (
 61            issubclass(sessiontype, bs.DualTeamSession)
 62            or issubclass(sessiontype, bs.FreeForAllSession)
 63            or issubclass(sessiontype, bs.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            bs.MusicType.EPIC if self._epic_mode else bs.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        bs.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        bs.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        bs.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) -> bs.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, bs.PlayerDiedMessage):
128            # Augment standard behavior.
129            super().handlemessage(msg)
130
131            curtime = bs.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, bs.CoopSession):
142                # Teams will still show up if we check now.. check in
143                # the next cycle.
144                bs.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                bs.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, bs.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        bs.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        # Random note: code like this is a handy way to plot out extents
181        # and debug things.
182        loc_test = False
183        if loc_test:
184            bs.newnode('locator', attrs={'position': (8, 6, -5.5)})
185            bs.newnode('locator', attrs={'position': (8, 6, -2.3)})
186            bs.newnode('locator', attrs={'position': (-7.3, 6, -5.5)})
187            bs.newnode('locator', attrs={'position': (-7.3, 6, -2.3)})
188
189        # Drop several bombs in series.
190        delay = 0.0
191        for _i in range(random.randrange(1, 3)):
192            # Drop them somewhere within our bounds with velocity pointing
193            # toward the opposite side.
194            pos = (
195                -7.3 + 15.3 * random.random(),
196                11,
197                -5.57 + 2.1 * random.random(),
198            )
199            dropdir = -1.0 if pos[0] > 0 else 1.0
200            vel = (
201                (-5.0 + random.random() * 30.0) * dropdir,
202                random.uniform(-3.066, -4.12),
203                0,
204            )
205            bs.timer(delay, bs.Call(self._drop_bomb, pos, vel))
206            delay += 0.1
207        self._set_meteor_timer()
208
209    def _drop_bomb(
210        self, position: Sequence[float], velocity: Sequence[float]
211    ) -> None:
212        Bomb(position=position, velocity=velocity).autoretain()
213
214    def _decrement_meteor_time(self) -> None:
215        self._meteor_time = max(0.01, self._meteor_time * 0.9)
216
217    def end_game(self) -> None:
218        cur_time = bs.time()
219        assert self._timer is not None
220        start_time = self._timer.getstarttime()
221
222        # Mark death-time as now for any still-living players
223        # and award players points for how long they lasted.
224        # (these per-player scores are only meaningful in team-games)
225        for team in self.teams:
226            for player in team.players:
227                survived = False
228
229                # Throw an extra fudge factor in so teams that
230                # didn't die come out ahead of teams that did.
231                if player.death_time is None:
232                    survived = True
233                    player.death_time = cur_time + 1
234
235                # Award a per-player score depending on how many seconds
236                # they lasted (per-player scores only affect teams mode;
237                # everywhere else just looks at the per-team score).
238                score = int(player.death_time - self._timer.getstarttime())
239                if survived:
240                    score += 50  # A bit extra for survivors.
241                self.stats.player_scored(player, score, screenmessage=False)
242
243        # Stop updating our time text, and set the final time to match
244        # exactly when our last guy died.
245        self._timer.stop(endtime=self._last_player_death_time)
246
247        # Ok now calc game results: set a score for each team and then tell
248        # the game to end.
249        results = bs.GameResults()
250
251        # Remember that 'free-for-all' mode is simply a special form
252        # of 'teams' mode where each player gets their own team, so we can
253        # just always deal in teams and have all cases covered.
254        for team in self.teams:
255            # Set the team score to the max time survived by any player on
256            # that team.
257            longest_life = 0.0
258            for player in team.players:
259                assert player.death_time is not None
260                longest_life = max(longest_life, player.death_time - start_time)
261
262            # Submit the score value in milliseconds.
263            results.set_team_score(team, int(1000.0 * longest_life))
264
265        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            bs.MusicType.EPIC if self._epic_mode else bs.MusicType.SURVIVAL
77        )
78        if self._epic_mode:
79            self.slow_motion = True

Instantiate the Activity.

name = 'Meteor Shower'
description = 'Dodge the falling bombs.'
available_settings = [BoolSetting(name='Epic Mode', default=False)]
scoreconfig = ScoreConfig(label='Survived', scoretype=<ScoreType.MILLISECONDS: 'ms'>, lower_is_better=False, none_is_winner=False, version='B')
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[bascenev1._session.Session]) -> list[str]:
53    @classmethod
54    def get_supported_maps(cls, sessiontype: type[bs.Session]) -> list[str]:
55        return ['Rampage']

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

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

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

default_music = None
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        bs.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        bs.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        bs.timer(5.0, self._check_end_game)

Called once the previous 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: 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 bascenev1.Player is leaving the Activity.

def spawn_player( self, player: Player) -> bascenev1._actor.Actor:
112    def spawn_player(self, player: Player) -> bs.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 bascenev1.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, bs.PlayerDiedMessage):
128            # Augment standard behavior.
129            super().handlemessage(msg)
130
131            curtime = bs.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, bs.CoopSession):
142                # Teams will still show up if we check now.. check in
143                # the next cycle.
144                bs.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                bs.timer(1.0, self._check_end_game)
150
151        else:
152            # Default handler:
153            return super().handlemessage(msg)
154        return None

General message handling; can be passed any message object.

def end_game(self) -> None:
217    def end_game(self) -> None:
218        cur_time = bs.time()
219        assert self._timer is not None
220        start_time = self._timer.getstarttime()
221
222        # Mark death-time as now for any still-living players
223        # and award players points for how long they lasted.
224        # (these per-player scores are only meaningful in team-games)
225        for team in self.teams:
226            for player in team.players:
227                survived = False
228
229                # Throw an extra fudge factor in so teams that
230                # didn't die come out ahead of teams that did.
231                if player.death_time is None:
232                    survived = True
233                    player.death_time = cur_time + 1
234
235                # Award a per-player score depending on how many seconds
236                # they lasted (per-player scores only affect teams mode;
237                # everywhere else just looks at the per-team score).
238                score = int(player.death_time - self._timer.getstarttime())
239                if survived:
240                    score += 50  # A bit extra for survivors.
241                self.stats.player_scored(player, score, screenmessage=False)
242
243        # Stop updating our time text, and set the final time to match
244        # exactly when our last guy died.
245        self._timer.stop(endtime=self._last_player_death_time)
246
247        # Ok now calc game results: set a score for each team and then tell
248        # the game to end.
249        results = bs.GameResults()
250
251        # Remember that 'free-for-all' mode is simply a special form
252        # of 'teams' mode where each player gets their own team, so we can
253        # just always deal in teams and have all cases covered.
254        for team in self.teams:
255            # Set the team score to the max time survived by any player on
256            # that team.
257            longest_life = 0.0
258            for player in team.players:
259                assert player.death_time is not None
260                longest_life = max(longest_life, player.death_time - start_time)
261
262            # Submit the score value in milliseconds.
263            results.set_team_score(team, int(1000.0 * longest_life))
264
265        self.end(results=results)

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

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 (bascenev1.GameActivity.setup_standard_time_limit()) will work with the game.

Inherited Members
bascenev1._teamgame.TeamGameActivity
on_transition_in
spawn_player_spaz
end
bascenev1._gameactivity.GameActivity
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
initialplayerinfos
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
bascenev1._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
paused_text
preloads
lobby
context
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
bascenev1._dependency.DependencyComponent
dep_is_present
get_dynamic_deps