diff --git a/.efrocachemap b/.efrocachemap
index 62ce73ba..6ff19b51 100644
--- a/.efrocachemap
+++ b/.efrocachemap
@@ -4132,16 +4132,16 @@
"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/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/63/2c/d64f68f0e4ecbb55f3731ad95530",
- "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/cd/c8c9b3e4a265ac816c5d249e4638",
- "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/92/c312438bf1dbdb599bd020a5c220",
- "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/75/6686aa5b6e0f88e1a40d444fd013",
- "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c1/bc/23b3f5d0929adf8c497accad24bb",
- "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/07/d95b4d6354acf4003f70307ba7cb",
- "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2c/bd/18dff8eda46be2d2edeee0a7ece9",
- "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/64/a0beab66455ed6be694583fb6d53",
- "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a2/ba/1e71e85b38eed56a55f8e0d85821",
- "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dd/38/d98994fed8732ab774e879b0c8a5",
- "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2c/e0/97ebbdf740a3bfbc5324f510204e",
- "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4e/69/2af7295ec87bcf480e57f41e19a7"
+ "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/15/7a/d4e39ad022b8365418ecee4d026b",
+ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/ad/7e371dfb7ed7b10d46f0bf9497d8",
+ "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/28/faa6501d779b381dec7fb9ac19c5",
+ "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/57/97d03c6230cfc4d9f0687249f408",
+ "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/e1/a3a86c40804f1e724c59ee04f1a2",
+ "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ae/78/7a6522e860506fe1046808ce7b0b",
+ "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/08/71/09be3ad2f8cf99f885549a7296a0",
+ "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/49/3c1d3c8a995df400e46df3470b02",
+ "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/43/d4/48ec85af308fd027d7dd06eaa650",
+ "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cc/1b/303089d3c1f3b7620c632ee864c3",
+ "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f2/55/890f1b498ccf5988dee573d5f3ca",
+ "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b9/b1/d96d693c3ad52cedd4f517fd9d94"
}
\ No newline at end of file
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index f8e28694..1763add7 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -398,6 +398,7 @@
curstate
curtime
curtimestr
+ customdata
customizebrowser
cutscenes
cval
@@ -604,6 +605,7 @@
factoryclass
fallbacks
farthestpt
+ fback
fbase
fclose
fcmd
@@ -874,6 +876,7 @@
icns
iconpicker
iconscale
+ iconsstorename
ident
idevices
ifeq
@@ -910,6 +913,7 @@
infotextcolor
inidividual
initializers
+ initialplayerinfos
initing
inits
inmobi
@@ -1110,6 +1114,8 @@
mapselect
maptype
markupbase
+ masktex
+ masktexstorename
mathmodule
mathnode
mathutils
@@ -1163,6 +1169,7 @@
moduledir
modulefinder
modulename
+ modulepath
modutils
moola
mopaque
@@ -1204,6 +1211,7 @@
myhome
myinput
mylist
+ mymodule
mynode
myobj
myprojname
@@ -1214,6 +1222,7 @@
mypytype
mysound
mytextnode
+ mythingie
myweakcall
mywidget
namedarg
@@ -1360,6 +1369,7 @@
pkgutil
playercast
playerdata
+ playerinfos
playerlostspaz
playernode
playerpt
@@ -1533,6 +1543,7 @@
qrcode
qrencode
qual
+ qualname
quoprimime
rando
randommodule
@@ -1786,8 +1797,10 @@
steelseries
stickman
storable
+ storagename
storedhash
storeitemui
+ storename
strftime
stringprep
stringptr
@@ -1913,6 +1926,7 @@
thanvannispen
thelaststand
themself
+ thingie
threadtype
throwiness
timedisplay
@@ -2095,6 +2109,8 @@
willeval
wincfg
wincount
+ winnergroup
+ winnergroups
winplt
winprj
winref
diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py
index f33fbb95..fb7554fd 100644
--- a/assets/src/ba_data/python/_ba.py
+++ b/assets/src/ba_data/python/_ba.py
@@ -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)
-# SOURCES_HASH=247084187994045015646460724420234222242
+# SOURCES_HASH=214847179904844500339904334878206016957
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
@@ -822,16 +822,11 @@ class SessionPlayer:
This bool value will be True once the Player has completed
any lobby character/team selection.
- team: ba.SessionTeam
+ sessionteam: ba.SessionTeam
The ba.SessionTeam this Player is on. If the SessionPlayer
is still in its lobby selecting a team/etc. then a
ba.SessionTeamNotFoundError will be raised.
- sessiondata: Dict
- A dict for use by the current ba.Session for
- storing data associated with this player.
- This persists for the duration of the session.
-
inputdevice: ba.InputDevice
The input device associated with the player.
@@ -853,8 +848,7 @@ class SessionPlayer:
"""
id: int
in_game: bool
- team: ba.SessionTeam
- sessiondata: Dict
+ sessionteam: ba.SessionTeam
inputdevice: ba.InputDevice
color: Sequence[float]
highlight: Sequence[float]
diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py
index 3a2d949a..936cdef6 100644
--- a/assets/src/ba_data/python/ba/__init__.py
+++ b/assets/src/ba_data/python/ba/__init__.py
@@ -73,7 +73,7 @@ from ba._campaign import Campaign
from ba._gameutils import (animate, animate_array, show_damage_count,
timestring, cameraflash)
from ba._general import (WeakCall, Call, existing, Existable,
- verify_object_death)
+ verify_object_death, storagename)
from ba._level import Level
from ba._lobby import Lobby, Chooser
from ba._math import normalized_color, is_point_in_box, vec3validate
diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py
index c5c5b8f7..6c494c5f 100644
--- a/assets/src/ba_data/python/ba/_activity.py
+++ b/assets/src/ba_data/python/ba/_activity.py
@@ -215,7 +215,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
self.lobby = None
self._stats: Optional[ba.Stats] = None
- self._gamedata: Optional[dict] = {}
+ self._customdata: Optional[dict] = {}
def __del__(self) -> None:
@@ -265,15 +265,15 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
"""
@property
- def gamedata(self) -> dict:
+ def customdata(self) -> dict:
"""Entities needing to store simple data with an activity can put it
here. This dict will be deleted when the activity expires, so contained
objects generally do not need to worry about handling expired
activities.
"""
assert not self._expired
- assert isinstance(self._gamedata, dict)
- return self._gamedata
+ assert isinstance(self._customdata, dict)
+ return self._customdata
@property
def expired(self) -> bool:
@@ -574,9 +574,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
def add_player(self, sessionplayer: ba.SessionPlayer) -> None:
"""(internal)"""
- assert sessionplayer.team is not None
+ assert sessionplayer.sessionteam is not None
sessionplayer.resetinput()
- sessionteam = sessionplayer.team
+ sessionteam = sessionplayer.sessionteam
assert sessionplayer in sessionteam.players
team = sessionteam.gameteam
assert team is not None
@@ -608,7 +608,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
player: Any = sessionplayer.gameplayer
assert isinstance(player, self._playertype)
- team: Any = sessionplayer.team.gameteam
+ team: Any = sessionplayer.sessionteam.gameteam
assert isinstance(team, self._teamtype)
assert player in team.players
@@ -795,9 +795,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
print_exception(f'Error in Activity on_expire() for {self}.')
try:
- self._gamedata = None
+ self._customdata = None
except Exception:
- print_exception(f'Error clearing gamedata for {self}.')
+ print_exception(f'Error clearing customdata for {self}.')
# Don't want to be holding any delay-delete refs at this point.
self._prune_delay_deletes()
diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py
index afca3247..cb03c75c 100644
--- a/assets/src/ba_data/python/ba/_activitytypes.py
+++ b/assets/src/ba_data/python/ba/_activitytypes.py
@@ -27,8 +27,8 @@ import _ba
from ba._activity import Activity
from ba._music import setmusic, MusicType
# False positive due to our class_generics_filter custom pylint filter.
-from ba._player import Player # pylint: disable=W0611
-from ba._team import Team # pylint: disable=W0611
+from ba import _player
+from ba import _team
if TYPE_CHECKING:
from typing import Any, Dict, Optional
@@ -36,6 +36,17 @@ if TYPE_CHECKING:
from ba._lobby import JoinInfo
+# Even though we don't need custom Player/Team types, define empty ones
+# so we don't have ba.Player[Any] and ba.Team[Any] as our types which
+# reduces type safety.
+class Player(_player.Player['Team']):
+ """Our player type for this game."""
+
+
+class Team(_team.Team[Player]):
+ """Our team type for this game."""
+
+
class EndSessionActivity(Activity[Player, Team]):
"""Special ba.Activity to fade out and end the current ba.Session."""
@@ -158,7 +169,7 @@ class ScoreScreenActivity(Activity[Player, Team]):
self._custom_continue_message: Optional[ba.Lstr] = None
self._server_transitioning: Optional[bool] = None
- def on_player_join(self, player: ba.Player) -> None:
+ def on_player_join(self, player: Player) -> None:
from ba import _general
super().on_player_join(player)
time_till_assign = max(
@@ -224,7 +235,7 @@ class ScoreScreenActivity(Activity[Player, Team]):
# Otherwise end the activity normally.
self.end()
- def _safe_assign(self, player: ba.Player) -> None:
+ def _safe_assign(self, player: Player) -> None:
# Just to be extra careful, don't assign if we're transitioning out.
# (though theoretically that would be ok).
diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py
index 052a77d0..22456491 100644
--- a/assets/src/ba_data/python/ba/_coopsession.py
+++ b/assets/src/ba_data/python/ba/_coopsession.py
@@ -341,37 +341,35 @@ class CoopSession(Session):
self.setactivity(_ba.new_activity(TransitionActivity))
else:
- player_info: List[ba.PlayerInfo]
+ playerinfos: List[ba.PlayerInfo]
# Generic team games.
if isinstance(results, TeamGameResults):
- player_info = results.get_player_info()
- score = results.get_team_score(results.get_teams()[0])
+ playerinfos = results.playerinfos
+ score = results.get_team_score(results.sessionteams[0])
fail_message = None
- score_order = ('decreasing' if results.get_lower_is_better()
- else 'increasing')
- if results.get_score_type() in (ScoreType.SECONDS,
- ScoreType.MILLISECONDS):
- score_type = 'time'
+ score_order = ('decreasing'
+ if results.lower_is_better else 'increasing')
+ if results.scoretype in (ScoreType.SECONDS,
+ ScoreType.MILLISECONDS):
+ scoretype = 'time'
# ScoreScreen wants hundredths of a second.
if score is not None:
- if results.get_score_type() is ScoreType.SECONDS:
+ if results.scoretype is ScoreType.SECONDS:
score *= 100
- elif (results.get_score_type() is
- ScoreType.MILLISECONDS):
+ elif results.scoretype is ScoreType.MILLISECONDS:
score //= 10
else:
raise RuntimeError('FIXME')
else:
- if results.get_score_type() is not ScoreType.POINTS:
- print(f'Unknown ScoreType:'
- f' "{results.get_score_type()}"')
- score_type = 'points'
+ if results.scoretype is not ScoreType.POINTS:
+ print(f'Unknown ScoreType:' f' "{results.scoretype}"')
+ scoretype = 'points'
# Old coop-game-specific results; should migrate away from these.
else:
- player_info = results.get('player_info')
+ playerinfos = results.get('playerinfos')
score = results['score'] if 'score' in results else None
fail_message = (results['fail_message']
if 'fail_message' in results else None)
@@ -380,12 +378,12 @@ class CoopSession(Session):
activity_score_type = (activity.get_score_type() if isinstance(
activity, CoopGameActivity) else None)
assert activity_score_type is not None
- score_type = activity_score_type
+ scoretype = activity_score_type
# Validate types.
- if player_info is not None:
- assert isinstance(player_info, list)
- assert (isinstance(i, PlayerInfo) for i in player_info)
+ if playerinfos is not None:
+ assert isinstance(playerinfos, list)
+ assert (isinstance(i, PlayerInfo) for i in playerinfos)
# Looks like we were in a round - check the outcome and
# go from there.
@@ -397,11 +395,11 @@ class CoopSession(Session):
self.setactivity(
_ba.new_activity(
CoopScoreScreen, {
- 'player_info': player_info,
+ 'playerinfos': playerinfos,
'score': score,
'fail_message': fail_message,
'score_order': score_order,
- 'score_type': score_type,
+ 'score_type': scoretype,
'outcome': outcome,
'campaign': self.campaign,
'level': self.campaign_level_name
diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py
index 4cdef7de..c07e0451 100644
--- a/assets/src/ba_data/python/ba/_dualteamsession.py
+++ b/assets/src/ba_data/python/ba/_dualteamsession.py
@@ -52,18 +52,17 @@ class DualTeamSession(MultiTeamSession):
TeamVictoryScoreScreenActivity)
from bastd.activity.multiteamvictory import (
TeamSeriesVictoryScoreScreenActivity)
- winners = results.get_winners()
+ winners = results.winnergroups
# If everyone has the same score, call it a draw.
if len(winners) < 2:
self.setactivity(_ba.new_activity(DrawScoreScreenActivity))
else:
winner = winners[0].teams[0]
- winner.sessiondata['score'] += 1
+ winner.customdata['score'] += 1
# If a team has won, show final victory screen.
- if winner.sessiondata['score'] >= (self._series_length -
- 1) / 2 + 1:
+ if winner.customdata['score'] >= (self._series_length - 1) / 2 + 1:
self.setactivity(
_ba.new_activity(TeamSeriesVictoryScoreScreenActivity,
{'winner': winner}))
diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py
index f7b1eeef..71ac1088 100644
--- a/assets/src/ba_data/python/ba/_freeforallsession.py
+++ b/assets/src/ba_data/python/ba/_freeforallsession.py
@@ -76,7 +76,7 @@ class FreeForAllSession(MultiTeamSession):
TeamSeriesVictoryScoreScreenActivity)
from bastd.activity.freeforallvictory import (
FreeForAllVictoryScoreScreenActivity)
- winners = results.get_winners()
+ winners = results.winnergroups
# If there's multiple players and everyone has the same score,
# call it a draw.
@@ -91,20 +91,20 @@ class FreeForAllSession(MultiTeamSession):
for i, winner in enumerate(winners):
for team in winner.teams:
points = (point_awards[i] if i in point_awards else 0)
- team.sessiondata['previous_score'] = (
- team.sessiondata['score'])
- team.sessiondata['score'] += points
+ team.customdata['previous_score'] = (
+ team.customdata['score'])
+ team.customdata['score'] += points
series_winners = [
team for team in self.teams
- if team.sessiondata['score'] >= self._ffa_series_length
+ if team.customdata['score'] >= self._ffa_series_length
]
series_winners.sort(reverse=True,
- key=lambda tm: (tm.sessiondata['score']))
+ key=lambda tm: (tm.customdata['score']))
if (len(series_winners) == 1
or (len(series_winners) > 1
- and series_winners[0].sessiondata['score'] !=
- series_winners[1].sessiondata['score'])):
+ and series_winners[0].customdata['score'] !=
+ series_winners[1].customdata['score'])):
self.setactivity(
_ba.new_activity(TeamSeriesVictoryScoreScreenActivity,
{'winner': series_winners[0]}))
diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py
index 6ed91a80..370bc7a5 100644
--- a/assets/src/ba_data/python/ba/_gameactivity.py
+++ b/assets/src/ba_data/python/ba/_gameactivity.py
@@ -284,7 +284,7 @@ class GameActivity(Activity[PlayerType, TeamType]):
# Holds some flattened info about the player set at the point
# when on_begin() is called.
- self.initial_player_info: Optional[List[ba.PlayerInfo]] = None
+ self.initialplayerinfos: Optional[List[ba.PlayerInfo]] = None
# Go ahead and get our map loading.
self._map_type = _map.get_map_class(self._calc_map_name(settings))
@@ -511,14 +511,14 @@ class GameActivity(Activity[PlayerType, TeamType]):
_ba.timer(2.5, self._show_tip)
# Store some basic info about players present at start time.
- self.initial_player_info = [
+ self.initialplayerinfos = [
PlayerInfo(name=p.getname(full=True), character=p.character)
for p in self.players
]
# Sort this by name so high score lists/etc will be consistent
# regardless of player join order.
- self.initial_player_info.sort(key=lambda x: x.name)
+ self.initialplayerinfos.sort(key=lambda x: x.name)
# If this is a tournament, query info about it such as how much
# time is left.
@@ -890,9 +890,10 @@ class GameActivity(Activity[PlayerType, TeamType]):
if player.actor and not self.has_ended():
from bastd.actor.respawnicon import RespawnIcon
- player.gamedata['respawn_timer'] = _ba.Timer(
+ player.customdata['respawn_timer'] = _ba.Timer(
respawn_time, WeakCall(self.spawn_player_if_exists, player))
- player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
+ player.customdata['respawn_icon'] = RespawnIcon(
+ player, respawn_time)
def spawn_player_if_exists(self, player: PlayerType) -> None:
"""
diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py
index ff185d56..c7009ff4 100644
--- a/assets/src/ba_data/python/ba/_gameresults.py
+++ b/assets/src/ba_data/python/ba/_gameresults.py
@@ -26,8 +26,6 @@ import weakref
from dataclasses import dataclass
from typing import TYPE_CHECKING
-from ba._team import Team
-
if TYPE_CHECKING:
from weakref import ReferenceType
from typing import Sequence, Tuple, Any, Optional, Dict, List, Union
@@ -56,56 +54,54 @@ class TeamGameResults:
self._game_set = False
self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam],
Optional[int]]] = {}
- self._teams: Optional[List[ReferenceType[ba.SessionTeam]]] = None
- self._player_info: Optional[List[ba.PlayerInfo]] = None
+ self._sessionteams: Optional[List[ReferenceType[
+ ba.SessionTeam]]] = None
+ self._playerinfos: Optional[List[ba.PlayerInfo]] = None
self._lower_is_better: Optional[bool] = None
self._score_label: Optional[str] = None
self._none_is_winner: Optional[bool] = None
- self._score_type: Optional[ba.ScoreType] = None
+ self._scoretype: Optional[ba.ScoreType] = None
def set_game(self, game: ba.GameActivity) -> None:
"""Set the game instance these results are applying to."""
if self._game_set:
raise RuntimeError('Game set twice for TeamGameResults.')
self._game_set = True
- self._teams = [weakref.ref(team) for team in game.teams]
+ self._sessionteams = [weakref.ref(team) for team in game.teams]
score_info = game.get_score_info()
- self._player_info = copy.deepcopy(game.initial_player_info)
+ self._playerinfos = copy.deepcopy(game.initialplayerinfos)
self._lower_is_better = score_info.lower_is_better
self._score_label = score_info.label
self._none_is_winner = score_info.none_is_winner
- self._score_type = score_info.scoretype
+ self._scoretype = score_info.scoretype
- def set_team_score(self, team: Union[ba.SessionTeam, ba.Team],
- score: Optional[int]) -> None:
+ def set_team_score(self, team: ba.Team, score: Optional[int]) -> None:
"""Set the score for a given ba.Team.
This can be a number or None.
(see the none_is_winner arg in the constructor)
"""
- if isinstance(team, Team):
- team = team.sessionteam
- self._scores[team.id] = (weakref.ref(team), score)
+ sessionteam = team.sessionteam
+ self._scores[sessionteam.id] = (weakref.ref(sessionteam), score)
- def get_team_score(self, team: Union[ba.SessionTeam,
- ba.Team]) -> Optional[int]:
- """Return the score for a given team."""
- if isinstance(team, Team):
- team = team.sessionteam
+ def get_team_score(self,
+ sessionteam: Union[ba.SessionTeam]) -> Optional[int]:
+ """Return the score for a given ba.SessionTeam."""
for score in list(self._scores.values()):
- if score[0]() is team:
+ if score[0]() is sessionteam:
return score[1]
# If we have no score value, assume None.
return None
- def get_teams(self) -> List[ba.SessionTeam]:
+ @property
+ def sessionteams(self) -> List[ba.SessionTeam]:
"""Return all ba.SessionTeams in the results."""
if not self._game_set:
raise RuntimeError("Can't get teams until game is set.")
teams = []
- assert self._teams is not None
- for team_ref in self._teams:
+ assert self._sessionteams is not None
+ for team_ref in self._sessionteams:
team = team_ref()
if team is not None:
teams.append(team)
@@ -130,55 +126,61 @@ class TeamGameResults:
if score[0]() is team.sessionteam:
if score[1] is None:
return Lstr(value='-')
- if self._score_type is ScoreType.SECONDS:
+ if self._scoretype is ScoreType.SECONDS:
return timestring(score[1] * 1000,
centi=False,
timeformat=TimeFormat.MILLISECONDS)
- if self._score_type is ScoreType.MILLISECONDS:
+ if self._scoretype is ScoreType.MILLISECONDS:
return timestring(score[1],
centi=True,
timeformat=TimeFormat.MILLISECONDS)
return Lstr(value=str(score[1]))
return Lstr(value='-')
- def get_player_info(self) -> List[ba.PlayerInfo]:
+ @property
+ def playerinfos(self) -> List[ba.PlayerInfo]:
"""Get info about the players represented by the results."""
if not self._game_set:
raise RuntimeError("Can't get player-info until game is set.")
- assert self._player_info is not None
- return self._player_info
+ assert self._playerinfos is not None
+ return self._playerinfos
- def get_score_type(self) -> ba.ScoreType:
- """Get the type of score."""
+ @property
+ def scoretype(self) -> ba.ScoreType:
+ """The type of score."""
if not self._game_set:
raise RuntimeError("Can't get score-type until game is set.")
- assert self._score_type is not None
- return self._score_type
+ assert self._scoretype is not None
+ return self._scoretype
- def get_score_name(self) -> str:
- """Get the name associated with scores ('points', etc)."""
+ @property
+ def score_label(self) -> str:
+ """The label associated with scores ('points', etc)."""
if not self._game_set:
- raise RuntimeError("Can't get score-name until game is set.")
+ raise RuntimeError("Can't get score-label until game is set.")
assert self._score_label is not None
return self._score_label
- def get_lower_is_better(self) -> bool:
- """Return whether lower scores are better."""
+ @property
+ def lower_is_better(self) -> bool:
+ """Whether lower scores are better."""
if not self._game_set:
raise RuntimeError("Can't get lower-is-better until game is set.")
assert self._lower_is_better is not None
return self._lower_is_better
- def get_winning_team(self) -> Optional[ba.SessionTeam]:
- """Get the winning ba.Team if there is exactly one; None otherwise."""
+ @property
+ def winning_team(self) -> Optional[ba.SessionTeam]:
+ """The winning ba.SessionTeam if there is exactly one, or else None."""
if not self._game_set:
raise RuntimeError("Can't get winners until game is set.")
- winners = self.get_winners()
+ winners = self.winnergroups
if winners and len(winners[0].teams) == 1:
return winners[0].teams[0]
return None
- def get_winners(self) -> List[WinnerGroup]:
+ @property
+ def winnergroups(self) -> List[WinnerGroup]:
"""Get an ordered list of winner groups."""
if not self._game_set:
raise RuntimeError("Can't get winners until game is set.")
@@ -200,17 +202,18 @@ class TeamGameResults:
results.sort(reverse=not self._lower_is_better, key=lambda x: x[0])
# Also group the 'None' scores.
- none_teams: List[ba.SessionTeam] = []
+ none_sessionteams: List[ba.SessionTeam] = []
for score in self._scores.values():
scoreteam = score[0]()
if scoreteam is not None and score[1] is None:
- none_teams.append(scoreteam)
+ none_sessionteams.append(scoreteam)
# Add the Nones to the list (either as winners or losers
# depending on the rules).
- if none_teams:
- nones: List[Tuple[Optional[int],
- List[ba.SessionTeam]]] = [(None, none_teams)]
+ if none_sessionteams:
+ nones: List[Tuple[Optional[int], List[ba.SessionTeam]]] = [
+ (None, none_sessionteams)
+ ]
if self._none_is_winner:
results = nones + results
else:
diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py
index 5ff0acd2..bb1f3bb5 100644
--- a/assets/src/ba_data/python/ba/_general.py
+++ b/assets/src/ba_data/python/ba/_general.py
@@ -25,6 +25,7 @@ import gc
import types
import weakref
import random
+import inspect
from typing import TYPE_CHECKING, TypeVar
from typing_extensions import Protocol
@@ -332,7 +333,45 @@ def _verify_object_death(wref: ReferenceType) -> None:
print(f'{Clr.YLW}Active References:{Clr.RST}')
i = 1
for ref in refs:
- # if isinstance(ref, types.FrameType):
- # continue
print(f'{Clr.YLW} reference {i}:{Clr.BLU} {ref}{Clr.RST}')
i += 1
+
+
+def storagename(basename: str) -> str:
+ """Generate a (hopefully) unique name for storing things in public places.
+
+ Category: General Utility Functions
+
+ This consists of a leading underscore, the module path at the
+ call site with dots replaced by underscores, the class name, and
+ the provided suffix. When storing data in public places such as
+ 'customdata' dicts, this minimizes the chance of collisions if a
+ module or class is duplicated or renamed.
+
+ # Example: generate a unique name for storage purposes:
+ class MyThingie:
+
+ # This will give something like '_mymodule_submodule_mythingie_data'.
+ _STORENAME = ba.storagename('data')
+
+ def __init__(self, activity):
+ # Store some data in the Activity we were passed
+ activity.customdata[self._STORENAME] = {}
+ """
+ frame = inspect.currentframe()
+ if frame is None:
+ raise RuntimeError('Cannot get current stack frame.')
+ fback = frame.f_back
+ if fback is None:
+ raise RuntimeError('Cannot get parent stack frame.')
+ modulepath = fback.f_globals.get('__name__')
+ if modulepath is None:
+ raise RuntimeError('Cannot get parent stack module path.')
+ assert isinstance(modulepath, str)
+ qualname = fback.f_locals.get('__qualname__')
+ if qualname is not None:
+ assert isinstance(qualname, str)
+ fullpath = f'_{modulepath}_{qualname.lower()}_{basename}'
+ else:
+ fullpath = f'_{modulepath}_{basename}'
+ return fullpath.replace('.', '_')
diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py
index 38016cf7..91a17e5c 100644
--- a/assets/src/ba_data/python/ba/_multiteamsession.py
+++ b/assets/src/ba_data/python/ba/_multiteamsession.py
@@ -156,7 +156,7 @@ class MultiTeamSession(Session):
return self._game_number
def on_team_join(self, team: ba.SessionTeam) -> None:
- team.sessiondata['previous_score'] = team.sessiondata['score'] = 0
+ team.customdata['previous_score'] = team.customdata['score'] = 0
def get_max_players(self) -> int:
"""Return max number of ba.Players allowed to join the game at once."""
@@ -174,7 +174,8 @@ class MultiTeamSession(Session):
from bastd.tutorial import TutorialActivity
from bastd.activity.multiteamvictory import (
TeamSeriesVictoryScoreScreenActivity)
- from ba import _activitytypes
+ from ba._activitytypes import (TransitionActivity, JoinActivity,
+ ScoreScreenActivity)
# If we have a tutorial to show, that's the first thing we do no
# matter what.
@@ -186,22 +187,20 @@ class MultiTeamSession(Session):
# to transition us into a round gracefully (otherwise we'd snap from
# one terrain to another instantly).
elif isinstance(activity, TutorialActivity):
- self.setactivity(
- _ba.new_activity(_activitytypes.TransitionActivity))
+ self.setactivity(_ba.new_activity(TransitionActivity))
# If we're in a between-round activity or a restart-activity, hop
# into a round.
elif isinstance(
activity,
- (_activitytypes.JoinActivity, _activitytypes.TransitionActivity,
- _activitytypes.ScoreScreenActivity)):
+ (JoinActivity, TransitionActivity, ScoreScreenActivity)):
# If we're coming from a series-end activity, reset scores.
if isinstance(activity, TeamSeriesVictoryScoreScreenActivity):
self.stats.reset()
self._game_number = 0
for team in self.teams:
- team.sessiondata['score'] = 0
+ team.customdata['score'] = 0
# Otherwise just set accum (per-game) scores.
else:
@@ -221,7 +220,7 @@ class MultiTeamSession(Session):
# ..but only ones who have been placed on a team
# (ie: no longer sitting in the lobby).
try:
- has_team = (player.team is not None)
+ has_team = (player.sessionteam is not None)
except NotFoundError:
has_team = False
if has_team:
@@ -263,7 +262,7 @@ class MultiTeamSession(Session):
_ba.timer(delay, Call(_ba.playsound, _ba.getsound('boxingBell')))
if announce_winning_team:
- winning_team = results.get_winning_team()
+ winning_team = results.winning_team
if winning_team is not None:
# Have all players celebrate.
celebrate_msg = CelebrateMessage(duration=10.0)
diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py
index c889d86a..b986d04c 100644
--- a/assets/src/ba_data/python/ba/_player.py
+++ b/assets/src/ba_data/python/ba/_player.py
@@ -23,7 +23,7 @@
from __future__ import annotations
from dataclasses import dataclass
-from typing import TYPE_CHECKING, TypeVar, Generic
+from typing import TYPE_CHECKING, TypeVar, Generic, cast
import _ba
from ba._error import SessionPlayerNotFoundError, print_exception
@@ -85,8 +85,7 @@ class Player(Generic[TeamType]):
_nodeactor: Optional[ba.NodeActor]
_expired: bool
_postinited: bool
- sessiondata: dict
- _gamedata: dict
+ _customdata: dict
# NOTE: avoiding having any __init__() here since it seems to not
# get called by default if a dataclass inherits from us.
@@ -118,10 +117,9 @@ class Player(Generic[TeamType]):
self.character = sessionplayer.character
self.color = sessionplayer.color
self.highlight = sessionplayer.highlight
- self._team = sessionplayer.team.gameteam # type: ignore
+ self._team = cast(TeamType, sessionplayer.sessionteam.gameteam)
assert self._team is not None
- self.sessiondata = sessionplayer.sessiondata
- self._gamedata = {}
+ self._customdata = {}
self._expired = False
self._postinited = True
node = _ba.newnode('player', attrs={'playerID': sessionplayer.id})
@@ -144,7 +142,7 @@ class Player(Generic[TeamType]):
print_exception(f'Error killing actor on leave for {self}')
self._nodeactor = None
del self._team
- del self._gamedata
+ del self._customdata
def expire(self) -> None:
"""Called when the Player is expiring (when its Activity does so).
@@ -163,7 +161,7 @@ class Player(Generic[TeamType]):
self._nodeactor = None
self.actor = None
del self._team
- del self._gamedata
+ del self._customdata
def on_expire(self) -> None:
"""Can be overridden to handle player expiration.
@@ -182,7 +180,7 @@ class Player(Generic[TeamType]):
return self._team
@property
- def gamedata(self) -> dict:
+ def customdata(self) -> dict:
"""Arbitrary values associated with the player.
Though it is encouraged that most player values be properly defined
on the ba.Player subclass, it may be useful for player-agnostic
@@ -193,7 +191,7 @@ class Player(Generic[TeamType]):
"""
assert self._postinited
assert not self._expired
- return self._gamedata
+ return self._customdata
@property
def sessionplayer(self) -> ba.SessionPlayer:
diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py
index 2de441ba..98b97728 100644
--- a/assets/src/ba_data/python/ba/_session.py
+++ b/assets/src/ba_data/python/ba/_session.py
@@ -259,7 +259,7 @@ class Session:
else:
# Ok, they've already entered the game. Remove them from
# teams/activities/etc.
- sessionteam = sessionplayer.team
+ sessionteam = sessionplayer.sessionteam
assert sessionteam is not None
_ba.screenmessage(
@@ -317,7 +317,7 @@ class Session:
else:
print('Team no in Session teams in on_player_leave.')
try:
- sessionteam.reset_sessiondata()
+ sessionteam.leave()
except Exception:
print_exception(f'Error clearing sessiondata'
f' for team {sessionteam} in session {self}.')
diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py
index 19db090d..cdc0271d 100644
--- a/assets/src/ba_data/python/ba/_stats.py
+++ b/assets/src/ba_data/python/ba/_stats.py
@@ -74,7 +74,7 @@ class PlayerRecord:
self._multi_kill_timer: Optional[ba.Timer] = None
self._multi_kill_count = 0
self._stats = weakref.ref(stats)
- self._last_player: Optional[ba.SessionPlayer] = None
+ self._last_sessionplayer: Optional[ba.SessionPlayer] = None
self._player: Optional[ba.SessionPlayer] = None
self._team: Optional[ReferenceType[ba.SessionTeam]] = None
self.streak = 0
@@ -110,7 +110,7 @@ class PlayerRecord:
def get_icon(self) -> Dict[str, Any]:
"""Get the icon for this instance's player."""
- player = self._last_player
+ player = self._last_sessionplayer
assert player is not None
return player.get_icon()
@@ -127,12 +127,12 @@ class PlayerRecord:
return stats.getactivity()
return None
- def associate_with_player(self, player: ba.SessionPlayer) -> None:
- """Associate this entry with a ba.Player."""
- self._team = weakref.ref(player.team)
- self.character = player.character
- self._last_player = player
- self._player = player
+ def associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None:
+ """Associate this entry with a ba.SessionPlayer."""
+ self._team = weakref.ref(sessionplayer.sessionteam)
+ self.character = sessionplayer.character
+ self._last_sessionplayer = sessionplayer
+ self._player = sessionplayer
self.streak = 0
def _end_multi_kill(self) -> None:
@@ -141,8 +141,8 @@ class PlayerRecord:
def get_last_player(self) -> ba.SessionPlayer:
"""Return the last ba.Player we were associated with."""
- assert self._last_player is not None
- return self._last_player
+ assert self._last_sessionplayer is not None
+ return self._last_sessionplayer
def submit_kill(self, showpoints: bool = True) -> None:
"""Submit a kill for this player entry."""
@@ -307,15 +307,14 @@ class Stats:
def register_player(self, player: ba.SessionPlayer) -> None:
"""Register a player with this score-set."""
+ assert player.exists() # Invalid refs should never be passed to funcs.
name = player.getname()
- name_full = player.getname(full=True)
- try:
+ if name in self._player_records:
# If the player already exists, update his character and such as
# it may have changed.
self._player_records[name].associate_with_player(player)
- except Exception:
- # FIXME: Shouldn't use top level Exception catch for logic.
- # Should only have this as a fallback and always log it.
+ else:
+ name_full = player.getname(full=True)
self._player_records[name] = PlayerRecord(name, name_full, player,
self)
@@ -331,11 +330,6 @@ class Stats:
records[record_id] = record
return records
- def player_got_hit(self, player: ba.SessionPlayer) -> None:
- """Call this when a player got hit."""
- s_player = self._player_records[player.getname()]
- s_player.streak = 0
-
def player_scored(self,
player: ba.Player,
base_points: int = 1,
diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py
index b60d294d..fa4be4d6 100644
--- a/assets/src/ba_data/python/ba/_team.py
+++ b/assets/src/ba_data/python/ba/_team.py
@@ -56,15 +56,10 @@ class SessionTeam:
players
The list of ba.SessionPlayers on the team.
- gamedata
- A dict for use by the current ba.Activity
- for storing data associated with this team.
- This gets cleared for each new ba.Activity.
-
- sessiondata
+ customdata
A dict for use by the current ba.Session for
storing data associated with this team.
- Unlike gamedata, this persists for the duration
+ Unlike customdata, this persists for the duration
of the session.
"""
@@ -72,8 +67,7 @@ class SessionTeam:
name: Union[ba.Lstr, str]
color: Tuple[float, ...] # FIXME: can't we make this fixed len?
players: List[ba.SessionPlayer]
- gamedata: Dict
- sessiondata: Dict
+ customdata: dict
id: int
def __init__(self,
@@ -90,12 +84,12 @@ class SessionTeam:
self.name = name
self.color = tuple(color)
self.players = []
- self.sessiondata = {}
+ self.customdata = {}
self.gameteam: Optional[Team] = None
- def reset_sessiondata(self) -> None:
+ def leave(self) -> None:
"""(internal)"""
- self.sessiondata = {}
+ self.customdata = {}
PlayerType = TypeVar('PlayerType', bound='ba.Player')
@@ -119,10 +113,7 @@ class Team(Generic[PlayerType]):
_sessionteam: ReferenceType[SessionTeam]
_expired: bool
_postinited: bool
- _gamedata: dict
-
- # TODO: kill these.
- sessiondata: dict
+ _customdata: dict
# NOTE: avoiding having any __init__() here since it seems to not
# get called by default if a dataclass inherits from us.
@@ -149,8 +140,7 @@ class Team(Generic[PlayerType]):
self.id = sessionteam.id
self.name = sessionteam.name
self.color = sessionteam.color
- self.sessiondata = sessionteam.sessiondata
- self._gamedata = {}
+ self._customdata = {}
self._expired = False
self._postinited = True
@@ -160,13 +150,12 @@ class Team(Generic[PlayerType]):
self.id = team_id
self.name = name
self.color = color
- self._gamedata = {}
- self.sessiondata = {}
+ self._customdata = {}
self._expired = False
self._postinited = True
@property
- def gamedata(self) -> dict:
+ def customdata(self) -> dict:
"""Arbitrary values associated with the team.
Though it is encouraged that most player values be properly defined
on the ba.Team subclass, it may be useful for player-agnostic
@@ -177,7 +166,7 @@ class Team(Generic[PlayerType]):
"""
assert self._postinited
assert not self._expired
- return self._gamedata
+ return self._customdata
def leave(self) -> None:
"""Called when the Team leaves a running game.
@@ -186,7 +175,7 @@ class Team(Generic[PlayerType]):
"""
assert self._postinited
assert not self._expired
- del self._gamedata
+ del self._customdata
del self.players
def expire(self) -> None:
@@ -203,7 +192,7 @@ class Team(Generic[PlayerType]):
except Exception:
print_exception(f'Error in on_expire for {self}.')
- del self._gamedata
+ del self._customdata
del self.players
def on_expire(self) -> None:
diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py
index e09d8d4c..45d4b0b2 100644
--- a/assets/src/ba_data/python/bastd/activity/coopscore.py
+++ b/assets/src/ba_data/python/bastd/activity/coopscore.py
@@ -137,9 +137,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
self._tournament_time_remaining_text: Optional[Text] = None
self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None
- self._player_info: List[ba.PlayerInfo] = settings['player_info']
- assert isinstance(self._player_info, list)
- assert (isinstance(i, ba.PlayerInfo) for i in self._player_info)
+ self._playerinfos: List[ba.PlayerInfo] = settings['playerinfos']
+ assert isinstance(self._playerinfos, list)
+ assert (isinstance(i, ba.PlayerInfo) for i in self._playerinfos)
self._score: Optional[int] = settings['score']
assert isinstance(self._score, (int, type(None)))
@@ -174,7 +174,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
self._game_name_str = self._campaign.name + ':' + self._level_name
self._game_config_str = str(len(
- self._player_info)) + 'p' + self._campaign.get_level(
+ self._playerinfos)) + 'p' + self._campaign.get_level(
self._level_name).get_score_version_string().replace(' ', '_')
# If game-center/etc scores are available we show our friends'
@@ -580,12 +580,12 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
ba.timer(5.2, ba.Call(ba.playsound, self._dingsound))
offs_x = -195
- if len(self._player_info) > 1:
+ if len(self._playerinfos) > 1:
pstr = ba.Lstr(value='- ${A} -',
subs=[('${A}',
ba.Lstr(resource='multiPlayerCountText',
subs=[('${COUNT}',
- str(len(self._player_info)))
+ str(len(self._playerinfos)))
]))])
else:
pstr = ba.Lstr(value='- ${A} -',
@@ -636,7 +636,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
ba.pushcall(ba.WeakCall(self._show_fail))
self._name_str = name_str = ', '.join(
- [p.name for p in self._player_info])
+ [p.name for p in self._playerinfos])
if self._show_friend_scores:
self._friends_loading_status = Text(
@@ -662,10 +662,10 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
our_high_scores_all = self._campaign.get_level(
self._level_name).get_high_scores()
try:
- our_high_scores = our_high_scores_all[str(len(self._player_info)) +
+ our_high_scores = our_high_scores_all[str(len(self._playerinfos)) +
' Player']
except Exception:
- our_high_scores = our_high_scores_all[str(len(self._player_info)) +
+ our_high_scores = our_high_scores_all[str(len(self._playerinfos)) +
' Player'] = []
if self._score is not None:
@@ -674,7 +674,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
'players': [{
'name': p.name,
'character': p.character
- } for p in self._player_info]
+ } for p in self._playerinfos]
}
]
our_high_scores.append(our_score)
@@ -789,7 +789,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
v_offs_extra = 20
v_offs_names = 0
scale = 1.0
- p_count = len(self._player_info)
+ p_count = len(self._playerinfos)
h_offs_extra -= 75
if p_count > 1:
h_offs_extra -= 20
@@ -841,7 +841,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
position=(ts_h_offs + 35 + h_offs_extra,
v_offs_extra + ts_height / 2 + -ts_height *
(i + 1) / 10 + v_offs_names + v_offs + 11.0),
- maxwidth=80.0 + 100.0 * len(self._player_info),
+ maxwidth=80.0 + 100.0 * len(self._playerinfos),
v_align=Text.VAlign.CENTER,
color=color1,
flash=flash,
@@ -1086,7 +1086,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
h_offs_extra = 0
v_offs_names = 0
scale = 1.0
- p_count = len(self._player_info)
+ p_count = len(self._playerinfos)
if p_count > 1:
h_offs_extra -= 40
if self._score_type != 'points':
@@ -1146,7 +1146,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
position=(ts_h_offs + 35 + h_offs_extra,
ts_height / 2 + -ts_height * (i + 1) / 10 +
v_offs_names + v_offs + 11.0),
- maxwidth=80.0 + 100.0 * len(self._player_info),
+ maxwidth=80.0 + 100.0 * len(self._playerinfos),
v_align=Text.VAlign.CENTER,
color=color1,
flash=flash,
diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py
index eb354366..5c7e28cd 100644
--- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py
+++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py
@@ -103,7 +103,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
def _show_team_name(self, pos_v: float, team: ba.SessionTeam,
kill_delay: float, shiftdelay: float) -> None:
- del kill_delay # unused arg
+ del kill_delay # Unused arg.
ZoomText(ba.Lstr(value='${A}:', subs=[('${A}', team.name)]),
position=(100, pos_v),
shiftposition=(-150, pos_v),
@@ -115,9 +115,9 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
color=team.color,
jitter=1.0).autoretain()
- def _show_team_old_score(self, pos_v: float, team: ba.SessionTeam,
+ def _show_team_old_score(self, pos_v: float, sessionteam: ba.SessionTeam,
shiftdelay: float) -> None:
- ZoomText(str(team.sessiondata['score'] - 1),
+ ZoomText(str(sessionteam.customdata['score'] - 1),
position=(150, pos_v),
maxwidth=100,
color=(0.6, 0.6, 0.7),
@@ -129,11 +129,11 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
h_align='left',
jitter=1.0).autoretain()
- def _show_team_score(self, pos_v: float, team: ba.SessionTeam,
+ def _show_team_score(self, pos_v: float, sessionteam: ba.SessionTeam,
scored: bool, kill_delay: float,
shiftdelay: float) -> None:
- del kill_delay # unused arg
- ZoomText(str(team.sessiondata['score']),
+ del kill_delay # Unused arg.
+ ZoomText(str(sessionteam.customdata['score']),
position=(150, pos_v),
maxwidth=100,
color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7),
diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py
index e0bcf462..9e0de4e8 100644
--- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py
+++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py
@@ -28,7 +28,7 @@ import ba
from bastd.activity.multiteamscore import MultiTeamScoreScreenActivity
if TYPE_CHECKING:
- from typing import Any, Dict, Optional, Set
+ from typing import Any, Dict, Optional, Set, Tuple
class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
@@ -60,13 +60,17 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
player_order_prev = list(self.players)
player_order_prev.sort(
reverse=True,
- key=lambda p:
- (p.team.sessiondata['previous_score'], p.getname(full=True)))
+ key=lambda p: (
+ p.team.sessionteam.customdata['previous_score'],
+ p.getname(full=True),
+ ))
player_order = list(self.players)
player_order.sort(reverse=True,
- key=lambda p:
- (p.team.sessiondata['score'], p.team.sessiondata[
- 'score'], p.getname(full=True)))
+ key=lambda p: (
+ p.team.sessionteam.customdata['score'],
+ p.team.sessionteam.customdata['score'],
+ p.getname(full=True),
+ ))
v_offs = -74.0 + spacing * len(player_order_prev) * 0.5
delay1 = 1.3 + 0.1
@@ -202,8 +206,9 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
transtime2: ts_h_offs - (95.0 + slide_amt) * scale
}))
- s_txt = _scoretxt(str(player.team.sessiondata['previous_score']),
- 80, 0, False, 0, 1.0)
+ s_txt = _scoretxt(
+ str(player.team.sessionteam.customdata['previous_score']), 80,
+ 0, False, 0, 1.0)
ba.timer(
tdelay + delay2,
ba.WeakCall(
@@ -219,8 +224,9 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
transtime2: ts_h_offs + (80.0 - slide_amt) * scale
}))
- score_change = (player.team.sessiondata['score'] -
- player.team.sessiondata['previous_score'])
+ score_change = (
+ player.team.sessionteam.customdata['score'] -
+ player.team.sessionteam.customdata['previous_score'])
if score_change > 0:
xval = 113
yval = 3.0
@@ -257,12 +263,11 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
tdelay + delay1,
ba.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1)))
for j in range(score_change):
- ba.timer(
- (tdelay + delay1 + 0.15 * j),
- ba.Call(
- _safesetattr, s_txt.node, 'text',
- str(player.team.sessiondata['previous_score'] + j +
- 1)))
+ ba.timer((tdelay + delay1 + 0.15 * j),
+ ba.Call(
+ _safesetattr, s_txt.node, 'text',
+ str(player.team.sessionteam.
+ customdata['previous_score'] + j + 1)))
tfin = tdelay + delay1 + 0.15 * j
if tfin not in sound_times:
sound_times.add(tfin)
diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py
index 75bf8e64..77b2a5f9 100644
--- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py
+++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py
@@ -121,8 +121,8 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
# Results is already sorted; just convert it into a list of
# score-set-entries.
- for winner in results.get_winners():
- for team in winner.teams:
+ for winnergroup in results.winnergroups:
+ for team in winnergroup.teams:
if len(team.players) == 1:
player_entry = _get_player_score_set_entry(
team.players[0])
@@ -172,8 +172,8 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
_txt(180, 4, ba.Lstr(resource='killsText'))
_txt(280, 4, ba.Lstr(resource='deathsText'), maxwidth=100)
- score_name = 'Score' if results is None else results.get_score_name()
- translated = ba.Lstr(translate=('scoreNames', score_name))
+ score_label = 'Score' if results is None else results.score_label
+ translated = ba.Lstr(translate=('scoreNames', score_label))
_txt(390, 0, translated)
diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py
index 5742bedb..39f37f8c 100644
--- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py
+++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py
@@ -79,7 +79,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
for _pkey, prec in self.stats.get_records().items():
if prec.player.in_game:
player_entries.append(
- (prec.player.team.sessiondata['score'],
+ (prec.player.sessionteam.customdata['score'],
prec.getname(full=True), prec))
player_entries.sort(reverse=True, key=lambda x: x[0])
else:
@@ -145,8 +145,8 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
win_score = (session.get_series_length() - 1) // 2 + 1
lose_score = 0
for team in self.teams:
- if team.sessiondata['score'] != win_score:
- lose_score = team.sessiondata['score']
+ if team.sessionteam.customdata['score'] != win_score:
+ lose_score = team.sessionteam.customdata['score']
if not self._is_ffa:
Text(ba.Lstr(resource='gamesToText',
@@ -309,7 +309,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
for _score, name, prec in player_entries:
tdelay -= 4 * t_incr
v_offs -= 40
- Text(str(prec.team.sessiondata['score'])
+ Text(str(prec.team.customdata['score'])
if self._is_ffa else str(prec.score),
color=(0.5, 0.5, 0.5, 1.0),
position=(ts_h_offs + 230, ts_height / 2 + v_offs),
diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py
index 9682bb98..6a7deb5e 100644
--- a/assets/src/ba_data/python/bastd/actor/respawnicon.py
+++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py
@@ -39,6 +39,9 @@ class RespawnIcon:
This is used to indicate that a ba.Player is waiting to respawn.
"""
+ _MASKTEXSTORENAME = ba.storagename('masktex')
+ _ICONSSTORENAME = ba.storagename('icons')
+
def __init__(self, player: ba.Player, respawn_time: float):
"""Instantiate with a ba.Player and respawn_time (in seconds)."""
self._visible = True
@@ -46,10 +49,10 @@ class RespawnIcon:
on_right, offs_extra, respawn_icons = self._get_context(player)
# Cache our mask tex on the team for easy access.
- mask_tex = player.team.gamedata.get('_spaz_respawn_icons_mask_tex')
+ mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME)
if mask_tex is None:
mask_tex = ba.gettexture('characterIconMask')
- player.team.gamedata['_spaz_respawn_icons_mask_tex'] = mask_tex
+ player.team.customdata[self._MASKTEXSTORENAME] = mask_tex
assert isinstance(mask_tex, ba.Texture)
# Now find the first unused slot and use that.
@@ -139,9 +142,9 @@ class RespawnIcon:
on_right = player.team.id % 2 == 1
# Store a list of icons in the team.
- icons = player.team.gamedata.get('_spaz_respawn_icons')
+ icons = player.team.customdata.get(self._ICONSSTORENAME)
if icons is None:
- player.team.gamedata['_spaz_respawn_icons'] = icons = {}
+ player.team.customdata[self._ICONSSTORENAME] = icons = {}
assert isinstance(icons, dict)
offs_extra = -20
@@ -149,9 +152,9 @@ class RespawnIcon:
on_right = False
# Store a list of icons in the activity.
- icons = activity.gamedata.get('_spaz_respawn_icons')
+ icons = activity.customdata.get(self._ICONSSTORENAME)
if icons is None:
- activity.gamedata['_spaz_respawn_icons'] = icons = {}
+ activity.customdata[self._ICONSSTORENAME] = icons = {}
assert isinstance(icons, dict)
if isinstance(activity.session, ba.FreeForAllSession):
diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py
index 16431102..448cd89a 100644
--- a/assets/src/ba_data/python/bastd/actor/scoreboard.py
+++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py
@@ -343,6 +343,8 @@ class Scoreboard:
category: Gameplay Classes
"""
+ _STORENAME = ba.storagename('entry')
+
def __init__(self, label: ba.Lstr = None, score_split: float = 0.7):
"""Instantiate a scoreboard.
@@ -382,8 +384,8 @@ class Scoreboard:
# Create a proxy in the team which will kill
# our entry when it dies (for convenience)
- assert '_scoreboard_entry' not in team.gamedata
- team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team)
+ assert self._STORENAME not in team.customdata
+ team.customdata[self._STORENAME] = _EntryProxy(self, team)
# Now set the entry.
self._entries[team.id].set_value(score=score,
diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py
index 744484d9..8ae90f0c 100644
--- a/assets/src/ba_data/python/bastd/game/conquest.py
+++ b/assets/src/ba_data/python/bastd/game/conquest.py
@@ -61,23 +61,25 @@ class ConquestFlag(Flag):
class Player(ba.Player['Team']):
"""Our player type for this game."""
+ # FIXME: We shouldn't be using customdata here
+ # (but need to update respawn funcs accordingly first).
@property
def respawn_timer(self) -> Optional[ba.Timer]:
"""Type safe access to standard respawn timer."""
- return self.gamedata.get('respawn_timer', None)
+ return self.customdata.get('respawn_timer', None)
@respawn_timer.setter
def respawn_timer(self, value: Optional[ba.Timer]) -> None:
- self.gamedata['respawn_timer'] = value
+ self.customdata['respawn_timer'] = value
@property
def respawn_icon(self) -> Optional[RespawnIcon]:
"""Type safe access to standard respawn icon."""
- return self.gamedata.get('respawn_icon', None)
+ return self.customdata.get('respawn_icon', None)
@respawn_icon.setter
def respawn_icon(self, value: Optional[RespawnIcon]) -> None:
- self.gamedata['respawn_icon'] = value
+ self.customdata['respawn_icon'] = value
class Team(ba.Team[Player]):
diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py
index c29301c4..bef86f60 100644
--- a/assets/src/ba_data/python/bastd/game/easteregghunt.py
+++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py
@@ -203,8 +203,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
# Respawn them shortly.
player = msg.getplayer(Player)
- assert self.initial_player_info is not None
- respawn_time = 2.0 + len(self.initial_player_info) * 1.0
+ assert self.initialplayerinfos is not None
+ respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0
player.respawn_timer = ba.Timer(
respawn_time, ba.Call(self.spawn_player_if_exists, player))
player.respawn_icon = RespawnIcon(player, respawn_time)
diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py
index 111ad9e3..e8c03711 100644
--- a/assets/src/ba_data/python/bastd/game/football.py
+++ b/assets/src/ba_data/python/bastd/game/football.py
@@ -441,7 +441,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
if ba.app.kiosk_mode:
controlsguide.ControlsGuide(delay=3.0, lifespan=10.0,
bright=True).autoretain()
- assert self.initial_player_info is not None
+ assert self.initialplayerinfos is not None
abot: Type[SpazBot]
bbot: Type[SpazBot]
cbot: Type[SpazBot]
@@ -450,36 +450,36 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
self._have_tnt = False
abot = (BrawlerBotLite
if self._preset == 'rookie_easy' else BrawlerBot)
- self._bot_types_initial = [abot] * len(self.initial_player_info)
+ self._bot_types_initial = [abot] * len(self.initialplayerinfos)
bbot = (BomberBotLite
if self._preset == 'rookie_easy' else BomberBot)
self._bot_types_7 = (
- [bbot] * (1 if len(self.initial_player_info) < 3 else 2))
+ [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
cbot = (BomberBot if self._preset == 'rookie_easy' else TriggerBot)
self._bot_types_14 = (
- [cbot] * (1 if len(self.initial_player_info) < 3 else 2))
+ [cbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
elif self._preset == 'tournament':
self._exclude_powerups = []
self._have_tnt = True
self._bot_types_initial = (
- [BrawlerBot] * (1 if len(self.initial_player_info) < 2 else 2))
+ [BrawlerBot] * (1 if len(self.initialplayerinfos) < 2 else 2))
self._bot_types_7 = (
- [TriggerBot] * (1 if len(self.initial_player_info) < 3 else 2))
+ [TriggerBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
self._bot_types_14 = (
- [ChargerBot] * (1 if len(self.initial_player_info) < 4 else 2))
+ [ChargerBot] * (1 if len(self.initialplayerinfos) < 4 else 2))
elif self._preset in ['pro', 'pro_easy', 'tournament_pro']:
self._exclude_powerups = ['curse']
self._have_tnt = True
self._bot_types_initial = [ChargerBot] * len(
- self.initial_player_info)
+ self.initialplayerinfos)
abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite)
typed_bot_list: List[Type[SpazBot]] = []
self._bot_types_7 = (
typed_bot_list + [abot] + [BomberBot] *
- (1 if len(self.initial_player_info) < 3 else 2))
+ (1 if len(self.initialplayerinfos) < 3 else 2))
bbot = (TriggerBotPro if self._preset == 'pro' else TriggerBot)
self._bot_types_14 = (
- [bbot] * (1 if len(self.initial_player_info) < 3 else 2))
+ [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
elif self._preset in ['uber', 'uber_easy']:
self._exclude_powerups = []
self._have_tnt = True
@@ -487,12 +487,11 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
bbot = (TriggerBotPro if self._preset == 'uber' else TriggerBot)
typed_bot_list_2: List[Type[SpazBot]] = []
self._bot_types_initial = (typed_bot_list_2 + [StickyBot] +
- [abot] * len(self.initial_player_info))
+ [abot] * len(self.initialplayerinfos))
self._bot_types_7 = (
- [bbot] * (1 if len(self.initial_player_info) < 3 else 2))
+ [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2))
self._bot_types_14 = (
- [ExplodeyBot] *
- (1 if len(self.initial_player_info) < 3 else 2))
+ [ExplodeyBot] * (1 if len(self.initialplayerinfos) < 3 else 2))
else:
raise Exception()
@@ -794,7 +793,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
'outcome': outcome,
'score': scoreval,
'score_order': 'decreasing',
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
})
def handlemessage(self, msg: Any) -> Any:
@@ -805,8 +804,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
# Respawn them shortly.
player = msg.getplayer(Player)
- assert self.initial_player_info is not None
- respawn_time = 2.0 + len(self.initial_player_info) * 1.0
+ assert self.initialplayerinfos is not None
+ respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0
player.respawn_timer = ba.Timer(
respawn_time, ba.Call(self.spawn_player_if_exists, player))
player.respawn_icon = RespawnIcon(player, respawn_time)
diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py
index aa940744..56c04457 100644
--- a/assets/src/ba_data/python/bastd/game/kingofthehill.py
+++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py
@@ -154,7 +154,6 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
ba.timer(1.0, self._tick, repeat=True)
self._flag_state = FlagState.NEW
Flag.project_stand(self._flag_pos)
-
self._flag = Flag(position=self._flag_pos,
touchable=False,
color=(1, 1, 1))
diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py
index 42e73e51..72e15581 100644
--- a/assets/src/ba_data/python/bastd/game/ninjafight.py
+++ b/assets/src/ba_data/python/bastd/game/ninjafight.py
@@ -113,12 +113,12 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
ChargerBot, pos=(-5, 3, -2), spawn_time=3.0))
# Add some extras for multiplayer or pro mode.
- assert self.initial_player_info is not None
- if len(self.initial_player_info) > 2 or is_pro:
+ assert self.initialplayerinfos is not None
+ if len(self.initialplayerinfos) > 2 or is_pro:
ba.timer(
5.0, lambda: self._bots.spawn_bot(
ChargerBot, pos=(0, 3, -5), spawn_time=3.0))
- if len(self.initial_player_info) > 3 or is_pro:
+ if len(self.initialplayerinfos) > 3 or is_pro:
ba.timer(
6.0, lambda: self._bots.spawn_bot(
ChargerBot, pos=(0, 3, 1), spawn_time=3.0))
diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py
index e08d0d78..430a7251 100644
--- a/assets/src/ba_data/python/bastd/game/onslaught.py
+++ b/assets/src/ba_data/python/bastd/game/onslaught.py
@@ -757,7 +757,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
'outcome': outcome,
'score': score,
'fail_message': fail_message,
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
},
delay=delay)
@@ -844,10 +844,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
for player in self.players:
try:
if player.is_alive():
- assert self.initial_player_info is not None
+ assert self.initialplayerinfos is not None
self.stats.player_scored(
player,
- int(100 / len(self.initial_player_info)),
+ int(100 / len(self.initialplayerinfos)),
scale=1.4,
color=(0.6, 0.6, 1.0, 1.0),
title=ba.Lstr(resource='completionBonusText'),
diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py
index c303f557..d4b1b6cb 100644
--- a/assets/src/ba_data/python/bastd/game/runaround.py
+++ b/assets/src/ba_data/python/bastd/game/runaround.py
@@ -563,7 +563,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
'outcome': outcome,
'score': score,
'fail_message': fail_message,
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
})
def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None:
@@ -1118,8 +1118,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
# Respawn them shortly.
player = msg.getplayer(Player)
- assert self.initial_player_info is not None
- respawn_time = 2.0 + len(self.initial_player_info) * 1.0
+ assert self.initialplayerinfos is not None
+ respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0
player.respawn_timer = ba.Timer(
respawn_time, ba.Call(self.spawn_player_if_exists, player))
player.respawn_icon = RespawnIcon(player, respawn_time)
diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py
index 20c4b626..77c74e81 100644
--- a/assets/src/ba_data/python/bastd/game/thelaststand.py
+++ b/assets/src/ba_data/python/bastd/game/thelaststand.py
@@ -196,7 +196,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
results={
'outcome': outcome,
'score': self._score,
- 'player_info': self.initial_player_info
+ 'playerinfos': self.initialplayerinfos
})
def _update_bots(self) -> None:
diff --git a/docs/ba_module.md b/docs/ba_module.md
index 34fb6596..af2783a2 100644
--- a/docs/ba_module.md
+++ b/docs/ba_module.md
@@ -1,5 +1,5 @@
-
last updated on 2020-06-01 for Ballistica version 1.5.0 build 20039
+last updated on 2020-06-02 for Ballistica version 1.5.0 build 20041
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 let me know. Happy modding!
@@ -92,6 +92,7 @@
ba.screenmessage()
ba.set_analytics_screen()
ba.setlanguage()
+ ba.storagename()
ba.time()
ba.timer()
ba.timestring()
@@ -343,8 +344,16 @@ actually award achievements.
can overlap during transitions.
Attributes:
-
+
+-
+
dict
+Entities needing to store simple data with an activity can put it
+ here. This dict will be deleted when the activity expires, so contained
+ objects generally do not need to worry about handling expired
+ activities.
+
+
-
bool
Whether the activity is expired.
@@ -353,14 +362,6 @@ actually award achievements.
At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.
-
--
-
dict
-Entities needing to store simple data with an activity can put it
- here. This dict will be deleted when the activity expires, so contained
- objects generally do not need to worry about handling expired
- activities.
-
-
ba.Node
@@ -1552,8 +1553,16 @@ start_long_action(callback_when_done=ba.ContextC
Attributes Inherited:
Attributes Defined Here:
-
+
+-
+
dict
+Entities needing to store simple data with an activity can put it
+ here. This dict will be deleted when the activity expires, so contained
+ objects generally do not need to worry about handling expired
+ activities.
+
+
-
bool
Whether the activity is expired.
@@ -1562,14 +1571,6 @@ start_long_action(callback_when_done=ba.ContextC
At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.
-
--
-
dict
-Entities needing to store simple data with an activity can put it
- here. This dict will be deleted when the activity expires, so contained
- objects generally do not need to worry about handling expired
- activities.
-
-
ba.Node
@@ -2145,8 +2146,16 @@ its time with lingering corpses, sound effects, etc.
Attributes Inherited:
Attributes Defined Here:
-
+
+-
+
dict
+Entities needing to store simple data with an activity can put it
+ here. This dict will be deleted when the activity expires, so contained
+ objects generally do not need to worry about handling expired
+ activities.
+
+
-
bool
Whether the activity is expired.
@@ -2155,14 +2164,6 @@ its time with lingering corpses, sound effects, etc.
At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.
-
--
-
dict
-Entities needing to store simple data with an activity can put it
- here. This dict will be deleted when the activity expires, so contained
- objects generally do not need to worry about handling expired
- activities.
-
-
ba.Node
@@ -3871,14 +3872,14 @@ even if myactor is set to None.
own custom ba.Player types.
Attributes:
-
+
-
Optional[ba.Actor]
The ba.Actor associated with the player.
--
+
-
dict
Arbitrary values associated with the player.
Though it is encouraged that most player values be properly defined
@@ -4111,9 +4112,9 @@ the type-checker properly identifies the returned value as one.
-
-
associate_with_player(self, player: ba.SessionPlayer) -> None
+associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None
-Associate this entry with a ba.Player.
+Associate this entry with a ba.SessionPlayer.
-
@@ -4556,7 +4557,7 @@ that a SessionPlayer is still present if retaining references to one
for any length of time.
Attributes:
-
+
-
str
@@ -4602,14 +4603,7 @@ any lobby character/team selection.
The input device associated with the player.
--
-
Dict
-A dict for use by the current ba.Session for
-storing data associated with this player.
-This persists for the duration of the session.
-
-
--
+
-
ba.SessionTeam
The ba.SessionTeam this Player is on. If the SessionPlayer
is still in its lobby selecting a team/etc. then a
@@ -4708,18 +4702,19 @@ other players.
each SessionTeam consists of just one SessionPlayer.
Attributes:
-
+
-
Tuple[float, ...]
The team's color.
--
-
Dict
-A dict for use by the current ba.Activity
-for storing data associated with this team.
-This gets cleared for each new ba.Activity.
+ -
+
dict
+A dict for use by the current ba.Session for
+storing data associated with this team.
+Unlike customdata, this persists for the duration
+of the session.
-
@@ -4736,14 +4731,6 @@ This gets cleared for each new ba.Activity.
List[ba.SessionPlayer]
The list of ba.SessionPlayers on the team.
-
--
-
Dict
-A dict for use by the current ba.Session for
-storing data associated with this team.
-Unlike gamedata, this persists for the duration
-of the session.
-
Methods:
@@ -4952,7 +4939,7 @@ of the session.
Methods:
-
+
-
ba.Stats()
@@ -4971,12 +4958,6 @@ of the session.
May return None.
-
--
-
player_got_hit(self, player: ba.SessionPlayer) -> None
-
-Call this when a player got hit.
-
-
player_scored(self, player: ba.Player, base_points: int = 1, target: Sequence[float] = None, kill: bool = False, victim_player: ba.Player = None, scale: float = 1.0, color: Sequence[float] = None, title: Union[str, ba.Lstr] = None, screenmessage: bool = True, display: bool = True, importance: int = 1, showpoints: bool = True, big_message: bool = False) -> int
@@ -5029,9 +5010,9 @@ of the session.
Attributes:
-
+
--
+
-
dict
Arbitrary values associated with the team.
Though it is encouraged that most player values be properly defined
@@ -5080,8 +5061,16 @@ of the session.
Attributes Inherited:
Attributes Defined Here:
-
+
+-
+
dict
+Entities needing to store simple data with an activity can put it
+ here. This dict will be deleted when the activity expires, so contained
+ objects generally do not need to worry about handling expired
+ activities.
+
+
-
bool
Whether the activity is expired.
@@ -5090,14 +5079,6 @@ of the session.
At this point no new nodes, timers, etc should be made,
run, etc, and the activity should be considered a 'zombie'.
-
--
-
dict
-Entities needing to store simple data with an activity can put it
- here. This dict will be deleted when the activity expires, so contained
- objects generally do not need to worry about handling expired
- activities.
-
-
ba.Node
@@ -5208,43 +5189,58 @@ Results for a completed ba.TeamGameActivity
Upon completion, a game should fill one of these out and pass it to its
ba.Activity.end() call.
+Attributes:
+
+
+-
+
bool
+Whether lower scores are better.
+
+
+-
+
List[ba.PlayerInfo]
+Get info about the players represented by the results.
+
+
+-
+
str
+The label associated with scores ('points', etc).
+
+
+-
+
ba.ScoreType
+The type of score.
+
+
+-
+
List[ba.SessionTeam]
+Return all ba.SessionTeams in the results.
+
+
+-
+
List[WinnerGroup]
+Get an ordered list of winner groups.
+
+
+-
+
Optional[ba.SessionTeam]
+The winning ba.SessionTeam if there is exactly one, or else None.
+
+
+
Methods:
-
+
-
ba.TeamGameResults()
Instantiate a results instance.
-
--
-
get_lower_is_better(self) -> bool
-
-Return whether lower scores are better.
-
-
--
-
get_player_info(self) -> List[ba.PlayerInfo]
-
-Get info about the players represented by the results.
-
-
--
-
get_score_name(self) -> str
-
-Get the name associated with scores ('points', etc).
-
-
--
-
get_score_type(self) -> ba.ScoreType
-
-Get the type of score.
-
-
-
get_team_score(self, team: Union[ba.SessionTeam, ba.Team]) -> Optional[int]
+get_team_score(self, sessionteam: Union[ba.SessionTeam]) -> Optional[int]
-Return the score for a given team.
+Return the score for a given ba.SessionTeam.
-
@@ -5254,24 +5250,6 @@ Results for a completed ba.TeamGameActivity
(properly formatted for the score type.)
-
--
-
get_teams(self) -> List[ba.SessionTeam]
-
-Return all ba.SessionTeams in the results.
-
-
--
-
get_winners(self) -> List[WinnerGroup]
-
-Get an ordered list of winner groups.
-
-
--
-
get_winning_team(self) -> Optional[ba.SessionTeam]
-
-Get the winning ba.Team if there is exactly one; None otherwise.
-
-
has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool
@@ -5286,7 +5264,7 @@ Results for a completed ba.TeamGameActivity
-
-
set_team_score(self, team: Union[ba.SessionTeam, ba.Team], score: Optional[int]) -> None
+set_team_score(self, team: ba.Team, score: Optional[int]) -> None
Set the score for a given ba.Team.
@@ -6422,6 +6400,30 @@ playing, the playing track will not be restarted.
Category: Gameplay Functions
+
+storagename(basename: str) -> str
+
+Generate a (hopefully) unique name for storing things in public places.
+
+Category: General Utility Functions
+
+This consists of a leading underscore, the module path at the
+call site with dots replaced by underscores, the class name, and
+the provided suffix. When storing data in public places such as
+'customdata' dicts, this minimizes the chance of collisions if a
+module or class is duplicated or renamed.
+
+# Example: generate a unique name for storage purposes:
+class MyThingie:
+
+ # This will give something like '_mymodule_submodule_mythingie_data'.
+ _STORENAME = ba.storagename('data')
+
+ def __init__(self, activity):
+ # Store some data in the Activity we were passed
+ activity.customdata[self._STORENAME] = {}
+
textwidget(edit: Widget = None, parent: Widget = None,