- Add support for multiple music sets.

This commit is contained in:
Michael Kamensky
2021-11-04 08:09:36 +03:00
parent 6c78256341
commit d942f89162
17 changed files with 115 additions and 21 deletions

View File

@@ -19,6 +19,7 @@ import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.screens.deckeditor.CDeckEditorUI;
import forge.screens.deckeditor.controllers.CEditorTokenViewer;
import forge.sound.MusicPlaylist;
import forge.sound.SoundSystem;
import forge.toolbox.*;
import forge.util.Localizer;
@@ -265,6 +266,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeMulliganRuleComboBox();
initializeAiProfilesComboBox();
initializeSoundSetsComboBox();
initializeMusicSetsComboBox();
initializeStackAdditionsComboBox();
initializeLandPlayedComboBox();
initializeColorIdentityCombobox();
@@ -472,13 +474,28 @@ public enum CSubmenuPreferences implements ICDoc {
private void initializeSoundSetsComboBox() {
final FPref userSetting = FPref.UI_CURRENT_SOUND_SET;
final FComboBoxPanel<String> panel = this.view.getSoundSetsComboBoxPanel();
final FComboBox<String> comboBox = createComboBox(SoundSystem.getAvailableSoundSets(), userSetting);
final FComboBox<String> comboBox = createComboBox(SoundSystem.instance.getAvailableSoundSets(), userSetting);
final String selectedItem = this.prefs.getPref(userSetting);
panel.setComboBox(comboBox, selectedItem);
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
SoundSystem.invalidateSoundCache();
SoundSystem.instance.invalidateSoundCache();
}
});
}
private void initializeMusicSetsComboBox() {
final FPref userSetting = FPref.UI_CURRENT_MUSIC_SET;
final FComboBoxPanel<String> panel = this.view.getMusicSetsComboBoxPanel();
final FComboBox<String> comboBox = createComboBox(SoundSystem.instance.getAvailableMusicSets(), userSetting);
final String selectedItem = this.prefs.getPref(userSetting);
panel.setComboBox(comboBox, selectedItem);
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
MusicPlaylist.invalidateMusicPlaylist();
SoundSystem.instance.changeBackgroundTrack();
}
});
}

View File

@@ -129,6 +129,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FComboBoxPanel<String> cbpCardArtPreference = new FComboBoxPanel<>(localizer.getMessage("lblPreferredArt")+":");
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
private final FComboBoxPanel<String> cbpSoundSets = new FComboBoxPanel<>(localizer.getMessage("cbpSoundSets")+":");
private final FComboBoxPanel<String> cbpMusicSets = new FComboBoxPanel<>(localizer.getMessage("cbpMusicSets")+":");
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
private final FComboBoxPanel<String> cbpLandPlayed = new FComboBoxPanel<>(localizer.getMessage("cbpLandPlayed")+":");
@@ -421,6 +422,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(cbEnableMusic, titleConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnableMusic")), descriptionConstraints);
pnlPrefs.add(cbpMusicSets, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpMusicSets")), descriptionConstraints);
pnlPrefs.add(cbAltSoundSystem, titleConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAltSoundSystem")), descriptionConstraints);
pnlPrefs.add(cbSROptimize, titleConstraints);
@@ -748,6 +752,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
return cbpSoundSets;
}
public FComboBoxPanel<String> getMusicSetsComboBoxPanel() {
return cbpMusicSets;
}
public FComboBoxPanel<String> getAiProfilesComboBoxPanel() {
return cbpAiProfiles;
}

View File

@@ -61,7 +61,7 @@ public class AudioClip implements IAudioClip {
}
public static boolean fileExists(String fileName) {
File fSound = new File(SoundSystem.getSoundDirectory(), fileName);
File fSound = new File(SoundSystem.instance.getSoundDirectory(), fileName);
return fSound.exists();
}
@@ -192,7 +192,7 @@ public class AudioClip implements IAudioClip {
}
private Clip createClip(String filename) {
File fSound = new File(SoundSystem.getSoundDirectory(), filename);
File fSound = new File(SoundSystem.instance.getSoundDirectory(), filename);
if (!fSound.exists()) {
throw new IllegalArgumentException("Sound file " + fSound.toString() + " does not exist, cannot make a clip of it");
}

View File

@@ -269,7 +269,7 @@ public class GuiMobile implements IGuiBase {
@Override
public IAudioClip createAudioClip(final String filename) {
return AudioClip.createClip(SoundSystem.getSoundDirectory() + filename);
return AudioClip.createClip(SoundSystem.instance.getSoundDirectory() + filename);
}
@Override

View File

@@ -18,6 +18,7 @@ import forge.screens.TabPageScreen;
import forge.screens.TabPageScreen.TabPage;
import forge.screens.home.HomeScreen;
import forge.screens.match.MatchController;
import forge.sound.MusicPlaylist;
import forge.sound.SoundSystem;
import forge.toolbox.FCheckBox;
import forge.toolbox.FGroupList;
@@ -615,14 +616,26 @@ public class SettingsPage extends TabPage<SettingsScreen> {
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_SOUND_SET,
localizer.getMessage("cbpSoundSets"),
localizer.getMessage("nlpSoundSets"),
SoundSystem.getAvailableSoundSets()) {
SoundSystem.instance.getAvailableSoundSets()) {
@Override
public void valueChanged(String newValue) {
super.valueChanged(newValue);
SoundSystem.invalidateSoundCache();
SoundSystem.instance.invalidateSoundCache();
}
},
7);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_CURRENT_MUSIC_SET,
localizer.getMessage("cbpMusicSets"),
localizer.getMessage("nlpMusicSets"),
SoundSystem.getAvailableMusicSets()) {
@Override
public void valueChanged(String newValue) {
super.valueChanged(newValue);
MusicPlaylist.invalidateMusicPlaylist();
SoundSystem.instance.changeBackgroundTrack();
}
},
7);
lstSettings.addItem(new CustomSelectSetting(FPref.UI_VOL_SOUNDS,
localizer.getMessage("cbAdjustSoundsVolume"),
localizer.getMessage("nlAdjustSoundsVolume"),

View File

@@ -1,6 +1,8 @@
#Add one announcement per line
Get in the discord if you aren't yet. https://discord.gg/3v9JCVr
Planar Conquest now features a new plane - Forgotten Realms, based on the AFR and AFC sets.
Forge now supports 100% of core and expansion set cards from Limited Edition Alpha to Innistrad: Midnight Hunt. This includes Equinox, Chaos Orb, and Falling Star.
Planar Conquest now features a new plane - Forgotten Realms, based on the AFR and AFC sets.
Several planes are now available in Planar Conquest in their Classic form, as originally intended by the author, without support for the newer sets and with the original events not modified with newer cards. These planes are available in addition to the contemporary versions of the planes and are marked as "Classic".
Sound sets are now configurable - you can place your sound sets under "sound" in your Forge cache (as subfolders) and then select them with the "Sound set" option.
Music sets are now configurable - you can place your music sets under "music" in your Forge cache (as subfolders) and then select them with the "Music set" option. The music set folder must have the same structure as "res/music", with "match" and "menus" subfolders containing relevant music tracks.
*** Android 7 & 8 support is now deprecated. Support will be dropped in an upcoming release. ***

View File

@@ -112,6 +112,7 @@ cbpCloseAction=Beenden
cbpDefaultFontSize=Standard Schriftgröße
cbpCardArtFormat=Kartenbildformat
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpAiProfiles=KI Persönlichkeit
cbpStackAdditions=Nachricht bei Stapeländerung
cbpDisplayCurrentCardColors=Zeige detaillierte Kartenfarben
@@ -143,6 +144,7 @@ nlUseSentry=Aktiviere, um automatische Fehlerberichte an die Entwickler zu sende
GamePlay=Spiel
nlpMulliganRule=Wähle die Version der Mulligan Regel
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=Wähle die Spielweise deines KI-Gegners.
nlpStackAdditions=Wähle, wann du über Änderungen am Stapel benachrichtigt werden möchtest: Niemals, immer oder nur für durch andere Spieler ausgelöste Effekte und Fähigkeiten
nlAnte=Entscheidet, ob um einen Einsatz (Ante) gespielt wird.

View File

@@ -114,6 +114,7 @@ cbpDefaultFontSize=Default Font Size
cbpCardArtFormat=Card Art Format
cbpAiProfiles=AI Personality
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpStackAdditions=Stack effect notifications
cbpDisplayCurrentCardColors=Show Detailed Card Color
cbpAutoYieldMode=Auto-Yield
@@ -144,6 +145,7 @@ nlUseSentry=When enabled, automatically submits bug reports to developers.
GamePlay=Gameplay
nlpMulliganRule=Choose the version of the Mulligan rule
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=Choose your AI opponent
nlpStackAdditions=Choose when you want to get visual notifications for an effect added to the stack: Never, always, or only for the effects cast/activated by a AI player or triggered by any player
nlAnte=Determines whether or not the game is played for ante.

View File

@@ -113,6 +113,7 @@ cbpCloseAction=Acción al cerrar
cbpDefaultFontSize=Tamaño de fuente predeterminado
cbpCardArtFormat=Card Art Format
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpAiProfiles=Personalidad de la IA
cbpStackAdditions=Efecto de la pila de notificaciones
cbpDisplayCurrentCardColors=Mostrar color de la carta
@@ -144,6 +145,7 @@ nlUseSentry=Cuando está habilitado, envía automáticamente informes de errores
GamePlay=Juego
nlpMulliganRule=Elige versión de reglas de mulligan
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=Elige tu oponente de la IA
nlpStackAdditions=Elige cuándo quieres recibir notificaciones visuales para un efecto añadido a la pila: Nunca, siempre o sólo para los efectos lanzados/activados por un jugador IA o activados por cualquier jugador
nlAnte=Determina si el juego se juega con apuesta o no.

View File

@@ -112,6 +112,7 @@ cbpCloseAction=Chiudi
cbpDefaultFontSize=Dimensione carattere predefinita
cbpCardArtFormat=Formato dell'Illustrazione delle carte
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpAiProfiles=Personalità dell''IA
cbpStackAdditions=Notifiche degli effetti in pila
cbpDisplayCurrentCardColors=Mostra colore scheda dettagliato
@@ -143,6 +144,7 @@ nlUseSentry=Se abilitato, invia automaticamente segnalazioni di bug agli svilupp
GamePlay=Gameplay
nlpMulliganRule=Scegli il tipo di Mulligan
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=Scegli il tuo avversario (IA)
nlpStackAdditions=Scegli quando vuoi ricevere una notifica visiva di un effetto aggiunto alla pila: Mai, sempre, o solo per gli effetti lanciati/attivati da un giocatore IA o innescati da un qualsiasi giocatore
nlAnte=Determina se l''incontro è giocato o meno con la posta.

View File

@@ -113,6 +113,7 @@ cbpCloseAction=閉じる時の動作
cbpDefaultFontSize=デフォルトのフォントサイズ
cbpCardArtFormat=カードのアートフォーマット
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpAiProfiles=AI の性格
cbpStackAdditions=スタック効果通知
cbpDisplayCurrentCardColors=詳細なカードの色を表示
@@ -144,6 +145,7 @@ nlUseSentry=有効にすると、バグレポートが開発者に自動的に
GamePlay=ゲーム設定
nlpMulliganRule=マリガンルールを選択する。
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=対戦相手 AI の性格を選択する。
nlpStackAdditions=スタックに追加された能力の視覚通知をいつ取得するかを選択しますNever[しない]、Always[常時]、またはAIプレーヤーによってキャスト/起動された能力、または任意のプレーヤーによって誘発された能力に対してのみ
nlAnte=ゲームでアンティ(賭け)ルールを適用するか選択する。

View File

@@ -113,6 +113,7 @@ cbpCloseAction=关闭动作
cbpDefaultFontSize=默认字体大小
cbpCardArtFormat=牌张插画格式
cbpSoundSets=Sound Set
cbpMusicSets=Music Set
cbpAiProfiles=AI强度
cbpStackAdditions=堆叠效应通知
cbpDisplayCurrentCardColors=显示卡牌颜色详情
@@ -144,6 +145,7 @@ nlUseSentry=启用后,会自动向开发人员提交错误报告。
GamePlay=游戏
nlpMulliganRule=选择调度规则
nlpSoundSets=Choose the sound set from the ones present in the "sound" folder in your Forge cache directory
nlpMusicSets=Choose the music set from the ones present in the "music" folder in your Forge cache directory
nlpAiProfiles=选择你的AI对手
nlpStackAdditions=选择何时因效应进入堆叠而提供视觉提醒从不总是任何由AI释放或起动以及由任何玩家触发的效应。
nlAnte=确定游戏是否使用赌注

View File

@@ -284,6 +284,7 @@ public final class ForgeConstants {
public static final String FONTS_DIR = CACHE_DIR + "fonts" + PATH_SEPARATOR;
public static final String CACHE_SKINS_DIR = CACHE_DIR + "skins" + PATH_SEPARATOR;
public static final String CACHE_SOUND_DIR = CACHE_DIR + "sound" + PATH_SEPARATOR;
public static final String CACHE_MUSIC_DIR = CACHE_DIR + "music" + PATH_SEPARATOR;
public static final String CACHE_TOKEN_PICS_DIR = PICS_DIR + "tokens" + PATH_SEPARATOR;
public static final String CACHE_ICON_PICS_DIR = PICS_DIR + "icons" + PATH_SEPARATOR;
public static final String CACHE_SYMBOLS_DIR = PICS_DIR + "symbols" + PATH_SEPARATOR;

View File

@@ -122,6 +122,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
UI_VOL_MUSIC ("100"),
UI_ALT_SOUND_SYSTEM ("false"),
UI_CURRENT_SOUND_SET("Default"),
UI_CURRENT_MUSIC_SET("Default"),
UI_CURRENT_AI_PROFILE ("Default"),
UI_CLONE_MODE_SOURCE ("false"),
UI_MATCH_IMAGE_VISIBLE ("true"),

View File

@@ -330,7 +330,7 @@ public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> imp
}
// Only proceed if the file actually exists
return new File(SoundSystem.getSoundDirectory(), effect).exists();
return new File(SoundSystem.instance.getSoundDirectory(), effect).exists();
}

View File

@@ -3,7 +3,6 @@ package forge.sound;
import java.io.File;
import java.io.FilenameFilter;
import forge.localinstance.properties.ForgeConstants;
import forge.util.MyRandom;
public enum MusicPlaylist {
@@ -13,13 +12,18 @@ public enum MusicPlaylist {
private final String subDir;
private int mostRecentTrackIdx = -1;
private String[] filenames;
private static boolean isInvalidated = false;
MusicPlaylist(String subDir0) {
subDir = subDir0;
}
public static void invalidateMusicPlaylist() {
isInvalidated = true;
}
public String getRandomFilename() {
if (filenames == null) {
if (filenames == null || isInvalidated) {
try {
FilenameFilter filter = new FilenameFilter(){
@Override
@@ -27,13 +31,14 @@ public enum MusicPlaylist {
return name.endsWith(".mp3") || name.endsWith(".wav") || name.endsWith(".m4a");
}
};
filenames = new File(ForgeConstants.MUSIC_DIR + subDir).list(filter);
filenames = new File(SoundSystem.instance.getMusicDirectory() + subDir).list(filter);
if (filenames == null) filenames = new String[0];
}
catch (Exception e) {
e.printStackTrace();
filenames = new String[0];
}
isInvalidated = false;
}
if (filenames.length == 0) { return null; }
@@ -50,6 +55,6 @@ public enum MusicPlaylist {
mostRecentTrackIdx = newIndex;
}
return ForgeConstants.MUSIC_DIR + subDir + filenames[mostRecentTrackIdx];
return SoundSystem.instance.getMusicDirectory() + subDir + filenames[mostRecentTrackIdx];
}
}

View File

@@ -1,18 +1,18 @@
package forge.sound;
import java.io.File;
import java.util.*;
import com.google.common.eventbus.Subscribe;
import forge.game.event.GameEvent;
import forge.gui.GuiBase;
import forge.gui.events.UiEvent;
import forge.localinstance.properties.ForgeConstants;
import forge.localinstance.properties.ForgePreferences;
import forge.localinstance.properties.ForgePreferences.FPref;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
import java.io.File;
import java.util.*;
/**
* Manages playback of all sounds for the client.
*/
@@ -245,7 +245,7 @@ public class SoundSystem {
}
}
public static String[] getAvailableSoundSets()
public String[] getAvailableSoundSets()
{
final List<String> availableSets = new ArrayList<>();
@@ -271,7 +271,7 @@ public class SoundSystem {
return availableSets.toArray(new String[availableSets.size()]);
}
public static String getSoundDirectory() {
public String getSoundDirectory() {
String profileName = FModel.getPreferences().getPref(FPref.UI_CURRENT_SOUND_SET);
if (profileName.equals("Default")) {
return ForgeConstants.SOUND_DIR;
@@ -279,9 +279,44 @@ public class SoundSystem {
return ForgeConstants.CACHE_SOUND_DIR + profileName + ForgeConstants.PATH_SEPARATOR;
}
}
public static void invalidateSoundCache() {
public void invalidateSoundCache() {
loadedClips.clear();
loadedScriptClips.clear();
}
public String getMusicDirectory() {
String profileName = FModel.getPreferences().getPref(ForgePreferences.FPref.UI_CURRENT_MUSIC_SET);
if (profileName.equals("Default")) {
return ForgeConstants.MUSIC_DIR;
} else {
return ForgeConstants.CACHE_MUSIC_DIR + profileName + ForgeConstants.PATH_SEPARATOR;
}
}
public static String[] getAvailableMusicSets()
{
final List<String> availableSets = new ArrayList<>();
final File dir = new File(ForgeConstants.CACHE_MUSIC_DIR);
if (dir != null && dir.exists()) {
final String[] files = dir.list();
for (String fileName : files) {
String fullPath = ForgeConstants.CACHE_MUSIC_DIR + fileName;
if (!fileName.equals("Default") && new File(fullPath).isDirectory()) {
availableSets.add(fileName);
}
}
}
Collections.sort(availableSets);
availableSets.add(0, "Default");
if (availableSets.size() == 1) {
// Default profile only - ensure that the preference is set accordingly
FModel.getPreferences().setPref(FPref.UI_CURRENT_MUSIC_SET, "Default");
}
return availableSets.toArray(new String[availableSets.size()]);
}
}