From 2a2e64b7ab29033d2167db0ce39739d15152c469 Mon Sep 17 00:00:00 2001
From: Eric Froemling
Date: Wed, 1 Apr 2020 01:22:26 -0700
Subject: [PATCH] Cleaned up music playback
---
.idea/dictionaries/ericf.xml | 5 +
CHANGELOG.md | 3 +
assets/src/ba_data/python/_ba.py | 114 +++---
assets/src/ba_data/python/ba/__init__.py | 2 +-
.../src/ba_data/python/ba/_activitytypes.py | 19 +-
assets/src/ba_data/python/ba/_app.py | 39 +-
assets/src/ba_data/python/ba/_gameactivity.py | 2 +-
assets/src/ba_data/python/ba/_map.py | 2 +-
assets/src/ba_data/python/ba/_music.py | 332 +++++++++---------
.../bastd/activity/multiteamendscreen.py | 2 +-
.../src/ba_data/python/bastd/game/assault.py | 4 +-
.../python/bastd/game/capturetheflag.py | 4 +-
.../ba_data/python/bastd/game/chosenone.py | 4 +-
.../src/ba_data/python/bastd/game/conquest.py | 4 +-
.../ba_data/python/bastd/game/deathmatch.py | 4 +-
.../python/bastd/game/easteregghunt.py | 2 +-
.../ba_data/python/bastd/game/elimination.py | 4 +-
.../src/ba_data/python/bastd/game/football.py | 6 +-
.../src/ba_data/python/bastd/game/hockey.py | 2 +-
.../src/ba_data/python/bastd/game/keepaway.py | 2 +-
.../python/bastd/game/kingofthehill.py | 2 +-
.../ba_data/python/bastd/game/meteorshower.py | 4 +-
.../ba_data/python/bastd/game/ninjafight.py | 2 +-
.../ba_data/python/bastd/game/onslaught.py | 4 +-
assets/src/ba_data/python/bastd/game/race.py | 5 +-
.../ba_data/python/bastd/game/runaround.py | 4 +-
.../python/bastd/game/targetpractice.py | 2 +-
.../ba_data/python/bastd/game/thelaststand.py | 2 +-
assets/src/ba_data/python/bastd/mainmenu.py | 2 +-
assets/src/ba_data/python/bastd/maps.py | 4 +-
assets/src/ba_data/python/bastd/tutorial.py | 2 +-
.../python/bastd/ui/soundtrack/browser.py | 16 +-
.../python/bastd/ui/soundtrack/edit.py | 14 +-
.../bastd/ui/soundtrack/entrytypeselect.py | 11 +-
docs/ba_module.md | 58 ++-
tools/update_project | 3 +
36 files changed, 386 insertions(+), 305 deletions(-)
diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index c755243e..9ea95dac 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -436,6 +436,7 @@
domreg
domsg
dont
+ doplay
doraise
dosend
dosomething
@@ -1066,6 +1067,7 @@
mtime
mtrans
mtvos
+ mtype
mult
multibytecodec
multikillcount
@@ -1074,6 +1076,8 @@
multiteamendscreen
multiteamjoinscreen
multithreaded
+ musicinfo
+ musicinfos
musicplayer
musictype
musopen
@@ -1526,6 +1530,7 @@
socketmodule
socketserver
somevar
+ soundtrackname
sourceimages
sourcelines
spacelen
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7204af67..b0c46787 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -50,6 +50,9 @@
- The bs.Vector class is no more; in its place is a shiny new ba.Vec3 which is implemented internally in C++ so its nice and speedy. Will probably update certain things like vector node attrs to support this class in the future since it makes vector math nice and convenient.
- Ok you get the point..
+### 1.4.151 (14371)
+- Added Chinese-Traditional language and improved translations for others.
+
### 1.4.150 (14369)
- Telnet port can now be specified in the config
- Telnet socket no longer opens on headless build when telnet access is off (reduces DoS attack potential)
diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py
index 2e170ee8..0b47f736 100644
--- a/assets/src/ba_data/python/_ba.py
+++ b/assets/src/ba_data/python/_ba.py
@@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
"""
# (hash we can use to see if this file is out of date)
-# SOURCES_HASH=107308741262112812748560676667362932520
+# SOURCES_HASH=237130603961569354119127975507628873256
# I'm sorry Pylint. I know this file saddens you. Be strong.
# pylint: disable=useless-suppression
@@ -2737,62 +2737,6 @@ def is_running_on_ouya() -> bool:
return bool()
-def itunes_get_library_source() -> None:
- """itunes_get_library_source() -> None
-
- (internal)
- """
- return None
-
-
-def itunes_get_playlists() -> List[str]:
- """itunes_get_playlists() -> List[str]
-
- (internal)
- """
- return ["blah", "blah2"]
-
-
-def itunes_get_volume() -> int:
- """itunes_get_volume() -> int
-
- (internal)
- """
- return int()
-
-
-def itunes_init() -> None:
- """itunes_init() -> None
-
- (internal)
- """
- return None
-
-
-def itunes_play_playlist(playlist: str) -> bool:
- """itunes_play_playlist(playlist: str) -> bool
-
- (internal)
- """
- return bool()
-
-
-def itunes_set_volume(volume: int) -> None:
- """itunes_set_volume(volume: int) -> None
-
- (internal)
- """
- return None
-
-
-def itunes_stop() -> None:
- """itunes_stop() -> None
-
- (internal)
- """
- return None
-
-
def lock_all_input() -> None:
"""lock_all_input() -> None
@@ -2825,6 +2769,62 @@ def log(message: str,
return None
+def mac_music_app_get_library_source() -> None:
+ """mac_music_app_get_library_source() -> None
+
+ (internal)
+ """
+ return None
+
+
+def mac_music_app_get_playlists() -> List[str]:
+ """mac_music_app_get_playlists() -> List[str]
+
+ (internal)
+ """
+ return ["blah", "blah2"]
+
+
+def mac_music_app_get_volume() -> int:
+ """mac_music_app_get_volume() -> int
+
+ (internal)
+ """
+ return int()
+
+
+def mac_music_app_init() -> None:
+ """mac_music_app_init() -> None
+
+ (internal)
+ """
+ return None
+
+
+def mac_music_app_play_playlist(playlist: str) -> bool:
+ """mac_music_app_play_playlist(playlist: str) -> bool
+
+ (internal)
+ """
+ return bool()
+
+
+def mac_music_app_set_volume(volume: int) -> None:
+ """mac_music_app_set_volume(volume: int) -> None
+
+ (internal)
+ """
+ return None
+
+
+def mac_music_app_stop() -> None:
+ """mac_music_app_stop() -> None
+
+ (internal)
+ """
+ return None
+
+
def mark_config_dirty() -> None:
"""mark_config_dirty() -> None
diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py
index cd490723..e175b7f7 100644
--- a/assets/src/ba_data/python/ba/__init__.py
+++ b/assets/src/ba_data/python/ba/__init__.py
@@ -78,7 +78,7 @@ from ba._messages import (OutOfBoundsMessage, DieMessage, StandMessage,
DroppedMessage, ShouldShatterMessage,
ImpactDamageMessage, FreezeMessage, ThawMessage,
HitMessage)
-from ba._music import setmusic, MusicPlayer
+from ba._music import setmusic, MusicPlayer, MusicType, MusicPlayMode
from ba._powerup import PowerupMessage, PowerupAcceptMessage
from ba._teambasesession import TeamBaseSession
from ba.ui import (OldWindow, UILocation, UILocationWindow, UIController,
diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py
index 293d22e0..a0fcf910 100644
--- a/assets/src/ba_data/python/ba/_activitytypes.py
+++ b/assets/src/ba_data/python/ba/_activitytypes.py
@@ -25,7 +25,8 @@ import time
from typing import TYPE_CHECKING
import _ba
-from ba import _activity
+from ba._activity import Activity
+from ba._music import setmusic, MusicType
if TYPE_CHECKING:
from typing import Any, Dict, Optional
@@ -33,7 +34,7 @@ if TYPE_CHECKING:
from ba._lobby import JoinInfo
-class EndSessionActivity(_activity.Activity):
+class EndSessionActivity(Activity):
"""Special ba.Activity to fade out and end the current ba.Session."""
def __init__(self, settings: Dict[str, Any]):
@@ -61,7 +62,7 @@ class EndSessionActivity(_activity.Activity):
call_after_ad(Call(_ba.new_host_session, MainMenuSession))
-class JoiningActivity(_activity.Activity):
+class JoiningActivity(Activity):
"""Standard activity for waiting for players to join.
It shows tips and other info and waits for all players to check ready.
@@ -88,18 +89,17 @@ class JoiningActivity(_activity.Activity):
# pylint: disable=cyclic-import
from bastd.actor.tipstext import TipsText
from bastd.actor.background import Background
- from ba import _music
super().on_transition_in()
self._background = Background(fade_time=0.5,
start_faded=True,
show_logo=True)
self._tips_text = TipsText()
- _music.setmusic('CharSelect')
+ setmusic(MusicType.CHAR_SELECT)
self._join_info = self.session.lobby.create_join_info()
_ba.set_analytics_screen('Joining Screen')
-class TransitionActivity(_activity.Activity):
+class TransitionActivity(Activity):
"""A simple overlay fade out/in.
Useful as a bare minimum transition between two level based activities.
@@ -132,7 +132,7 @@ class TransitionActivity(_activity.Activity):
_ba.timer(0.1, self.end)
-class ScoreScreenActivity(_activity.Activity):
+class ScoreScreenActivity(Activity):
"""A standard score screen that fades in and shows stuff for a while.
After a specified delay, player input is assigned to end the activity.
@@ -151,7 +151,7 @@ class ScoreScreenActivity(_activity.Activity):
self._tips_text: Optional[ba.Actor] = None
self._kicked_off_server_shutdown = False
self._kicked_off_server_restart = False
- self._default_music: Optional[str] = 'Scores'
+ self._default_music: Optional[MusicType] = MusicType.SCORES
self._default_show_tips = True
def on_player_join(self, player: ba.Player) -> None:
@@ -168,14 +168,13 @@ class ScoreScreenActivity(_activity.Activity):
def on_transition_in(self) -> None:
from bastd.actor.tipstext import TipsText
from bastd.actor.background import Background
- from ba import _music
super().on_transition_in()
self._background = Background(fade_time=0.5,
start_faded=False,
show_logo=True)
if self._default_show_tips:
self._tips_text = TipsText()
- _music.setmusic(self._default_music)
+ setmusic(self._default_music)
def on_begin(self, custom_continue_message: ba.Lstr = None) -> None:
# FIXME: Unify args.
diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py
index d3a04242..45b5ed31 100644
--- a/assets/src/ba_data/python/ba/_app.py
+++ b/assets/src/ba_data/python/ba/_app.py
@@ -259,6 +259,7 @@ class App:
the single shared instance.
"""
# pylint: disable=too-many-statements
+ from ba._music import MusicPlayMode
# _test_https()
@@ -270,26 +271,44 @@ class App:
# refreshed/etc.
self.fg_state = 0
- # Environment stuff (pulling these out as attrs so we can type-check
- # them).
+ # Environment stuff.
+ # (pulling these into attrs so we can type-check them)
+
env = _ba.env()
self._build_number: int = env['build_number']
+ assert isinstance(self._build_number, int)
self._config_file_path: str = env['config_file_path']
+ assert isinstance(self._config_file_path, str)
self._locale: str = env['locale']
+ assert isinstance(self._locale, str)
self._user_agent_string: str = env['user_agent_string']
+ assert isinstance(self._user_agent_string, str)
self._version: str = env['version']
+ assert isinstance(self._version, str)
self._debug_build: bool = env['debug_build']
+ assert isinstance(self._debug_build, bool)
self._test_build: bool = env['test_build']
+ assert isinstance(self._test_build, bool)
self._user_scripts_directory: str = env['user_scripts_directory']
+ assert isinstance(self._user_scripts_directory, str)
self._system_scripts_directory: str = env['system_scripts_directory']
+ assert isinstance(self._system_scripts_directory, str)
self._platform: str = env['platform']
+ assert isinstance(self._platform, str)
self._subplatform: str = env['subplatform']
+ assert isinstance(self._subplatform, str)
self._interface_type: str = env['interface_type']
+ assert isinstance(self._interface_type, str)
self._on_tv: bool = env['on_tv']
+ assert isinstance(self._on_tv, bool)
self._vr_mode: bool = env['vr_mode']
+ assert isinstance(self._vr_mode, bool)
self.protocol_version: int = env['protocol_version']
+ assert isinstance(self.protocol_version, int)
self.toolbar_test: bool = env['toolbar_test']
+ assert isinstance(self.toolbar_test, bool)
self.kiosk_mode: bool = env['kiosk_mode']
+ assert isinstance(self.kiosk_mode, bool)
# Misc.
self.default_language = self._get_default_language()
@@ -339,12 +358,12 @@ class App:
# Music.
self.music: Optional[ba.Node] = None
- self.music_mode: str = 'regular'
+ self.music_mode: ba.MusicPlayMode = MusicPlayMode.REGULAR
self.music_player: Optional[ba.MusicPlayer] = None
self.music_player_type: Optional[Type[ba.MusicPlayer]] = None
- self.music_types: Dict[str, Optional[str]] = {
- 'regular': None,
- 'test': None
+ self.music_types: Dict[ba.MusicPlayMode, Optional[ba.MusicType]] = {
+ MusicPlayMode.REGULAR: None,
+ MusicPlayMode.TEST: None
}
# Language.
@@ -443,15 +462,16 @@ class App:
cfg = self.config
- # Set up our app delegate.
self.delegate = appdelegate.AppDelegate()
+
self.uicontroller = bsui.UIController()
_achievement.init_achievements()
spazappearance.register_appearances()
_campaign.init_campaigns()
if _ba.env()['platform'] == 'android':
self.music_player_type = _music.InternalMusicPlayer
- elif _ba.env()['platform'] == 'mac' and hasattr(_ba, 'itunes_init'):
+ elif _ba.env()['platform'] == 'mac' and hasattr(
+ _ba, 'mac_music_app_init'):
self.music_player_type = _music.MacITunesMusicPlayer
# FIXME: This should not be hard-coded.
@@ -550,6 +570,8 @@ class App:
launch_count = cfg.get('launchCount', 0)
launch_count += 1
+ # So we know how many times we've run the game at various
+ # version milestones.
for key in ('lc14173', 'lc14292'):
cfg.setdefault(key, launch_count)
@@ -615,7 +637,6 @@ class App:
If there's a foreground host-activity that says it's pausable, tell it
to pause ..we now no longer pause if there are connected clients.
"""
- # pylint: disable=cyclic-import
activity = _ba.get_foreground_host_activity()
if (activity is not None and activity.allow_pausing
and not _ba.have_connected_clients()):
diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py
index f0ce5613..1d0ca1e6 100644
--- a/assets/src/ba_data/python/ba/_gameactivity.py
+++ b/assets/src/ba_data/python/ba/_gameactivity.py
@@ -308,7 +308,7 @@ class GameActivity(Activity):
# Music that should play in on_transition_in()
# (unless overridden by the map).
- self._default_music: Optional[str] = None
+ self._default_music: Optional[ba.MusicType] = None
# Go ahead and get our map loading.
map_name: str
diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py
index f2c17cd7..921c39b0 100644
--- a/assets/src/ba_data/python/ba/_map.py
+++ b/assets/src/ba_data/python/ba/_map.py
@@ -196,7 +196,7 @@ class Map(Actor):
return cls.name
@classmethod
- def get_music_type(cls) -> Optional[str]:
+ def get_music_type(cls) -> Optional[ba.MusicType]:
"""Return a music-type string that should be played on this map.
If None is returned, default music will be used.
diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py
index d696cb7e..1669c53f 100644
--- a/assets/src/ba_data/python/ba/_music.py
+++ b/assets/src/ba_data/python/ba/_music.py
@@ -26,11 +26,44 @@ import os
import random
import threading
from typing import TYPE_CHECKING
+from enum import Enum
import _ba
if TYPE_CHECKING:
- from typing import Callable, Any, List, Optional, Dict, Union
+ from typing import Callable, Any, List, Optional, Dict, Union, Tuple
+
+
+class MusicType(Enum):
+ """Types of music available to play in-game."""
+ MENU = 'Menu'
+ VICTORY = 'Victory'
+ CHAR_SELECT = 'CharSelect'
+ RUN_AWAY = 'RunAway'
+ ONSLAUGHT = 'Onslaught'
+ KEEP_AWAY = 'Keep Away'
+ RACE = 'Race'
+ EPIC_RACE = 'Epic Race'
+ SCORES = 'Scores'
+ GRAND_ROMP = 'GrandRomp'
+ TO_THE_DEATH = 'ToTheDeath'
+ CHOSEN_ONE = 'Chosen One'
+ FORWARD_MARCH = 'ForwardMarch'
+ FLAG_CATCHER = 'FlagCatcher'
+ SURVIVAL = 'Survival'
+ EPIC = 'Epic'
+ SPORTS = 'Sports'
+ HOCKEY = 'Hockey'
+ FOOTBALL = 'Football'
+ FLYING = 'Flying'
+ SCARY = 'Scary'
+ MARCHING = 'Marching'
+
+
+class MusicPlayMode(Enum):
+ """Influences behavior when playing music."""
+ REGULAR = 'regular'
+ TEST = 'test'
class MusicPlayer:
@@ -229,12 +262,13 @@ class InternalMusicPlayer(MusicPlayer):
# For internal music player.
+# FIXME: this only applies to Android currently.
def get_valid_music_file_extensions() -> List[str]:
"""Return file extensions for types playable on this device."""
return ['mp3', 'ogg', 'm4a', 'wav', 'flac', 'mid']
-class ITunesThread(threading.Thread):
+class MacMusicAppThread(threading.Thread):
"""Thread which wrangles iTunes/Music.app playback"""
def __init__(self) -> None:
@@ -246,16 +280,16 @@ class ITunesThread(threading.Thread):
self._orig_volume: Optional[int] = None
def run(self) -> None:
- """Run the iTunes/Music.app thread."""
+ """Run the Music.app thread."""
from ba._general import Call
from ba._lang import Lstr
from ba._enums import TimeType
- _ba.set_thread_name("BA_ITunesThread")
- _ba.itunes_init()
+ _ba.set_thread_name("BA_MacMusicAppThread")
+ _ba.mac_music_app_init()
- # It looks like launching iTunes here on 10.7/10.8 knocks us
- # out of fullscreen; ick. That might be a bug, but for now we
- # can work around it by reactivating ourself after.
+ # Let's mention to the user we're launching Music.app in case
+ # it causes any funny business (this used to background the app
+ # sometimes, though I think that is fixed now)
def do_print() -> None:
_ba.timer(1.0,
Call(_ba.screenmessage, Lstr(resource='usingItunesText'),
@@ -265,12 +299,8 @@ class ITunesThread(threading.Thread):
_ba.pushcall(do_print, from_other_thread=True)
# Here we grab this to force the actual launch.
- # Currently (on 10.8 at least) this is causing a switch
- # away from our fullscreen window. to work around this we
- # explicitly focus our main window to bring ourself back.
- _ba.itunes_get_volume()
- _ba.pushcall(_ba.focus_window, from_other_thread=True)
- _ba.itunes_get_library_source()
+ _ba.mac_music_app_get_volume()
+ _ba.mac_music_app_get_library_source()
done = False
while not done:
self._commands_available.wait()
@@ -307,8 +337,8 @@ class ITunesThread(threading.Thread):
if old_volume > 0.0 and volume == 0.0:
try:
assert self._orig_volume is not None
- _ba.itunes_stop()
- _ba.itunes_set_volume(self._orig_volume)
+ _ba.mac_music_app_stop()
+ _ba.mac_music_app_set_volume(self._orig_volume)
except Exception as exc:
print('Error stopping iTunes music:', exc)
elif self._volume > 0:
@@ -316,8 +346,8 @@ class ITunesThread(threading.Thread):
# If volume was zero, store pre-playing volume and start
# playing.
if old_volume == 0.0:
- self._orig_volume = _ba.itunes_get_volume()
- self._update_itunes_volume()
+ self._orig_volume = _ba.mac_music_app_get_volume()
+ self._update_mac_music_app_volume()
if old_volume == 0.0:
self._play_current_playlist()
@@ -341,7 +371,7 @@ class ITunesThread(threading.Thread):
self, target: Callable[[List[str]], None]) -> None:
from ba._general import Call
try:
- playlists = _ba.itunes_get_playlists()
+ playlists = _ba.mac_music_app_get_playlists()
playlists = [
p for p in playlists if p not in [
'Music', 'Movies', 'TV Shows', 'Podcasts', 'iTunes\xa0U',
@@ -360,8 +390,8 @@ class ITunesThread(threading.Thread):
if self._current_playlist is not None and self._volume > 0:
try:
assert self._orig_volume is not None
- _ba.itunes_stop()
- _ba.itunes_set_volume(self._orig_volume)
+ _ba.mac_music_app_stop()
+ _ba.mac_music_app_set_volume(self._orig_volume)
except Exception as exc:
print('Error stopping iTunes music:', exc)
self._current_playlist = None
@@ -371,16 +401,16 @@ class ITunesThread(threading.Thread):
if self._current_playlist is not None and self._volume > 0:
try:
assert self._orig_volume is not None
- _ba.itunes_stop()
- _ba.itunes_set_volume(self._orig_volume)
+ _ba.mac_music_app_stop()
+ _ba.mac_music_app_set_volume(self._orig_volume)
except Exception as exc:
print('Error stopping iTunes music:', exc)
# Set our playlist and play it if our volume is up.
self._current_playlist = target
if self._volume > 0:
- self._orig_volume = (_ba.itunes_get_volume())
- self._update_itunes_volume()
+ self._orig_volume = (_ba.mac_music_app_get_volume())
+ self._update_mac_music_app_volume()
self._play_current_playlist()
def _handle_die_command(self) -> None:
@@ -390,8 +420,8 @@ class ITunesThread(threading.Thread):
if self._current_playlist is not None and self._volume > 0:
try:
assert self._orig_volume is not None
- _ba.itunes_stop()
- _ba.itunes_set_volume(self._orig_volume)
+ _ba.mac_music_app_stop()
+ _ba.mac_music_app_set_volume(self._orig_volume)
except Exception as exc:
print('Error stopping iTunes music:', exc)
@@ -400,7 +430,7 @@ class ITunesThread(threading.Thread):
from ba import _lang
from ba._general import Call
assert self._current_playlist is not None
- if _ba.itunes_play_playlist(self._current_playlist):
+ if _ba.mac_music_app_play_playlist(self._current_playlist):
pass
else:
_ba.pushcall(Call(
@@ -413,8 +443,9 @@ class ITunesThread(threading.Thread):
_error.print_exception(
f"error playing playlist {self._current_playlist}")
- def _update_itunes_volume(self) -> None:
- _ba.itunes_set_volume(max(0, min(100, int(100.0 * self._volume))))
+ def _update_mac_music_app_volume(self) -> None:
+ _ba.mac_music_app_set_volume(
+ max(0, min(100, int(100.0 * self._volume))))
class MacITunesMusicPlayer(MusicPlayer):
@@ -425,7 +456,7 @@ class MacITunesMusicPlayer(MusicPlayer):
def __init__(self) -> None:
super().__init__()
- self._thread = ITunesThread()
+ self._thread = MacMusicAppThread()
self._thread.start()
def on_select_entry(self, callback: Callable[[Any], None],
@@ -479,7 +510,8 @@ def music_volume_changed(val: float) -> None:
app.music_player.set_volume(val)
-def set_music_play_mode(mode: str, force_restart: bool = False) -> None:
+def set_music_play_mode(mode: MusicPlayMode,
+ force_restart: bool = False) -> None:
"""Sets music play mode; used for soundtrack testing/etc."""
app = _ba.app
old_mode = app.music_mode
@@ -490,8 +522,9 @@ def set_music_play_mode(mode: str, force_restart: bool = False) -> None:
# actually play anything until its requested.
# If we're switching *out* of test mode though
# we want to go back to whatever the normal song was.
- if mode == 'regular':
- do_play_music(app.music_types['regular'])
+ if mode is MusicPlayMode.REGULAR:
+ mtype = app.music_types[MusicPlayMode.REGULAR]
+ do_play_music(None if mtype is None else mtype.value)
def supports_soundtrack_entry_type(entry_type: str) -> bool:
@@ -556,17 +589,11 @@ def get_soundtrack_entry_name(entry: Any) -> str:
return 'default'
-def setmusic(musictype: Optional[str], continuous: bool = False) -> None:
+def setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None:
"""Set or stop the current music based on a string musictype.
category: Gameplay Functions
- Current valid values for 'musictype': 'Menu', 'Victory', 'CharSelect',
- 'RunAway', 'Onslaught', 'Keep Away', 'Race', 'Epic Race', 'Scores',
- 'GrandRomp', 'ToTheDeath', 'Chosen One', 'ForwardMarch', 'FlagCatcher',
- 'Survival', 'Epic', 'Sports', 'Hockey', 'Football', 'Flying', 'Scary',
- 'Marching'.
-
This function will handle loading and playing sound media as necessary,
and also supports custom user soundtracks on specific platforms so the
user can override particular game music with their own.
@@ -585,7 +612,7 @@ def setmusic(musictype: Optional[str], continuous: bool = False) -> None:
# not an actual sound node create.
gnode = _gameutils.sharedobj('globals')
gnode.music_continuous = continuous
- gnode.music = '' if musictype is None else musictype
+ gnode.music = '' if musictype is None else musictype.value
gnode.music_count += 1
@@ -595,27 +622,33 @@ def handle_app_resume() -> None:
do_play_music(None)
-def do_play_music(musictype: Optional[str],
+def do_play_music(musictype: Union[MusicType, str, None],
continuous: bool = False,
- mode: str = 'regular',
- testsoundtrack: Dict = None) -> None:
+ mode: MusicPlayMode = MusicPlayMode.REGULAR,
+ testsoundtrack: Dict[str, Any] = None) -> None:
"""Plays the requested music type/mode.
For most cases setmusic() is the proper call to use, which itself calls
this. Certain cases, however, such as soundtrack testing, may require
calling this directly.
"""
- # pylint: disable=too-many-branches
- # pylint: disable=too-many-statements
+
+ # We can be passed a MusicType or the string value of one.
+ if musictype is not None:
+ try:
+ musictype = MusicType(musictype)
+ except ValueError:
+ print(f"Invalid music type: '{musictype}'")
+ musictype = None
+
app = _ba.app
with _ba.Context('ui'):
# If they don't want to restart music and we're already
# playing what's requested, we're done.
- if continuous and app.music_types[mode] == musictype:
+ if continuous and app.music_types[mode] is musictype:
return
app.music_types[mode] = musictype
- cfg = app.config
# If the OS tells us there's currently music playing,
# all our operations default to playing nothing.
@@ -632,127 +665,104 @@ def do_play_music(musictype: Optional[str],
# entry for this music-type, and if we have one, have the music-player
# play it. If not, we'll play game music ourself.
if musictype is not None and app.music_player_type is not None:
- try:
- soundtrack: Dict
- if testsoundtrack is not None:
- soundtrack = testsoundtrack
- else:
- soundtrack = cfg['Soundtracks'][cfg['Soundtrack']]
- entry = soundtrack[musictype]
- except Exception:
- entry = None
+ if testsoundtrack is not None:
+ soundtrack = testsoundtrack
+ else:
+ soundtrack = _get_user_soundtrack()
+ entry = soundtrack.get(musictype.value)
else:
entry = None
# Go through music-player.
if entry is not None:
-
- # Stop any existing internal music.
- if app.music is not None:
- app.music.delete()
- app.music = None
-
- # Play music-player music.
- get_music_player().play(entry)
+ _play_music_player_music(entry)
# Handle via internal music.
else:
- if musictype is not None:
- loop = True
- if musictype == 'Menu':
- filename = 'menuMusic'
- volume = 5.0
- elif musictype == 'Victory':
- filename = 'victoryMusic'
- volume = 6.0
- loop = False
- elif musictype == 'CharSelect':
- filename = 'charSelectMusic'
- volume = 2.0
- elif musictype == 'RunAway':
- filename = 'runAwayMusic'
- volume = 6.0
- elif musictype == 'Onslaught':
- filename = 'runAwayMusic'
- volume = 6.0
- elif musictype == 'Keep Away':
- filename = 'runAwayMusic'
- volume = 6.0
- elif musictype == 'Race':
- filename = 'runAwayMusic'
- volume = 6.0
- elif musictype == 'Epic Race':
- filename = 'slowEpicMusic'
- volume = 6.0
- elif musictype == 'Scores':
- filename = 'scoresEpicMusic'
- volume = 3.0
- loop = False
- elif musictype == 'GrandRomp':
- filename = 'grandRompMusic'
- volume = 6.0
- elif musictype == 'ToTheDeath':
- filename = 'toTheDeathMusic'
- volume = 6.0
- elif musictype == 'Chosen One':
- filename = 'survivalMusic'
- volume = 4.0
- elif musictype == 'ForwardMarch':
- filename = 'forwardMarchMusic'
- volume = 4.0
- elif musictype == 'FlagCatcher':
- filename = 'flagCatcherMusic'
- volume = 6.0
- elif musictype == 'Survival':
- filename = 'survivalMusic'
- volume = 4.0
- elif musictype == 'Epic':
- filename = 'slowEpicMusic'
- volume = 6.0
- elif musictype == 'Sports':
- filename = 'sportsMusic'
- volume = 4.0
- elif musictype == 'Hockey':
- filename = 'sportsMusic'
- volume = 4.0
- elif musictype == 'Football':
- filename = 'sportsMusic'
- volume = 4.0
- elif musictype == 'Flying':
- filename = 'flyingMusic'
- volume = 4.0
- elif musictype == 'Scary':
- filename = 'scaryMusic'
- volume = 4.0
- elif musictype == 'Marching':
- filename = 'whenJohnnyComesMarchingHomeMusic'
- volume = 4.0
- else:
- print("Unknown music: '" + musictype + "'")
- filename = 'flagCatcherMusic'
- volume = 6.0
+ _play_internal_music(musictype)
- # Stop any existing music-player playback.
- if app.music_player is not None:
- app.music_player.stop()
- # Stop any existing internal music.
- if app.music:
- app.music.delete()
- app.music = None
+def _get_user_soundtrack() -> Dict[str, Any]:
+ """Return current user soundtrack or empty dict otherwise."""
+ cfg = _ba.app.config
+ soundtrack: Dict[str, Any] = {}
+ soundtrackname = cfg.get('Soundtrack')
+ if soundtrackname is not None:
+ try:
+ soundtrack = cfg['Soundtracks'][soundtrackname]
+ except Exception as exc:
+ print(f"Error looking up user soundtrack: {exc}")
+ soundtrack = {}
+ return soundtrack
- # Start up new internal music.
- if musictype is not None:
- # FIXME: Currently this won't start playing if we're paused
- # since attr values don't get updated until
- # node updates happen. :-(
- # Update: hmm I don't think that's true anymore. Should check.
- app.music = _ba.newnode(type='sound',
- attrs={
- 'sound': _ba.getsound(filename),
- 'positional': False,
- 'music': True,
- 'volume': volume,
- 'loop': loop
- })
+def _play_music_player_music(entry: Any) -> None:
+ app = _ba.app
+
+ # Stop any existing internal music.
+ if app.music is not None:
+ app.music.delete()
+ app.music = None
+
+ # Do the thing.
+ get_music_player().play(entry)
+
+
+def _play_internal_music(musictype: Optional[MusicType]) -> None:
+ app = _ba.app
+
+ # Stop any existing music-player playback.
+ if app.music_player is not None:
+ app.music_player.stop()
+
+ # Stop any existing internal music.
+ if app.music:
+ app.music.delete()
+ app.music = None
+
+ # Start up new internal music.
+ if musictype is not None:
+
+ # Filenames/volume/loop for our built-in music.
+ musicinfos: Dict[MusicType, Tuple[str, float, bool]] = {
+ MusicType.MENU: ('menuMusic', 5.0, True),
+ MusicType.VICTORY: ('victoryMusic', 6.0, False),
+ MusicType.CHAR_SELECT: ('charSelectMusic', 2.0, True),
+ MusicType.RUN_AWAY: ('runAwayMusic', 6.0, True),
+ MusicType.ONSLAUGHT: ('runAwayMusic', 6.0, True),
+ MusicType.KEEP_AWAY: ('runAwayMusic', 6.0, True),
+ MusicType.RACE: ('runAwayMusic', 6.0, True),
+ MusicType.EPIC_RACE: ('slowEpicMusic', 6.0, True),
+ MusicType.SCORES: ('scoresEpicMusic', 3.0, False),
+ MusicType.GRAND_ROMP: ('grandRompMusic', 6.0, True),
+ MusicType.TO_THE_DEATH: ('toTheDeathMusic', 6.0, True),
+ MusicType.CHOSEN_ONE: ('survivalMusic', 4.0, True),
+ MusicType.FORWARD_MARCH: ('forwardMarchMusic', 4.0, True),
+ MusicType.FLAG_CATCHER: ('flagCatcherMusic', 6.0, True),
+ MusicType.SURVIVAL: ('survivalMusic', 4.0, True),
+ MusicType.EPIC: ('slowEpicMusic', 6.0, True),
+ MusicType.SPORTS: ('sportsMusic', 4.0, True),
+ MusicType.HOCKEY: ('sportsMusic', 4.0, True),
+ MusicType.FOOTBALL: ('sportsMusic', 4.0, True),
+ MusicType.FLYING: ('flyingMusic', 4.0, True),
+ MusicType.SCARY: ('scaryMusic', 4.0, True),
+ MusicType.MARCHING:
+ ('whenJohnnyComesMarchingHomeMusic', 4.0, True),
+ }
+ musicinfo = musicinfos.get(musictype)
+ if musicinfo is None:
+ print(f"Unknown music: '{musictype}'")
+ filename = 'flagCatcherMusic'
+ volume = 6.0
+ loop = True
+ else:
+ filename, volume, loop = musicinfo
+
+ app.music = _ba.newnode(type='sound',
+ attrs={
+ 'sound': _ba.getsound(filename),
+ 'positional': False,
+ 'music': True,
+ 'volume': volume,
+ 'loop': loop
+ })
diff --git a/assets/src/ba_data/python/bastd/activity/multiteamendscreen.py b/assets/src/ba_data/python/bastd/activity/multiteamendscreen.py
index 042cefb1..18b8be64 100644
--- a/assets/src/ba_data/python/bastd/activity/multiteamendscreen.py
+++ b/assets/src/ba_data/python/bastd/activity/multiteamendscreen.py
@@ -340,7 +340,7 @@ class TeamSeriesVictoryScoreScreenActivity(TeamsScoreScreenActivity):
# Make sure we don't stomp on the next activity's music choice.
if not self.is_transitioning_out():
- ba.setmusic('Victory')
+ ba.setmusic(ba.MusicType.VICTORY)
def _show_winner(self, team: ba.Team) -> None:
from bastd.actor.image import Image
diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py
index 2d2b13e2..6e237236 100644
--- a/assets/src/ba_data/python/bastd/game/assault.py
+++ b/assets/src/ba_data/python/bastd/game/assault.py
@@ -94,8 +94,8 @@ class AssaultGame(ba.TeamGameActivity):
return 'touch ${ARG1} flags', self.settings['Score to Win']
def on_transition_in(self) -> None:
- self._default_music = ('Epic' if self.settings['Epic Mode'] else
- 'ForwardMarch')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.FORWARD_MARCH)
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py
index c2086979..c252aba1 100644
--- a/assets/src/ba_data/python/bastd/game/capturetheflag.py
+++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py
@@ -135,8 +135,8 @@ class CaptureTheFlagGame(ba.TeamGameActivity):
return 'return ${ARG1} flags', self.settings['Score to Win']
def on_transition_in(self) -> None:
- self._default_music = ('Epic' if self.settings['Epic Mode'] else
- 'FlagCatcher')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.FLAG_CATCHER)
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py
index 2c83efc2..a3616c2b 100644
--- a/assets/src/ba_data/python/bastd/game/chosenone.py
+++ b/assets/src/ba_data/python/bastd/game/chosenone.py
@@ -118,8 +118,8 @@ class ChosenOneGame(ba.TeamGameActivity):
return 'There can be only one.'
def on_transition_in(self) -> None:
- self._default_music = ('Epic'
- if self.settings['Epic Mode'] else 'Chosen One')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.CHOSEN_ONE)
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py
index 112b5561..0b861cec 100644
--- a/assets/src/ba_data/python/bastd/game/conquest.py
+++ b/assets/src/ba_data/python/bastd/game/conquest.py
@@ -123,8 +123,8 @@ class ConquestGame(ba.TeamGameActivity):
return 'secure all ${ARG1} flags', len(self.map.flag_points)
def on_transition_in(self) -> None:
- self._default_music = ('Epic'
- if self.settings['Epic Mode'] else 'GrandRomp')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.GRAND_ROMP)
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py
index d31f18ce..f63fc2e4 100644
--- a/assets/src/ba_data/python/bastd/game/deathmatch.py
+++ b/assets/src/ba_data/python/bastd/game/deathmatch.py
@@ -115,8 +115,8 @@ class DeathMatchGame(ba.TeamGameActivity):
return 'kill ${ARG1} enemies', self._score_to_win
def on_transition_in(self) -> None:
- self._default_music = ('Epic'
- if self.settings['Epic Mode'] else 'ToTheDeath')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.TO_THE_DEATH)
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py
index e17cee1a..e3eed70d 100644
--- a/assets/src/ba_data/python/bastd/game/easteregghunt.py
+++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py
@@ -97,7 +97,7 @@ class EasterEggHuntGame(ba.TeamGameActivity):
# ..we can go ahead and set our music and whatnot.
def on_transition_in(self) -> None:
- self._default_music = 'ForwardMarch'
+ self._default_music = ba.MusicType.FORWARD_MARCH
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py
index 1c618b9d..801899f9 100644
--- a/assets/src/ba_data/python/bastd/game/elimination.py
+++ b/assets/src/ba_data/python/bastd/game/elimination.py
@@ -244,8 +244,8 @@ class EliminationGame(ba.TeamGameActivity):
self.session, ba.TeamsSession) else 'last one standing wins'
def on_transition_in(self) -> None:
- self._default_music = ('Epic'
- if self.settings['Epic Mode'] else 'Survival')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.SURVIVAL)
super().on_transition_in()
self._start_time = ba.time()
diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py
index 6157bc11..f7bef46f 100644
--- a/assets/src/ba_data/python/bastd/game/football.py
+++ b/assets/src/ba_data/python/bastd/game/football.py
@@ -146,7 +146,7 @@ class FootballTeamGame(ba.TeamGameActivity):
return 'score a touchdown'
def on_transition_in(self) -> None:
- self._default_music = 'Football'
+ self._default_music = ba.MusicType.FOOTBALL
super().on_transition_in()
def on_begin(self) -> None:
@@ -397,7 +397,7 @@ class FootballCoopGame(ba.CoopGameActivity):
self._flag: Optional[FootballFlag] = None
def on_transition_in(self) -> None:
- self._default_music = 'Football'
+ self._default_music = ba.MusicType.FOOTBALL
super().on_transition_in()
self._scoreboard = Scoreboard()
self._flag_spawn_pos = self.map.get_flag_position(None)
@@ -748,7 +748,7 @@ class FootballCoopGame(ba.CoopGameActivity):
if team is self._bot_team:
self.continue_or_end_game()
else:
- ba.setmusic('Victory')
+ ba.setmusic(ba.MusicType.VICTORY)
# Completion achievements.
assert self._bot_team is not None
diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py
index 4e463096..3110d8b5 100644
--- a/assets/src/ba_data/python/bastd/game/hockey.py
+++ b/assets/src/ba_data/python/bastd/game/hockey.py
@@ -207,7 +207,7 @@ class HockeyGame(ba.TeamGameActivity):
return 'score ${ARG1} goals', self.settings['Score to Win']
def on_transition_in(self) -> None:
- self._default_music = 'Hockey'
+ self._default_music = ba.MusicType.HOCKEY
super().on_transition_in()
def on_begin(self) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py
index c7b1b1c4..bdc1bbb8 100644
--- a/assets/src/ba_data/python/bastd/game/keepaway.py
+++ b/assets/src/ba_data/python/bastd/game/keepaway.py
@@ -124,7 +124,7 @@ class KeepAwayGame(ba.TeamGameActivity):
self.settings['Hold Time'])
def on_transition_in(self) -> None:
- self._default_music = 'Keep Away'
+ self._default_music = ba.MusicType.KEEP_AWAY
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py
index 33e249d1..6d0dfa9d 100644
--- a/assets/src/ba_data/python/bastd/game/kingofthehill.py
+++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py
@@ -133,7 +133,7 @@ class KingOfTheHillGame(ba.TeamGameActivity):
self.settings['Hold Time'])
def on_transition_in(self) -> None:
- self._default_music = 'Scary'
+ self._default_music = ba.MusicType.SCARY
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py
index c3583cee..4073df37 100644
--- a/assets/src/ba_data/python/bastd/game/meteorshower.py
+++ b/assets/src/ba_data/python/bastd/game/meteorshower.py
@@ -91,8 +91,8 @@ class MeteorShowerGame(ba.TeamGameActivity):
# Called when our game is transitioning in but not ready to start;
# ..we can go ahead and set our music and whatnot.
def on_transition_in(self) -> None:
- self._default_music = ('Epic'
- if self.settings['Epic Mode'] else 'Survival')
+ self._default_music = (ba.MusicType.EPIC if self.settings['Epic Mode']
+ else ba.MusicType.SURVIVAL)
super().on_transition_in()
# Called when our game actually starts.
diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py
index d8ad7e07..ce2866e5 100644
--- a/assets/src/ba_data/python/bastd/game/ninjafight.py
+++ b/assets/src/ba_data/python/bastd/game/ninjafight.py
@@ -84,7 +84,7 @@ class NinjaFightGame(ba.TeamGameActivity):
# Called when our game is transitioning in but not ready to begin;
# we can go ahead and start creating stuff, playing music, etc.
def on_transition_in(self) -> None:
- self._default_music = 'ToTheDeath'
+ self._default_music = ba.MusicType.TO_THE_DEATH
super().on_transition_in()
# Called when our game actually begins.
diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py
index f2edcd67..aaa0f4c3 100644
--- a/assets/src/ba_data/python/bastd/game/onslaught.py
+++ b/assets/src/ba_data/python/bastd/game/onslaught.py
@@ -180,7 +180,7 @@ class OnslaughtGame(ba.CoopGameActivity):
'color': (0.3, 0.8, 0.3, 1.0),
'text': ''
}))
- ba.setmusic('Onslaught')
+ ba.setmusic(ba.MusicType.ONSLAUGHT)
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
score_split=0.5)
@@ -769,7 +769,7 @@ class OnslaughtGame(ba.CoopGameActivity):
base_delay += 0.85
ba.playsound(self._winsound)
ba.cameraflash()
- ba.setmusic('Victory')
+ ba.setmusic(ba.MusicType.VICTORY)
self._game_over = True
# Can't just pass delay to do_end because our extra bonuses
diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py
index e1ceb11c..46032cc5 100644
--- a/assets/src/ba_data/python/bastd/game/race.py
+++ b/assets/src/ba_data/python/bastd/game/race.py
@@ -172,8 +172,9 @@ class RaceGame(ba.TeamGameActivity):
return 'run 1 lap'
def on_transition_in(self) -> None:
- self._default_music = ('Epic Race'
- if self.settings['Epic Mode'] else 'Race')
+ self._default_music = (ba.MusicType.EPIC_RACE
+ if self.settings['Epic Mode'] else
+ ba.MusicType.RACE)
super().on_transition_in()
pts = self.map.get_def_points('race_point')
diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py
index d3fd6c67..95496c1d 100644
--- a/assets/src/ba_data/python/bastd/game/runaround.py
+++ b/assets/src/ba_data/python/bastd/game/runaround.py
@@ -130,7 +130,7 @@ class RunaroundGame(ba.CoopGameActivity):
self._wave_update_timer: Optional[ba.Timer] = None
def on_transition_in(self) -> None:
- self._default_music = 'Marching'
+ self._default_music = ba.MusicType.MARCHING
super().on_transition_in()
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
score_split=0.5)
@@ -630,7 +630,7 @@ class RunaroundGame(ba.CoopGameActivity):
base_delay += 0.85
ba.playsound(self._winsound)
ba.cameraflash()
- ba.setmusic('Victory')
+ ba.setmusic(ba.MusicType.VICTORY)
self._game_over = True
ba.timer(base_delay, ba.Call(self.do_end, 'victory'))
return
diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py
index 967ba13e..6ef51b8d 100644
--- a/assets/src/ba_data/python/bastd/game/targetpractice.py
+++ b/assets/src/ba_data/python/bastd/game/targetpractice.py
@@ -81,7 +81,7 @@ class TargetPracticeGame(ba.TeamGameActivity):
self._countdown: Optional[OnScreenCountdown] = None
def on_transition_in(self) -> None:
- self._default_music = 'ForwardMarch'
+ self._default_music = ba.MusicType.FORWARD_MARCH
super().on_transition_in()
def on_team_join(self, team: ba.Team) -> None:
diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py
index 4c4003ff..9c61aa3e 100644
--- a/assets/src/ba_data/python/bastd/game/thelaststand.py
+++ b/assets/src/ba_data/python/bastd/game/thelaststand.py
@@ -98,7 +98,7 @@ class TheLastStandGame(ba.CoopGameActivity):
def on_transition_in(self) -> None:
from bastd.actor.scoreboard import Scoreboard
- self._default_music = 'Epic'
+ self._default_music = ba.MusicType.EPIC
super().on_transition_in()
ba.timer(1.3, ba.Call(ba.playsound, self._new_wave_sound))
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py
index 32e88584..3bedc1b9 100644
--- a/assets/src/ba_data/python/bastd/mainmenu.py
+++ b/assets/src/ba_data/python/bastd/mainmenu.py
@@ -822,7 +822,7 @@ class MainMenuActivity(ba.Activity):
with ba.Context(self):
_preload1()
- ba.timer(0.5, lambda: ba.setmusic('Menu'))
+ ba.timer(0.5, lambda: ba.setmusic(ba.MusicType.MENU))
def _preload1() -> None:
diff --git a/assets/src/ba_data/python/bastd/maps.py b/assets/src/ba_data/python/bastd/maps.py
index 9d4ea0db..fb156ee5 100644
--- a/assets/src/ba_data/python/bastd/maps.py
+++ b/assets/src/ba_data/python/bastd/maps.py
@@ -1216,8 +1216,8 @@ class HappyThoughts(ba.Map):
return data
@classmethod
- def get_music_type(cls) -> str:
- return 'Flying'
+ def get_music_type(cls) -> ba.MusicType:
+ return ba.MusicType.FLYING
def __init__(self) -> None:
super().__init__(vr_overlay_offset=(0, -3.7, 2.5))
diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py
index 1aa81925..49ba92ef 100644
--- a/assets/src/ba_data/python/bastd/tutorial.py
+++ b/assets/src/ba_data/python/bastd/tutorial.py
@@ -234,7 +234,7 @@ class TutorialActivity(ba.Activity):
def on_transition_in(self) -> None:
super().on_transition_in()
- ba.setmusic('CharSelect', continuous=True)
+ ba.setmusic(ba.MusicType.CHAR_SELECT, continuous=True)
self._map = self._map_type()
def on_begin(self) -> None:
diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
index f062fec4..3be46c26 100644
--- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
+++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
@@ -188,7 +188,7 @@ class SoundtrackBrowserWindow(ba.OldWindow):
ba.widget(edit=btn,
left_widget=_ba.get_special_widget('back_button'))
- # keep our lock images up to date/etc.
+ # Keep our lock images up to date/etc.
self._update_timer = ba.Timer(1.0,
ba.WeakCall(self._update),
timetype=ba.TimeType.REAL,
@@ -282,10 +282,10 @@ class SoundtrackBrowserWindow(ba.OldWindow):
else:
sdtk = cfg['Soundtracks'][self._selected_soundtrack]
- # find a valid dup name that doesn't exist
+ # Find a valid dup name that doesn't exist.
test_index = 1
copy_text = ba.Lstr(resource='copyOfText').evaluate()
- # get just 'Copy' or whatnot
+ # Get just 'Copy' or whatnot.
copy_word = copy_text.replace('${NAME}', '').strip()
base_name = self._get_soundtrack_display_name(
self._selected_soundtrack).evaluate()
@@ -294,7 +294,7 @@ class SoundtrackBrowserWindow(ba.OldWindow):
assert isinstance(base_name, bytes)
base_name = base_name.decode('utf-8')
- # if it looks like a copy, strip digits and spaces off the end
+ # If it looks like a copy, strip digits and spaces off the end.
if copy_word in base_name:
while base_name[-1].isdigit() or base_name[-1] == ' ':
base_name = base_name[:-1]
@@ -320,14 +320,14 @@ class SoundtrackBrowserWindow(ba.OldWindow):
cfg = ba.app.config
current_soundtrack = cfg.setdefault('Soundtrack', '__default__')
- # if it varies from current, commit and play
+ # If it varies from current, commit and play.
if current_soundtrack != name and self._allow_changing_soundtracks:
ba.playsound(ba.getsound('gunCocking'))
cfg['Soundtrack'] = self._selected_soundtrack
cfg.commit()
- # just play whats already playing.. this'll grab it from the
- # new soundtrack
- do_play_music(ba.app.music_types['regular'])
+ # Just play whats already playing.. this'll grab it from the
+ # new soundtrack.
+ do_play_music(ba.app.music_types[ba.MusicPlayMode.REGULAR])
def _back(self) -> None:
# pylint: disable=cyclic-import
diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
index 9a96de21..1ad8746a 100644
--- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
+++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
@@ -280,7 +280,7 @@ class SoundtrackEditWindow(ba.OldWindow):
size=(50, 32),
label=ba.Lstr(resource=self._r + '.testText'),
text_scale=0.6,
- on_activate_call=ba.Call(self._test, song_type),
+ on_activate_call=ba.Call(self._test, ba.MusicType(song_type)),
up_widget=prev_test_button
if prev_test_button is not None else self._text_field)
if prev_test_button is not None:
@@ -330,7 +330,7 @@ class SoundtrackEditWindow(ba.OldWindow):
ba.Call(self._restore_editor, state, song_type), entry,
selection_target_name).get_root_widget())
- def _test(self, song_type: str) -> None:
+ def _test(self, song_type: ba.MusicType) -> None:
from ba.internal import set_music_play_mode, do_play_music
# Warn if volume is zero.
@@ -339,8 +339,10 @@ class SoundtrackEditWindow(ba.OldWindow):
ba.screenmessage(ba.Lstr(resource=self._r +
'.musicVolumeZeroWarning'),
color=(1, 0.5, 0))
- set_music_play_mode('test')
- do_play_music(song_type, mode='test', testsoundtrack=self._soundtrack)
+ set_music_play_mode(ba.MusicPlayMode.TEST)
+ do_play_music(song_type,
+ mode=ba.MusicPlayMode.TEST,
+ testsoundtrack=self._soundtrack)
def _get_entry_button_display_name(self,
entry: Any) -> Union[str, ba.Lstr]:
@@ -369,7 +371,7 @@ class SoundtrackEditWindow(ba.OldWindow):
from ba.internal import set_music_play_mode
from bastd.ui.soundtrack import browser as stb
# Resets music back to normal.
- set_music_play_mode('regular')
+ set_music_play_mode(ba.MusicPlayMode.REGULAR)
ba.containerwidget(edit=self._root_widget, transition='out_right')
ba.app.main_menu_window = (stb.SoundtrackBrowserWindow(
transition='in_left').get_root_widget())
@@ -411,7 +413,7 @@ class SoundtrackEditWindow(ba.OldWindow):
ba.containerwidget(edit=self._root_widget, transition='out_right')
# Resets music back to normal.
- set_music_play_mode('regular', force_restart=True)
+ set_music_play_mode(ba.MusicPlayMode.REGULAR, force_restart=True)
ba.app.main_menu_window = (stb.SoundtrackBrowserWindow(
transition='in_left').get_root_widget())
diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py
index 6969b183..8c8c5e2a 100644
--- a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py
+++ b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py
@@ -51,11 +51,12 @@ class SoundtrackEntryTypeSelectWindow(ba.OldWindow):
spacing = 80
do_default = True
- do_itunes_playlist = supports_soundtrack_entry_type('iTunesPlaylist')
+ do_mac_music_app_playlist = supports_soundtrack_entry_type(
+ 'iTunesPlaylist')
do_music_file = supports_soundtrack_entry_type('musicFile')
do_music_folder = supports_soundtrack_entry_type('musicFolder')
- if do_itunes_playlist:
+ if do_mac_music_app_playlist:
self._height += spacing
if do_music_file:
self._height += spacing
@@ -108,13 +109,13 @@ class SoundtrackEntryTypeSelectWindow(ba.OldWindow):
ba.containerwidget(edit=self._root_widget, selected_child=btn)
v -= spacing
- if do_itunes_playlist:
+ if do_mac_music_app_playlist:
btn = ba.buttonwidget(
parent=self._root_widget,
size=(self._width - 100, 60),
position=(50, v),
label=ba.Lstr(resource=self._r + '.useITunesPlaylistText'),
- on_activate_call=self._on_itunes_playlist_press,
+ on_activate_call=self._on_mac_music_app_playlist_press,
icon=None)
if current_entry_type == 'iTunesPlaylist':
ba.containerwidget(edit=self._root_widget, selected_child=btn)
@@ -145,7 +146,7 @@ class SoundtrackEntryTypeSelectWindow(ba.OldWindow):
ba.containerwidget(edit=self._root_widget, selected_child=btn)
v -= spacing
- def _on_itunes_playlist_press(self) -> None:
+ def _on_mac_music_app_playlist_press(self) -> None:
from ba.internal import (get_soundtrack_entry_type,
get_soundtrack_entry_name)
from bastd.ui.soundtrack import itunes
diff --git a/docs/ba_module.md b/docs/ba_module.md
index a7e84299..b16d0d05 100644
--- a/docs/ba_module.md
+++ b/docs/ba_module.md
@@ -1,5 +1,5 @@
-last updated on 2020-03-31 for Ballistica version 1.5.0 build 20001
+last updated on 2020-04-01 for Ballistica version 1.5.0 build 20001
This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please let me know. Happy modding!
@@ -174,7 +174,7 @@
ba.WidgetNotFoundError
-
+
-
+
@@ -2806,7 +2808,7 @@ as far from these players as possible.
<class method>
-get_music_type() -> Optional[str]
+get_music_type() -> Optional[ba.MusicType]
Return a music-type string that should be played on this map.
@@ -3146,6 +3148,46 @@ signify that the default soundtrack should be used..
+inherits from: enum.Enum
+Influences behavior when playing music.
+
+Values:
+
+
+inherits from: enum.Enum
+Types of music available to play in-game.
+
+Values:
+
+- MENU
+- VICTORY
+- CHAR_SELECT
+- RUN_AWAY
+- ONSLAUGHT
+- KEEP_AWAY
+- RACE
+- EPIC_RACE
+- SCORES
+- GRAND_ROMP
+- TO_THE_DEATH
+- CHOSEN_ONE
+- FORWARD_MARCH
+- FLAG_CATCHER
+- SURVIVAL
+- EPIC
+- SPORTS
+- HOCKEY
+- FOOTBALL
+- FLYING
+- SCARY
+- MARCHING
+
+
<top level class>
@@ -5627,18 +5669,12 @@ are applied to the Widget.
setmusic(musictype: Optional[str], continuous: bool = False) -> None
+setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None
Set or stop the current music based on a string musictype.
Category: Gameplay Functions
-Current valid values for 'musictype': 'Menu', 'Victory', 'CharSelect',
-'RunAway', 'Onslaught', 'Keep Away', 'Race', 'Epic Race', 'Scores',
-'GrandRomp', 'ToTheDeath', 'Chosen One', 'ForwardMarch', 'FlagCatcher',
-'Survival', 'Epic', 'Sports', 'Hockey', 'Football', 'Flying', 'Scary',
-'Marching'.
-
This function will handle loading and playing sound media as necessary,
and also supports custom user soundtracks on specific platforms so the
user can override particular game music with their own.
diff --git a/tools/update_project b/tools/update_project
index 16387d33..f8ad1c9f 100755
--- a/tools/update_project
+++ b/tools/update_project
@@ -105,6 +105,9 @@ class App:
self._check_sync_states()
self._find_sources_and_headers('src/ballistica')
+
+ # FIXME: It might make more sense to have some of these checks
+ # run via 'make check' rather than here through 'make update'.
self._check_source_files()
self._check_headers()