This commit is contained in:
Eric Froemling 2020-06-04 21:20:25 -07:00
parent 690ca375af
commit 431e6e80bf
16 changed files with 210 additions and 196 deletions

View File

@ -35,6 +35,7 @@
<w>actionhero</w>
<w>activityname</w>
<w>activityplayer</w>
<w>activityteam</w>
<w>activitytypes</w>
<w>activityutils</w>
<w>actorclass</w>
@ -2178,6 +2179,7 @@
<w>yapf</w>
<w>yapfconfig</w>
<w>yinyang</w>
<w>yoffs</w>
<w>ypos</w>
<w>yres</w>
<w>yscl</w>

View File

@ -557,7 +557,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
sessionplayer.resetinput()
sessionteam = sessionplayer.sessionteam
assert sessionplayer in sessionteam.players
team = sessionteam.gameteam
team = sessionteam.activityteam
assert team is not None
sessionplayer.setactivity(self)
with _ba.Context(self):
@ -587,7 +587,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
player: Any = sessionplayer.activityplayer
assert isinstance(player, self._playertype)
team: Any = sessionplayer.sessionteam.gameteam
team: Any = sessionplayer.sessionteam.activityteam
assert isinstance(team, self._teamtype)
assert player in team.players
@ -629,7 +629,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
assert not self.expired
with _ba.Context(self):
sessionteam.gameteam = team = self.create_team(sessionteam)
sessionteam.activityteam = team = self.create_team(sessionteam)
team.postinit(sessionteam)
self.teams.append(team)
try:
@ -643,9 +643,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
(internal)
"""
assert not self.expired
assert sessionteam.gameteam is not None
assert sessionteam.activityteam is not None
team: Any = sessionteam.gameteam
team: Any = sessionteam.activityteam
assert isinstance(team, self._teamtype)
assert team in self.teams
@ -663,7 +663,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
except Exception:
print_exception(f'Error on leave for {team} in {self}.')
sessionteam.gameteam = None
sessionteam.activityteam = None
# Add the team to a list to keep it around for a while. This is
# to discourage logic from firing on team object death, which
@ -854,7 +854,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
try:
sessionteam = team.sessionteam
sessionteam.gameteam = None
sessionteam.activityteam = None
except SessionTeamNotFoundError:
# It is expected that Team objects may last longer than
# the SessionTeam they came from (game objects may hold

View File

@ -346,7 +346,7 @@ class CoopSession(Session):
# Generic team games.
if isinstance(results, GameResults):
playerinfos = results.playerinfos
score = results.get_team_score(results.sessionteams[0])
score = results.get_sessionteam_score(results.sessionteams[0])
fail_message = None
score_order = ('decreasing'
if results.lower_is_better else 'increasing')

View File

@ -50,7 +50,6 @@ class GameResults:
"""
def __init__(self) -> None:
"""Instantiate a results instance."""
self._game_set = False
self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam],
Optional[int]]] = {}
@ -76,7 +75,7 @@ class GameResults:
self._scoretype = scoreconfig.scoretype
def set_team_score(self, team: ba.Team, score: Optional[int]) -> None:
"""Set the score for a given ba.Team.
"""Set the score for a given team.
This can be a number or None.
(see the none_is_winner arg in the constructor)
@ -84,7 +83,8 @@ class GameResults:
sessionteam = team.sessionteam
self._scores[sessionteam.id] = (weakref.ref(sessionteam), score)
def get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]:
def get_sessionteam_score(self,
sessionteam: ba.SessionTeam) -> Optional[int]:
"""Return the score for a given ba.SessionTeam."""
for score in list(self._scores.values()):
if score[0]() is sessionteam:
@ -106,12 +106,13 @@ class GameResults:
teams.append(team)
return teams
def has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool:
"""Return whether there is a score for a given team."""
def has_score_for_sessionteam(self, sessionteam: ba.SessionTeam) -> bool:
"""Return whether there is a score for a given session-team."""
return any(s[0]() is sessionteam for s in self._scores.values())
def get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr:
"""Return the score for the given ba.Team as an Lstr.
def get_sessionteam_score_str(self,
sessionteam: ba.SessionTeam) -> ba.Lstr:
"""Return the score for the given session-team as an Lstr.
(properly formatted for the score type.)
"""
@ -169,7 +170,7 @@ class GameResults:
return self._lower_is_better
@property
def winning_team(self) -> Optional[ba.SessionTeam]:
def winning_sessionteam(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.")

View File

@ -262,12 +262,12 @@ class MultiTeamSession(Session):
_ba.timer(delay, Call(_ba.playsound, _ba.getsound('boxingBell')))
if announce_winning_team:
winning_team = results.winning_team
if winning_team is not None:
winning_sessionteam = results.winning_sessionteam
if winning_sessionteam is not None:
# Have all players celebrate.
celebrate_msg = CelebrateMessage(duration=10.0)
assert winning_team.gameteam is not None
for player in winning_team.gameteam.players:
assert winning_sessionteam.activityteam is not None
for player in winning_sessionteam.activityteam.players:
if player.actor:
player.actor.handlemessage(celebrate_msg)
cameraflash()
@ -278,11 +278,11 @@ class MultiTeamSession(Session):
else:
wins_resource = 'winsTeamText'
wins_text = Lstr(resource=wins_resource,
subs=[('${NAME}', winning_team.name)])
subs=[('${NAME}', winning_sessionteam.name)])
activity.show_zoom_message(
wins_text,
scale=0.85,
color=normalized_color(winning_team.color),
color=normalized_color(winning_sessionteam.color),
)

View File

@ -81,6 +81,7 @@ class Player(Generic[TeamType]):
actor: Optional[ba.Actor]
color: Sequence[float]
highlight: Sequence[float]
_team: TeamType
_sessionplayer: ba.SessionPlayer
_nodeactor: Optional[ba.NodeActor]
@ -118,7 +119,7 @@ class Player(Generic[TeamType]):
self.character = sessionplayer.character
self.color = sessionplayer.color
self.highlight = sessionplayer.highlight
self._team = cast(TeamType, sessionplayer.sessionteam.gameteam)
self._team = cast(TeamType, sessionplayer.sessionteam.activityteam)
assert self._team is not None
self._customdata = {}
self._expired = False

View File

@ -306,7 +306,7 @@ class Session:
# Remove their Team from the Activity.
if activity is not None:
if sessionteam.gameteam in activity.teams:
if sessionteam.activityteam in activity.teams:
activity.remove_team(sessionteam)
else:
print('Team not found in Activity in on_player_leave.')

View File

@ -85,7 +85,7 @@ class SessionTeam:
self.color = tuple(color)
self.players = []
self.customdata = {}
self.gameteam: Optional[Team] = None
self.activityteam: Optional[Team] = None
def leave(self) -> None:
"""(internal)"""

View File

@ -194,12 +194,15 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None:
if not isinstance(widget, _ba.Widget):
raise TypeError('widget arg is not a ba.Widget')
def foobar() -> None:
"""Just testing."""
if DEBUG_UI_CLEANUP_CHECKS:
print('uicleanupcheck widget dying...')
if bool(False):
def foobar() -> None:
"""Just testing."""
if DEBUG_UI_CLEANUP_CHECKS:
print('uicleanupcheck widget dying...')
widget.add_delete_callback(foobar)
widget.add_delete_callback(foobar)
_ba.app.uicleanupchecks.append(
UICleanupCheck(obj=weakref.ref(obj),
widget=widget,

View File

@ -88,16 +88,16 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
def _get_prec_score(p_rec: ba.PlayerRecord) -> Optional[int]:
if is_free_for_all and results is not None:
assert isinstance(results, ba.GameResults)
assert p_rec.team.gameteam is not None
val = results.get_team_score(p_rec.team)
assert p_rec.team.activityteam is not None
val = results.get_sessionteam_score(p_rec.team)
return val
return p_rec.accumscore
def _get_prec_score_str(p_rec: ba.PlayerRecord) -> Union[str, ba.Lstr]:
if is_free_for_all and results is not None:
assert isinstance(results, ba.GameResults)
assert p_rec.team.gameteam is not None
val = results.get_team_score_str(p_rec.team)
assert p_rec.team.activityteam is not None
val = results.get_sessionteam_score_str(p_rec.team)
assert val is not None
return val
return str(p_rec.accumscore)
@ -139,18 +139,18 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
# Just want living player entries.
player_records = [p[2] for p in player_records_scores if p[2]]
v_offs = -140.0 + spacing * len(player_records) * 0.5
voffs = -140.0 + spacing * len(player_records) * 0.5
def _txt(x_offs: float,
y_offs: float,
def _txt(xoffs: float,
yoffs: float,
text: ba.Lstr,
h_align: Text.HAlign = Text.HAlign.RIGHT,
extrascale: float = 1.0,
maxwidth: Optional[float] = 120.0) -> None:
Text(text,
color=(0.5, 0.5, 0.6, 0.5),
position=(ts_h_offs + x_offs * scale,
ts_v_offset + (v_offs + y_offs + 4.0) * scale),
position=(ts_h_offs + xoffs * scale,
ts_v_offset + (voffs + yoffs + 4.0) * scale),
h_align=h_align,
v_align=Text.VAlign.CENTER,
scale=0.8 * scale * extrascale,
@ -193,7 +193,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
maxwidth: float = 70.0) -> None:
Text(text,
position=(ts_h_offs + x_offs * scale,
ts_v_offset + (v_offs + 15) * scale),
ts_v_offset + (voffs + 15) * scale),
scale=scale,
color=(1.0, 0.9, 0.5, 1.0) if highlight else
(0.5, 0.5, 0.6, 0.5),
@ -205,10 +205,10 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
for playerrec in player_records:
tdelay += 0.05
v_offs -= spacing
voffs -= spacing
Image(playerrec.get_icon(),
position=(ts_h_offs - 12 * scale,
ts_v_offset + (v_offs + 15.0) * scale),
ts_v_offset + (voffs + 15.0) * scale),
scale=(30.0 * scale, 30.0 * scale),
transition=Image.Transition.IN_LEFT,
transition_delay=tdelay).autoretain()
@ -216,7 +216,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity):
maxwidth=160,
scale=0.75 * scale,
position=(ts_h_offs + 10.0 * scale,
ts_v_offset + (v_offs + 15) * scale),
ts_v_offset + (voffs + 15) * scale),
h_align=Text.HAlign.LEFT,
v_align=Text.VAlign.CENTER,
color=ba.safecolor(playerrec.team.color + (1, )),

View File

@ -61,7 +61,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
self._show_up_next = False
self._custom_continue_message = sval
super().on_begin()
winning_team = self.settings_raw['winner']
winning_sessionteam = self.settings_raw['winner']
# Pause a moment before playing victory music.
ba.timer(0.6, ba.WeakCall(self._play_victory_music))
@ -171,7 +171,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity):
if not self._is_ffa:
mvp, mvp_name = None, None
for entry in player_entries:
if entry[2].team == winning_team:
if entry[2].team == winning_sessionteam:
mvp = entry[2]
mvp_name = entry[1]
break

View File

@ -177,7 +177,8 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]):
else:
# Default handler:
super().handlemessage(msg)
return super().handlemessage(msg)
return None
def _check_end_game(self) -> None:
living_team_count = 0

View File

@ -532,16 +532,13 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
self._race_started = True
def _update_player_order(self) -> None:
# FIXME: tidy this up
# Calc all player distances.
for player in self.players:
pos: Optional[ba.Vec3]
try:
assert isinstance(player.actor, PlayerSpaz)
assert player.actor.node
pos = ba.Vec3(player.actor.node.position)
except Exception:
pos = player.position
except ba.NotFoundError:
pos = None
if pos is not None:
r_index = player.last_region
@ -560,14 +557,11 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
p_list.sort(reverse=True, key=lambda x: x[0])
for i, plr in enumerate(p_list):
try:
plr[1].rank = i
if plr[1].actor:
node = plr[1].distance_txt
if node:
node.text = str(i + 1) if plr[1].is_alive() else ''
except Exception:
ba.print_exception('error updating player orders')
plr[1].rank = i
if plr[1].actor:
node = plr[1].distance_txt
if node:
node.text = str(i + 1) if plr[1].is_alive() else ''
def _spawn_bomb(self) -> None:
if self._front_race_region is None:
@ -730,7 +724,8 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, ba.PlayerDiedMessage):
super().handlemessage(msg) # Augment default behavior.
# Augment default behavior.
super().handlemessage(msg)
player = msg.getplayer(Player)
if not player.finished:
self.respawn_player(player, respawn_time=1)

View File

@ -38,6 +38,7 @@ class PlaylistTypeVars:
from ba.internal import (get_default_teams_playlist,
get_default_free_for_all_playlist)
self.sessiontype: Type[ba.Session]
if issubclass(sessiontype, ba.DualTeamSession):
play_mode_name = ba.Lstr(resource='playModes.teamsText',
fallback_resource='teamsText')
@ -47,6 +48,7 @@ class PlaylistTypeVars:
self.window_title_name = ba.Lstr(resource='playModes.teamsText',
fallback_resource='teamsText')
self.sessiontype = ba.DualTeamSession
elif issubclass(sessiontype, ba.FreeForAllSession):
play_mode_name = ba.Lstr(resource='playModes.freeForAllText',
fallback_resource='freeForAllText')
@ -57,6 +59,7 @@ class PlaylistTypeVars:
resource='playModes.freeForAllText',
fallback_resource='freeForAllText')
self.sessiontype = ba.FreeForAllSession
else:
raise TypeError('playlist type vars undefined for session type: ' +
str(sessiontype))

View File

@ -42,7 +42,7 @@ class PlaylistBrowserWindow(ba.Window):
origin_widget: ba.Widget = None):
# pylint: disable=too-many-statements
# pylint: disable=cyclic-import
from bastd.ui import playlist
from bastd.ui.playlist import PlaylistTypeVars
# If they provided an origin-widget, scale up from that.
scale_origin: Optional[Tuple[float, float]]
@ -62,8 +62,8 @@ class PlaylistBrowserWindow(ba.Window):
ba.app.main_window = 'Free-for-All Game Select'
ba.set_analytics_screen('FreeForAll Window')
else:
raise TypeError(f'invalid sessiontype: {sessiontype}')
self._pvars = playlist.PlaylistTypeVars(sessiontype)
raise TypeError(f'Invalid sessiontype: {sessiontype}.')
self._pvars = PlaylistTypeVars(sessiontype)
self._sessiontype = sessiontype
@ -74,39 +74,45 @@ class PlaylistBrowserWindow(ba.Window):
# On new installations, go ahead and create a few playlists
# besides the hard-coded default one:
if not _ba.get_account_misc_val('madeStandardPlaylists', False):
# yapf: disable
_ba.add_transaction({
'type': 'ADD_PLAYLIST',
'playlistType': 'Free-for-All',
'type':
'ADD_PLAYLIST',
'playlistType':
'Free-for-All',
'playlistName':
ba.Lstr(resource='singleGamePlaylistNameText'
).evaluate().replace(
'${GAME}',
ba.Lstr(
translate=('gameNames',
'Death Match')).evaluate()),
ba.Lstr(translate=('gameNames',
'Death Match')).evaluate()),
'playlist': [
{'type': 'bs_death_match.DeathMatchGame',
'settings': {
'Epic Mode': False,
'Kills to Win Per Player': 10,
'Respawn Times': 1.0,
'Time Limit': 300,
'map': 'Doom Shroom'}
{
'type': 'bs_death_match.DeathMatchGame',
'settings': {
'Epic Mode': False,
'Kills to Win Per Player': 10,
'Respawn Times': 1.0,
'Time Limit': 300,
'map': 'Doom Shroom'
}
},
{
'type': 'bs_death_match.DeathMatchGame',
'settings': {
'Epic Mode': False,
'Kills to Win Per Player': 10,
'Respawn Times': 1.0,
'Time Limit': 300,
'map': 'Crag Castle'
}
},
{'type': 'bs_death_match.DeathMatchGame',
'settings': {
'Epic Mode': False,
'Kills to Win Per Player': 10,
'Respawn Times': 1.0,
'Time Limit': 300,
'map': 'Crag Castle'}
}
]
})
_ba.add_transaction({
'type': 'ADD_PLAYLIST',
'playlistType': 'Team Tournament',
'type':
'ADD_PLAYLIST',
'playlistType':
'Team Tournament',
'playlistName':
ba.Lstr(
resource='singleGamePlaylistNameText'
@ -115,92 +121,102 @@ class PlaylistBrowserWindow(ba.Window):
ba.Lstr(translate=('gameNames',
'Capture the Flag')).evaluate()),
'playlist': [
{'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Bridgit',
'Score to Win': 3,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 0,
'Respawn Times': 1.0,
'Time Limit': 600,
'Epic Mode': False}
{
'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Bridgit',
'Score to Win': 3,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 0,
'Respawn Times': 1.0,
'Time Limit': 600,
'Epic Mode': False
}
},
{'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Roundabout',
'Score to Win': 2,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 0,
'Respawn Times': 1.0,
'Time Limit': 600,
'Epic Mode': False}
{
'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Roundabout',
'Score to Win': 2,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 0,
'Respawn Times': 1.0,
'Time Limit': 600,
'Epic Mode': False
}
},
{
'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Tip Top',
'Score to Win': 2,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 3,
'Respawn Times': 1.0,
'Time Limit': 300,
'Epic Mode': False
}
},
{'type': 'bs_capture_the_flag.CTFGame',
'settings': {
'map': 'Tip Top',
'Score to Win': 2,
'Flag Idle Return Time': 30,
'Flag Touch Return Time': 3,
'Respawn Times': 1.0,
'Time Limit': 300,
'Epic Mode': False}
}
]
})
_ba.add_transaction({
'type': 'ADD_PLAYLIST',
'playlistType': 'Team Tournament',
'type':
'ADD_PLAYLIST',
'playlistType':
'Team Tournament',
'playlistName':
ba.Lstr(translate=('playlistNames',
'Just Sports')).evaluate(),
ba.Lstr(translate=('playlistNames', 'Just Sports')
).evaluate(),
'playlist': [
{'type': 'bs_hockey.HockeyGame',
'settings': {
'Time Limit': 0,
'map': 'Hockey Stadium',
'Score to Win': 1,
'Respawn Times': 1.0}
{
'type': 'bs_hockey.HockeyGame',
'settings': {
'Time Limit': 0,
'map': 'Hockey Stadium',
'Score to Win': 1,
'Respawn Times': 1.0
}
},
{
'type': 'bs_football.FootballTeamGame',
'settings': {
'Time Limit': 0,
'map': 'Football Stadium',
'Score to Win': 21,
'Respawn Times': 1.0
}
},
{'type': 'bs_football.FootballTeamGame',
'settings': {
'Time Limit': 0,
'map': 'Football Stadium',
'Score to Win': 21,
'Respawn Times': 1.0}
}
]
})
_ba.add_transaction({
'type': 'ADD_PLAYLIST',
'playlistType': 'Free-for-All',
'type':
'ADD_PLAYLIST',
'playlistType':
'Free-for-All',
'playlistName':
ba.Lstr(translate=('playlistNames',
'Just Epic')).evaluate(),
'playlist': [
{'type': 'bs_elimination.EliminationGame',
'settings': {
'Time Limit': 120,
'map': 'Tip Top',
'Respawn Times': 1.0,
'Lives Per Player': 1,
'Epic Mode': 1}
ba.Lstr(translate=('playlistNames', 'Just Epic')
).evaluate(),
'playlist': [{
'type': 'bs_elimination.EliminationGame',
'settings': {
'Time Limit': 120,
'map': 'Tip Top',
'Respawn Times': 1.0,
'Lives Per Player': 1,
'Epic Mode': 1
}
]
}]
})
_ba.add_transaction({
'type': 'SET_MISC_VAL',
'name': 'madeStandardPlaylists',
'value': True
})
# yapf: enable
_ba.run_transactions()
# Get the current selection (if any).
try:
self._selected_playlist = ba.app.config[self._pvars.config_name +
' Playlist Selection']
except Exception:
self._selected_playlist = None
self._selected_playlist = ba.app.config.get(self._pvars.config_name +
' Playlist Selection')
self._width = 900 if ba.app.small_ui else 800
x_inset = 50 if ba.app.small_ui else 0
@ -270,12 +286,13 @@ class PlaylistBrowserWindow(ba.Window):
self._config_name_full = self._pvars.config_name + ' Playlists'
self._last_config = None
# update now and once per second.. (this should do our initial refresh)
# Update now and once per second.
# (this should do our initial refresh)
self._update()
self._update_timer = ba.Timer(1.0,
ba.WeakCall(self._update),
timetype=ba.TimeType.REAL,
repeat=True)
self._update()
def _refresh(self) -> None:
# FIXME: Should tidy this up.
@ -292,13 +309,13 @@ class PlaylistBrowserWindow(ba.Window):
self._save_state()
self._subcontainer.delete()
# make sure config exists
# Make sure config exists.
if self._config_name_full not in ba.app.config:
ba.app.config[self._config_name_full] = {}
items = list(ba.app.config[self._config_name_full].items())
# make sure everything is unicode
# Make sure everything is unicode.
items = [(i[0].decode(), i[1]) if not isinstance(i[0], str) else i
for i in items]
@ -507,7 +524,7 @@ class PlaylistBrowserWindow(ba.Window):
v -= scl * 130.0
except Exception:
ba.print_exception('error listing playlist maps')
ba.print_exception('Error listing playlist maps.')
if not map_images:
ba.textwidget(parent=self._subcontainer,
@ -563,43 +580,39 @@ class PlaylistBrowserWindow(ba.Window):
def _on_playlist_press(self, button: ba.Widget,
playlist_name: str) -> None:
# pylint: disable=cyclic-import
from bastd.ui import playoptions
from bastd.ui.playoptions import PlayOptionsWindow
# Make sure the target playlist still exists.
try:
exists = (playlist_name == '__default__' or playlist_name
in ba.app.config[self._config_name_full])
except Exception:
exists = False
exists = (playlist_name == '__default__'
or playlist_name in ba.app.config.get(
self._config_name_full, {}))
if not exists:
return
self._save_state()
playoptions.PlayOptionsWindow(
sessiontype=self._sessiontype,
scale_origin=button.get_screen_space_center(),
playlist=playlist_name,
delegate=self)
PlayOptionsWindow(sessiontype=self._sessiontype,
scale_origin=button.get_screen_space_center(),
playlist=playlist_name,
delegate=self)
def _on_customize_press(self) -> None:
# pylint: disable=cyclic-import
from bastd.ui.playlist import customizebrowser as cb
from bastd.ui.playlist.customizebrowser import (
PlaylistCustomizeBrowserWindow)
self._save_state()
ba.containerwidget(edit=self._root_widget, transition='out_left')
ba.app.main_menu_window = (cb.PlaylistCustomizeBrowserWindow(
ba.app.main_menu_window = (PlaylistCustomizeBrowserWindow(
origin_widget=self._customize_button,
sessiontype=self._sessiontype).get_root_widget())
def _on_back_press(self) -> None:
# pylint: disable=cyclic-import
from bastd.ui import play
from bastd.ui.play import PlayWindow
# Store our selected playlist if that's changed.
if self._selected_playlist is not None:
try:
prev_sel = ba.app.config[self._pvars.config_name +
' Playlist Selection']
except Exception:
prev_sel = None
prev_sel = ba.app.config.get(self._pvars.config_name +
' Playlist Selection')
if self._selected_playlist != prev_sel:
cfg = ba.app.config
cfg[self._pvars.config_name +
@ -609,7 +622,7 @@ class PlaylistBrowserWindow(ba.Window):
self._save_state()
ba.containerwidget(edit=self._root_widget,
transition=self._transition_out)
ba.app.main_menu_window = (play.PlayWindow(
ba.app.main_menu_window = (PlayWindow(
transition='in_left').get_root_widget())
def _save_state(self) -> None:
@ -628,14 +641,11 @@ class PlaylistBrowserWindow(ba.Window):
raise Exception('unrecognized selected widget')
ba.app.window_states[self.__class__.__name__] = sel_name
except Exception:
ba.print_exception('error saving state for', self.__class__)
ba.print_exception(f'Error saving state for {self}.')
def _restore_state(self) -> None:
try:
try:
sel_name = ba.app.window_states[self.__class__.__name__]
except Exception:
sel_name = None
sel_name = ba.app.window_states.get(self.__class__.__name__)
if sel_name == 'Back':
sel = self._back_button
elif sel_name == 'Scroll':
@ -649,4 +659,4 @@ class PlaylistBrowserWindow(ba.Window):
sel = self._scrollwidget
ba.containerwidget(edit=self._root_widget, selected_child=sel)
except Exception:
ba.print_exception('error restoring state for', self.__class__)
ba.print_exception(f'Error restoring state for {self}.')

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2020-06-03 for Ballistica version 1.5.0 build 20045</em></h4>
<h4><em>last updated on 2020-06-04 for Ballistica version 1.5.0 build 20045</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>
@ -2719,7 +2719,7 @@ Results for a completed game.</p>
<a href="#method_ba_Activity__end">ba.Activity.end</a>() call.</p>
<h3>Attributes:</h3>
<h5><a href="#attr_ba_GameResults__lower_is_better">lower_is_better</a>, <a href="#attr_ba_GameResults__playerinfos">playerinfos</a>, <a href="#attr_ba_GameResults__score_label">score_label</a>, <a href="#attr_ba_GameResults__scoretype">scoretype</a>, <a href="#attr_ba_GameResults__sessionteams">sessionteams</a>, <a href="#attr_ba_GameResults__winnergroups">winnergroups</a>, <a href="#attr_ba_GameResults__winning_team">winning_team</a></h5>
<h5><a href="#attr_ba_GameResults__lower_is_better">lower_is_better</a>, <a href="#attr_ba_GameResults__playerinfos">playerinfos</a>, <a href="#attr_ba_GameResults__score_label">score_label</a>, <a href="#attr_ba_GameResults__scoretype">scoretype</a>, <a href="#attr_ba_GameResults__sessionteams">sessionteams</a>, <a href="#attr_ba_GameResults__winnergroups">winnergroups</a>, <a href="#attr_ba_GameResults__winning_sessionteam">winning_sessionteam</a></h5>
<dl>
<dt><h4><a name="attr_ba_GameResults__lower_is_better">lower_is_better</a></h4></dt><dd>
<p><span>bool</span></p>
@ -2751,39 +2751,37 @@ Results for a completed game.</p>
<p>Get an ordered list of winner groups.</p>
</dd>
<dt><h4><a name="attr_ba_GameResults__winning_team">winning_team</a></h4></dt><dd>
<dt><h4><a name="attr_ba_GameResults__winning_sessionteam">winning_sessionteam</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_GameResults____init__">&lt;constructor&gt;</a>, <a href="#method_ba_GameResults__get_team_score">get_team_score()</a>, <a href="#method_ba_GameResults__get_team_score_str">get_team_score_str()</a>, <a href="#method_ba_GameResults__has_score_for_team">has_score_for_team()</a>, <a href="#method_ba_GameResults__set_game">set_game()</a>, <a href="#method_ba_GameResults__set_team_score">set_team_score()</a></h5>
<h5><a href="#method_ba_GameResults____init__">&lt;constructor&gt;</a>, <a href="#method_ba_GameResults__get_sessionteam_score">get_sessionteam_score()</a>, <a href="#method_ba_GameResults__get_sessionteam_score_str">get_sessionteam_score_str()</a>, <a href="#method_ba_GameResults__has_score_for_sessionteam">has_score_for_sessionteam()</a>, <a href="#method_ba_GameResults__set_game">set_game()</a>, <a href="#method_ba_GameResults__set_team_score">set_team_score()</a></h5>
<dl>
<dt><h4><a name="method_ba_GameResults____init__">&lt;constructor&gt;</a></dt></h4><dd>
<p><span>ba.GameResults()</span></p>
<p>Instantiate a results instance.</p>
</dd>
<dt><h4><a name="method_ba_GameResults__get_team_score">get_team_score()</a></dt></h4><dd>
<p><span>get_team_score(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; Optional[int]</span></p>
<dt><h4><a name="method_ba_GameResults__get_sessionteam_score">get_sessionteam_score()</a></dt></h4><dd>
<p><span>get_sessionteam_score(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; Optional[int]</span></p>
<p>Return the score for a given <a href="#class_ba_SessionTeam">ba.SessionTeam</a>.</p>
</dd>
<dt><h4><a name="method_ba_GameResults__get_team_score_str">get_team_score_str()</a></dt></h4><dd>
<p><span>get_team_score_str(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; <a href="#class_ba_Lstr">ba.Lstr</a></span></p>
<dt><h4><a name="method_ba_GameResults__get_sessionteam_score_str">get_sessionteam_score_str()</a></dt></h4><dd>
<p><span>get_sessionteam_score_str(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; <a href="#class_ba_Lstr">ba.Lstr</a></span></p>
<p>Return the score for the given <a href="#class_ba_Team">ba.Team</a> as an Lstr.</p>
<p>Return the score for the given session-team as an Lstr.</p>
<p>(properly formatted for the score type.)</p>
</dd>
<dt><h4><a name="method_ba_GameResults__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>) -&gt; bool</span></p>
<dt><h4><a name="method_ba_GameResults__has_score_for_sessionteam">has_score_for_sessionteam()</a></dt></h4><dd>
<p><span>has_score_for_sessionteam(self, sessionteam: <a href="#class_ba_SessionTeam">ba.SessionTeam</a>) -&gt; bool</span></p>
<p>Return whether there is a score for a given team.</p>
<p>Return whether there is a score for a given session-team.</p>
</dd>
<dt><h4><a name="method_ba_GameResults__set_game">set_game()</a></dt></h4><dd>
@ -2795,7 +2793,7 @@ Results for a completed game.</p>
<dt><h4><a name="method_ba_GameResults__set_team_score">set_team_score()</a></dt></h4><dd>
<p><span>set_team_score(self, team: <a href="#class_ba_Team">ba.Team</a>, score: Optional[int]) -&gt; None</span></p>
<p>Set the score for a given <a href="#class_ba_Team">ba.Team</a>.</p>
<p>Set the score for a given team.</p>
<p>This can be a number or None.
(see the none_is_winner arg in the constructor)</p>