mirror of
https://github.com/badvision/lawless-legends.git
synced 2025-03-01 03:30:04 +00:00
Merge branch 'master' of github.com:badvision/lawless-legends
This commit is contained in:
commit
5651578bbd
@ -10,26 +10,12 @@ import jace.core.Card;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.Utility;
|
||||
import jace.lawless.LawlessComputer;
|
||||
import jace.lawless.LawlessHacks;
|
||||
import jace.library.MediaCache;
|
||||
import jace.library.MediaConsumer;
|
||||
import jace.library.MediaConsumerParent;
|
||||
import jace.library.MediaEntry;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.animation.FadeTransition;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.Timeline;
|
||||
@ -44,6 +30,7 @@ import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.effect.DropShadow;
|
||||
@ -52,18 +39,21 @@ import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.CornerRadii;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author blurry
|
||||
@ -97,6 +87,9 @@ public class JaceUIController {
|
||||
@FXML
|
||||
private Button menuButton;
|
||||
|
||||
@FXML
|
||||
private ComboBox musicSelection;
|
||||
|
||||
Computer computer;
|
||||
|
||||
private final BooleanProperty aspectRatioCorrectionEnabled = new SimpleBooleanProperty(false);
|
||||
@ -166,6 +159,12 @@ public class JaceUIController {
|
||||
}
|
||||
|
||||
private void hideControlOverlay(MouseEvent evt) {
|
||||
if (evt == null || evt.getSource() != null && (
|
||||
evt.getSource() == musicSelection ||
|
||||
(evt.getSource() == rootPane && musicSelection.isFocused())
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
if (menuButtonPane.isVisible()) {
|
||||
FadeTransition ft1 = new FadeTransition(Duration.millis(500), menuButtonPane);
|
||||
ft1.setFromValue(1.0);
|
||||
@ -237,6 +236,9 @@ public class JaceUIController {
|
||||
// Kind of redundant but make sure speed is properly set as if the user did it
|
||||
setSpeed(Emulator.logic.speedSetting);
|
||||
});
|
||||
musicSelection.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
((LawlessHacks) ((LawlessComputer) computer).activeCheatEngine).changeMusicScore(String.valueOf(newValue));
|
||||
});
|
||||
}
|
||||
|
||||
private void connectButtons(Node n) {
|
||||
|
@ -20,25 +20,16 @@ package jace.apple2e;
|
||||
|
||||
import jace.LawlessLegends;
|
||||
import jace.config.ConfigurableField;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Device;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
import jace.core.SoundGeneratorDevice;
|
||||
import jace.core.SoundMixer;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import jace.core.*;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
import java.io.*;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.stage.FileChooser;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
/**
|
||||
* Apple // Speaker Emulation Created on May 9, 2007, 9:55 PM
|
||||
@ -205,8 +196,10 @@ public class Speaker extends SoundGeneratorDevice {
|
||||
bufferPos = 0;
|
||||
}
|
||||
secondaryBuffer = buffer;
|
||||
if (sdl != null && buffer != null) {
|
||||
sdl.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset idle counter whenever sound playback occurs
|
||||
|
@ -8,8 +8,16 @@ import javafx.beans.property.DoubleProperty;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Hacks that affect lawless legends gameplay
|
||||
@ -23,6 +31,8 @@ public class LawlessHacks extends Cheats {
|
||||
|
||||
public LawlessHacks(Computer computer) {
|
||||
super(computer);
|
||||
readScores();
|
||||
currentScore = SCORE_ORCHESTRAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,13 +74,15 @@ public class LawlessHacks extends Cheats {
|
||||
}
|
||||
|
||||
int currentSong;
|
||||
boolean repeatSong = false;
|
||||
Thread playbackEffect;
|
||||
MediaPlayer currentSongPlayer;
|
||||
MediaPlayer currentSfxPlayer;
|
||||
|
||||
private void playSound(int soundNumber) {
|
||||
boolean isMusic = soundNumber >= 0;
|
||||
int track = soundNumber & 0x07f;
|
||||
int track = soundNumber & 0x03f;
|
||||
repeatSong = (soundNumber & 0x040) > 0;
|
||||
if (track == 0) {
|
||||
if (isMusic) {
|
||||
// System.out.println("Stop music");
|
||||
@ -88,8 +100,20 @@ public class LawlessHacks extends Cheats {
|
||||
}
|
||||
}
|
||||
|
||||
private Media getAudioTrack(String file) {
|
||||
String pathStr = "jace/data/sound/" + file;
|
||||
private Media getAudioTrack(int number) {
|
||||
Map<Integer, String> score = scores.get(currentScore);
|
||||
if (score == null) {
|
||||
return null;
|
||||
}
|
||||
String filename = score.get(number);
|
||||
if (filename == null) {
|
||||
score = scores.get("common");
|
||||
if (score == null || !score.containsKey(number)) {
|
||||
return null;
|
||||
}
|
||||
filename = score.get(number);
|
||||
}
|
||||
String pathStr = "jace/data/sound/" + filename;
|
||||
// System.out.println("looking in "+pathStr);
|
||||
URL path = getClass().getClassLoader().getResource(pathStr);
|
||||
if (path == null) {
|
||||
@ -150,15 +174,15 @@ public class LawlessHacks extends Cheats {
|
||||
int FADE_SPEED = 100; // 100ms per 5%, or 2 second duration
|
||||
|
||||
private void startNewSong(int track) {
|
||||
if (track != currentSong || currentSongPlayer == null) {
|
||||
if (track != currentSong || currentSongPlayer == null || isMusicEnabled()) {
|
||||
// If the same song is already playing don't restart it
|
||||
Media song = getAudioTrack("BGM-" + track + ".mp3");
|
||||
Media song = getAudioTrack(track);
|
||||
if (song == null) {
|
||||
System.out.println("Unable to start song " + track + "; File not found");
|
||||
return;
|
||||
}
|
||||
currentSongPlayer = new MediaPlayer(song);
|
||||
currentSongPlayer.setCycleCount(MediaPlayer.INDEFINITE);
|
||||
currentSongPlayer.setCycleCount(repeatSong ? MediaPlayer.INDEFINITE : 1);
|
||||
currentSongPlayer.setVolume(0.0);
|
||||
currentSongPlayer.play();
|
||||
currentSong = track;
|
||||
@ -185,12 +209,16 @@ public class LawlessHacks extends Cheats {
|
||||
|
||||
private void stopMusic() {
|
||||
stopSongEffect();
|
||||
fadeOutSong(null);
|
||||
fadeOutSong(()->{
|
||||
if (!repeatSong) {
|
||||
currentSong = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void playSfx(int track) {
|
||||
new Thread(() -> {
|
||||
Media sfx = getAudioTrack("SFX-" + track + ".mp3");
|
||||
Media sfx = getAudioTrack(track + 128);
|
||||
if (sfx == null) {
|
||||
System.out.println("Unable to start SFX " + track + "; File not found");
|
||||
return;
|
||||
@ -208,4 +236,63 @@ public class LawlessHacks extends Cheats {
|
||||
}
|
||||
}
|
||||
|
||||
public static final String SCORE_NONE = "none";
|
||||
public static final String SCORE_COMMON = "common";
|
||||
public static final String SCORE_ORCHESTRAL = "orchestral";
|
||||
public static final String SCORE_CHIPTUNE = "chiptune";
|
||||
|
||||
private String currentScore = SCORE_COMMON;
|
||||
public void changeMusicScore(String score) {
|
||||
if (currentScore.equalsIgnoreCase(score)) {
|
||||
return;
|
||||
}
|
||||
boolean wasStoppedPreviously = !isMusicEnabled();
|
||||
currentScore = score.toLowerCase(Locale.ROOT);
|
||||
if (currentScore.equalsIgnoreCase(SCORE_NONE)) {
|
||||
stopMusic();
|
||||
currentSong = -1;
|
||||
} else if ((currentSongPlayer != null || wasStoppedPreviously) && currentSong > 0) {
|
||||
int currentSongTemp = currentSong;
|
||||
currentSong = Integer.MAX_VALUE;
|
||||
startNewSong(currentSongTemp);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMusicEnabled() {
|
||||
return currentScore != null && !currentScore.equalsIgnoreCase(SCORE_NONE);
|
||||
}
|
||||
|
||||
Pattern COMMENT = Pattern.compile("\\s*[-#;']+.*");
|
||||
Pattern LABEL = Pattern.compile("[A-Za-z\\s\\-_]+");
|
||||
Pattern ENTRY = Pattern.compile("([0-9]+)\\s+(.*)");
|
||||
private Map<String, Map<Integer, String>> scores = new HashMap<>();
|
||||
private void readScores() {
|
||||
InputStream data = getClass().getClassLoader().getResourceAsStream("jace/data/sound/scores.txt");
|
||||
readScores(data);
|
||||
}
|
||||
|
||||
private void readScores(InputStream data) {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(data));
|
||||
reader.lines().forEach(line -> {
|
||||
if (COMMENT.matcher(line).matches() || line.trim().isEmpty()) {
|
||||
// System.out.println("Ignoring: "+line);
|
||||
return;
|
||||
} else if (LABEL.matcher(line).matches()) {
|
||||
currentScore = line.toLowerCase(Locale.ROOT);
|
||||
scores.put(currentScore, new HashMap<>());
|
||||
// System.out.println("Score: "+ currentScore);
|
||||
} else {
|
||||
Matcher m = ENTRY.matcher(line);
|
||||
if (m.matches()) {
|
||||
int num = Integer.parseInt(m.group(1));
|
||||
String file = m.group(2);
|
||||
scores.get(currentScore).put(num, file);
|
||||
// System.out.println("Score: " + currentScore + "; Song: " + num + "; " + file);
|
||||
} else {
|
||||
// System.out.println("Couldn't parse: " + line);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.collections.FXCollections?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Slider?>
|
||||
<?import javafx.scene.image.Image?>
|
||||
<?import javafx.scene.image.ImageView?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.TilePane?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.image.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import java.lang.String?>
|
||||
<AnchorPane id="AnchorPane" fx:id="rootPane" prefHeight="384.0" prefWidth="560.0" style="-fx-background-color: black;" stylesheets="@../styles/style.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="jace.JaceUIController">
|
||||
<children>
|
||||
<StackPane fx:id="stackPane" prefHeight="384.0" prefWidth="560.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
@ -83,8 +77,22 @@
|
||||
</Button>
|
||||
</children>
|
||||
</TilePane>
|
||||
<!-- <TilePane alignment="TOP_RIGHT" hgap="5.0" vgap="5.0" HBox.hgrow="ALWAYS">
|
||||
<TilePane alignment="TOP_RIGHT" hgap="5.0" vgap="5.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Label styleClass="musicLabel">Music:</Label>
|
||||
<ComboBox fx:id="musicSelection">
|
||||
<items>
|
||||
<FXCollections fx:factory="observableArrayList">
|
||||
<String fx:value="Orchestral" />
|
||||
<String fx:value="Chiptune" />
|
||||
<String fx:value="None" />
|
||||
</FXCollections>
|
||||
</items>
|
||||
<value>
|
||||
<String fx:value="Orchestral"/>
|
||||
</value>
|
||||
</ComboBox>
|
||||
<!--
|
||||
<Button contentDisplay="TOP" mnemonicParsing="false" styleClass="uiActionButton" text="IDE">
|
||||
<graphic>
|
||||
<ImageView>
|
||||
@ -112,8 +120,9 @@
|
||||
</ImageView>
|
||||
</graphic>
|
||||
</Button>
|
||||
-->
|
||||
</children>
|
||||
</TilePane>-->
|
||||
</TilePane>
|
||||
</children>
|
||||
</HBox>
|
||||
</top>
|
||||
|
@ -0,0 +1,48 @@
|
||||
---- Scores file defines all the music and SFX
|
||||
---- Note: Anything that is shared for all scores is under the "common" section
|
||||
---- Lines that start with dashes, hash marks, single quotes are treated as comments
|
||||
Common
|
||||
--- Sound effects start at number 129
|
||||
129 bang.mp3
|
||||
130 boom.mp3
|
||||
|
||||
Orchestral
|
||||
1 Title.mp3
|
||||
2 Miller.mp3
|
||||
3 Tragedy.mp3
|
||||
4 Victory.mp3
|
||||
5 Grub.mp3
|
||||
6 mines.mp3
|
||||
7 Texas.mp3
|
||||
8 Strange.mp3
|
||||
9 Oro.mp3
|
||||
10 Village.mp3
|
||||
11 Sanctuary.mp3
|
||||
12 Meriposa.mp3
|
||||
13 Freemont.mp3
|
||||
14 Littlecreek.mp3
|
||||
15 Grove.mp3
|
||||
16 Poverty.mp3
|
||||
17 Killed.mp3
|
||||
18 Wilderness.mp3
|
||||
|
||||
---- Chiptune version uses the blips and bleeps that are the voice of a generation
|
||||
Chiptune
|
||||
1 Title8.mp3
|
||||
2 Miller8.mp3
|
||||
3 Tragedy8.mp3
|
||||
4 Victory8.mp3
|
||||
5 Grub8.mp3
|
||||
6 Mines8.mp3
|
||||
7 Texas8.mp3
|
||||
8 Strange8.mp3
|
||||
9 Oro8.mp3
|
||||
10 Village8.mp3
|
||||
11 Sanctuary8.mp3
|
||||
12 Mariposa8.mp3
|
||||
13 Freemont8.mp3
|
||||
14 Littlecreek8.mp3
|
||||
15 Grove8.mp3
|
||||
16 Poverty8.mp3
|
||||
17 Killed8.mp3
|
||||
18 Wilderness8.mp3
|
@ -26,11 +26,16 @@
|
||||
-fx-background-radius: 10px;
|
||||
}
|
||||
|
||||
.menuButton, .uiActionButton, .uiSpeedSlider ImageView, .uiSpeedSlider Slider, .uiSpeedSlider AnchorPane {
|
||||
.menuButton, .uiActionButton, .uiSpeedSlider ImageView, .uiSpeedSlider Slider, .uiSpeedSlider AnchorPane, .musicLabel {
|
||||
-fx-background-color: rgba(0, 0, 0, 0.75);
|
||||
-fx-text-fill: #a0FFa0
|
||||
}
|
||||
|
||||
.musicLabel {
|
||||
-fx-text-alignment: right;
|
||||
-fx-font-size:18pt;
|
||||
}
|
||||
|
||||
.uiActionButton ImageView, .uiSpeedSlider ImageView {
|
||||
-fx-effect: dropshadow(gaussian , rgba(64,255,64,0.25) , 2,1.0,0,0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user