mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-27 01:13:13 +08:00
Cleaned up music playback
This commit is contained in:
parent
6f3f1644b4
commit
2a2e64b7ab
5
.idea/dictionaries/ericf.xml
generated
5
.idea/dictionaries/ericf.xml
generated
@ -436,6 +436,7 @@
|
||||
<w>domreg</w>
|
||||
<w>domsg</w>
|
||||
<w>dont</w>
|
||||
<w>doplay</w>
|
||||
<w>doraise</w>
|
||||
<w>dosend</w>
|
||||
<w>dosomething</w>
|
||||
@ -1066,6 +1067,7 @@
|
||||
<w>mtime</w>
|
||||
<w>mtrans</w>
|
||||
<w>mtvos</w>
|
||||
<w>mtype</w>
|
||||
<w>mult</w>
|
||||
<w>multibytecodec</w>
|
||||
<w>multikillcount</w>
|
||||
@ -1074,6 +1076,8 @@
|
||||
<w>multiteamendscreen</w>
|
||||
<w>multiteamjoinscreen</w>
|
||||
<w>multithreaded</w>
|
||||
<w>musicinfo</w>
|
||||
<w>musicinfos</w>
|
||||
<w>musicplayer</w>
|
||||
<w>musictype</w>
|
||||
<w>musopen</w>
|
||||
@ -1526,6 +1530,7 @@
|
||||
<w>socketmodule</w>
|
||||
<w>socketserver</w>
|
||||
<w>somevar</w>
|
||||
<w>soundtrackname</w>
|
||||
<w>sourceimages</w>
|
||||
<w>sourcelines</w>
|
||||
<w>spacelen</w>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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()):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
})
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||
<h4><em>last updated on 2020-03-31 for Ballistica version 1.5.0 build 20001</em></h4>
|
||||
<h4><em>last updated on 2020-04-01 for Ballistica version 1.5.0 build 20001</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>
|
||||
@ -174,7 +174,7 @@
|
||||
<li><a href="#class_ba_WidgetNotFoundError">ba.WidgetNotFoundError</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
<h4><a name="class_category_Misc">Misc</a></h4>
|
||||
<h4><a name="class_category_Misc_Classes">Misc Classes</a></h4>
|
||||
<ul>
|
||||
<li><a href="#class_ba_Achievement">ba.Achievement</a></li>
|
||||
<li><a href="#class_ba_AppDelegate">ba.AppDelegate</a></li>
|
||||
@ -184,10 +184,12 @@
|
||||
<li><a href="#class_ba_DependencySet">ba.DependencySet</a></li>
|
||||
<li><a href="#class_ba_Lobby">ba.Lobby</a></li>
|
||||
<li><a href="#class_ba_MusicPlayer">ba.MusicPlayer</a></li>
|
||||
<li><a href="#class_ba_MusicPlayMode">ba.MusicPlayMode</a></li>
|
||||
<li><a href="#class_ba_MusicType">ba.MusicType</a></li>
|
||||
<li><a href="#class_ba_OldWindow">ba.OldWindow</a></li>
|
||||
<li><a href="#class_ba_UIController">ba.UIController</a></li>
|
||||
</ul>
|
||||
<h4><a name="function_category_Misc">Misc</a></h4>
|
||||
<h4><a name="function_category_Misc_Functions">Misc Functions</a></h4>
|
||||
<ul>
|
||||
<li><a href="#function_ba_show_damage_count">ba.show_damage_count()</a></li>
|
||||
</ul>
|
||||
@ -2806,7 +2808,7 @@ as far from these players as possible.</p>
|
||||
</dd>
|
||||
<dt><h4><a name="method_ba_Map__get_music_type">get_music_type()</a></dt></h4><dd>
|
||||
<h5><span><em><class method></span></em></h5>
|
||||
<p><span>get_music_type() -> Optional[str] </span></p>
|
||||
<p><span>get_music_type() -> Optional[<a href="#class_ba_MusicType">ba.MusicType</a>] </span></p>
|
||||
|
||||
<p>Return a music-type string that should be played on this map.</p>
|
||||
|
||||
@ -3146,6 +3148,46 @@ signify that the default soundtrack should be used..</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_MusicPlayMode">ba.MusicPlayMode</a></strong></h3>
|
||||
<p>inherits from: enum.Enum</p>
|
||||
<p>Influences behavior when playing music.</p>
|
||||
|
||||
<h3>Values:</h3>
|
||||
<ul>
|
||||
<li>REGULAR</li>
|
||||
<li>TEST</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_MusicType">ba.MusicType</a></strong></h3>
|
||||
<p>inherits from: enum.Enum</p>
|
||||
<p>Types of music available to play in-game.</p>
|
||||
|
||||
<h3>Values:</h3>
|
||||
<ul>
|
||||
<li>MENU</li>
|
||||
<li>VICTORY</li>
|
||||
<li>CHAR_SELECT</li>
|
||||
<li>RUN_AWAY</li>
|
||||
<li>ONSLAUGHT</li>
|
||||
<li>KEEP_AWAY</li>
|
||||
<li>RACE</li>
|
||||
<li>EPIC_RACE</li>
|
||||
<li>SCORES</li>
|
||||
<li>GRAND_ROMP</li>
|
||||
<li>TO_THE_DEATH</li>
|
||||
<li>CHOSEN_ONE</li>
|
||||
<li>FORWARD_MARCH</li>
|
||||
<li>FLAG_CATCHER</li>
|
||||
<li>SURVIVAL</li>
|
||||
<li>EPIC</li>
|
||||
<li>SPORTS</li>
|
||||
<li>HOCKEY</li>
|
||||
<li>FOOTBALL</li>
|
||||
<li>FLYING</li>
|
||||
<li>SCARY</li>
|
||||
<li>MARCHING</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_Node">ba.Node</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
@ -5627,18 +5669,12 @@ are applied to the Widget.</p>
|
||||
|
||||
<hr>
|
||||
<h2><strong><a name="function_ba_setmusic">ba.setmusic()</a></strong></h3>
|
||||
<p><span>setmusic(musictype: Optional[str], continuous: bool = False) -> None</span></p>
|
||||
<p><span>setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None</span></p>
|
||||
|
||||
<p>Set or stop the current music based on a string musictype.</p>
|
||||
|
||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
||||
|
||||
<p>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'.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user