mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-03 22:14:45 +08:00
More type safety and simplifying
This commit is contained in:
parent
ae0c9dde20
commit
24f2792234
@ -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"
|
||||
}
|
||||
16
.idea/dictionaries/ericf.xml
generated
16
.idea/dictionaries/ericf.xml
generated
@ -398,6 +398,7 @@
|
||||
<w>curstate</w>
|
||||
<w>curtime</w>
|
||||
<w>curtimestr</w>
|
||||
<w>customdata</w>
|
||||
<w>customizebrowser</w>
|
||||
<w>cutscenes</w>
|
||||
<w>cval</w>
|
||||
@ -604,6 +605,7 @@
|
||||
<w>factoryclass</w>
|
||||
<w>fallbacks</w>
|
||||
<w>farthestpt</w>
|
||||
<w>fback</w>
|
||||
<w>fbase</w>
|
||||
<w>fclose</w>
|
||||
<w>fcmd</w>
|
||||
@ -874,6 +876,7 @@
|
||||
<w>icns</w>
|
||||
<w>iconpicker</w>
|
||||
<w>iconscale</w>
|
||||
<w>iconsstorename</w>
|
||||
<w>ident</w>
|
||||
<w>idevices</w>
|
||||
<w>ifeq</w>
|
||||
@ -910,6 +913,7 @@
|
||||
<w>infotextcolor</w>
|
||||
<w>inidividual</w>
|
||||
<w>initializers</w>
|
||||
<w>initialplayerinfos</w>
|
||||
<w>initing</w>
|
||||
<w>inits</w>
|
||||
<w>inmobi</w>
|
||||
@ -1110,6 +1114,8 @@
|
||||
<w>mapselect</w>
|
||||
<w>maptype</w>
|
||||
<w>markupbase</w>
|
||||
<w>masktex</w>
|
||||
<w>masktexstorename</w>
|
||||
<w>mathmodule</w>
|
||||
<w>mathnode</w>
|
||||
<w>mathutils</w>
|
||||
@ -1163,6 +1169,7 @@
|
||||
<w>moduledir</w>
|
||||
<w>modulefinder</w>
|
||||
<w>modulename</w>
|
||||
<w>modulepath</w>
|
||||
<w>modutils</w>
|
||||
<w>moola</w>
|
||||
<w>mopaque</w>
|
||||
@ -1204,6 +1211,7 @@
|
||||
<w>myhome</w>
|
||||
<w>myinput</w>
|
||||
<w>mylist</w>
|
||||
<w>mymodule</w>
|
||||
<w>mynode</w>
|
||||
<w>myobj</w>
|
||||
<w>myprojname</w>
|
||||
@ -1214,6 +1222,7 @@
|
||||
<w>mypytype</w>
|
||||
<w>mysound</w>
|
||||
<w>mytextnode</w>
|
||||
<w>mythingie</w>
|
||||
<w>myweakcall</w>
|
||||
<w>mywidget</w>
|
||||
<w>namedarg</w>
|
||||
@ -1360,6 +1369,7 @@
|
||||
<w>pkgutil</w>
|
||||
<w>playercast</w>
|
||||
<w>playerdata</w>
|
||||
<w>playerinfos</w>
|
||||
<w>playerlostspaz</w>
|
||||
<w>playernode</w>
|
||||
<w>playerpt</w>
|
||||
@ -1533,6 +1543,7 @@
|
||||
<w>qrcode</w>
|
||||
<w>qrencode</w>
|
||||
<w>qual</w>
|
||||
<w>qualname</w>
|
||||
<w>quoprimime</w>
|
||||
<w>rando</w>
|
||||
<w>randommodule</w>
|
||||
@ -1786,8 +1797,10 @@
|
||||
<w>steelseries</w>
|
||||
<w>stickman</w>
|
||||
<w>storable</w>
|
||||
<w>storagename</w>
|
||||
<w>storedhash</w>
|
||||
<w>storeitemui</w>
|
||||
<w>storename</w>
|
||||
<w>strftime</w>
|
||||
<w>stringprep</w>
|
||||
<w>stringptr</w>
|
||||
@ -1913,6 +1926,7 @@
|
||||
<w>thanvannispen</w>
|
||||
<w>thelaststand</w>
|
||||
<w>themself</w>
|
||||
<w>thingie</w>
|
||||
<w>threadtype</w>
|
||||
<w>throwiness</w>
|
||||
<w>timedisplay</w>
|
||||
@ -2095,6 +2109,8 @@
|
||||
<w>willeval</w>
|
||||
<w>wincfg</w>
|
||||
<w>wincount</w>
|
||||
<w>winnergroup</w>
|
||||
<w>winnergroups</w>
|
||||
<w>winplt</w>
|
||||
<w>winprj</w>
|
||||
<w>winref</w>
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}))
|
||||
|
||||
@ -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]}))
|
||||
|
||||
@ -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:
|
||||
"""
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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('.', '_')
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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}.')
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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]):
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-06-01 for Ballistica version 1.5.0 build 20039</em></h4>
|
||||
<h4><em>last updated on 2020-06-02 for Ballistica version 1.5.0 build 20041</em></h4>
|
||||
<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>
|
||||
<hr>
|
||||
@ -92,6 +92,7 @@
|
||||
<li><a href="#function_ba_screenmessage">ba.screenmessage()</a></li>
|
||||
<li><a href="#function_ba_set_analytics_screen">ba.set_analytics_screen()</a></li>
|
||||
<li><a href="#function_ba_setlanguage">ba.setlanguage()</a></li>
|
||||
<li><a href="#function_ba_storagename">ba.storagename()</a></li>
|
||||
<li><a href="#function_ba_time">ba.time()</a></li>
|
||||
<li><a href="#function_ba_timer">ba.timer()</a></li>
|
||||
<li><a href="#function_ba_timestring">ba.timestring()</a></li>
|
||||
@ -343,8 +344,16 @@ actually award achievements.</p>
|
||||
can overlap during transitions.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_Activity__expired">expired</a>, <a href="#attr_ba_Activity__gamedata">gamedata</a>, <a href="#attr_ba_Activity__globalsnode">globalsnode</a>, <a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__playertype">playertype</a>, <a href="#attr_ba_Activity__session">session</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__stats">stats</a>, <a href="#attr_ba_Activity__teams">teams</a>, <a href="#attr_ba_Activity__teamtype">teamtype</a></h5>
|
||||
<h5><a href="#attr_ba_Activity__customdata">customdata</a>, <a href="#attr_ba_Activity__expired">expired</a>, <a href="#attr_ba_Activity__globalsnode">globalsnode</a>, <a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__playertype">playertype</a>, <a href="#attr_ba_Activity__session">session</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__stats">stats</a>, <a href="#attr_ba_Activity__teams">teams</a>, <a href="#attr_ba_Activity__teamtype">teamtype</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_Activity__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Activity__expired">expired</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether the activity is expired.</p>
|
||||
@ -353,14 +362,6 @@ actually award achievements.</p>
|
||||
At this point no new nodes, timers, etc should be made,
|
||||
run, etc, and the activity should be considered a 'zombie'.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Activity__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Activity__globalsnode">globalsnode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
@ -1552,8 +1553,16 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
|
||||
<h3>Attributes Defined Here:</h3>
|
||||
<h5><a href="#attr_ba_CoopGameActivity__expired">expired</a>, <a href="#attr_ba_CoopGameActivity__gamedata">gamedata</a>, <a href="#attr_ba_CoopGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_CoopGameActivity__map">map</a>, <a href="#attr_ba_CoopGameActivity__playertype">playertype</a>, <a href="#attr_ba_CoopGameActivity__session">session</a>, <a href="#attr_ba_CoopGameActivity__stats">stats</a>, <a href="#attr_ba_CoopGameActivity__teamtype">teamtype</a></h5>
|
||||
<h5><a href="#attr_ba_CoopGameActivity__customdata">customdata</a>, <a href="#attr_ba_CoopGameActivity__expired">expired</a>, <a href="#attr_ba_CoopGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_CoopGameActivity__map">map</a>, <a href="#attr_ba_CoopGameActivity__playertype">playertype</a>, <a href="#attr_ba_CoopGameActivity__session">session</a>, <a href="#attr_ba_CoopGameActivity__stats">stats</a>, <a href="#attr_ba_CoopGameActivity__teamtype">teamtype</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_CoopGameActivity__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_CoopGameActivity__expired">expired</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether the activity is expired.</p>
|
||||
@ -1562,14 +1571,6 @@ start_long_action(callback_when_done=<a href="#class_ba_ContextCall">ba.ContextC
|
||||
At this point no new nodes, timers, etc should be made,
|
||||
run, etc, and the activity should be considered a 'zombie'.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_CoopGameActivity__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_CoopGameActivity__globalsnode">globalsnode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
@ -2145,8 +2146,16 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
|
||||
<h3>Attributes Defined Here:</h3>
|
||||
<h5><a href="#attr_ba_GameActivity__expired">expired</a>, <a href="#attr_ba_GameActivity__gamedata">gamedata</a>, <a href="#attr_ba_GameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_GameActivity__map">map</a>, <a href="#attr_ba_GameActivity__playertype">playertype</a>, <a href="#attr_ba_GameActivity__session">session</a>, <a href="#attr_ba_GameActivity__stats">stats</a>, <a href="#attr_ba_GameActivity__teamtype">teamtype</a></h5>
|
||||
<h5><a href="#attr_ba_GameActivity__customdata">customdata</a>, <a href="#attr_ba_GameActivity__expired">expired</a>, <a href="#attr_ba_GameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_GameActivity__map">map</a>, <a href="#attr_ba_GameActivity__playertype">playertype</a>, <a href="#attr_ba_GameActivity__session">session</a>, <a href="#attr_ba_GameActivity__stats">stats</a>, <a href="#attr_ba_GameActivity__teamtype">teamtype</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_GameActivity__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_GameActivity__expired">expired</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether the activity is expired.</p>
|
||||
@ -2155,14 +2164,6 @@ its time with lingering corpses, sound effects, etc.</p>
|
||||
At this point no new nodes, timers, etc should be made,
|
||||
run, etc, and the activity should be considered a 'zombie'.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_GameActivity__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_GameActivity__globalsnode">globalsnode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
@ -3871,14 +3872,14 @@ even if myactor is set to None.</p>
|
||||
own custom <a href="#class_ba_Player">ba.Player</a> types.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_Player__actor">actor</a>, <a href="#attr_ba_Player__gamedata">gamedata</a>, <a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__position">position</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a>, <a href="#attr_ba_Player__team">team</a></h5>
|
||||
<h5><a href="#attr_ba_Player__actor">actor</a>, <a href="#attr_ba_Player__customdata">customdata</a>, <a href="#attr_ba_Player__node">node</a>, <a href="#attr_ba_Player__position">position</a>, <a href="#attr_ba_Player__sessionplayer">sessionplayer</a>, <a href="#attr_ba_Player__team">team</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_Player__actor">actor</a></h4></dt><dd>
|
||||
<p><span>Optional[<a href="#class_ba_Actor">ba.Actor</a>]</span></p>
|
||||
<p>The <a href="#class_ba_Actor">ba.Actor</a> associated with the player.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_Player__gamedata">gamedata</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_Player__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerRecord__associate_with_player">associate_with_player()</a></dt></h4><dd>
|
||||
<p><span>associate_with_player(self, player: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -> None</span></p>
|
||||
<p><span>associate_with_player(self, sessionplayer: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -> None</span></p>
|
||||
|
||||
<p>Associate this entry with a <a href="#class_ba_Player">ba.Player</a>.</p>
|
||||
<p>Associate this entry with a <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_PlayerRecord__cancel_multi_kill_timer">cancel_multi_kill_timer()</a></dt></h4><dd>
|
||||
@ -4556,7 +4557,7 @@ that a SessionPlayer is still present if retaining references to one
|
||||
for any length of time.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_SessionPlayer__character">character</a>, <a href="#attr_ba_SessionPlayer__color">color</a>, <a href="#attr_ba_SessionPlayer__gameplayer">gameplayer</a>, <a href="#attr_ba_SessionPlayer__highlight">highlight</a>, <a href="#attr_ba_SessionPlayer__id">id</a>, <a href="#attr_ba_SessionPlayer__in_game">in_game</a>, <a href="#attr_ba_SessionPlayer__inputdevice">inputdevice</a>, <a href="#attr_ba_SessionPlayer__sessiondata">sessiondata</a>, <a href="#attr_ba_SessionPlayer__team">team</a></h5>
|
||||
<h5><a href="#attr_ba_SessionPlayer__character">character</a>, <a href="#attr_ba_SessionPlayer__color">color</a>, <a href="#attr_ba_SessionPlayer__gameplayer">gameplayer</a>, <a href="#attr_ba_SessionPlayer__highlight">highlight</a>, <a href="#attr_ba_SessionPlayer__id">id</a>, <a href="#attr_ba_SessionPlayer__in_game">in_game</a>, <a href="#attr_ba_SessionPlayer__inputdevice">inputdevice</a>, <a href="#attr_ba_SessionPlayer__sessionteam">sessionteam</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__character">character</a></h4></dt><dd>
|
||||
<p><span> str</span></p>
|
||||
@ -4602,14 +4603,7 @@ any lobby character/team selection.</p>
|
||||
<p>The input device associated with the player.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__sessiondata">sessiondata</a></h4></dt><dd>
|
||||
<p><span> Dict</span></p>
|
||||
<p>A dict for use by the current <a href="#class_ba_Session">ba.Session</a> for
|
||||
storing data associated with this player.
|
||||
This persists for the duration of the session.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__team">team</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_SessionPlayer__sessionteam">sessionteam</a></h4></dt><dd>
|
||||
<p><span> <a href="#class_ba_SessionTeam">ba.SessionTeam</a></span></p>
|
||||
<p>The <a href="#class_ba_SessionTeam">ba.SessionTeam</a> this Player is on. If the SessionPlayer
|
||||
is still in its lobby selecting a team/etc. then a
|
||||
@ -4708,18 +4702,19 @@ other players.</p>
|
||||
each SessionTeam consists of just one SessionPlayer.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_SessionTeam__color">color</a>, <a href="#attr_ba_SessionTeam__gamedata">gamedata</a>, <a href="#attr_ba_SessionTeam__id">id</a>, <a href="#attr_ba_SessionTeam__name">name</a>, <a href="#attr_ba_SessionTeam__players">players</a>, <a href="#attr_ba_SessionTeam__sessiondata">sessiondata</a></h5>
|
||||
<h5><a href="#attr_ba_SessionTeam__color">color</a>, <a href="#attr_ba_SessionTeam__customdata">customdata</a>, <a href="#attr_ba_SessionTeam__id">id</a>, <a href="#attr_ba_SessionTeam__name">name</a>, <a href="#attr_ba_SessionTeam__players">players</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_SessionTeam__color">color</a></h4></dt><dd>
|
||||
<p><span>Tuple[float, ...]</span></p>
|
||||
<p>The team's color.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionTeam__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span>Dict</span></p>
|
||||
<p>A dict for use by the current <a href="#class_ba_Activity">ba.Activity</a>
|
||||
for storing data associated with this team.
|
||||
This gets cleared for each new <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
<dt><h4><a name="attr_ba_SessionTeam__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>A dict for use by the current <a href="#class_ba_Session">ba.Session</a> for
|
||||
storing data associated with this team.
|
||||
Unlike customdata, this persists for the duration
|
||||
of the session.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionTeam__id">id</a></h4></dt><dd>
|
||||
@ -4736,14 +4731,6 @@ This gets cleared for each new <a href="#class_ba_Activity">ba.Activity</a>.</p>
|
||||
<p><span>List[<a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>]</span></p>
|
||||
<p>The list of <a href="#class_ba_SessionPlayer">ba.SessionPlayers</a> on the team.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_SessionTeam__sessiondata">sessiondata</a></h4></dt><dd>
|
||||
<p><span>Dict</span></p>
|
||||
<p>A dict for use by the current <a href="#class_ba_Session">ba.Session</a> for
|
||||
storing data associated with this team.
|
||||
Unlike gamedata, this persists for the duration
|
||||
of the session.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
@ -4952,7 +4939,7 @@ of the session.</p>
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_Stats____init__"><constructor></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_got_hit">player_got_hit()</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__"><constructor></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>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_Stats____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.Stats()</span></p>
|
||||
@ -4971,12 +4958,6 @@ of the session.</p>
|
||||
|
||||
<p>May return None.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_got_hit">player_got_hit()</a></dt></h4><dd>
|
||||
<p><span>player_got_hit(self, player: <a href="#class_ba_SessionPlayer">ba.SessionPlayer</a>) -> None</span></p>
|
||||
|
||||
<p>Call this when a player got hit.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Stats__player_scored">player_scored()</a></dt></h4><dd>
|
||||
<p><span>player_scored(self, player: <a href="#class_ba_Player">ba.Player</a>, base_points: int = 1, target: Sequence[float] = None, kill: bool = False, victim_player: <a href="#class_ba_Player">ba.Player</a> = None, scale: float = 1.0, color: Sequence[float] = None, title: Union[str, <a href="#class_ba_Lstr">ba.Lstr</a>] = None, screenmessage: bool = True, display: bool = True, importance: int = 1, showpoints: bool = True, big_message: bool = False) -> int</span></p>
|
||||
@ -5029,9 +5010,9 @@ of the session.</p>
|
||||
</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_Team__gamedata">gamedata</a>, <a href="#attr_ba_Team__sessionteam">sessionteam</a></h5>
|
||||
<h5><a href="#attr_ba_Team__customdata">customdata</a>, <a href="#attr_ba_Team__sessionteam">sessionteam</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_Team__gamedata">gamedata</a></h4></dt><dd>
|
||||
<dt><h4><a name="attr_ba_Team__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>Arbitrary values associated with the team.
|
||||
Though it is encouraged that most player values be properly defined
|
||||
@ -5080,8 +5061,16 @@ of the session.</p>
|
||||
<h3>Attributes Inherited:</h3>
|
||||
<h5><a href="#attr_ba_Activity__players">players</a>, <a href="#attr_ba_Activity__settings_raw">settings_raw</a>, <a href="#attr_ba_Activity__teams">teams</a></h5>
|
||||
<h3>Attributes Defined Here:</h3>
|
||||
<h5><a href="#attr_ba_TeamGameActivity__expired">expired</a>, <a href="#attr_ba_TeamGameActivity__gamedata">gamedata</a>, <a href="#attr_ba_TeamGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_TeamGameActivity__map">map</a>, <a href="#attr_ba_TeamGameActivity__playertype">playertype</a>, <a href="#attr_ba_TeamGameActivity__session">session</a>, <a href="#attr_ba_TeamGameActivity__stats">stats</a>, <a href="#attr_ba_TeamGameActivity__teamtype">teamtype</a></h5>
|
||||
<h5><a href="#attr_ba_TeamGameActivity__customdata">customdata</a>, <a href="#attr_ba_TeamGameActivity__expired">expired</a>, <a href="#attr_ba_TeamGameActivity__globalsnode">globalsnode</a>, <a href="#attr_ba_TeamGameActivity__map">map</a>, <a href="#attr_ba_TeamGameActivity__playertype">playertype</a>, <a href="#attr_ba_TeamGameActivity__session">session</a>, <a href="#attr_ba_TeamGameActivity__stats">stats</a>, <a href="#attr_ba_TeamGameActivity__teamtype">teamtype</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_TeamGameActivity__customdata">customdata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameActivity__expired">expired</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether the activity is expired.</p>
|
||||
@ -5090,14 +5079,6 @@ of the session.</p>
|
||||
At this point no new nodes, timers, etc should be made,
|
||||
run, etc, and the activity should be considered a 'zombie'.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameActivity__gamedata">gamedata</a></h4></dt><dd>
|
||||
<p><span>dict</span></p>
|
||||
<p>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.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameActivity__globalsnode">globalsnode</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||
@ -5208,43 +5189,58 @@ Results for a completed <a href="#class_ba_TeamGameActivity">ba.TeamGameActivity
|
||||
<p>Upon completion, a game should fill one of these out and pass it to its
|
||||
<a href="#method_ba_Activity__end">ba.Activity.end</a>() call.</p>
|
||||
|
||||
<h3>Attributes:</h3>
|
||||
<h5><a href="#attr_ba_TeamGameResults__lower_is_better">lower_is_better</a>, <a href="#attr_ba_TeamGameResults__playerinfos">playerinfos</a>, <a href="#attr_ba_TeamGameResults__score_label">score_label</a>, <a href="#attr_ba_TeamGameResults__scoretype">scoretype</a>, <a href="#attr_ba_TeamGameResults__sessionteams">sessionteams</a>, <a href="#attr_ba_TeamGameResults__winnergroups">winnergroups</a>, <a href="#attr_ba_TeamGameResults__winning_team">winning_team</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__lower_is_better">lower_is_better</a></h4></dt><dd>
|
||||
<p><span>bool</span></p>
|
||||
<p>Whether lower scores are better.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__playerinfos">playerinfos</a></h4></dt><dd>
|
||||
<p><span>List[<a href="#class_ba_PlayerInfo">ba.PlayerInfo</a>]</span></p>
|
||||
<p>Get info about the players represented by the results.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__score_label">score_label</a></h4></dt><dd>
|
||||
<p><span>str</span></p>
|
||||
<p>The label associated with scores ('points', etc).</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__scoretype">scoretype</a></h4></dt><dd>
|
||||
<p><span><a href="#class_ba_ScoreType">ba.ScoreType</a></span></p>
|
||||
<p>The type of score.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__sessionteams">sessionteams</a></h4></dt><dd>
|
||||
<p><span>List[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p>
|
||||
<p>Return all <a href="#class_ba_SessionTeam">ba.SessionTeams</a> in the results.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__winnergroups">winnergroups</a></h4></dt><dd>
|
||||
<p><span>List[WinnerGroup]</span></p>
|
||||
<p>Get an ordered list of winner groups.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="attr_ba_TeamGameResults__winning_team">winning_team</a></h4></dt><dd>
|
||||
<p><span>Optional[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p>
|
||||
<p>The winning <a href="#class_ba_SessionTeam">ba.SessionTeam</a> if there is exactly one, or else None.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods:</h3>
|
||||
<h5><a href="#method_ba_TeamGameResults____init__"><constructor></a>, <a href="#method_ba_TeamGameResults__get_lower_is_better">get_lower_is_better()</a>, <a href="#method_ba_TeamGameResults__get_player_info">get_player_info()</a>, <a href="#method_ba_TeamGameResults__get_score_name">get_score_name()</a>, <a href="#method_ba_TeamGameResults__get_score_type">get_score_type()</a>, <a href="#method_ba_TeamGameResults__get_team_score">get_team_score()</a>, <a href="#method_ba_TeamGameResults__get_team_score_str">get_team_score_str()</a>, <a href="#method_ba_TeamGameResults__get_teams">get_teams()</a>, <a href="#method_ba_TeamGameResults__get_winners">get_winners()</a>, <a href="#method_ba_TeamGameResults__get_winning_team">get_winning_team()</a>, <a href="#method_ba_TeamGameResults__has_score_for_team">has_score_for_team()</a>, <a href="#method_ba_TeamGameResults__set_game">set_game()</a>, <a href="#method_ba_TeamGameResults__set_team_score">set_team_score()</a></h5>
|
||||
<h5><a href="#method_ba_TeamGameResults____init__"><constructor></a>, <a href="#method_ba_TeamGameResults__get_team_score">get_team_score()</a>, <a href="#method_ba_TeamGameResults__get_team_score_str">get_team_score_str()</a>, <a href="#method_ba_TeamGameResults__has_score_for_team">has_score_for_team()</a>, <a href="#method_ba_TeamGameResults__set_game">set_game()</a>, <a href="#method_ba_TeamGameResults__set_team_score">set_team_score()</a></h5>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_TeamGameResults____init__"><constructor></a></dt></h4><dd>
|
||||
<p><span>ba.TeamGameResults()</span></p>
|
||||
|
||||
<p>Instantiate a results instance.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_lower_is_better">get_lower_is_better()</a></dt></h4><dd>
|
||||
<p><span>get_lower_is_better(self) -> bool</span></p>
|
||||
|
||||
<p>Return whether lower scores are better.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_player_info">get_player_info()</a></dt></h4><dd>
|
||||
<p><span>get_player_info(self) -> List[<a href="#class_ba_PlayerInfo">ba.PlayerInfo</a>]</span></p>
|
||||
|
||||
<p>Get info about the players represented by the results.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_score_name">get_score_name()</a></dt></h4><dd>
|
||||
<p><span>get_score_name(self) -> str</span></p>
|
||||
|
||||
<p>Get the name associated with scores ('points', etc).</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_score_type">get_score_type()</a></dt></h4><dd>
|
||||
<p><span>get_score_type(self) -> <a href="#class_ba_ScoreType">ba.ScoreType</a></span></p>
|
||||
|
||||
<p>Get the type of score.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_team_score">get_team_score()</a></dt></h4><dd>
|
||||
<p><span>get_team_score(self, team: Union[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>, <a href="#class_ba_Team">ba.Team</a>]) -> Optional[int]</span></p>
|
||||
<p><span>get_team_score(self, sessionteam: Union[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]) -> Optional[int]</span></p>
|
||||
|
||||
<p>Return the score for a given team.</p>
|
||||
<p>Return the score for a given <a href="#class_ba_SessionTeam">ba.SessionTeam</a>.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_team_score_str">get_team_score_str()</a></dt></h4><dd>
|
||||
@ -5254,24 +5250,6 @@ Results for a completed <a href="#class_ba_TeamGameActivity">ba.TeamGameActivity
|
||||
|
||||
<p>(properly formatted for the score type.)</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_teams">get_teams()</a></dt></h4><dd>
|
||||
<p><span>get_teams(self) -> List[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p>
|
||||
|
||||
<p>Return all <a href="#class_ba_SessionTeam">ba.SessionTeams</a> in the results.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_winners">get_winners()</a></dt></h4><dd>
|
||||
<p><span>get_winners(self) -> List[WinnerGroup]</span></p>
|
||||
|
||||
<p>Get an ordered list of winner groups.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__get_winning_team">get_winning_team()</a></dt></h4><dd>
|
||||
<p><span>get_winning_team(self) -> Optional[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>]</span></p>
|
||||
|
||||
<p>Get the winning <a href="#class_ba_Team">ba.Team</a> if there is exactly one; None otherwise.</p>
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__has_score_for_team">has_score_for_team()</a></dt></h4><dd>
|
||||
<p><span>has_score_for_team(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -> bool</span></p>
|
||||
@ -5286,7 +5264,7 @@ Results for a completed <a href="#class_ba_TeamGameActivity">ba.TeamGameActivity
|
||||
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_TeamGameResults__set_team_score">set_team_score()</a></dt></h4><dd>
|
||||
<p><span>set_team_score(self, team: Union[<a href="#class_ba_SessionTeam">ba.SessionTeam</a>, <a href="#class_ba_Team">ba.Team</a>], score: Optional[int]) -> None</span></p>
|
||||
<p><span>set_team_score(self, team: <a href="#class_ba_Team">ba.Team</a>, score: Optional[int]) -> None</span></p>
|
||||
|
||||
<p>Set the score for a given <a href="#class_ba_Team">ba.Team</a>.</p>
|
||||
|
||||
@ -6422,6 +6400,30 @@ playing, the playing track will not be restarted.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_storagename">ba.storagename()</a></strong></h3>
|
||||
<p><span>storagename(basename: str) -> str</span></p>
|
||||
|
||||
<p>Generate a (hopefully) unique name for storing things in public places.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_General_Utility_Functions">General Utility Functions</a></p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<pre><span><em><small># Example: generate a unique name for storage purposes:</small></em></span>
|
||||
class MyThingie:</pre>
|
||||
|
||||
<pre><span><em><small> # This will give something like '_mymodule_submodule_mythingie_data'.</small></em></span>
|
||||
_STORENAME = <a href="#function_ba_storagename">ba.storagename</a>('data')</pre>
|
||||
|
||||
<p> def __init__(self, activity):
|
||||
# Store some data in the Activity we were passed
|
||||
activity.customdata[self._STORENAME] = {}</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_textwidget">ba.textwidget()</a></strong></h3>
|
||||
<p><span>textwidget(edit: Widget = None, parent: Widget = None,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user