More general type cleanup

This commit is contained in:
Eric Froemling 2020-06-03 01:24:12 -07:00
parent 9c81450c92
commit 9a48d6581a
18 changed files with 187 additions and 262 deletions

View File

@ -4132,16 +4132,16 @@
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/a5/bc48ad0c1b5757913b8d354e4302", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/7f/785a205dbe19ee4099f427dd9ca2",
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e0/cd115dbd1ce795e9b6a2878e8912", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/10/7ab16ca078a401bbbe2310660b85",
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/78/d3166e9e3f2f443c13838768b4ee", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/f5/be729c0261c6326c3ef92330b764",
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/79/af/4d26abbac53e9fc396d1fc5660ae", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/9d/98bc183187af679fbc6531e3ac04",
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/85/8d8d8d74685d0823bc341942c31c", "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/07/aed82d9bc9c5b4dd3457fcea9a8a",
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/81/06f6dff6c5686d1b2ffb1b44bb46", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/5e/a837ebb98b829cd3bebf081e02b0",
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/34/96/f1d361405a41d118016a576ef517", "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/a0/3204f264abfd13f40f7f4f72aa65",
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/7e/116fdd2bb269fd3c4c3826f526b9", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/ab/de21be17db5b93a7191c353dbce8",
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/75/a6/320d0a4b79a1e0c0cb8fecbc69e2", "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/54/5a/e32b46e614ed37c7ebe42c73b03c",
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/de/f35f0be58d20cc58cf1ba078013a", "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/09/2245bdaf317da30c7d63d8559c82",
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2b/23/849c8e6286a8de4f6140f249c59a", "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f6/45/6972dd74de4fc822a28e995a4a0d",
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ba/fd/49fe8a41b0448e2fd81a462618cb" "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/74/e8ff832e808ceaa07a4015fb2a5f"
} }

View File

@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
""" """
# (hash we can use to see if this file is out of date) # (hash we can use to see if this file is out of date)
# SOURCES_HASH=289441941088504861465847265420796017643 # SOURCES_HASH=102801821147286215106809880997032542189
# I'm sorry Pylint. I know this file saddens you. Be strong. # I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression # pylint: disable=useless-suppression

View File

@ -73,7 +73,7 @@ from ba._appconfig import AppConfig
from ba._appdelegate import AppDelegate from ba._appdelegate import AppDelegate
from ba._apputils import is_browser_likely_available from ba._apputils import is_browser_likely_available
from ba._campaign import Campaign from ba._campaign import Campaign
from ba._gameutils import (animate, animate_array, show_damage_count, from ba._gameutils import (GameTip, animate, animate_array, show_damage_count,
timestring, cameraflash) timestring, cameraflash)
from ba._general import (WeakCall, Call, existing, Existable, from ba._general import (WeakCall, Call, existing, Existable,
verify_object_death, storagename) verify_object_death, storagename)

View File

@ -169,12 +169,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
# FIXME: Relocate or remove the need for this stuff. # FIXME: Relocate or remove the need for this stuff.
self.paused_text: Optional[ba.Actor] = None self.paused_text: Optional[ba.Actor] = None
self.spaz_respawn_icons_right: Dict[int, RespawnIcon]
session = _ba.getsession() self._session = weakref.ref(_ba.getsession())
if session is None:
raise RuntimeError('No current session')
self._session = weakref.ref(session)
# Preloaded data for actors, maps, etc; indexed by type. # Preloaded data for actors, maps, etc; indexed by type.
self.preloads: Dict[Type, Any] = {} self.preloads: Dict[Type, Any] = {}
@ -193,12 +189,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self._delay_delete_teams: List[TeamType] = [] self._delay_delete_teams: List[TeamType] = []
self._players_that_left: List[ReferenceType[PlayerType]] = [] self._players_that_left: List[ReferenceType[PlayerType]] = []
self._teams_that_left: List[ReferenceType[TeamType]] = [] self._teams_that_left: List[ReferenceType[TeamType]] = []
# This gets set once another activity has begun transitioning in but
# before this one is killed. The on_transition_out() method is also
# called at this time. Make sure to not assign player inputs,
# change music, or anything else with global implications once this
# happens.
self._transitioning_out = False self._transitioning_out = False
# A handy place to put most actors; this list is pruned of dead # A handy place to put most actors; this list is pruned of dead
@ -209,7 +199,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self._last_prune_dead_actors_time = _ba.time() self._last_prune_dead_actors_time = _ba.time()
self._prune_dead_actors_timer: Optional[ba.Timer] = None self._prune_dead_actors_timer: Optional[ba.Timer] = None
# This stuff gets filled in just before on_begin() is called.
self.teams = [] self.teams = []
self.players = [] self.players = []

View File

@ -36,14 +36,14 @@ class AppDelegate:
def create_default_game_settings_ui( def create_default_game_settings_ui(
self, gameclass: Type[ba.GameActivity], self, gameclass: Type[ba.GameActivity],
sessionclass: Type[ba.Session], config: Optional[dict], sessiontype: Type[ba.Session], settings: Optional[dict],
completion_call: Callable[[Optional[dict]], None]) -> None: completion_call: Callable[[Optional[dict]], None]) -> None:
"""Launch a UI to configure the given game config. """Launch a UI to configure the given game config.
It should manipulate the contents of config and call completion_call It should manipulate the contents of config and call completion_call
when done. when done.
""" """
del gameclass, sessionclass, config, completion_call # unused del gameclass, sessiontype, settings, completion_call # Unused.
from ba import _error from ba import _error
_error.print_error( _error.print_error(
"create_default_game_settings_ui needs to be overridden") "create_default_game_settings_ui needs to be overridden")

View File

@ -312,7 +312,7 @@ class CoopSession(Session):
# Skip players that are still choosing a team. # Skip players that are still choosing a team.
if player.in_game: if player.in_game:
self.stats.register_player(player) self.stats.register_sessionplayer(player)
self.stats.setactivity(next_game) self.stats.setactivity(next_game)
# Now flip the current activity. # Now flip the current activity.

View File

@ -54,7 +54,8 @@ class GameActivity(Activity[PlayerType, TeamType]):
""" """
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
tips: List[Union[str, Dict[str, Any]]] = [] # Tips to be presented to the user at the start of the game.
tips: List[Union[str, ba.GameTip]] = []
# Default getname() will return this if not None. # Default getname() will return this if not None.
name: Optional[str] = None name: Optional[str] = None
@ -82,16 +83,16 @@ class GameActivity(Activity[PlayerType, TeamType]):
@classmethod @classmethod
def create_settings_ui( def create_settings_ui(
cls, cls,
sessionclass: Type[ba.Session], sessiontype: Type[ba.Session],
settings: Optional[dict], settings: Optional[dict],
completion_call: Callable[[Optional[dict]], None], completion_call: Callable[[Optional[dict]], None],
) -> None: ) -> None:
"""Launch an in-game UI to configure settings for a game type. """Launch an in-game UI to configure settings for a game type.
'sessionclass' should be the ba.Session class the game will be used in. 'sessiontype' should be the ba.Session class the game will be used in.
'config' should be an existing config dict (specifies 'edit' ui mode) 'settings' should be an existing settings dict (implies 'edit'
or None (specifies 'add' ui mode). ui mode) or None (implies 'add' ui mode).
'completion_call' will be called with a filled-out settings dict on 'completion_call' will be called with a filled-out settings dict on
success or None on cancel. success or None on cancel.
@ -103,14 +104,14 @@ class GameActivity(Activity[PlayerType, TeamType]):
""" """
delegate = _ba.app.delegate delegate = _ba.app.delegate
assert delegate is not None assert delegate is not None
delegate.create_default_game_settings_ui(cls, sessionclass, settings, delegate.create_default_game_settings_ui(cls, sessiontype, settings,
completion_call) completion_call)
@classmethod @classmethod
def getscoreconfig(cls) -> ba.ScoreConfig: def getscoreconfig(cls) -> ba.ScoreConfig:
"""Return info about game scoring setup; can be overridden by games.""" """Return info about game scoring setup; can be overridden by games."""
return cls.scoreconfig if cls.scoreconfig is not None else ScoreConfig( return (cls.scoreconfig
) if cls.scoreconfig is not None else ScoreConfig())
@classmethod @classmethod
def getname(cls) -> str: def getname(cls) -> str:
@ -170,62 +171,8 @@ class GameActivity(Activity[PlayerType, TeamType]):
@classmethod @classmethod
def get_available_settings( def get_available_settings(
cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]:
""" """Return a list of settings relevant to this game type when
Called by the default ba.GameActivity.create_settings_ui() running under the provided session type.
implementation; should return a dict of config options to be presented
to the user for the given ba.Session type.
The format for settings is a list of 2-member tuples consisting
of a name and a dict of options.
Available Setting Options:
'default': This determines the default value as well as the
type (int, float, or bool)
'min_value': Minimum value for int/float settings.
'max_value': Maximum value for int/float settings.
'choices': A list of name/value pairs the user can choose from by name.
'increment': Value increment for int/float settings.
# example get_available_settings() for a capture-the-flag game:
@classmethod
def get_available_settings(cls, sessiontype):
return [("Score to Win", {
'default': 3,
'min_value': 1
}),
("Flag Touch Return Time", {
'default': 0,
'min_value': 0,
'increment': 1
}),
("Flag Idle Return Time", {
'default': 30,
'min_value': 5,
'increment': 5
}),
("Time Limit", {
'default': 0,
'choices': [
('None', 0), ('1 Minute', 60), ('2 Minutes', 120),
('5 Minutes', 300), ('10 Minutes', 600),
('20 Minutes', 1200)
]
}),
("Respawn Times", {
'default': 1.0,
'choices': [
('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0),
('Long', 2.0), ('Longer', 4.0)
]
}),
("Epic Mode", {
'default': False
})]
""" """
del sessiontype # Unused arg. del sessiontype # Unused arg.
return [] if cls.available_settings is None else cls.available_settings return [] if cls.available_settings is None else cls.available_settings
@ -403,7 +350,6 @@ class GameActivity(Activity[PlayerType, TeamType]):
return '' return ''
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
# Make our map. # Make our map.
@ -575,8 +521,9 @@ class GameActivity(Activity[PlayerType, TeamType]):
victim_player=player, victim_player=player,
importance=importance, importance=importance,
showpoints=self.show_kill_points) showpoints=self.show_kill_points)
return None else:
return super().handlemessage(msg) return super().handlemessage(msg)
return None
def _show_scoreboard_info(self) -> None: def _show_scoreboard_info(self) -> None:
"""Create the game info display. """Create the game info display.
@ -599,7 +546,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
else: else:
sb_desc_l = sb_desc_in sb_desc_l = sb_desc_in
if not isinstance(sb_desc_l[0], str): if not isinstance(sb_desc_l[0], str):
raise TypeError('Invalid format for instance description') raise TypeError('Invalid format for instance description.')
is_empty = (sb_desc_l[0] == '') is_empty = (sb_desc_l[0] == '')
subs = [] subs = []
@ -608,9 +555,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
translation = Lstr(translate=('gameDescriptions', sb_desc_l[0]), translation = Lstr(translate=('gameDescriptions', sb_desc_l[0]),
subs=subs) subs=subs)
sb_desc = translation sb_desc = translation
vrmode = _ba.app.vr_mode vrmode = _ba.app.vr_mode
yval = -34 if is_empty else -20 yval = -34 if is_empty else -20
yval -= 16 yval -= 16
sbpos = ((15, yval) if isinstance(self.session, FreeForAllSession) else sbpos = ((15, yval) if isinstance(self.session, FreeForAllSession) else
@ -727,7 +672,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
def _show_tip(self) -> None: def _show_tip(self) -> None:
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
from ba._gameutils import animate from ba._gameutils import animate, GameTip
from ba._enums import SpecialChar from ba._enums import SpecialChar
# If there's any tips left on the list, display one. # If there's any tips left on the list, display one.
@ -735,14 +680,12 @@ class GameActivity(Activity[PlayerType, TeamType]):
tip = self.tips.pop(random.randrange(len(self.tips))) tip = self.tips.pop(random.randrange(len(self.tips)))
tip_title = Lstr(value='${A}:', tip_title = Lstr(value='${A}:',
subs=[('${A}', Lstr(resource='tipText'))]) subs=[('${A}', Lstr(resource='tipText'))])
icon = None icon: Optional[ba.Texture] = None
sound = None sound: Optional[ba.Sound] = None
if isinstance(tip, dict): if isinstance(tip, GameTip):
if 'icon' in tip: icon = tip.icon
icon = tip['icon'] sound = tip.sound
if 'sound' in tip: tip = tip.text
sound = tip['sound']
tip = tip['tip']
assert isinstance(tip, str) assert isinstance(tip, str)
# Do a few substitutions. # Do a few substitutions.
@ -844,12 +787,11 @@ class GameActivity(Activity[PlayerType, TeamType]):
super().end(results, delay, force) super().end(results, delay, force)
def end_game(self) -> None: def end_game(self) -> None:
""" """Tell the game to wrap up and call ba.Activity.end() immediately.
Tells the game to wrap itself 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 This method should be overridden by subclasses. A game should always
there is no 'winner' yet; this way things like the standard time-limit 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. (ba.GameActivity.setup_standard_time_limit()) will work with the game.
""" """
print('WARNING: default end_game() implementation called;' print('WARNING: default end_game() implementation called;'

View File

@ -84,8 +84,7 @@ class GameResults:
sessionteam = team.sessionteam sessionteam = team.sessionteam
self._scores[sessionteam.id] = (weakref.ref(sessionteam), score) self._scores[sessionteam.id] = (weakref.ref(sessionteam), score)
def get_team_score(self, def get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]:
sessionteam: Union[ba.SessionTeam]) -> Optional[int]:
"""Return the score for a given ba.SessionTeam.""" """Return the score for a given ba.SessionTeam."""
for score in list(self._scores.values()): for score in list(self._scores.values()):
if score[0]() is sessionteam: if score[0]() is sessionteam:
@ -111,7 +110,7 @@ class GameResults:
"""Return whether there is a score for a given team.""" """Return whether there is a score for a given team."""
return any(s[0]() is sessionteam for s in self._scores.values()) return any(s[0]() is sessionteam for s in self._scores.values())
def get_team_score_str(self, team: ba.Team) -> ba.Lstr: def get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr:
"""Return the score for the given ba.Team as an Lstr. """Return the score for the given ba.Team as an Lstr.
(properly formatted for the score type.) (properly formatted for the score type.)
@ -123,7 +122,7 @@ class GameResults:
if not self._game_set: if not self._game_set:
raise RuntimeError("Can't get team-score-str until game is set.") raise RuntimeError("Can't get team-score-str until game is set.")
for score in list(self._scores.values()): for score in list(self._scores.values()):
if score[0]() is team.sessionteam: if score[0]() is sessionteam:
if score[1] is None: if score[1] is None:
return Lstr(value='-') return Lstr(value='-')
if self._scoretype is ScoreType.SECONDS: if self._scoretype is ScoreType.SECONDS:

View File

@ -22,6 +22,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import _ba import _ba
@ -42,6 +43,17 @@ TROPHY_CHARS = {
} }
@dataclass
class GameTip:
"""Defines a tip presentable to the user at the start of a game.
Category: Gameplay Classes
"""
text: str
icon: Optional[ba.Texture] = None
sound: Optional[ba.Sound] = None
def get_trophy_string(trophy_id: str) -> str: def get_trophy_string(trophy_id: str) -> str:
"""Given a trophy id, returns a string to visualize it.""" """Given a trophy id, returns a string to visualize it."""
if trophy_id in TROPHY_CHARS: if trophy_id in TROPHY_CHARS:

View File

@ -123,7 +123,7 @@ def json_prep(data: Any) -> Any:
def utf8_all(data: Any) -> Any: def utf8_all(data: Any) -> Any:
"""Convert any unicode data in provided sequence(s)to utf8 bytes.""" """Convert any unicode data in provided sequence(s) to utf8 bytes."""
if isinstance(data, dict): if isinstance(data, dict):
return dict((utf8_all(key), utf8_all(value)) return dict((utf8_all(key), utf8_all(value))
for key, value in list(data.items())) for key, value in list(data.items()))

View File

@ -224,7 +224,7 @@ class MultiTeamSession(Session):
except NotFoundError: except NotFoundError:
has_team = False has_team = False
if has_team: if has_team:
self.stats.register_player(player) self.stats.register_sessionplayer(player)
self.stats.setactivity(next_game) self.stats.setactivity(next_game)
# Now flip the current activity. # Now flip the current activity.

View File

@ -26,7 +26,8 @@ from dataclasses import dataclass
from typing import TYPE_CHECKING, TypeVar, Generic, cast from typing import TYPE_CHECKING, TypeVar, Generic, cast
import _ba import _ba
from ba._error import SessionPlayerNotFoundError, print_exception from ba._error import (SessionPlayerNotFoundError, print_exception,
ActorNotFoundError)
from ba._messages import DeathType, DieMessage from ba._messages import DeathType, DieMessage
if TYPE_CHECKING: if TYPE_CHECKING:
@ -219,11 +220,12 @@ class Player(Generic[TeamType]):
def position(self) -> ba.Vec3: def position(self) -> ba.Vec3:
"""The position of the player, as defined by its current ba.Actor. """The position of the player, as defined by its current ba.Actor.
This value is undefined when the player has no Actor. If the player currently has no actor, raises a ba.ActorNotFoundError.
""" """
assert self._postinited assert self._postinited
assert not self._expired assert not self._expired
assert self.actor is not None if self.actor is None:
raise ActorNotFoundError
return _ba.Vec3(self.node.position) return _ba.Vec3(self.node.position)
def exists(self) -> bool: def exists(self) -> bool:

View File

@ -84,6 +84,10 @@ class Session:
Whether players should be allowed to join in the middle of Whether players should be allowed to join in the middle of
activities. activities.
customdata
A shared dictionary for objects to use as storage on this session.
Ensure that keys here are unique to avoid collisions.
""" """
use_teams: bool = False use_teams: bool = False
use_team_colors: bool = True use_team_colors: bool = True
@ -95,6 +99,7 @@ class Session:
max_players: int max_players: int
min_players: int min_players: int
players: List[ba.SessionPlayer] players: List[ba.SessionPlayer]
customdata: dict
teams: List[ba.SessionTeam] teams: List[ba.SessionTeam]
def __init__(self, def __init__(self,
@ -166,6 +171,7 @@ class Session:
self.min_players = min_players self.min_players = min_players
self.max_players = max_players self.max_players = max_players
self.customdata = {}
self._in_set_activity = False self._in_set_activity = False
self._next_team_id = 0 self._next_team_id = 0
self._activity_retained: Optional[ba.Activity] = None self._activity_retained: Optional[ba.Activity] = None
@ -695,7 +701,7 @@ class Session:
color=chooser.get_color(), color=chooser.get_color(),
highlight=chooser.get_highlight()) highlight=chooser.get_highlight())
self.stats.register_player(sessionplayer) self.stats.register_sessionplayer(sessionplayer)
if pass_to_activity: if pass_to_activity:
activity.add_player(sessionplayer) activity.add_player(sessionplayer)
return sessionplayer return sessionplayer

View File

@ -28,7 +28,7 @@ from dataclasses import dataclass
import _ba import _ba
from ba._error import (print_exception, print_error, SessionTeamNotFoundError, from ba._error import (print_exception, print_error, SessionTeamNotFoundError,
SessionPlayerNotFoundError) SessionPlayerNotFoundError, NotFoundError)
if TYPE_CHECKING: if TYPE_CHECKING:
import ba import ba
@ -61,8 +61,8 @@ class PlayerRecord:
""" """
character: str character: str
def __init__(self, name: str, name_full: str, player: ba.SessionPlayer, def __init__(self, name: str, name_full: str,
stats: ba.Stats): sessionplayer: ba.SessionPlayer, stats: ba.Stats):
self.name = name self.name = name
self.name_full = name_full self.name_full = name_full
self.score = 0 self.score = 0
@ -75,10 +75,10 @@ class PlayerRecord:
self._multi_kill_count = 0 self._multi_kill_count = 0
self._stats = weakref.ref(stats) self._stats = weakref.ref(stats)
self._last_sessionplayer: Optional[ba.SessionPlayer] = None self._last_sessionplayer: Optional[ba.SessionPlayer] = None
self._player: Optional[ba.SessionPlayer] = None self._sessionplayer: Optional[ba.SessionPlayer] = None
self._team: Optional[ReferenceType[ba.SessionTeam]] = None self._sessionteam: Optional[ReferenceType[ba.SessionTeam]] = None
self.streak = 0 self.streak = 0
self.associate_with_player(player) self.associate_with_sessionplayer(sessionplayer)
@property @property
def team(self) -> ba.SessionTeam: def team(self) -> ba.SessionTeam:
@ -87,8 +87,8 @@ class PlayerRecord:
This can still return a valid result even if the player is gone. This can still return a valid result even if the player is gone.
Raises a ba.SessionTeamNotFoundError if the team no longer exists. Raises a ba.SessionTeamNotFoundError if the team no longer exists.
""" """
assert self._team is not None assert self._sessionteam is not None
team = self._team() team = self._sessionteam()
if team is None: if team is None:
raise SessionTeamNotFoundError() raise SessionTeamNotFoundError()
return team return team
@ -100,9 +100,9 @@ class PlayerRecord:
Raises a ba.SessionPlayerNotFoundError if the player Raises a ba.SessionPlayerNotFoundError if the player
no longer exists. no longer exists.
""" """
if not self._player: if not self._sessionplayer:
raise SessionPlayerNotFoundError() raise SessionPlayerNotFoundError()
return self._player return self._sessionplayer
def getname(self, full: bool = False) -> str: def getname(self, full: bool = False) -> str:
"""Return the player entry's name.""" """Return the player entry's name."""
@ -127,19 +127,20 @@ class PlayerRecord:
return stats.getactivity() return stats.getactivity()
return None return None
def associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None: def associate_with_sessionplayer(self,
sessionplayer: ba.SessionPlayer) -> None:
"""Associate this entry with a ba.SessionPlayer.""" """Associate this entry with a ba.SessionPlayer."""
self._team = weakref.ref(sessionplayer.sessionteam) self._sessionteam = weakref.ref(sessionplayer.sessionteam)
self.character = sessionplayer.character self.character = sessionplayer.character
self._last_sessionplayer = sessionplayer self._last_sessionplayer = sessionplayer
self._player = sessionplayer self._sessionplayer = sessionplayer
self.streak = 0 self.streak = 0
def _end_multi_kill(self) -> None: def _end_multi_kill(self) -> None:
self._multi_kill_timer = None self._multi_kill_timer = None
self._multi_kill_count = 0 self._multi_kill_count = 0
def get_last_player(self) -> ba.SessionPlayer: def get_last_sessionplayer(self) -> ba.SessionPlayer:
"""Return the last ba.Player we were associated with.""" """Return the last ba.Player we were associated with."""
assert self._last_sessionplayer is not None assert self._last_sessionplayer is not None
return self._last_sessionplayer return self._last_sessionplayer
@ -204,18 +205,20 @@ class PlayerRecord:
# Only award this if they're still alive and we can get # Only award this if they're still alive and we can get
# a current position for them. # a current position for them.
our_pos: Optional[Sequence[float]] = None our_pos: Optional[ba.Vec3] = None
if self._player is not None: if self._sessionplayer is not None:
if self._player.activityplayer is not None: if self._sessionplayer.activityplayer is not None:
if self._player.activityplayer.node: try:
our_pos = self._player.activityplayer.node.position our_pos = self._sessionplayer.activityplayer.position
except NotFoundError:
pass
if our_pos is None: if our_pos is None:
return return
# Jitter position a bit since these often come in clusters. # Jitter position a bit since these often come in clusters.
our_pos = (our_pos[0] + (random.random() - 0.5) * 2.0, our_pos = _ba.Vec3(our_pos[0] + (random.random() - 0.5) * 2.0,
our_pos[1] + (random.random() - 0.5) * 2.0, our_pos[1] + (random.random() - 0.5) * 2.0,
our_pos[2] + (random.random() - 0.5) * 2.0) our_pos[2] + (random.random() - 0.5) * 2.0)
activity = self.getactivity() activity = self.getactivity()
if activity is not None: if activity is not None:
PopupText(Lstr( PopupText(Lstr(
@ -305,14 +308,14 @@ class Stats:
s_player.accum_killed_count = 0 s_player.accum_killed_count = 0
s_player.streak = 0 s_player.streak = 0
def register_player(self, player: ba.SessionPlayer) -> None: def register_sessionplayer(self, player: ba.SessionPlayer) -> None:
"""Register a player with this score-set.""" """Register a ba.SessionPlayer with this score-set."""
assert player.exists() # Invalid refs should never be passed to funcs. assert player.exists() # Invalid refs should never be passed to funcs.
name = player.getname() name = player.getname()
if name in self._player_records: if name in self._player_records:
# If the player already exists, update his character and such as # If the player already exists, update his character and such as
# it may have changed. # it may have changed.
self._player_records[name].associate_with_player(player) self._player_records[name].associate_with_sessionplayer(player)
else: else:
name_full = player.getname(full=True) name_full = player.getname(full=True)
self._player_records[name] = PlayerRecord(name, name_full, player, self._player_records[name] = PlayerRecord(name, name_full, player,
@ -325,7 +328,7 @@ class Stats:
# Go through our player records and return ones whose player id still # Go through our player records and return ones whose player id still
# corresponds to a player with that name. # corresponds to a player with that name.
for record_id, record in self._player_records.items(): for record_id, record in self._player_records.items():
lastplayer = record.get_last_player() lastplayer = record.get_last_sessionplayer()
if lastplayer and lastplayer.getname() == record_id: if lastplayer and lastplayer.getname() == record_id:
records[record_id] = record records[record_id] = record
return records return records

View File

@ -97,7 +97,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
if is_free_for_all and results is not None: if is_free_for_all and results is not None:
assert isinstance(results, ba.GameResults) assert isinstance(results, ba.GameResults)
assert p_rec.team.gameteam is not None assert p_rec.team.gameteam is not None
val = results.get_team_score_str(p_rec.team.gameteam) val = results.get_team_score_str(p_rec.team)
assert val is not None assert val is not None
return val return val
return str(p_rec.accumscore) return str(p_rec.accumscore)

View File

@ -34,7 +34,7 @@ class AppDelegate(ba.AppDelegate):
def create_default_game_settings_ui( def create_default_game_settings_ui(
self, gameclass: Type[ba.GameActivity], self, gameclass: Type[ba.GameActivity],
sessionclass: Type[ba.Session], config: Optional[dict], sessiontype: Type[ba.Session], settings: Optional[dict],
completion_call: Callable[[Optional[dict]], Any]) -> None: completion_call: Callable[[Optional[dict]], Any]) -> None:
"""(internal)""" """(internal)"""
@ -42,6 +42,6 @@ class AppDelegate(ba.AppDelegate):
from bastd.ui.playlist.editgame import PlaylistEditGameWindow from bastd.ui.playlist.editgame import PlaylistEditGameWindow
prev_window = ba.app.main_menu_window prev_window = ba.app.main_menu_window
ba.app.main_menu_window = (PlaylistEditGameWindow( ba.app.main_menu_window = (PlaylistEditGameWindow(
gameclass, sessionclass, config, gameclass, sessiontype, settings,
completion_call=completion_call).get_root_widget()) completion_call=completion_call).get_root_widget())
ba.containerwidget(edit=prev_window, transition='out_left') ba.containerwidget(edit=prev_window, transition='out_left')

View File

@ -141,7 +141,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
name = 'Onslaught' name = 'Onslaught'
description = 'Defeat all enemies.' description = 'Defeat all enemies.'
tips: List[Union[str, Dict[str, Any]]] = [ tips: List[Union[str, ba.GameTip]] = [
'Hold any button to run.' 'Hold any button to run.'
' (Trigger buttons work well if you have them)', ' (Trigger buttons work well if you have them)',
'Try tricking enemies into killing eachother or running off cliffs.', 'Try tricking enemies into killing eachother or running off cliffs.',
@ -213,43 +213,45 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
def on_transition_in(self) -> None: def on_transition_in(self) -> None:
super().on_transition_in() super().on_transition_in()
session = ba.getsession() customdata = ba.getsession().customdata
# Show special landmine tip on rookie preset. # Show special landmine tip on rookie preset.
if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
# Show once per session only (then we revert to regular tips). # Show once per session only (then we revert to regular tips).
if not getattr(session, '_g_showed_onslaught_landmine_tip', False): if not customdata.get('_showed_onslaught_landmine_tip', False):
setattr(session, '_g_showed_onslaught_landmine_tip', True) customdata['_showed_onslaught_landmine_tip'] = True
self.tips = [{ self.tips = [
'tip': 'Land-mines are a good way' ba.GameTip(
' to stop speedy enemies.', 'Land-mines are a good way to stop speedy enemies.',
'icon': ba.gettexture('powerupLandMines'), icon=ba.gettexture('powerupLandMines'),
'sound': ba.getsound('ding') sound=ba.getsound('ding'))
}] ]
# Show special tnt tip on pro preset. # Show special tnt tip on pro preset.
if self._preset in {Preset.PRO, Preset.PRO_EASY}: if self._preset in {Preset.PRO, Preset.PRO_EASY}:
# Show once per session only (then we revert to regular tips). # Show once per session only (then we revert to regular tips).
if not getattr(session, '_g_showed_onslaught_tnt_tip', False): if not customdata.get('_showed_onslaught_tnt_tip', False):
setattr(session, '_g_showed_onslaught_tnt_tip', True) customdata['_showed_onslaught_tnt_tip'] = True
self.tips = [{ self.tips = [
'tip': 'Take out a group of enemies by\n' ba.GameTip(
'setting off a bomb near a TNT box.', 'Take out a group of enemies by\n'
'icon': ba.gettexture('tnt'), 'setting off a bomb near a TNT box.',
'sound': ba.getsound('ding') icon=ba.gettexture('tnt'),
}] sound=ba.getsound('ding'))
]
# Show special curse tip on uber preset. # Show special curse tip on uber preset.
if self._preset in {Preset.UBER, Preset.UBER_EASY}: if self._preset in {Preset.UBER, Preset.UBER_EASY}:
# Show once per session only (then we revert to regular tips). # Show once per session only (then we revert to regular tips).
if not getattr(session, '_g_showed_onslaught_curse_tip', False): if not customdata.get('_showed_onslaught_curse_tip', False):
setattr(session, '_g_showed_onslaught_curse_tip', True) customdata['_showed_onslaught_curse_tip'] = True
self.tips = [{ self.tips = [
'tip': 'Curse boxes turn you into a ticking time bomb.\n' ba.GameTip(
'The only cure is to quickly grab a health-pack.', 'Curse boxes turn you into a ticking time bomb.\n'
'icon': ba.gettexture('powerupCurse'), 'The only cure is to quickly grab a health-pack.',
'sound': ba.getsound('ding') icon=ba.gettexture('powerupCurse'),
}] sound=ba.getsound('ding'))
]
self._spawn_info_text = ba.NodeActor( self._spawn_info_text = ba.NodeActor(
ba.newnode('text', ba.newnode('text',

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND --> <!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-06-02 for Ballistica version 1.5.0 build 20043</em></h4> <h4><em>last updated on 2020-06-03 for Ballistica version 1.5.0 build 20044</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module, <p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p> which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr> <hr>
@ -21,6 +21,7 @@
</ul> </ul>
<li><a href="#class_ba_Chooser">ba.Chooser</a></li> <li><a href="#class_ba_Chooser">ba.Chooser</a></li>
<li><a href="#class_ba_GameResults">ba.GameResults</a></li> <li><a href="#class_ba_GameResults">ba.GameResults</a></li>
<li><a href="#class_ba_GameTip">ba.GameTip</a></li>
<li><a href="#class_ba_InputDevice">ba.InputDevice</a></li> <li><a href="#class_ba_InputDevice">ba.InputDevice</a></li>
<li><a href="#class_ba_Level">ba.Level</a></li> <li><a href="#class_ba_Level">ba.Level</a></li>
<li><a href="#class_ba_Lobby">ba.Lobby</a></li> <li><a href="#class_ba_Lobby">ba.Lobby</a></li>
@ -1100,7 +1101,7 @@ manually.</p>
<h3>Methods:</h3> <h3>Methods:</h3>
<dl> <dl>
<dt><h4><a name="method_ba_AppDelegate__create_default_game_settings_ui">create_default_game_settings_ui()</a></dt></h4><dd> <dt><h4><a name="method_ba_AppDelegate__create_default_game_settings_ui">create_default_game_settings_ui()</a></dt></h4><dd>
<p><span>create_default_game_settings_ui(self, gameclass: Type[<a href="#class_ba_GameActivity">ba.GameActivity</a>], sessionclass: Type[<a href="#class_ba_Session">ba.Session</a>], config: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -&gt; None</span></p> <p><span>create_default_game_settings_ui(self, gameclass: Type[<a href="#class_ba_GameActivity">ba.GameActivity</a>], sessiontype: Type[<a href="#class_ba_Session">ba.Session</a>], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -&gt; None</span></p>
<p>Launch a UI to configure the given game config.</p> <p>Launch a UI to configure the given game config.</p>
@ -1733,7 +1734,7 @@ and it should begin its actual game logic.</p>
high score lists.</p> high score lists.</p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__customdata">customdata</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<h5><a href="#attr_ba_CoopSession__campaign">campaign</a>, <a href="#attr_ba_CoopSession__sessionglobalsnode">sessionglobalsnode</a></h5> <h5><a href="#attr_ba_CoopSession__campaign">campaign</a>, <a href="#attr_ba_CoopSession__sessionglobalsnode">sessionglobalsnode</a></h5>
<dl> <dl>
@ -2091,7 +2092,7 @@ its time with lingering corpses, sound effects, etc.</p>
</p> </p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__customdata">customdata</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<dl> <dl>
<dt><h4><a name="attr_ba_DualTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd> <dt><h4><a name="attr_ba_DualTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
@ -2156,7 +2157,7 @@ its time with lingering corpses, sound effects, etc.</p>
<p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p> <p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p>
<p>The position of the player, as defined by its current <a href="#class_ba_Actor">ba.Actor</a>.</p> <p>The position of the player, as defined by its current <a href="#class_ba_Actor">ba.Actor</a>.</p>
<p> This value is undefined when the player has no Actor.</p> <p> If the player currently has no actor, raises a <a href="#class_ba_ActorNotFoundError">ba.ActorNotFoundError</a>.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_EmptyPlayer__sessionplayer">sessionplayer</a></h4></dt><dd> <dt><h4><a name="attr_ba_EmptyPlayer__sessionplayer">sessionplayer</a></h4></dt><dd>
@ -2272,7 +2273,7 @@ its time with lingering corpses, sound effects, etc.</p>
</p> </p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__customdata">customdata</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<dl> <dl>
<dt><h4><a name="attr_ba_FreeForAllSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd> <dt><h4><a name="attr_ba_FreeForAllSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
@ -2407,14 +2408,14 @@ and calls either end_game or continue_game depending on the result</p>
</dd> </dd>
<dt><h4><a name="method_ba_GameActivity__create_settings_ui">create_settings_ui()</a></dt></h4><dd> <dt><h4><a name="method_ba_GameActivity__create_settings_ui">create_settings_ui()</a></dt></h4><dd>
<h5><span><em>&lt;class method&gt;</span></em></h5> <h5><span><em>&lt;class method&gt;</span></em></h5>
<p><span>create_settings_ui(sessionclass: Type[<a href="#class_ba_Session">ba.Session</a>], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -&gt; None </span></p> <p><span>create_settings_ui(sessiontype: Type[<a href="#class_ba_Session">ba.Session</a>], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -&gt; None </span></p>
<p>Launch an in-game UI to configure settings for a game type.</p> <p>Launch an in-game UI to configure settings for a game type.</p>
<p>'sessionclass' should be the <a href="#class_ba_Session">ba.Session</a> class the game will be used in.</p> <p>'sessiontype' should be the <a href="#class_ba_Session">ba.Session</a> class the game will be used in.</p>
<p>'config' should be an existing config dict (specifies 'edit' ui mode) <p>'settings' should be an existing settings dict (implies 'edit'
or None (specifies 'add' ui mode).</p> ui mode) or None (implies 'add' ui mode).</p>
<p>'completion_call' will be called with a filled-out settings dict on <p>'completion_call' will be called with a filled-out settings dict on
success or None on cancel.</p> success or None on cancel.</p>
@ -2439,11 +2440,11 @@ will replace the old.</p>
<dt><h4><a name="method_ba_GameActivity__end_game">end_game()</a></dt></h4><dd> <dt><h4><a name="method_ba_GameActivity__end_game">end_game()</a></dt></h4><dd>
<p><span>end_game(self) -&gt; None</span></p> <p><span>end_game(self) -&gt; None</span></p>
<p>Tells the game to wrap itself up and call <a href="#method_ba_Activity__end">ba.Activity.end</a>() <p>Tell the game to wrap up and call <a href="#method_ba_Activity__end">ba.Activity.end</a>() immediately.</p>
immediately. This method should be overridden by subclasses.</p>
<p>A game should always be prepared to end and deliver results, even if <p>This method should be overridden by subclasses. A game should always
there is no 'winner' yet; this way things like the standard time-limit be prepared to end and deliver results, even if there is no 'winner'
yet; this way things like the standard time-limit
(<a href="#method_ba_GameActivity__setup_standard_time_limit">ba.GameActivity.setup_standard_time_limit</a>()) will work with the game.</p> (<a href="#method_ba_GameActivity__setup_standard_time_limit">ba.GameActivity.setup_standard_time_limit</a>()) will work with the game.</p>
</dd> </dd>
@ -2451,61 +2452,8 @@ there is no 'winner' yet; this way things like the standard time-limit
<h5><span><em>&lt;class method&gt;</span></em></h5> <h5><span><em>&lt;class method&gt;</span></em></h5>
<p><span>get_available_settings(sessiontype: Type[<a href="#class_ba_Session">ba.Session</a>]) -&gt; List[<a href="#class_ba_Setting">ba.Setting</a>] </span></p> <p><span>get_available_settings(sessiontype: Type[<a href="#class_ba_Session">ba.Session</a>]) -&gt; List[<a href="#class_ba_Setting">ba.Setting</a>] </span></p>
<p>Called by the default <a href="#method_ba_GameActivity__create_settings_ui">ba.GameActivity.create_settings_ui</a>() <p>Return a list of settings relevant to this game type when
implementation; should return a dict of config options to be presented running under the provided session type.</p>
to the user for the given <a href="#class_ba_Session">ba.Session</a> type.</p>
<p>The format for settings is a list of 2-member tuples consisting
of a name and a dict of options.</p>
<p><strong>Available Setting Options:</strong></p>
<p>'default': This determines the default value as well as the
type (int, float, or bool)</p>
<p>'min_value': Minimum value for int/float settings.</p>
<p>'max_value': Maximum value for int/float settings.</p>
<p>'choices': A list of name/value pairs the user can choose from by name.</p>
<p>'increment': Value increment for int/float settings.</p>
<pre><span><em><small># example get_available_settings() for a capture-the-flag game:</small></em></span>
@classmethod
def get_available_settings(cls, sessiontype):
return [("Score to Win", {
'default': 3,
'min_value': 1
}),
("Flag Touch Return Time", {
'default': 0,
'min_value': 0,
'increment': 1
}),
("Flag Idle Return Time", {
'default': 30,
'min_value': 5,
'increment': 5
}),
("Time Limit", {
'default': 0,
'choices': [
('None', 0), ('1 Minute', 60), ('2 Minutes', 120),
('5 Minutes', 300), ('10 Minutes', 600),
('20 Minutes', 1200)
]
}),
("Respawn Times", {
'default': 1.0,
'choices': [
('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0),
('Long', 2.0), ('Longer', 4.0)
]
}),
("Epic Mode", {
'default': False
})]</pre>
</dd> </dd>
<dt><h4><a name="method_ba_GameActivity__get_description">get_description()</a></dt></h4><dd> <dt><h4><a name="method_ba_GameActivity__get_description">get_description()</a></dt></h4><dd>
@ -2821,13 +2769,13 @@ Results for a completed game.</p>
</dd> </dd>
<dt><h4><a name="method_ba_GameResults__get_team_score">get_team_score()</a></dt></h4><dd> <dt><h4><a name="method_ba_GameResults__get_team_score">get_team_score()</a></dt></h4><dd>
<p><span>get_team_score(self, sessionteam: Union[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]) -&gt; Optional[int]</span></p> <p><span>get_team_score(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; Optional[int]</span></p>
<p>Return the score for a given <a href="#class_ba_SessionTeam">ba.SessionTeam</a>.</p> <p>Return the score for a given <a href="#class_ba_SessionTeam">ba.SessionTeam</a>.</p>
</dd> </dd>
<dt><h4><a name="method_ba_GameResults__get_team_score_str">get_team_score_str()</a></dt></h4><dd> <dt><h4><a name="method_ba_GameResults__get_team_score_str">get_team_score_str()</a></dt></h4><dd>
<p><span>get_team_score_str(self, team: <a href="#class_ba_Team">ba.Team</a>) -&gt; <a href="#class_ba_Lstr">ba.Lstr</a></span></p> <p><span>get_team_score_str(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; <a href="#class_ba_Lstr">ba.Lstr</a></span></p>
<p>Return the score for the given <a href="#class_ba_Team">ba.Team</a> as an Lstr.</p> <p>Return the score for the given <a href="#class_ba_Team">ba.Team</a> as an Lstr.</p>
@ -2854,6 +2802,22 @@ Results for a completed game.</p>
<p>This can be a number or None. <p>This can be a number or None.
(see the none_is_winner arg in the constructor)</p> (see the none_is_winner arg in the constructor)</p>
</dd>
</dl>
<hr>
<h2><strong><a name="class_ba_GameTip">ba.GameTip</a></strong></h3>
<p><em>&lt;top level class&gt;</em>
</p>
<p>Defines a tip presentable to the user at the start of a game.</p>
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a>
</p>
<h3>Methods:</h3>
<dl>
<dt><h4><a name="method_ba_GameTip____init__">&lt;constructor&gt;</a></dt></h4><dd>
<p><span>ba.GameTip(text: str, icon: Optional[<a href="#class_ba_Texture">ba.Texture</a>] = None, sound: Optional[<a href="#class_ba_Sound">ba.Sound</a>] = None)</span></p>
</dd> </dd>
</dl> </dl>
<hr> <hr>
@ -3728,7 +3692,7 @@ Use <a href="#function_ba_getmodel">ba.getmodel</a>() to instantiate one.</p>
</p> </p>
<h3>Attributes Inherited:</h3> <h3>Attributes Inherited:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__customdata">customdata</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<h3>Attributes Defined Here:</h3> <h3>Attributes Defined Here:</h3>
<dl> <dl>
<dt><h4><a name="attr_ba_MultiTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd> <dt><h4><a name="attr_ba_MultiTeamSession__sessionglobalsnode">sessionglobalsnode</a></h4></dt><dd>
@ -4248,7 +4212,7 @@ even if myactor is set to None.</p>
<p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p> <p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p>
<p>The position of the player, as defined by its current <a href="#class_ba_Actor">ba.Actor</a>.</p> <p>The position of the player, as defined by its current <a href="#class_ba_Actor">ba.Actor</a>.</p>
<p> This value is undefined when the player has no Actor.</p> <p> If the player currently has no actor, raises a <a href="#class_ba_ActorNotFoundError">ba.ActorNotFoundError</a>.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_Player__sessionplayer">sessionplayer</a></h4></dt><dd> <dt><h4><a name="attr_ba_Player__sessionplayer">sessionplayer</a></h4></dt><dd>
@ -4446,14 +4410,14 @@ the type-checker properly identifies the returned value as one.</p>
</dd> </dd>
</dl> </dl>
<h3>Methods:</h3> <h3>Methods:</h3>
<h5><a href="#method_ba_PlayerRecord____init__">&lt;constructor&gt;</a>, <a href="#method_ba_PlayerRecord__associate_with_player">associate_with_player()</a>, <a href="#method_ba_PlayerRecord__cancel_multi_kill_timer">cancel_multi_kill_timer()</a>, <a href="#method_ba_PlayerRecord__get_icon">get_icon()</a>, <a href="#method_ba_PlayerRecord__get_last_player">get_last_player()</a>, <a href="#method_ba_PlayerRecord__getactivity">getactivity()</a>, <a href="#method_ba_PlayerRecord__getname">getname()</a>, <a href="#method_ba_PlayerRecord__submit_kill">submit_kill()</a></h5> <h5><a href="#method_ba_PlayerRecord____init__">&lt;constructor&gt;</a>, <a href="#method_ba_PlayerRecord__associate_with_sessionplayer">associate_with_sessionplayer()</a>, <a href="#method_ba_PlayerRecord__cancel_multi_kill_timer">cancel_multi_kill_timer()</a>, <a href="#method_ba_PlayerRecord__get_icon">get_icon()</a>, <a href="#method_ba_PlayerRecord__get_last_sessionplayer">get_last_sessionplayer()</a>, <a href="#method_ba_PlayerRecord__getactivity">getactivity()</a>, <a href="#method_ba_PlayerRecord__getname">getname()</a>, <a href="#method_ba_PlayerRecord__submit_kill">submit_kill()</a></h5>
<dl> <dl>
<dt><h4><a name="method_ba_PlayerRecord____init__">&lt;constructor&gt;</a></dt></h4><dd> <dt><h4><a name="method_ba_PlayerRecord____init__">&lt;constructor&gt;</a></dt></h4><dd>
<p><span>ba.PlayerRecord(name: str, name_full: str, player: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>, stats: <a href="#class_ba_Stats">ba.Stats</a>)</span></p> <p><span>ba.PlayerRecord(name: str, name_full: str, sessionplayer: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>, stats: <a href="#class_ba_Stats">ba.Stats</a>)</span></p>
</dd> </dd>
<dt><h4><a name="method_ba_PlayerRecord__associate_with_player">associate_with_player()</a></dt></h4><dd> <dt><h4><a name="method_ba_PlayerRecord__associate_with_sessionplayer">associate_with_sessionplayer()</a></dt></h4><dd>
<p><span>associate_with_player(self, sessionplayer: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -&gt; None</span></p> <p><span>associate_with_sessionplayer(self, sessionplayer: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -&gt; None</span></p>
<p>Associate this entry with a <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>.</p> <p>Associate this entry with a <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>.</p>
@ -4470,8 +4434,8 @@ the type-checker properly identifies the returned value as one.</p>
<p>Get the icon for this instance's player.</p> <p>Get the icon for this instance's player.</p>
</dd> </dd>
<dt><h4><a name="method_ba_PlayerRecord__get_last_player">get_last_player()</a></dt></h4><dd> <dt><h4><a name="method_ba_PlayerRecord__get_last_sessionplayer">get_last_sessionplayer()</a></dt></h4><dd>
<p><span>get_last_player(self) -&gt; <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></span></p> <p><span>get_last_sessionplayer(self) -&gt; <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a></span></p>
<p>Return the last <a href="#class_ba_Player">ba.Player</a> we were associated with.</p> <p>Return the last <a href="#class_ba_Player">ba.Player</a> we were associated with.</p>
@ -4700,13 +4664,19 @@ Pass 0 or a negative number for no ban time.</p>
maintaining state between them (players, teams, score tallies, etc).</p> maintaining state between them (players, teams, score tallies, etc).</p>
<h3>Attributes:</h3> <h3>Attributes:</h3>
<h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__sessionglobalsnode">sessionglobalsnode</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5> <h5><a href="#attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a>, <a href="#attr_ba_Session__customdata">customdata</a>, <a href="#attr_ba_Session__lobby">lobby</a>, <a href="#attr_ba_Session__max_players">max_players</a>, <a href="#attr_ba_Session__min_players">min_players</a>, <a href="#attr_ba_Session__players">players</a>, <a href="#attr_ba_Session__sessionglobalsnode">sessionglobalsnode</a>, <a href="#attr_ba_Session__teams">teams</a>, <a href="#attr_ba_Session__use_team_colors">use_team_colors</a>, <a href="#attr_ba_Session__use_teams">use_teams</a></h5>
<dl> <dl>
<dt><h4><a name="attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a></h4></dt><dd> <dt><h4><a name="attr_ba_Session__allow_mid_activity_joins">allow_mid_activity_joins</a></h4></dt><dd>
<p><span>bool</span></p> <p><span>bool</span></p>
<p>Whether players should be allowed to join in the middle of <p>Whether players should be allowed to join in the middle of
activities.</p> activities.</p>
</dd>
<dt><h4><a name="attr_ba_Session__customdata">customdata</a></h4></dt><dd>
<p><span>dict</span></p>
<p>A shared dictionary for objects to use as storage on this session.
Ensure that keys here are unique to avoid collisions.</p>
</dd> </dd>
<dt><h4><a name="attr_ba_Session__lobby">lobby</a></h4></dt><dd> <dt><h4><a name="attr_ba_Session__lobby">lobby</a></h4></dt><dd>
<p><span><a href="#class_ba_Lobby">ba.Lobby</a></span></p> <p><span><a href="#class_ba_Lobby">ba.Lobby</a></span></p>
@ -5290,7 +5260,7 @@ of the session.</p>
</p> </p>
<h3>Methods:</h3> <h3>Methods:</h3>
<h5><a href="#method_ba_Stats____init__">&lt;constructor&gt;</a>, <a href="#method_ba_Stats__get_records">get_records()</a>, <a href="#method_ba_Stats__getactivity">getactivity()</a>, <a href="#method_ba_Stats__player_scored">player_scored()</a>, <a href="#method_ba_Stats__player_was_killed">player_was_killed()</a>, <a href="#method_ba_Stats__register_player">register_player()</a>, <a href="#method_ba_Stats__reset">reset()</a>, <a href="#method_ba_Stats__reset_accum">reset_accum()</a>, <a href="#method_ba_Stats__setactivity">setactivity()</a></h5> <h5><a href="#method_ba_Stats____init__">&lt;constructor&gt;</a>, <a href="#method_ba_Stats__get_records">get_records()</a>, <a href="#method_ba_Stats__getactivity">getactivity()</a>, <a href="#method_ba_Stats__player_scored">player_scored()</a>, <a href="#method_ba_Stats__player_was_killed">player_was_killed()</a>, <a href="#method_ba_Stats__register_sessionplayer">register_sessionplayer()</a>, <a href="#method_ba_Stats__reset">reset()</a>, <a href="#method_ba_Stats__reset_accum">reset_accum()</a>, <a href="#method_ba_Stats__setactivity">setactivity()</a></h5>
<dl> <dl>
<dt><h4><a name="method_ba_Stats____init__">&lt;constructor&gt;</a></dt></h4><dd> <dt><h4><a name="method_ba_Stats____init__">&lt;constructor&gt;</a></dt></h4><dd>
<p><span>ba.Stats()</span></p> <p><span>ba.Stats()</span></p>
@ -5324,10 +5294,10 @@ of the session.</p>
<p>Should be called when a player is killed.</p> <p>Should be called when a player is killed.</p>
</dd> </dd>
<dt><h4><a name="method_ba_Stats__register_player">register_player()</a></dt></h4><dd> <dt><h4><a name="method_ba_Stats__register_sessionplayer">register_sessionplayer()</a></dt></h4><dd>
<p><span>register_player(self, player: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -&gt; None</span></p> <p><span>register_sessionplayer(self, player: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -&gt; None</span></p>
<p>Register a player with this score-set.</p> <p>Register a <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a> with this score-set.</p>
</dd> </dd>
<dt><h4><a name="method_ba_Stats__reset">reset()</a></dt></h4><dd> <dt><h4><a name="method_ba_Stats__reset">reset()</a></dt></h4><dd>