Merge branch 'master' of github.com:badvision/lawless-legends
@ -5,7 +5,7 @@
|
||||
<artifactId>OutlawEditor</artifactId>
|
||||
<name>OutlawEditor</name>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mainClass>org.badvision.outlaweditor.Application</mainClass>
|
||||
@ -22,7 +22,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-scr-plugin</artifactId>
|
||||
<version>1.24.0</version>
|
||||
<version>1.26.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate-scr-scrdescriptor</id>
|
||||
@ -40,7 +40,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>5.1.2</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
@ -52,7 +52,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack-dependencies</id>
|
||||
@ -79,7 +79,7 @@
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<version>3.0.2</version>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -88,12 +88,12 @@
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
<version>3.6.1</version>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jvnet.jaxb2.maven2</groupId>
|
||||
<artifactId>maven-jaxb2-plugin</artifactId>
|
||||
<version>0.13.2</version>
|
||||
<version>0.14.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@ -113,7 +113,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jvnet.jaxb2_commons</groupId>
|
||||
<artifactId>jaxb2-basics</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</configuration>
|
||||
@ -128,24 +128,24 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jvnet.jaxb2_commons</groupId>
|
||||
<artifactId>jaxb2-basics</artifactId>
|
||||
<version>0.11.1</version>
|
||||
<version>0.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.framework</artifactId>
|
||||
<version>5.6.4</version>
|
||||
<version>5.6.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.main</artifactId>
|
||||
<version>5.6.4</version>
|
||||
<version>5.6.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
@ -155,22 +155,22 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.scr</artifactId>
|
||||
<version>2.0.12</version>
|
||||
<version>2.1.26</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>3.16</version>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>3.16</version>
|
||||
<version>5.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.controlsfx</groupId>
|
||||
<artifactId>controlsfx</artifactId>
|
||||
<version>8.40.15</version>
|
||||
<version>8.40.18</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -35,8 +35,6 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.DataFormat;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.input.ScrollEvent;
|
||||
import javafx.scene.layout.Pane;
|
||||
@ -72,6 +70,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
double tileWidth = getCurrentPlatform().tileRenderer.getWidth() * zoom;
|
||||
double tileHeight = getCurrentPlatform().tileRenderer.getHeight() * zoom;
|
||||
Color cursorAssistColor = new Color(0.2, 0.2, 1.0, 0.4);
|
||||
Script highlightedScript = null;
|
||||
|
||||
@Override
|
||||
protected void onEntityUpdated() {
|
||||
@ -134,7 +133,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
getCurrentMap().shift(amt, 0);
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void buildEditorUI(Pane tileEditorAnchorPane) {
|
||||
anchorPane = tileEditorAnchorPane;
|
||||
@ -192,6 +191,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
|
||||
public void setSelectedScript(Script script) {
|
||||
selectedScript = script;
|
||||
highlightedScript = script;
|
||||
}
|
||||
|
||||
public Script getSelectedScript() {
|
||||
@ -314,7 +314,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
}
|
||||
for (int x = 0; x <= cols; x++) {
|
||||
for (int y = 0; y <= rows; y++) {
|
||||
if (highlightScripts(x, y, currentMap.getLocationScripts(posX + x, posY + y))) {
|
||||
if (highlightScripts(x, y, currentMap.getLocationScripts(posX + x, posY + y), highlightedScript)) {
|
||||
tiles[x][y] = "SCRIPT";
|
||||
}
|
||||
}
|
||||
@ -391,7 +391,7 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
}
|
||||
}
|
||||
|
||||
private boolean highlightScripts(int x, int y, List<Script> scripts) {
|
||||
private boolean highlightScripts(int x, int y, List<Script> scripts, Script extraHighlight) {
|
||||
if (scripts == null || scripts.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@ -400,6 +400,14 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
return false;
|
||||
}
|
||||
GraphicsContext gc = drawCanvas.getGraphicsContext2D();
|
||||
if (highlightedScript != null && visibleScripts.contains(extraHighlight)) {
|
||||
Color color = currentMap.getScriptColor(extraHighlight).get().brighter();
|
||||
color = Color.color(color.getRed(), color.getGreen(), color.getBlue(), 0.5);
|
||||
gc.setFill(color);
|
||||
double xx = x * tileWidth;
|
||||
double yy = y * tileHeight;
|
||||
gc.fillRect(xx, yy, tileWidth, tileHeight);
|
||||
}
|
||||
int idx = 0;
|
||||
double xx = x * tileWidth;
|
||||
double yy = y * tileHeight;
|
||||
@ -499,8 +507,8 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
|
||||
public void copyScript(Script s) {
|
||||
java.util.Map<DataFormat, Object> clip = new HashMap<>();
|
||||
clip.put(DataFormat.PLAIN_TEXT, "selection/map/" +
|
||||
ApplicationState.getInstance().getGameData().getMap().indexOf(getEntity()) +
|
||||
clip.put(DataFormat.PLAIN_TEXT, "selection/map/" +
|
||||
ApplicationState.getInstance().getGameData().getMap().indexOf(getEntity()) +
|
||||
"/script/" + getEntity().getScripts().getScript().indexOf(s));
|
||||
Clipboard.getSystemClipboard().setContent(clip);
|
||||
}
|
||||
|
@ -307,13 +307,13 @@ public class DataUtilities {
|
||||
|
||||
public static String getStringValueFromCell(Cell cell) {
|
||||
switch (cell.getCellType()) {
|
||||
case Cell.CELL_TYPE_BOOLEAN:
|
||||
case BOOLEAN:
|
||||
return Boolean.toString(cell.getBooleanCellValue());
|
||||
case Cell.CELL_TYPE_BLANK:
|
||||
case BLANK:
|
||||
return null;
|
||||
case Cell.CELL_TYPE_NUMERIC:
|
||||
case NUMERIC:
|
||||
return Double.toString(cell.getNumericCellValue());
|
||||
case Cell.CELL_TYPE_STRING:
|
||||
case STRING:
|
||||
return cell.getStringCellValue();
|
||||
default:
|
||||
return "???";
|
||||
|
@ -401,6 +401,7 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
|
||||
} else {
|
||||
getCurrentEditor().setSelectedScript(newValue);
|
||||
}
|
||||
getCurrentEditor().redraw();
|
||||
}
|
||||
});
|
||||
scriptEraseTool.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> {
|
||||
|
@ -72,6 +72,8 @@ public class SheetEditorControllerImpl extends SheetEditorController {
|
||||
createMenuItem("Insert Row", () -> insertRow(new Row(), getSelectedRow())),
|
||||
createMenuItem("Clone Row", () -> cloneRow(editor.getSheet().getRows().getRow().get(getSelectedRow()))),
|
||||
createMenuItem("Delete Row", () -> deleteRowWithConfirmation(editor.getSheet().getRows().getRow().get(getSelectedRow()))),
|
||||
createMenuItem("Delete Column", () -> deleteColumnWithConfirmation(editor.getSheet().getColumns().getColumn().get(getSelectedColumn()))),
|
||||
createMenuItem("Rename Column", () -> renameColumn(editor.getSheet().getColumns().getColumn().get(getSelectedColumn()))),
|
||||
createMenuItem("Sort ascending", () -> {
|
||||
int sortCol = table.getSelectionModel().getFocusedCell().getColumn();
|
||||
table.setComparator((a,b)->compare(getCellFromRow(a, sortCol), getCellFromRow(b, sortCol)));
|
||||
@ -99,6 +101,10 @@ public class SheetEditorControllerImpl extends SheetEditorController {
|
||||
return table.getSelectionModel().getFocusedCell().getRow();
|
||||
}
|
||||
|
||||
private int getSelectedColumn() {
|
||||
return table.getSelectionModel().getFocusedCell().getColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doImport(ActionEvent event) {
|
||||
FileChooser openFileDialog = new FileChooser();
|
||||
@ -116,12 +122,13 @@ public class SheetEditorControllerImpl extends SheetEditorController {
|
||||
}).collect(Collectors.toCollection(editor.getSheet().getColumns()::getColumn));
|
||||
|
||||
editor.getSheet().setRows(new Rows());
|
||||
List<String> header = data.get(0);
|
||||
data.stream().skip(1)
|
||||
.map(cols -> {
|
||||
Row r = new Row();
|
||||
for (int i = 0; i < cols.size(); i++) {
|
||||
if (cols.get(i) != null) {
|
||||
setValue(r.getOtherAttributes(), data.get(0).get(i), cols.get(i));
|
||||
if (cols.get(i) != null && header.size() > i && header.get(i) != null) {
|
||||
setValue(r.getOtherAttributes(), header.get(i), cols.get(i));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>org.8bitbunch</groupId>
|
||||
<artifactId>lawlesslegends</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<version>3.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>lawlesslegends</name>
|
||||
@ -26,7 +26,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack-dependencies</id>
|
||||
@ -45,7 +45,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack-dependencies</id>
|
||||
@ -78,7 +78,7 @@
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
<version>3.5</version>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
@ -87,14 +87,19 @@
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
<version>0.9.9</version>
|
||||
<version>0.9.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.collections</groupId>
|
||||
<artifactId>eclipse-collections</artifactId>
|
||||
<version>10.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial.thirdparty</groupId>
|
||||
<artifactId>nestedvm</artifactId>
|
||||
|
@ -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) {
|
||||
|
@ -44,6 +44,7 @@ abstract public class RAM128k extends RAM {
|
||||
Logger LOG = Logger.getLogger(RAM128k.class.getName());
|
||||
|
||||
Map<String, PagedMemory> banks;
|
||||
Map<String, PagedMemory> memoryConfigurations = new HashMap<>();
|
||||
String state = "???";
|
||||
|
||||
private Map<String, PagedMemory> getBanks() {
|
||||
@ -90,8 +91,8 @@ abstract public class RAM128k extends RAM {
|
||||
// 64 da : Dump all memory mappings
|
||||
System.out.println("Active banks");
|
||||
for (int i = 0; i < 256; i++) {
|
||||
byte[] read = activeRead.get(i);
|
||||
byte[] write = activeWrite.get(i);
|
||||
byte[] read = this.activeRead.get(i);
|
||||
byte[] write = this.activeWrite.get(i);
|
||||
String readBank = getBanks().keySet().stream().filter(bank -> {
|
||||
PagedMemory mem = getBanks().get(bank);
|
||||
for (byte[] page : mem.getMemory()) {
|
||||
@ -162,148 +163,250 @@ abstract public class RAM128k extends RAM {
|
||||
|
||||
private final Semaphore configurationSemaphone = new Semaphore(1, true);
|
||||
|
||||
public String getReadConfiguration() {
|
||||
String rstate = "";
|
||||
if (SoftSwitches.RAMRD.getState()) {
|
||||
rstate += "Ra";
|
||||
} else {
|
||||
rstate += "R0";
|
||||
}
|
||||
String LCR = "L0R";
|
||||
if (SoftSwitches.LCRAM.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
LCR = "L1R";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCR = "L2R";
|
||||
}
|
||||
} else {
|
||||
LCR = "L1aR";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCR = "L2aR";
|
||||
}
|
||||
}
|
||||
}
|
||||
rstate += LCR;
|
||||
if (SoftSwitches.CXROM.getState()) {
|
||||
rstate += "CXROM";
|
||||
} else {
|
||||
rstate += "!CX";
|
||||
if (SoftSwitches.SLOTC3ROM.isOff()) {
|
||||
rstate += "C3";
|
||||
}
|
||||
if (SoftSwitches.INTC8ROM.isOn()) {
|
||||
rstate += "C8";
|
||||
} else {
|
||||
rstate += String.format("C8%d", getActiveSlot());
|
||||
}
|
||||
}
|
||||
|
||||
return rstate;
|
||||
}
|
||||
|
||||
public String getWriteConfiguration() {
|
||||
String wstate = "";
|
||||
if (SoftSwitches.RAMWRT.getState()) {
|
||||
wstate += "Wa";
|
||||
} else {
|
||||
wstate += "W0";
|
||||
}
|
||||
String LCW = "L0W";
|
||||
if (SoftSwitches.LCWRITE.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
LCW = "L1W";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCW = "L2W";
|
||||
}
|
||||
} else {
|
||||
LCW = "L1aW";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCW = "L2aW";
|
||||
}
|
||||
}
|
||||
}
|
||||
wstate += LCW;
|
||||
return wstate;
|
||||
}
|
||||
|
||||
public String getAuxZPConfiguration() {
|
||||
String astate = "";
|
||||
if (SoftSwitches._80STORE.isOn()) {
|
||||
astate += "80S";
|
||||
if (SoftSwitches.PAGE2.isOn()) {
|
||||
astate += "2";
|
||||
}
|
||||
if (SoftSwitches.HIRES.isOn()) {
|
||||
astate += "H";
|
||||
}
|
||||
}
|
||||
|
||||
// Handle zero-page bankswitching
|
||||
if (SoftSwitches.AUXZP.getState()) {
|
||||
astate += "Za";
|
||||
} else {
|
||||
astate += "Z0";
|
||||
}
|
||||
return astate;
|
||||
}
|
||||
|
||||
public PagedMemory buildReadConfiguration() {
|
||||
PagedMemory read = new PagedMemory(0x10000, PagedMemory.Type.RAM, computer);
|
||||
// First off, set up read/write for main memory (might get changed later on)
|
||||
read.fillBanks(SoftSwitches.RAMRD.getState() ? getAuxMemory() : mainMemory);
|
||||
|
||||
// Handle language card softswitches
|
||||
read.fillBanks(rom);
|
||||
if (SoftSwitches.LCRAM.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
read.fillBanks(languageCard);
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
read.fillBanks(languageCard2);
|
||||
}
|
||||
} else {
|
||||
read.fillBanks(getAuxLanguageCard());
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
read.fillBanks(getAuxLanguageCard2());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle 80STORE logic for bankswitching video ram
|
||||
if (SoftSwitches._80STORE.isOn()) {
|
||||
read.setBanks(0x04, 0x04, 0x04,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
if (SoftSwitches.HIRES.isOn()) {
|
||||
read.setBanks(0x020, 0x020, 0x020,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle zero-page bankswitching
|
||||
if (SoftSwitches.AUXZP.getState()) {
|
||||
// Aux pages 0 and 1
|
||||
read.setBanks(0, 2, 0, getAuxMemory());
|
||||
} else {
|
||||
// Main pages 0 and 1
|
||||
read.setBanks(0, 2, 0, mainMemory);
|
||||
}
|
||||
|
||||
/*
|
||||
INTCXROM SLOTC3ROM C1,C2,C4-CF C3
|
||||
0 0 slot rom
|
||||
0 1 slot slot
|
||||
1 - rom rom
|
||||
*/
|
||||
if (SoftSwitches.CXROM.getState()) {
|
||||
// Enable C1-CF to point to rom
|
||||
read.setBanks(0, 0x0F, 0x0C1, cPageRom);
|
||||
} else {
|
||||
// Enable C1-CF to point to slots
|
||||
for (int slot = 1; slot <= 7; slot++) {
|
||||
PagedMemory page = getCard(slot).map(Card::getCxRom).orElse(blank);
|
||||
read.setBanks(0, 1, 0x0c0 + slot, page);
|
||||
}
|
||||
if (getActiveSlot() == 0) {
|
||||
for (int i = 0x0C8; i < 0x0D0; i++) {
|
||||
read.set(i, blank.get(0));
|
||||
}
|
||||
} else {
|
||||
getCard(getActiveSlot()).ifPresent(c -> read.setBanks(0, 8, 0x0c8, c.getC8Rom()));
|
||||
}
|
||||
if (SoftSwitches.SLOTC3ROM.isOff()) {
|
||||
// Enable C3 to point to internal ROM
|
||||
read.setBanks(2, 1, 0x0C3, cPageRom);
|
||||
}
|
||||
if (SoftSwitches.INTC8ROM.isOn()) {
|
||||
// Enable C8-CF to point to internal ROM
|
||||
read.setBanks(7, 8, 0x0C8, cPageRom);
|
||||
}
|
||||
}
|
||||
// All ROM reads not intecepted will return 0xFF! (TODO: floating bus)
|
||||
read.set(0x0c0, blank.get(0));
|
||||
return read;
|
||||
}
|
||||
|
||||
public PagedMemory buildWriteConfiguration() {
|
||||
PagedMemory write = new PagedMemory(0x10000, PagedMemory.Type.RAM, computer);
|
||||
// First off, set up read/write for main memory (might get changed later on)
|
||||
write.fillBanks(SoftSwitches.RAMWRT.getState() ? getAuxMemory() : mainMemory);
|
||||
|
||||
// Handle language card softswitches
|
||||
for (int i = 0x0c0; i < 0x0d0; i++) {
|
||||
write.set(i, null);
|
||||
}
|
||||
if (SoftSwitches.LCWRITE.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
write.fillBanks(languageCard);
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
write.fillBanks(languageCard2);
|
||||
}
|
||||
} else {
|
||||
write.fillBanks(getAuxLanguageCard());
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
write.fillBanks(getAuxLanguageCard2());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Make 0xd000 - 0xffff non-writable!
|
||||
for (int i = 0x0d0; i < 0x0100; i++) {
|
||||
write.set(i, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle 80STORE logic for bankswitching video ram
|
||||
if (SoftSwitches._80STORE.isOn()) {
|
||||
write.setBanks(0x04, 0x04, 0x04,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
if (SoftSwitches.HIRES.isOn()) {
|
||||
write.setBanks(0x020, 0x020, 0x020,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle zero-page bankswitching
|
||||
if (SoftSwitches.AUXZP.getState()) {
|
||||
// Aux pages 0 and 1
|
||||
write.setBanks(0, 2, 0, getAuxMemory());
|
||||
} else {
|
||||
// Main pages 0 and 1
|
||||
write.setBanks(0, 2, 0, mainMemory);
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void configureActiveMemory() {
|
||||
|
||||
String auxZpConfiguration = getAuxZPConfiguration();
|
||||
String readConfiguration = getReadConfiguration() + auxZpConfiguration;
|
||||
String writeConfiguration = getWriteConfiguration() + auxZpConfiguration;
|
||||
String newState = readConfiguration + ";" + writeConfiguration;
|
||||
if (newState.equals(state)) {
|
||||
return;
|
||||
}
|
||||
state = newState;
|
||||
|
||||
try {
|
||||
state = "";
|
||||
log("MMU Switches");
|
||||
configurationSemaphone.acquire();
|
||||
// First off, set up read/write for main memory (might get changed later on)
|
||||
if (SoftSwitches.RAMRD.getState()) {
|
||||
state = "Ra";
|
||||
} else {
|
||||
state = "R0";
|
||||
}
|
||||
activeRead.fillBanks(SoftSwitches.RAMRD.getState() ? getAuxMemory() : mainMemory);
|
||||
if (SoftSwitches.RAMWRT.getState()) {
|
||||
state += "Wa";
|
||||
} else {
|
||||
state += "W0";
|
||||
}
|
||||
activeWrite.fillBanks(SoftSwitches.RAMWRT.getState() ? getAuxMemory() : mainMemory);
|
||||
|
||||
// Handle language card softswitches
|
||||
activeRead.fillBanks(rom);
|
||||
//activeRead.fillBanks(cPageRom);
|
||||
for (int i = 0x0c0; i < 0x0d0; i++) {
|
||||
activeWrite.set(i, null);
|
||||
}
|
||||
String LCR = "L0R";
|
||||
if (SoftSwitches.LCRAM.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
LCR = "L1R";
|
||||
activeRead.fillBanks(languageCard);
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCR = "L2R";
|
||||
activeRead.fillBanks(languageCard2);
|
||||
}
|
||||
} else {
|
||||
activeRead.fillBanks(getAuxLanguageCard());
|
||||
LCR = "L1aR";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCR = "L2aR";
|
||||
activeRead.fillBanks(getAuxLanguageCard2());
|
||||
}
|
||||
}
|
||||
if (memoryConfigurations.containsKey(readConfiguration)) {
|
||||
activeRead = memoryConfigurations.get(readConfiguration);
|
||||
} else {
|
||||
activeRead = buildReadConfiguration();
|
||||
memoryConfigurations.put(readConfiguration, activeRead);
|
||||
}
|
||||
|
||||
String LCW = "L0W";
|
||||
if (SoftSwitches.LCWRITE.isOn()) {
|
||||
if (SoftSwitches.AUXZP.isOff()) {
|
||||
LCW = "L1W";
|
||||
activeWrite.fillBanks(languageCard);
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
LCW = "L2W";
|
||||
activeWrite.fillBanks(languageCard2);
|
||||
}
|
||||
} else {
|
||||
activeWrite.fillBanks(getAuxLanguageCard());
|
||||
LCW = "L1aW";
|
||||
if (SoftSwitches.LCBANK1.isOff()) {
|
||||
activeWrite.fillBanks(getAuxLanguageCard2());
|
||||
LCW = "L2aW";
|
||||
}
|
||||
}
|
||||
if (memoryConfigurations.containsKey(writeConfiguration)) {
|
||||
activeWrite = memoryConfigurations.get(writeConfiguration);
|
||||
} else {
|
||||
// Make 0xd000 - 0xffff non-writable!
|
||||
for (int i = 0x0d0; i < 0x0100; i++) {
|
||||
activeWrite.set(i, null);
|
||||
}
|
||||
activeWrite = buildWriteConfiguration();
|
||||
memoryConfigurations.put(writeConfiguration, activeWrite);
|
||||
}
|
||||
|
||||
state += String.format(",%s,%s", LCR, LCW);
|
||||
// Handle 80STORE logic for bankswitching video ram
|
||||
if (SoftSwitches._80STORE.isOn()) {
|
||||
state += ",80S";
|
||||
if (SoftSwitches.PAGE2.isOn()) {
|
||||
state += "2";
|
||||
}
|
||||
activeRead.setBanks(0x04, 0x04, 0x04,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
activeWrite.setBanks(0x04, 0x04, 0x04,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
if (SoftSwitches.HIRES.isOn()) {
|
||||
state += "H";
|
||||
activeRead.setBanks(0x020, 0x020, 0x020,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
activeWrite.setBanks(0x020, 0x020, 0x020,
|
||||
SoftSwitches.PAGE2.isOn() ? getAuxMemory() : mainMemory);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle zero-page bankswitching
|
||||
if (SoftSwitches.AUXZP.getState()) {
|
||||
state += ",Za";
|
||||
// Aux pages 0 and 1
|
||||
activeRead.setBanks(0, 2, 0, getAuxMemory());
|
||||
activeWrite.setBanks(0, 2, 0, getAuxMemory());
|
||||
} else {
|
||||
state += ",Z0";
|
||||
// Main pages 0 and 1
|
||||
activeRead.setBanks(0, 2, 0, mainMemory);
|
||||
activeWrite.setBanks(0, 2, 0, mainMemory);
|
||||
}
|
||||
|
||||
/*
|
||||
INTCXROM SLOTC3ROM C1,C2,C4-CF C3
|
||||
0 0 slot rom
|
||||
0 1 slot slot
|
||||
1 - rom rom
|
||||
*/
|
||||
if (SoftSwitches.CXROM.getState()) {
|
||||
// Enable C1-CF to point to rom
|
||||
activeRead.setBanks(0, 0x0F, 0x0C1, cPageRom);
|
||||
} else {
|
||||
// Enable C1-CF to point to slots
|
||||
for (int slot = 1; slot <= 7; slot++) {
|
||||
PagedMemory page = getCard(slot).map(Card::getCxRom).orElse(blank);
|
||||
activeRead.setBanks(0, 1, 0x0c0 + slot, page);
|
||||
}
|
||||
if (getActiveSlot() == 0) {
|
||||
for (int i = 0x0C8; i < 0x0D0; i++) {
|
||||
activeRead.set(i, blank.get(0));
|
||||
}
|
||||
} else {
|
||||
getCard(getActiveSlot()).ifPresent(c -> activeRead.setBanks(0, 8, 0x0c8, c.getC8Rom()));
|
||||
}
|
||||
if (SoftSwitches.SLOTC3ROM.isOff()) {
|
||||
// Enable C3 to point to internal ROM
|
||||
activeRead.setBanks(2, 1, 0x0C3, cPageRom);
|
||||
state += ",C30";
|
||||
}
|
||||
if (SoftSwitches.INTC8ROM.isOn()) {
|
||||
state += ",C80";
|
||||
// Enable C8-CF to point to internal ROM
|
||||
activeRead.setBanks(7, 8, 0x0C8, cPageRom);
|
||||
} else {
|
||||
state += String.format(",C8%d", getActiveSlot());
|
||||
}
|
||||
}
|
||||
// All ROM reads not intecepted will return 0xFF! (TODO: floating bus)
|
||||
activeRead.set(0x0c0, blank.get(0));
|
||||
configurationSemaphone.release();
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.getLogger(RAM128k.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@ -349,6 +452,8 @@ abstract public class RAM128k extends RAM {
|
||||
}
|
||||
// System.out.println("Finished reading rom with " + inputRom.available() + " bytes left unread!");
|
||||
//dump();
|
||||
// Clear cached configurations as we might have outdated references now
|
||||
memoryConfigurations.clear();
|
||||
configureActiveMemory();
|
||||
}
|
||||
|
||||
@ -406,5 +511,7 @@ abstract public class RAM128k extends RAM {
|
||||
languageCard2 = currentMemory.languageCard2;
|
||||
cards = currentMemory.cards;
|
||||
activeSlot = currentMemory.activeSlot;
|
||||
// Clear cached configurations as we might have outdated references now
|
||||
memoryConfigurations.clear();
|
||||
}
|
||||
}
|
||||
|
@ -20,12 +20,8 @@ package jace.core;
|
||||
|
||||
import jace.state.Stateful;
|
||||
import jace.config.Reconfigurable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import org.eclipse.collections.api.list.MutableList;
|
||||
import org.eclipse.collections.impl.factory.Lists;
|
||||
|
||||
/**
|
||||
* Device is a very simple abstraction of any emulation component. A device
|
||||
@ -35,42 +31,43 @@ import javafx.beans.property.SimpleBooleanProperty;
|
||||
*
|
||||
* Depending on the type of device, some special work might be required to
|
||||
* attach or detach it to the active emulation (such as what should happen when
|
||||
* a card is inserted or removed from a slot?)
|
||||
* Created on May 10, 2007, 5:46 PM
|
||||
* a card is inserted or removed from a slot?) Created on May 10, 2007, 5:46 PM
|
||||
*
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
@Stateful
|
||||
public abstract class Device implements Reconfigurable {
|
||||
|
||||
protected Computer computer;
|
||||
private List<Device> children;
|
||||
|
||||
private MutableList<Device> children;
|
||||
|
||||
private Device() {
|
||||
children = Collections.synchronizedList(new ArrayList<>());
|
||||
// TODO: Previously this was synchronized -- confirm this is safe to leave unsynchronized
|
||||
children = Lists.mutable.<Device>empty();
|
||||
}
|
||||
|
||||
|
||||
public Device(Computer computer) {
|
||||
this();
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
|
||||
// Number of cycles to do nothing (for cpu/video cycle accuracy)
|
||||
@Stateful
|
||||
private int waitCycles = 0;
|
||||
@Stateful
|
||||
private final BooleanProperty run = new SimpleBooleanProperty(true);
|
||||
private boolean run = true;
|
||||
@Stateful
|
||||
public boolean isPaused = false;
|
||||
@Stateful
|
||||
public boolean isAttached = false;
|
||||
|
||||
|
||||
public void addChildDevice(Device d) {
|
||||
children.add(d);
|
||||
if (isAttached) {
|
||||
d.attach();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void removeChildDevice(Device d) {
|
||||
children.remove(d);
|
||||
d.suspend();
|
||||
@ -78,19 +75,19 @@ public abstract class Device implements Reconfigurable {
|
||||
d.detach();
|
||||
}
|
||||
}
|
||||
|
||||
public void addAllDevices(Collection<Device> devices) {
|
||||
|
||||
public void addAllDevices(Iterable<Device> devices) {
|
||||
devices.forEach(this::addChildDevice);
|
||||
}
|
||||
|
||||
public List<Device> getChildren() {
|
||||
return Collections.unmodifiableList(children);
|
||||
|
||||
public Iterable<Device> getChildren() {
|
||||
return children.asUnmodifiable();
|
||||
}
|
||||
|
||||
public BooleanProperty getRunningProperty() {
|
||||
public boolean getRunningProperty() {
|
||||
return run;
|
||||
}
|
||||
|
||||
|
||||
public void addWaitCycles(int wait) {
|
||||
waitCycles += wait;
|
||||
}
|
||||
@ -100,38 +97,24 @@ public abstract class Device implements Reconfigurable {
|
||||
}
|
||||
|
||||
public void doTick() {
|
||||
/*
|
||||
if (waitCycles <= 0)
|
||||
tick();
|
||||
else
|
||||
waitCycles--;
|
||||
*/
|
||||
|
||||
if (!run.get()) {
|
||||
// System.out.println("Device stopped: " + getName());
|
||||
isPaused = true;
|
||||
return;
|
||||
}
|
||||
// The following might be as much as 7% faster than the above
|
||||
// My guess is that the above results in a GOTO
|
||||
// whereas the following pre-emptive return avoids that
|
||||
if (waitCycles > 0) {
|
||||
if (run) {
|
||||
children.forEach(Device::tick);
|
||||
if (waitCycles <= 0) {
|
||||
tick();
|
||||
return;
|
||||
}
|
||||
waitCycles--;
|
||||
return;
|
||||
}
|
||||
// Implicit else...
|
||||
children.forEach(Device::doTick);
|
||||
tick();
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return run.get();
|
||||
return run;
|
||||
}
|
||||
|
||||
public synchronized void setRun(boolean run) {
|
||||
// System.out.println(Thread.currentThread().getName() + (run ? " resuming " : " suspending ")+ getDeviceName());
|
||||
isPaused = false;
|
||||
this.run.set(run);
|
||||
this.run = run;
|
||||
}
|
||||
|
||||
protected abstract String getDeviceName();
|
||||
|
@ -103,6 +103,11 @@ public class CardRamworks extends RAM128k {
|
||||
return getAuxBank(BankType.LANGUAGE_CARD_2, currentBank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuxZPConfiguration() {
|
||||
return super.getAuxZPConfiguration() + String.format("AB%2d", currentBank);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Ramworks III";
|
||||
|
@ -195,7 +195,7 @@ public class ZipWarpAccelerator extends Device {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (zipUnlockCount > 0) {
|
||||
if (zipUnlockCount > 0.0) {
|
||||
zipUnlockCount -= UNLOCK_PENALTY_PER_TICK;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -11,8 +17,9 @@ import jace.lawless.LawlessVideo.RenderEngine;
|
||||
public class LawlessHacks extends Cheats {
|
||||
|
||||
// Modes specified by the game engine
|
||||
int MODE_SOFTSWITCH = 0x0C020;
|
||||
|
||||
int MODE_SOFTSWITCH_MIN = 0x0C049;
|
||||
int MODE_SOFTSWITCH_MAX = 0x0C04F;
|
||||
int SFX_TRIGGER = 0x0C069;
|
||||
|
||||
public LawlessHacks(Computer computer) {
|
||||
super(computer);
|
||||
@ -27,11 +34,15 @@ public class LawlessHacks extends Cheats {
|
||||
public void registerListeners() {
|
||||
// Observe graphics changes
|
||||
addCheat(RAMEvent.TYPE.ANY, false, (e) -> {
|
||||
if ((e.getAddress() & 0x0FFF0) == MODE_SOFTSWITCH) {
|
||||
System.out.println("Trapped " + e.getType().toString() + " to $"+Integer.toHexString(e.getAddress()));
|
||||
setEngineByOrdinal(e.getAddress() - MODE_SOFTSWITCH);
|
||||
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, MODE_SOFTSWITCH | 0x0f);
|
||||
}, MODE_SOFTSWITCH_MIN, MODE_SOFTSWITCH_MAX);
|
||||
addCheat(RAMEvent.TYPE.WRITE, false, (e) -> {
|
||||
playSound(e.getNewValue());
|
||||
}, SFX_TRIGGER, SFX_TRIGGER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class LawlessVideo extends VideoNTSC {
|
||||
39, 130, 78, 191
|
||||
}),
|
||||
TITLE(new int[]{
|
||||
56, 162, 224, 190
|
||||
16, 162, 64, 190
|
||||
}),
|
||||
UNKNOWN;
|
||||
boolean[][] colorMask;
|
||||
|
@ -83,7 +83,7 @@
|
||||
</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>
|
||||
<Button contentDisplay="TOP" mnemonicParsing="false" styleClass="uiActionButton" text="IDE">
|
||||
<graphic>
|
||||
@ -113,7 +113,7 @@
|
||||
</graphic>
|
||||
</Button>
|
||||
</children>
|
||||
</TilePane>
|
||||
</TilePane>-->
|
||||
</children>
|
||||
</HBox>
|
||||
</top>
|
||||
@ -153,7 +153,7 @@
|
||||
</TilePane>
|
||||
<TilePane alignment="TOP_RIGHT" hgap="5.0" vgap="5.0" HBox.hgrow="ALWAYS">
|
||||
<children>
|
||||
<Button contentDisplay="TOP" mnemonicParsing="false" styleClass="uiActionButton" text="Play">
|
||||
<!-- <Button contentDisplay="TOP" mnemonicParsing="false" styleClass="uiActionButton" text="Play">
|
||||
<graphic>
|
||||
<ImageView>
|
||||
<image>
|
||||
@ -161,7 +161,7 @@
|
||||
</image>
|
||||
</ImageView>
|
||||
</graphic>
|
||||
</Button>
|
||||
</Button>-->
|
||||
<Button alignment="TOP_LEFT" contentDisplay="TOP" mnemonicParsing="false" styleClass="uiActionButton" text="Restart" TilePane.alignment="TOP_RIGHT">
|
||||
<graphic>
|
||||
<ImageView>
|
||||
|
Before Width: | Height: | Size: 724 B After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 914 B After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 4.0 KiB |
@ -32,7 +32,7 @@
|
||||
}
|
||||
|
||||
.uiActionButton ImageView, .uiSpeedSlider ImageView {
|
||||
-fx-effect: dropshadow(gaussian , rgba(128,255,128,0.75) , 2,1.0,0,0);
|
||||
-fx-effect: dropshadow(gaussian , rgba(64,255,64,0.25) , 2,1.0,0,0);
|
||||
}
|
||||
|
||||
.uiSpeedSlider AnchorPane {
|
||||
|
@ -5,13 +5,13 @@
|
||||
*/
|
||||
package jace.ide;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import jace.applesoft.ApplesoftProgram;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
@ -55,14 +55,14 @@ public class ApplesoftTest {
|
||||
|
||||
@Test
|
||||
public void deserializeBinaryTest() {
|
||||
ApplesoftProgram program = ApplesoftProgram.fromBinary(Lists.newArrayList(lemonadeStandBinary), 0x0801);
|
||||
ApplesoftProgram program = ApplesoftProgram.fromBinary(Arrays.asList(lemonadeStandBinary), 0x0801);
|
||||
assertNotNull(program);
|
||||
assertNotSame("", program.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundTripStringComparisonTest() {
|
||||
ApplesoftProgram program = ApplesoftProgram.fromBinary(Lists.newArrayList(lemonadeStandBinary), 0x0801);
|
||||
ApplesoftProgram program = ApplesoftProgram.fromBinary(Arrays.asList(lemonadeStandBinary), 0x0801);
|
||||
String serialized = program.toString();
|
||||
ApplesoftProgram deserialized = ApplesoftProgram.fromString(serialized);
|
||||
String[] serializedLines = serialized.split("\\n");
|
||||
|