Some refinements to capture text inside the graphics area

This commit is contained in:
Brendan Robert 2018-02-04 22:30:24 -06:00
parent c50ea6ec77
commit 69261e6915
2 changed files with 53 additions and 33 deletions

View File

@ -1,11 +1,11 @@
package jace.lawless;
import jace.apple2e.MOS65C02;
import jace.apple2e.SoftSwitches;
import jace.cheat.Cheats;
import jace.core.Computer;
import jace.core.RAMEvent;
import jace.lawless.LawlessVideo.RenderEngine;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Hacks that affect lawless legends gameplay
@ -14,13 +14,12 @@ public class LawlessHacks extends Cheats {
// Location of font routines
int FONT_ROUTINES = 0x0EC00;
int FONT_ROUTINES_END = 0x0f800;
int FONT_SPEEDUP_CYCLES = 10000;
int FONT_ROUTINES_LEN = 0x0f00;
int ENGINE_ADDR = 0x06000;
int ENGINE_FIRST_OPCODE = ENGINE_ADDR + (13 * 3);
int DETECT_ENGINE_WRITE = 0x060FF;
Cheats speedupRequester = this;
AtomicInteger speedupCounter = new AtomicInteger();
public LawlessHacks(Computer computer) {
super(computer);
@ -28,15 +27,22 @@ public class LawlessHacks extends Cheats {
@Override
public void registerListeners() {
for (int entry = 0; entry < 13; entry++) {
int targetAddress = FONT_ROUTINES + (entry * 3);
addCheat(RAMEvent.TYPE.EXECUTE, (e) -> {
if (e.getAddress() == targetAddress) {
computer.motherboard.requestSpeed(speedupRequester);
speedupCounter.set(FONT_SPEEDUP_CYCLES);
}
}, targetAddress);
}
// Observe graphics changes
addCheat(RAMEvent.TYPE.WRITE, (e) -> {
if (e.getAddress() >= 0x02000 && e.getAddress() <= 0x05FFF) {
((LawlessVideo) computer.getVideo()).setBWFlag(e.getAddress(),
SoftSwitches.RAMWRT.getState() ||
computer.getCpu().getProgramCounter() < FONT_ROUTINES ||
computer.getCpu().getProgramCounter() > FONT_ROUTINES_END);
}
}, 0x02000, 0x05FFF);
// Watch for font routine usage for speedup
addCheat(RAMEvent.TYPE.EXECUTE, (e) -> {
if ((e.getAddress() & 0x0ff00) == FONT_ROUTINES) {
computer.motherboard.requestSpeed(this);
}
}, FONT_ROUTINES, FONT_ROUTINES | 0x0ff);
// Try to detect engines changing
addCheat(RAMEvent.TYPE.WRITE, false, (e) -> {
if (e.getAddress() == DETECT_ENGINE_WRITE) {
detectActiveEngine();
@ -51,18 +57,10 @@ public class LawlessHacks extends Cheats {
@Override
public void tick() {
if (speedupCounter.get() > 0 && speedupCounter.decrementAndGet() <= 0) {
int pc = computer.getCpu().getProgramCounter();
if (pc >= FONT_ROUTINES && pc <= FONT_ROUTINES + FONT_ROUTINES_LEN) {
speedupCounter.addAndGet(500);
computer.motherboard.requestSpeed(speedupRequester);
} else {
computer.motherboard.cancelSpeedRequest(speedupRequester);
}
}
}
private void detectActiveEngine() {
LawlessVideo video = (LawlessVideo) computer.getVideo();
// for (int i = 0x06000; i < 0x06080;) {
// System.out.printf("%04x: ", i);
// for (int j = 0; j < 16; j++, i++) {
@ -76,19 +74,19 @@ public class LawlessHacks extends Cheats {
if (firstPageByte == MOS65C02.OPCODE.JMP_AB.getCode()
&& firstDataByte == MOS65C02.OPCODE.LDX_ZP.getCode()) {
// 2D Engine: First instruction is LDX MAP_PARTITION
LawlessVideo.setEngine(RenderEngine._2D);
video.setEngine(RenderEngine._2D);
} else if (firstPageByte == MOS65C02.OPCODE.JMP_AB.getCode()
&& firstDataByte == 0
&& secondDataByte == 0) {
// 3D Engine: First byte is a zero for MapHeader
LawlessVideo.setEngine(RenderEngine._3D);
video.setEngine(RenderEngine._3D);
} else if (firstPageByte == MOS65C02.OPCODE.JMP_AB.getCode()
&& firstDataByte == 0
&& secondDataByte == 0x067) {
// 3D Engine: First byte is a zero for MapHeader
LawlessVideo.setEngine(RenderEngine.PORTRAIT);
video.setEngine(RenderEngine.PORTRAIT);
} else {
LawlessVideo.setEngine(RenderEngine.UNKNOWN);
video.setEngine(RenderEngine.UNKNOWN);
}
}

View File

@ -17,7 +17,9 @@ public class LawlessVideo extends VideoNTSC {
private static RenderEngine activeEngine = RenderEngine.UNKNOWN;
private boolean invActive = false;
private boolean titleScreen = false;
private boolean[][] activeMask = new boolean[192][80];
public static enum RenderEngine {
_2D(new int[]{
9, 8, 34, 17,
@ -63,10 +65,30 @@ public class LawlessVideo extends VideoNTSC {
super(computer);
}
public static void setEngine(RenderEngine e) {
public void setEngine(RenderEngine e) {
activeEngine = e;
Emulator.computer.onNextVBL(()->Emulator.computer.getVideo().forceRefresh());
// System.out.println("Detected engine: " + e.name());
for (int y=0; y < 192; y++) {
System.arraycopy(e.colorMask[y], 0, activeMask[y], 0, 80);
}
Emulator.computer.onNextVBL(() -> Emulator.computer.getVideo().forceRefresh());
System.out.println("Detected engine: " + e.name());
}
public void setBWFlag(int addr, boolean b) {
addr &= 0x01FFF;
int row = VideoNTSC.identifyHiresRow(addr);
if (row < 0 || row > 192) {
return;
}
int col = addr - VideoNTSC.calculateHiresOffset(row);
if (row > 20 && row < 136 && col < 20) {
boolean prev = activeMask[row][col*2];
activeMask[row][col*2] = b;
activeMask[row][col*2+1] = b;
if (prev ^ b) {
redraw();
}
}
}
static public int[] divBy56 = new int[560];
@ -86,10 +108,10 @@ public class LawlessVideo extends VideoNTSC {
int row6 = getSummary(6);
int row7 = getSummary(7);
// Rows 6,7 = White
invActive = row5 == 0
&& row6 == 1270
invActive = row5 == 0
&& row6 == 1270
&& row7 == 1270;
titleScreen = row4 == 828 && row5 == 513 && row6 == 382;
titleScreen = row4 == 828 && row5 == 513 && row6 == 382;
}
public int getSummary(int row) {
@ -106,7 +128,7 @@ public class LawlessVideo extends VideoNTSC {
public void hblankStart(WritableImage screen, int y, boolean isDirty) {
int rowStart = getCurrentWriter().getYOffset(y);
if (rowStart >= 0x02000) {
boolean[] color = activeEngine.colorMask[y];
boolean[] color = activeMask[y];
if (titleScreen) {
color = RenderEngine.UNKNOWN.colorMask[y];
} else if (invActive) {