mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-01-18 19:31:49 +00:00
Adding music/sfx playback support
This commit is contained in:
parent
2e779e05f4
commit
5f8171500f
@ -5,6 +5,7 @@
|
||||
*/
|
||||
package jace;
|
||||
|
||||
import jace.apple2e.SoftSwitches;
|
||||
import jace.apple2e.VideoNTSC;
|
||||
import jace.config.Configuration;
|
||||
import jace.core.RAMEvent;
|
||||
@ -18,9 +19,6 @@ import jace.lawless.LawlessHacks;
|
||||
import jace.lawless.LawlessImageTool;
|
||||
import jace.lawless.LawlessVideo;
|
||||
import jace.ui.MetacheatUI;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@ -31,6 +29,10 @@ import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author blurry
|
||||
@ -43,6 +45,7 @@ public class LawlessLegends extends Application {
|
||||
public JaceUIController controller;
|
||||
|
||||
static boolean romStarted = false;
|
||||
static public boolean PRODUCTION_MODE = true;
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
@ -126,21 +129,26 @@ public class LawlessLegends extends Application {
|
||||
*/
|
||||
private void bootWatchdog() {
|
||||
romStarted = false;
|
||||
RAMListener startListener = Emulator.computer.getMemory().
|
||||
observe(RAMEvent.TYPE.EXECUTE, 0x0c700, (e) -> {
|
||||
romStarted = true;
|
||||
});
|
||||
Emulator.computer.invokeColdStart();
|
||||
try {
|
||||
Thread.sleep(7500);
|
||||
if (!romStarted) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot not detected, performing a cold start");
|
||||
Emulator.computer.invokeColdStart();
|
||||
if (PRODUCTION_MODE) {
|
||||
RAMListener startListener = Emulator.computer.getMemory().
|
||||
observe(RAMEvent.TYPE.EXECUTE, 0x0c700, (e) -> {
|
||||
romStarted = true;
|
||||
});
|
||||
Emulator.computer.invokeColdStart();
|
||||
try {
|
||||
Thread.sleep(7500);
|
||||
if (!romStarted) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot not detected, performing a cold start");
|
||||
Emulator.computer.invokeColdStart();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(LawlessLegends.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(LawlessLegends.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Emulator.computer.getMemory().removeListener(startListener);
|
||||
} else {
|
||||
romStarted = true;
|
||||
Emulator.computer.invokeColdStart();
|
||||
}
|
||||
Emulator.computer.getMemory().removeListener(startListener);
|
||||
}
|
||||
|
||||
private void configureEmulatorForGame() {
|
||||
@ -151,15 +159,23 @@ public class LawlessLegends extends Application {
|
||||
Emulator.computer.enableStateManager = false;
|
||||
Emulator.computer.ramCard.setValue(CardRamworks.class);
|
||||
Emulator.computer.videoRenderer.setValue(LawlessVideo.class);
|
||||
Emulator.computer.card7.setValue(CardMassStorage.class);
|
||||
Emulator.computer.card6.setValue(CardDiskII.class);
|
||||
Emulator.computer.card5.setValue(CardRamFactor.class);
|
||||
Emulator.computer.card4.setValue(null);
|
||||
Emulator.computer.card2.setValue(null);
|
||||
if (PRODUCTION_MODE) {
|
||||
Emulator.computer.card7.setValue(CardMassStorage.class);
|
||||
Emulator.computer.card6.setValue(CardDiskII.class);
|
||||
Emulator.computer.card5.setValue(CardRamFactor.class);
|
||||
Emulator.computer.card4.setValue(null);
|
||||
Emulator.computer.card2.setValue(null);
|
||||
}
|
||||
Emulator.computer.cheatEngine.setValue(LawlessHacks.class);
|
||||
Configuration.buildTree();
|
||||
Emulator.computer.reconfigure();
|
||||
VideoNTSC.setVideoMode(VideoNTSC.VideoMode.TextFriendly, false);
|
||||
((LawlessImageTool) Emulator.computer.getUpgradeHandler()).loadGame();
|
||||
if (PRODUCTION_MODE) {
|
||||
((LawlessImageTool) Emulator.computer.getUpgradeHandler()).loadGame();
|
||||
} else {
|
||||
for (SoftSwitches s : SoftSwitches.values()) {
|
||||
s.getSwitch().reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,8 +291,11 @@ public class Apple2e extends Computer {
|
||||
loadRom("jace/data/apple2e.rom");
|
||||
}
|
||||
RAM128k ram = (RAM128k) getMemory();
|
||||
ram.activeRead.writeByte(0x0fffc, (byte) 0x000);
|
||||
ram.activeRead.writeByte(0x0fffd, (byte) 0x0c7);
|
||||
if (LawlessLegends.PRODUCTION_MODE) {
|
||||
// Force Slot 7 boot
|
||||
ram.activeRead.writeByte(0x0fffc, (byte) 0x000);
|
||||
ram.activeRead.writeByte(0x0fffd, (byte) 0x0c7);
|
||||
}
|
||||
|
||||
if (getVideo() == null || getVideo().getClass() != videoRenderer.getValue()) {
|
||||
if (getVideo() != null) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package jace.lawless;
|
||||
|
||||
import jace.LawlessLegends;
|
||||
import jace.apple2e.Apple2e;
|
||||
import jace.apple2e.RAM128k;
|
||||
import jace.apple2e.SoftSwitches;
|
||||
@ -54,7 +55,7 @@ public class LawlessComputer extends Apple2e {
|
||||
for (SoftSwitches s : SoftSwitches.values()) {
|
||||
s.getSwitch().reset();
|
||||
}
|
||||
if (showBootAnimation) {
|
||||
if (showBootAnimation && LawlessLegends.PRODUCTION_MODE) {
|
||||
(new Thread(this::startAnimation)).start();
|
||||
} else {
|
||||
finishColdStart();
|
||||
|
@ -4,6 +4,12 @@ import jace.cheat.Cheats;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.lawless.LawlessVideo.RenderEngine;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Hacks that affect lawless legends gameplay
|
||||
@ -13,6 +19,7 @@ public class LawlessHacks extends Cheats {
|
||||
// Modes specified by the game engine
|
||||
int MODE_SOFTSWITCH_MIN = 0x0C049;
|
||||
int MODE_SOFTSWITCH_MAX = 0x0C04F;
|
||||
int SFX_TRIGGER = 0x0C069;
|
||||
|
||||
public LawlessHacks(Computer computer) {
|
||||
super(computer);
|
||||
@ -27,12 +34,15 @@ public class LawlessHacks extends Cheats {
|
||||
public void registerListeners() {
|
||||
// Observe graphics changes
|
||||
addCheat(RAMEvent.TYPE.ANY, false, (e) -> {
|
||||
int addr = e.getAddress() ;
|
||||
if (addr >= MODE_SOFTSWITCH_MIN && e.getAddress() <= MODE_SOFTSWITCH_MAX) {
|
||||
System.out.println("Trapped " + e.getType().toString() + " to $"+Integer.toHexString(e.getAddress()));
|
||||
int addr = e.getAddress();
|
||||
if (addr >= MODE_SOFTSWITCH_MIN && e.getAddress() <= MODE_SOFTSWITCH_MAX) {
|
||||
System.out.println("Trapped " + e.getType().toString() + " to $" + Integer.toHexString(e.getAddress()));
|
||||
setEngineByOrdinal(e.getAddress() - MODE_SOFTSWITCH_MIN);
|
||||
}
|
||||
}, MODE_SOFTSWITCH_MIN, MODE_SOFTSWITCH_MAX);
|
||||
addCheat(RAMEvent.TYPE.WRITE, false, (e) -> {
|
||||
playSound(e.getNewValue());
|
||||
}, SFX_TRIGGER, SFX_TRIGGER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,4 +62,150 @@ public class LawlessHacks extends Cheats {
|
||||
video.setEngine(RenderEngine.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
int currentSong;
|
||||
Thread playbackEffect;
|
||||
MediaPlayer currentSongPlayer;
|
||||
MediaPlayer currentSfxPlayer;
|
||||
|
||||
private void playSound(int soundNumber) {
|
||||
boolean isMusic = soundNumber >= 0;
|
||||
int track = soundNumber & 0x07f;
|
||||
if (track == 0) {
|
||||
if (isMusic) {
|
||||
// System.out.println("Stop music");
|
||||
stopMusic();
|
||||
} else {
|
||||
// System.out.println("Stop sfx");
|
||||
stopSfx();
|
||||
}
|
||||
} else if (isMusic) {
|
||||
// System.out.println("Play music "+track);
|
||||
playMusic(track);
|
||||
} else {
|
||||
// System.out.println("Play sfx "+track);
|
||||
playSfx(track);
|
||||
}
|
||||
}
|
||||
|
||||
private Media getAudioTrack(String file) {
|
||||
String pathStr = "jace/data/sound/" + file;
|
||||
// System.out.println("looking in "+pathStr);
|
||||
URL path = getClass().getClassLoader().getResource(pathStr);
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new Media(path.toURI().toString());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void playMusic(int track) {
|
||||
if (currentSong != track) {
|
||||
fadeOutSong(() -> startNewSong(track));
|
||||
} else {
|
||||
new Thread(() -> startNewSong(track)).start();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopSongEffect() {
|
||||
if (playbackEffect != null && playbackEffect.isAlive()) {
|
||||
playbackEffect.interrupt();
|
||||
Thread.yield();
|
||||
}
|
||||
playbackEffect = null;
|
||||
}
|
||||
|
||||
private void fadeOutSong(Runnable nextAction) {
|
||||
stopSongEffect();
|
||||
if (currentSongPlayer != null) {
|
||||
playbackEffect = new Thread(() -> {
|
||||
DoubleProperty volume = currentSongPlayer.volumeProperty();
|
||||
while (playbackEffect == Thread.currentThread() && currentSongPlayer != null && volume.get() > 0.0) {
|
||||
// System.out.println("Fading down: " + volume.get());
|
||||
volume.set(volume.get() - FADE_AMT);
|
||||
try {
|
||||
Thread.sleep(FADE_SPEED);
|
||||
} catch (InterruptedException e) {
|
||||
playbackEffect = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
currentSongPlayer.stop();
|
||||
currentSongPlayer = null;
|
||||
if (nextAction != null) {
|
||||
nextAction.run();
|
||||
}
|
||||
});
|
||||
playbackEffect.start();
|
||||
} else if (nextAction != null) {
|
||||
new Thread(nextAction).start();
|
||||
}
|
||||
}
|
||||
|
||||
double FADE_AMT = 0.05; // 5% per interval, or 20 stops between 0% and 100%
|
||||
int FADE_SPEED = 100; // 100ms per 5%, or 2 second duration
|
||||
|
||||
private void startNewSong(int track) {
|
||||
if (track != currentSong || currentSongPlayer == null) {
|
||||
// If the same song is already playing don't restart it
|
||||
Media song = getAudioTrack("BGM-" + track + ".mp3");
|
||||
if (song == null) {
|
||||
System.out.println("Unable to start song " + track + "; File not found");
|
||||
return;
|
||||
}
|
||||
currentSongPlayer = new MediaPlayer(song);
|
||||
currentSongPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||
currentSongPlayer.setVolume(0.0);
|
||||
currentSongPlayer.play();
|
||||
currentSong = track;
|
||||
}
|
||||
// But if the same song was already playing but possibly fading out
|
||||
// then this will fade it back in neatly.
|
||||
stopSongEffect();
|
||||
// System.out.println("Starting "+track+" NOW");
|
||||
playbackEffect = new Thread(() -> {
|
||||
DoubleProperty volume = currentSongPlayer.volumeProperty();
|
||||
while (playbackEffect == Thread.currentThread() && currentSongPlayer != null && volume.get() < 1.0) {
|
||||
volume.set(volume.get() + FADE_AMT);
|
||||
// System.out.println("Fading up: " + volume.get());
|
||||
try {
|
||||
Thread.sleep(FADE_SPEED);
|
||||
} catch (InterruptedException e) {
|
||||
playbackEffect = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
playbackEffect.start();
|
||||
}
|
||||
|
||||
private void stopMusic() {
|
||||
stopSongEffect();
|
||||
fadeOutSong(null);
|
||||
}
|
||||
|
||||
private void playSfx(int track) {
|
||||
new Thread(() -> {
|
||||
Media sfx = getAudioTrack("SFX-" + track + ".mp3");
|
||||
if (sfx == null) {
|
||||
System.out.println("Unable to start SFX " + track + "; File not found");
|
||||
return;
|
||||
}
|
||||
currentSfxPlayer = new MediaPlayer(sfx);
|
||||
currentSfxPlayer.setCycleCount(1);
|
||||
currentSfxPlayer.play();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void stopSfx() {
|
||||
if (currentSfxPlayer != null) {
|
||||
currentSfxPlayer.stop();
|
||||
currentSfxPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user