mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-06-26 00:29:30 +00:00
Basic speedup hacks and B&W rendering for text
This commit is contained in:
parent
cfb90d27a1
commit
05e59a5454
|
@ -12,7 +12,7 @@
|
|||
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-classpath %classpath jace.JaceApplication</exec.args>
|
||||
<exec.args>-classpath %classpath jace.LawlessLegends</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
</properties>
|
||||
</action>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-classpath %classpath jace.JaceApplication</exec.args>
|
||||
<exec.args>-classpath %classpath jace.LawlessLegends</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
<jpda.listen>true</jpda.listen>
|
||||
</properties>
|
||||
|
@ -41,7 +41,7 @@
|
|||
<goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
|
||||
</goals>
|
||||
<properties>
|
||||
<exec.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath jace.JaceApplication</exec.args>
|
||||
<exec.args>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath jace.LawlessLegends</exec.args>
|
||||
<exec.executable>java</exec.executable>
|
||||
<jpda.listen>true</jpda.listen>
|
||||
</properties>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
package jace;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import jace.config.Configuration;
|
||||
import jace.core.RAM;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.RAMListener;
|
||||
|
@ -14,9 +14,10 @@ import jace.hardware.CardDiskII;
|
|||
import jace.hardware.CardMockingboard;
|
||||
import jace.hardware.CardRamFactor;
|
||||
import jace.hardware.CardRamworks;
|
||||
import jace.hardware.CardThunderclock;
|
||||
import jace.hardware.PassportMidiInterface;
|
||||
import jace.hardware.massStorage.CardMassStorage;
|
||||
import jace.lawless.LawlessHacks;
|
||||
import jace.lawless.LawlessVideo;
|
||||
import jace.library.DiskType;
|
||||
import jace.library.MediaEntry;
|
||||
import jace.library.MediaEntry.MediaFile;
|
||||
|
@ -24,7 +25,6 @@ import jace.ui.MetacheatUI;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
@ -66,7 +66,7 @@ public class LawlessLegends extends Application {
|
|||
primaryStage.setScene(s);
|
||||
primaryStage.setTitle("Lawless Legends");
|
||||
EmulatorUILogic.scaleIntegerRatio();
|
||||
Utility.loadIcon("revolver_icon.png").ifPresent(primaryStage.getIcons()::add);
|
||||
Utility.loadIcon("game_icon.png").ifPresent(primaryStage.getIcons()::add);
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
|
@ -153,11 +153,14 @@ public class LawlessLegends extends Application {
|
|||
Emulator.computer.joy2enabled = false;
|
||||
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(CardMockingboard.class);
|
||||
Emulator.computer.card2.setValue(PassportMidiInterface.class);
|
||||
Emulator.computer.cheatEngine.setValue(LawlessHacks.class);
|
||||
Configuration.buildTree();
|
||||
Emulator.computer.reconfigure();
|
||||
RAM memory = Emulator.computer.memory;
|
||||
|
||||
|
|
|
@ -57,14 +57,14 @@ public class VideoNTSC extends VideoDHGR {
|
|||
public boolean enableVideo7 = true;
|
||||
// Scanline represents 560 bits, divided up into 28-bit words
|
||||
int[] scanline = new int[20];
|
||||
static int[] divBy28 = new int[560];
|
||||
static public int[] divBy28 = new int[560];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 560; i++) {
|
||||
divBy28[i] = i / 28;
|
||||
}
|
||||
}
|
||||
boolean[] colorActive = new boolean[80];
|
||||
protected boolean[] colorActive = new boolean[80];
|
||||
int rowStart = 0;
|
||||
|
||||
public VideoNTSC(Computer computer) {
|
||||
|
|
|
@ -97,7 +97,7 @@ public abstract class Cheats extends Device {
|
|||
super.detach();
|
||||
}
|
||||
|
||||
abstract void registerListeners();
|
||||
public abstract void registerListeners();
|
||||
|
||||
protected void unregisterListeners() {
|
||||
listeners.stream().forEach((l) -> {
|
||||
|
|
|
@ -134,7 +134,7 @@ public class MetaCheat extends Cheats {
|
|||
}
|
||||
|
||||
@Override
|
||||
void registerListeners() {
|
||||
public void registerListeners() {
|
||||
}
|
||||
|
||||
public void addCheat(DynamicCheat cheat) {
|
||||
|
|
|
@ -70,7 +70,7 @@ public class MontezumasRevengeCheats extends Cheats {
|
|||
};
|
||||
|
||||
@Override
|
||||
void registerListeners() {
|
||||
public void registerListeners() {
|
||||
RAM memory = Emulator.computer.memory;
|
||||
if (repulsiveHack) {
|
||||
addCheat(RAMEvent.TYPE.WRITE, this::repulsiveBehavior, 0x1508, 0x1518);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
package jace.lawless;
|
||||
|
||||
import jace.apple2e.MOS65C02;
|
||||
import jace.cheat.Cheats;
|
||||
import jace.core.Computer;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.Utility;
|
||||
import jace.lawless.LawlessVideo.RenderEngine;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Hacks that affect lawless legends gameplay
|
||||
*/
|
||||
public class LawlessHacks extends Cheats {
|
||||
|
||||
Computer computer;
|
||||
// Location of font routines
|
||||
int FONT_ROUTINES = 0x0EC00;
|
||||
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);
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
addCheat(RAMEvent.TYPE.WRITE, false, (e) -> {
|
||||
if (e.getAddress() == DETECT_ENGINE_WRITE) {
|
||||
detectActiveEngine();
|
||||
}
|
||||
}, DETECT_ENGINE_WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceName() {
|
||||
return "Lawless Legends optimizations";
|
||||
}
|
||||
|
||||
@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() {
|
||||
// for (int i = 0x06000; i < 0x06080;) {
|
||||
// System.out.printf("%04x: ", i);
|
||||
// for (int j = 0; j < 16; j++, i++) {
|
||||
// System.out.printf("%02x ", computer.getMemory().readRaw(i) & 0x0ff);
|
||||
// }
|
||||
// System.out.println();
|
||||
// }
|
||||
int firstPageByte = computer.getMemory().readRaw(ENGINE_ADDR) & 0x0ff;
|
||||
int firstDataByte = computer.getMemory().readRaw(ENGINE_FIRST_OPCODE) & 0x0ff;
|
||||
int secondDataByte = computer.getMemory().readRaw(ENGINE_FIRST_OPCODE + 1) & 0x0ff;
|
||||
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);
|
||||
} 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);
|
||||
} 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);
|
||||
} else {
|
||||
LawlessVideo.setEngine(RenderEngine.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package jace.lawless;
|
||||
|
||||
import jace.apple2e.RAM128k;
|
||||
import jace.apple2e.VideoNTSC;
|
||||
import jace.core.Computer;
|
||||
import jace.core.PagedMemory;
|
||||
import java.util.Arrays;
|
||||
import javafx.scene.image.WritableImage;
|
||||
|
||||
/**
|
||||
* Lawless-enhanced video output for readable text
|
||||
*/
|
||||
public class LawlessVideo extends VideoNTSC {
|
||||
|
||||
private static RenderEngine activeEngine = RenderEngine.UNKNOWN;
|
||||
private boolean invActive = false;
|
||||
private boolean titleScreen = false;
|
||||
|
||||
public static enum RenderEngine {
|
||||
_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, 184,
|
||||
8, 172, 14, 182,}),
|
||||
INVENTORY(new int[]{
|
||||
2, 6, 78, 186
|
||||
}),
|
||||
PORTRAIT, 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(Computer computer) {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
public static void setEngine(RenderEngine e) {
|
||||
activeEngine = e;
|
||||
// System.out.println("Detected engine: " + e.name());
|
||||
}
|
||||
|
||||
static public int[] divBy56 = new int[560];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 560; i++) {
|
||||
divBy56[i] = i / 56;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void vblankStart() {
|
||||
super.vblankStart();
|
||||
// Row 5 = Black
|
||||
int row4 = getSummary(4);
|
||||
int row5 = getSummary(5);
|
||||
int row6 = getSummary(6);
|
||||
int row7 = getSummary(7);
|
||||
// Rows 6,7 = White
|
||||
invActive = row5 == 0
|
||||
&& row6 == 1270
|
||||
&& row7 == 1270;
|
||||
titleScreen = row4 == 828 && row5 == 513 && row6 == 382;
|
||||
}
|
||||
|
||||
public int getSummary(int row) {
|
||||
PagedMemory mainMemory = ((RAM128k) computer.getMemory()).getMainMemory();
|
||||
int rowAddr = getCurrentWriter().getYOffset(row);
|
||||
int total = 0;
|
||||
for (int i = rowAddr + 4; i < rowAddr + 14; i++) {
|
||||
total += mainMemory.readByte(i) & 0x07f;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hblankStart(WritableImage screen, int y, boolean isDirty) {
|
||||
int rowStart = getCurrentWriter().getYOffset(y);
|
||||
if (rowStart >= 0x02000 && !titleScreen) {
|
||||
boolean[] color = activeEngine.colorMask[y];
|
||||
if (invActive) {
|
||||
color = RenderEngine.INVENTORY.colorMask[y];
|
||||
} else if (activeEngine == RenderEngine.PORTRAIT) {
|
||||
color = RenderEngine._2D.colorMask[y];
|
||||
}
|
||||
System.arraycopy(color, 0, colorActive, 0, 80);
|
||||
}
|
||||
super.hblankStart(screen, y, isDirty); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in New Issue
Block a user