Simplified the text enhancement hacks and bumped speed back to 200%

This commit is contained in:
Brendan Robert 2024-03-12 23:50:05 -05:00
parent d81d0fedd7
commit 2ed008c9c3
6 changed files with 64 additions and 97 deletions

View File

@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import jace.apple2e.MOS65C02;
import jace.apple2e.RAM128k;
import jace.apple2e.VideoNTSC;
import jace.cheat.Cheats.Cheat;
@ -144,7 +145,7 @@ public class LawlessLegends extends Application {
c.coldStart();
try {
Thread.sleep(watchdogDelay);
if (!romStarted.get() || !c.isRunning() || c.getCpu().getProgramCounter() == 0xc700 || c.getCpu().getProgramCounter() == 0) {
if (!romStarted.get() || !c.isRunning() || c.getCpu().getProgramCounter() == MOS65C02.FASTBOOT || c.getCpu().getProgramCounter() == 0) {
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Boot not detected, performing a cold start");
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Old PC: {0}", c.getCpu().getProgramCounter());
resetEmulator();

View File

@ -64,7 +64,7 @@ public class Apple2e extends Computer {
static int IRQ_VECTOR = 0x003F2;
@ConfigurableField(name = "Production mode", shortName = "production")
public boolean PRODUCTION_MODE = false;
public boolean PRODUCTION_MODE = true;
@ConfigurableField(name = "Slot 1", shortName = "s1card")
public DeviceSelection<Cards> card1 = new DeviceSelection<>(Cards.class, null);
@ConfigurableField(name = "Slot 2", shortName = "s2card")
@ -116,6 +116,9 @@ public class Apple2e extends Computer {
try {
setCpu(new MOS65C02());
setMotherboard(new Motherboard(null));
if (PRODUCTION_MODE) {
getMotherboard().setSpeedInPercentage(200);
}
} catch (Throwable t) {
System.err.println("Unable to initialize virtual machine");
t.printStackTrace(System.err);
@ -135,6 +138,11 @@ public class Apple2e extends Computer {
r.resetState();
for (SoftSwitches s : SoftSwitches.values()) {
if ((s.getSwitch() instanceof VideoSoftSwitch)) {
if (s == SoftSwitches.TEXT && PRODUCTION_MODE) {
s.getSwitch().setState(true);
} else {
s.getSwitch().reset();
}
s.getSwitch().reset();
}
}

View File

@ -40,9 +40,9 @@ public class MOS65C02 extends CPU {
private static final Logger LOG = Logger.getLogger(MOS65C02.class.getName());
public boolean readAddressTriggersEvent = true;
static int RESET_VECTOR = 0x00FFFC;
static int INT_VECTOR = 0x00FFFE;
static int FASTBOOT = 0x00FAA9;
public static int RESET_VECTOR = 0x00FFFC;
public static int INT_VECTOR = 0x00FFFE;
public static int FASTBOOT = 0x00FAA9;
@Stateful
public int A = 0x0FF;
@Stateful

View File

@ -16,6 +16,8 @@
package jace.core;
import jace.apple2e.SoftSwitches;
/**
* A RAM event is defined as anything that causes a read or write to the
* mainboard RAM of the computer. This could be the result of an indirect
@ -147,4 +149,21 @@ public class RAMEvent {
public final boolean isIntercepted() {
return valueIntercepted;
}
public boolean isMainMemory() {
if (type.isRead() && SoftSwitches.RAMRD.isOn()) {
return false;
} else if (!type.isRead() && SoftSwitches.RAMWRT.isOn()) {
return false;
} else if (address < 0x0200) {
// Check if zero page is pointed to auxiliary memory
return SoftSwitches.AUXZP.isOff();
}
if ((address >= 0x400 && address < 0x0800) || (address >= 0x2000 && address < 0x4000)) {
if (SoftSwitches._80STORE.isOn() && SoftSwitches.PAGE2.isOn()) {
return false;
}
}
return true;
}
}

View File

@ -16,9 +16,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jace.Emulator;
import jace.apple2e.VideoDHGR;
import jace.cheat.Cheats;
import jace.core.RAMEvent;
import jace.lawless.LawlessVideo.RenderEngine;
import javafx.util.Duration;
/**
@ -45,12 +45,8 @@ public class LawlessHacks extends Cheats {
@Override
public void registerListeners() {
// Observe graphics changes
addCheat("Lawless Legends Graphics Modes", RAMEvent.TYPE.ANY, (e) -> {
int addr = e.getAddress();
if (addr >= MODE_SOFTSWITCH_MIN && e.getAddress() <= MODE_SOFTSWITCH_MAX) {
setEngineByOrdinal(e.getAddress() - MODE_SOFTSWITCH_MIN);
}
}, MODE_SOFTSWITCH_MIN, MODE_SOFTSWITCH_MAX);
addCheat("Lawless Text Speedup", RAMEvent.TYPE.EXECUTE, this::fastText, 0x0ee00, 0x0ee00 + 0x0f00);
addCheat("Lawless Text Enhancement", RAMEvent.TYPE.WRITE, this::enhanceText, 0x02000, 0x03fff);
addCheat("Lawless Legends Music Commands", RAMEvent.TYPE.WRITE, (e) -> {
playSound(e.getNewValue());
}, SFX_TRIGGER);
@ -65,14 +61,33 @@ public class LawlessHacks extends Cheats {
public void tick() {
}
private void setEngineByOrdinal(int mode) {
// Speed up text rendering
private void fastText(RAMEvent e) {
if (e.isMainMemory() && e.getOldValue() != 0x060) {
Emulator.withComputer((c->c.getMotherboard().requestSpeed(this)));
} else {
Emulator.withComputer((c->c.getMotherboard().cancelSpeedRequest(this)));
}
}
// Enhance text rendering by forcing the text to be pure B&W
private void enhanceText(RAMEvent e) {
if (!e.isMainMemory()) {
return;
}
int pc = Emulator.withComputer(c->c.getCpu().getProgramCounter(), 0);
boolean drawingText = pc == 0x0ee46 || pc > 0x0f300;
Emulator.withVideo(v -> {
if (v instanceof LawlessVideo) {
LawlessVideo video = (LawlessVideo) v;
if (mode >= 0 && mode < RenderEngine.values().length) {
video.setEngine(RenderEngine.values()[mode]);
} else {
video.setEngine(RenderEngine.UNKNOWN);
int addr = e.getAddress();
int y = VideoDHGR.identifyHiresRow(addr);
if (y >= 0 && y <= 192) {
int x = addr - video.getCurrentWriter().getYOffset(y);
if (x >= 0 && x < 40) {
video.activeMask[y][x*2] = !drawingText;
video.activeMask[y][x*2+1] = !drawingText;
}
}
}
});

View File

@ -2,94 +2,23 @@ package jace.lawless;
import java.util.Arrays;
import jace.Emulator;
import jace.apple2e.RAM128k;
import jace.apple2e.VideoNTSC;
import jace.core.PagedMemory;
import jace.core.Video;
import javafx.scene.image.WritableImage;
/**
* Lawless-enhanced video output for readable text
*/
public class LawlessVideo extends VideoNTSC {
public final boolean[][] activeMask = new boolean[192][80];
private static RenderEngine activeEngine = RenderEngine.UNKNOWN;
private boolean titleScreen = true;
private final boolean[][] activeMask = new boolean[192][80];
public enum RenderEngine {
FULL_COLOR,
FULL_TEXT(new int[]{
2, 6, 78, 186
}),
_2D(new int[]{
9, 8, 34, 17,
44, 24, 76, 136,
44, 143, 76, 184
}),
_3D(new int[]{
9, 8, 34, 17,
44, 24, 76, 136,
44, 143, 76, 183,
8, 172, 14, 182,}),
MAP(new int[]{
2, 6, 78, 11,
2, 11, 4, 186,
76, 11, 78, 186,
2, 182, 78, 186,
28, 3, 52, 6
}),
STORYBOOK(new int[]{
0, 0, 39, 191,
39, 130, 78, 191
}),
TITLE(new int[]{
16, 154, 64, 190
}),
UNKNOWN;
boolean[][] colorMask;
RenderEngine(int[] mask) {
this();
for (int i = 0; i < mask.length; i += 4) {
int x1 = mask[i],
y1 = mask[i + 1],
x2 = mask[i + 2],
y2 = mask[i + 3];
for (int y = y1; y < y2; y++) {
for (int x = x1; x < x2; x++) {
colorMask[y][x] = false;
}
}
}
}
RenderEngine() {
colorMask = new boolean[192][80];
for (int y = 0; y < 192; y++) {
colorMask[y] = new boolean[80];
Arrays.fill(colorMask[y], true);
}
}
}
public LawlessVideo() {
super();
this.vblankStart();
}
public void setEngine(RenderEngine e) {
if (activeEngine != e) {
titleScreen = false;
activeEngine = e;
for (int y=0; y < 192; y++) {
System.arraycopy(activeEngine.colorMask[y], 0, activeMask[y], 0, 80);
}
Emulator.withComputer(c->c.onNextVBL(Video::forceRefresh));
System.out.println("Detected engine: " + e.name());
for (boolean[] row : activeMask) {
Arrays.fill(row, true);
}
}
@ -100,7 +29,6 @@ public class LawlessVideo extends VideoNTSC {
divBy56[i] = i / 56;
}
}
public int getSummary(int row) {
PagedMemory mainMemory = ((RAM128k) getMemory()).getMainMemory();
int rowAddr = getCurrentWriter().getYOffset(row);
@ -118,11 +46,7 @@ public class LawlessVideo extends VideoNTSC {
}
int rowStart = getCurrentWriter().getYOffset(y);
if (rowStart >= 0x02000) {
boolean[] color = activeMask[y];
if (titleScreen) {
color = RenderEngine.FULL_COLOR.colorMask[y];
}
System.arraycopy(color, 0, colorActive, 0, 80);
System.arraycopy(activeMask[y], 0, colorActive, 0, 80);
}
super.hblankStart(screen, y, isDirty);
}