mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-06-07 10:29:31 +00:00
Compare commits
7 Commits
ff839e3af9
...
3a980611d7
Author | SHA1 | Date | |
---|---|---|---|
|
3a980611d7 | ||
|
b9ae1990e8 | ||
|
f9114248d1 | ||
|
d4d3c59b8c | ||
|
c540527370 | ||
|
3f359cf3ff | ||
|
b258ed441a |
|
@ -63,7 +63,7 @@ public class Apple2e extends Computer {
|
||||||
static int IRQ_VECTOR = 0x003F2;
|
static int IRQ_VECTOR = 0x003F2;
|
||||||
|
|
||||||
@ConfigurableField(name = "Production mode", shortName = "production")
|
@ConfigurableField(name = "Production mode", shortName = "production")
|
||||||
public boolean PRODUCTION_MODE = true;
|
public boolean PRODUCTION_MODE = false;
|
||||||
@ConfigurableField(name = "Slot 1", shortName = "s1card")
|
@ConfigurableField(name = "Slot 1", shortName = "s1card")
|
||||||
public DeviceSelection<Cards> card1 = new DeviceSelection<>(Cards.class, null);
|
public DeviceSelection<Cards> card1 = new DeviceSelection<>(Cards.class, null);
|
||||||
@ConfigurableField(name = "Slot 2", shortName = "s2card")
|
@ConfigurableField(name = "Slot 2", shortName = "s2card")
|
||||||
|
|
|
@ -1246,13 +1246,11 @@ public class MOS65C02 extends CPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getState() {
|
public String getState() {
|
||||||
return String.format("%s %s %s 01%s %s",
|
return byte2(A) +
|
||||||
byte2(A),
|
" " + byte2(X) +
|
||||||
byte2(X),
|
" " + byte2(Y) +
|
||||||
byte2(Y),
|
" 01" + byte2(STACK) +
|
||||||
byte2(STACK),
|
getFlags();
|
||||||
getFlags()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFlags() {
|
public String getFlags() {
|
||||||
|
|
|
@ -223,7 +223,7 @@ abstract public class RAM128k extends RAM {
|
||||||
if (SoftSwitches.INTC8ROM.isOn()) {
|
if (SoftSwitches.INTC8ROM.isOn()) {
|
||||||
rstate += "C8";
|
rstate += "C8";
|
||||||
} else {
|
} else {
|
||||||
rstate += String.format("C8%d", getActiveSlot());
|
rstate += "C8"+getActiveSlot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,8 @@ public abstract class Cheats extends Device {
|
||||||
Metacheat("Metacheat", MetaCheat.class, MetaCheat::new),
|
Metacheat("Metacheat", MetaCheat.class, MetaCheat::new),
|
||||||
MontezumasRevenge("Montezuma's Revenge", MontezumasRevengeCheats.class, MontezumasRevengeCheats::new),
|
MontezumasRevenge("Montezuma's Revenge", MontezumasRevengeCheats.class, MontezumasRevengeCheats::new),
|
||||||
PrinceOfPersia("Prince of Persia", PrinceOfPersiaCheats.class, PrinceOfPersiaCheats::new),
|
PrinceOfPersia("Prince of Persia", PrinceOfPersiaCheats.class, PrinceOfPersiaCheats::new),
|
||||||
LawlessHacks("Lawless Legends Enhancements", LawlessHacks.class, LawlessHacks::new);
|
LawlessHacks("Lawless Legends Enhancements", LawlessHacks.class, LawlessHacks::new),
|
||||||
|
ProgramIdentity("Identify program", ProgramIdentity.class, ProgramIdentity::new);
|
||||||
|
|
||||||
Supplier<Cheats> factory;
|
Supplier<Cheats> factory;
|
||||||
String name;
|
String name;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package jace.cheat;
|
package jace.cheat;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
@ -77,6 +78,15 @@ public class MemoryCell implements Comparable<MemoryCell> {
|
||||||
return address - o.address;
|
return address - o.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof MemoryCell) {
|
||||||
|
MemoryCell om = (MemoryCell) o;
|
||||||
|
return address == om.address || (x == om.x && y == om.y);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasCounts() {
|
public boolean hasCounts() {
|
||||||
return hasCount.get();
|
return hasCount.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class MetaCheat extends Cheats {
|
||||||
public int historyLength = 10;
|
public int historyLength = 10;
|
||||||
|
|
||||||
private int startAddress = 0;
|
private int startAddress = 0;
|
||||||
private int endAddress = 0x0ffff;
|
private int endAddress = 0x0BFFF;
|
||||||
private final StringProperty startAddressProperty = new SimpleStringProperty(Integer.toHexString(startAddress));
|
private final StringProperty startAddressProperty = new SimpleStringProperty(Integer.toHexString(startAddress));
|
||||||
private final StringProperty endAddressProperty = new SimpleStringProperty(Integer.toHexString(endAddress));
|
private final StringProperty endAddressProperty = new SimpleStringProperty(Integer.toHexString(endAddress));
|
||||||
private boolean byteSized = true;
|
private boolean byteSized = true;
|
||||||
|
@ -248,26 +248,33 @@ public class MetaCheat extends Cheats {
|
||||||
int last = result.lastObservedValue;
|
int last = result.lastObservedValue;
|
||||||
result.lastObservedValue = val;
|
result.lastObservedValue = val;
|
||||||
switch (searchType) {
|
switch (searchType) {
|
||||||
case VALUE:
|
case VALUE -> {
|
||||||
int compare = parseInt(searchValueProperty.get());
|
int compare = parseInt(searchValueProperty.get());
|
||||||
return compare != val;
|
return compare != val;
|
||||||
case CHANGE:
|
}
|
||||||
|
case CHANGE -> {
|
||||||
switch (searchChangeType) {
|
switch (searchChangeType) {
|
||||||
case AMOUNT:
|
case AMOUNT -> {
|
||||||
int amount = parseInt(searchChangeByProperty().getValue());
|
int amount = parseInt(searchChangeByProperty().getValue());
|
||||||
return (val - last) != amount;
|
return (val - last) != amount;
|
||||||
case GREATER:
|
}
|
||||||
|
case GREATER -> {
|
||||||
return val <= last;
|
return val <= last;
|
||||||
case ANY_CHANGE:
|
}
|
||||||
|
case ANY_CHANGE -> {
|
||||||
return val == last;
|
return val == last;
|
||||||
case LESS:
|
}
|
||||||
|
case LESS -> {
|
||||||
return val >= last;
|
return val >= last;
|
||||||
case NO_CHANGE:
|
}
|
||||||
|
case NO_CHANGE -> {
|
||||||
return val != last;
|
return val != last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case TEXT:
|
|
||||||
break;
|
case TEXT -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -309,15 +316,9 @@ public class MetaCheat extends Cheats {
|
||||||
memoryCells.values().stream()
|
memoryCells.values().stream()
|
||||||
.filter(MemoryCell::hasCounts)
|
.filter(MemoryCell::hasCounts)
|
||||||
.forEach((cell) -> {
|
.forEach((cell) -> {
|
||||||
if (cell.execCount.get() > 0) {
|
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
||||||
cell.execCount.set(Math.max(0, cell.execCount.get() - fadeRate));
|
cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
|
||||||
}
|
cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
|
||||||
if (cell.readCount.get() > 0) {
|
|
||||||
cell.readCount.set(Math.max(0, cell.readCount.get() - fadeRate));
|
|
||||||
}
|
|
||||||
if (cell.writeCount.get() > 0) {
|
|
||||||
cell.writeCount.set(Math.max(0, cell.writeCount.get() - fadeRate));
|
|
||||||
}
|
|
||||||
if (MemoryCell.listener != null) {
|
if (MemoryCell.listener != null) {
|
||||||
MemoryCell.listener.changed(null, cell, cell);
|
MemoryCell.listener.changed(null, cell, cell);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
package jace.cheat;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
|
import jace.apple2e.RAM128k;
|
||||||
|
import jace.apple2e.SoftSwitches;
|
||||||
|
import jace.core.PagedMemory;
|
||||||
|
import jace.core.RAMEvent;
|
||||||
|
import jace.core.RAMEvent.TYPE;
|
||||||
|
|
||||||
|
public class ProgramIdentity extends Cheats {
|
||||||
|
private Map<String, String> programIdentities;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerListeners() {
|
||||||
|
addCheat("Track execution", TYPE.ANY, this::trackActivity, 0, 0x0ffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDeviceName() {
|
||||||
|
return "Program Identity";
|
||||||
|
}
|
||||||
|
|
||||||
|
int INTERVAL = 1000000;
|
||||||
|
int THRESHOLD_VALUE = 10000;
|
||||||
|
int CLIP_VALUE = THRESHOLD_VALUE * 2;
|
||||||
|
int DECAY = THRESHOLD_VALUE / 2;
|
||||||
|
|
||||||
|
int[] programRegions = new int[512];
|
||||||
|
private void trackActivity(RAMEvent e) {
|
||||||
|
int bank = e.getAddress() >> 8;
|
||||||
|
if (bank >= 0xc0 && bank < 0xd0) {
|
||||||
|
// Skip I/O region
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Detect language card ram execution
|
||||||
|
if (bank >= 0xd0 && SoftSwitches.LCRAM.isOff()) {
|
||||||
|
// Skip rom execution
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!e.isMainMemory()) {
|
||||||
|
bank += 256;
|
||||||
|
}
|
||||||
|
if (e.getType() == RAMEvent.TYPE.EXECUTE) {
|
||||||
|
programRegions[bank] = Math.min(CLIP_VALUE, programRegions[bank] + 1);
|
||||||
|
} else if (e.getType() == RAMEvent.TYPE.WRITE) {
|
||||||
|
programRegions[bank] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateChecksum() {
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
RAM128k ram = (RAM128k) getMemory();
|
||||||
|
int bankCount = 0;
|
||||||
|
for (int i=0; i < 512; i++) {
|
||||||
|
if (programRegions[i] > THRESHOLD_VALUE) {
|
||||||
|
PagedMemory mem = ram.getMainMemory();
|
||||||
|
if (i >= 0x0d0 && i < 0x0100) {
|
||||||
|
mem = ram.getLanguageCard();
|
||||||
|
} else if (i >= 0x0100 && i < 0x01d0) {
|
||||||
|
mem = ram.getAuxMemory();
|
||||||
|
} else if (i >= 0x01d0) {
|
||||||
|
mem = ram.getAuxLanguageCard();
|
||||||
|
}
|
||||||
|
bankCount++;
|
||||||
|
crc.update(mem.getMemoryPage((i & 0x0ff) << 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Long.toHexString(crc.getValue())+"-"+bankCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
super.resume();
|
||||||
|
Arrays.fill(programRegions, 0);
|
||||||
|
readProgramIdentities();
|
||||||
|
}
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
String lastChecksum = "";
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (counter++ >= INTERVAL) {
|
||||||
|
String checksum = generateChecksum();
|
||||||
|
if (!checksum.equals(lastChecksum)) {
|
||||||
|
String identity = programIdentities.getOrDefault(checksum, "UNKNOWN");
|
||||||
|
System.out.println(checksum + "," + identity);
|
||||||
|
lastChecksum = checksum;
|
||||||
|
}
|
||||||
|
counter = 0;
|
||||||
|
for (int i=0; i < 512; i++) {
|
||||||
|
programRegions[i] = Math.max(0, programRegions[i] - DECAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readProgramIdentities() {
|
||||||
|
// Read from resources file
|
||||||
|
InputStream in = Cheats.class.getResourceAsStream("/jace/cheats/program-identities.txt");
|
||||||
|
try {
|
||||||
|
programIdentities = new HashMap<>();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
String[] parts = line.split(",");
|
||||||
|
programIdentities.put(parts[0], parts[1]);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -100,10 +100,20 @@ public abstract class IndependentTimedDevice extends TimedDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int SLEEP_PRECISION_LIMIT = 100;
|
||||||
public void sleepUntil(Long time) {
|
public void sleepUntil(Long time) {
|
||||||
if (time != null) {
|
if (time != null) {
|
||||||
while (System.nanoTime() < time) {
|
while (System.nanoTime() < time) {
|
||||||
Thread.onSpinWait();
|
int waitTime = (int) ((time - System.nanoTime()) / 1000000);
|
||||||
|
if (waitTime >= SLEEP_PRECISION_LIMIT) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(waitTime);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Thread.onSpinWait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package jace.ui;
|
package jace.ui;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListSet;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
|
@ -384,8 +383,7 @@ public class MetacheatUI {
|
||||||
public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP);
|
public static final int MEMORY_BOX_TOTAL_SIZE = (MEMORY_BOX_SIZE + MEMORY_BOX_GAP);
|
||||||
public int memoryViewColumns;
|
public int memoryViewColumns;
|
||||||
public int memoryViewRows;
|
public int memoryViewRows;
|
||||||
|
public static Map<Integer, MemoryCell> redrawNodes = new ConcurrentSkipListMap<>();
|
||||||
public static Set<MemoryCell> redrawNodes = new ConcurrentSkipListSet<>();
|
|
||||||
ScheduledExecutorService animationTimer = null;
|
ScheduledExecutorService animationTimer = null;
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
ScheduledFuture animationFuture = null;
|
ScheduledFuture animationFuture = null;
|
||||||
|
@ -432,13 +430,11 @@ public class MetacheatUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processMemoryViewUpdates() {
|
private void processMemoryViewUpdates() {
|
||||||
boolean isRunning = Emulator.withComputer(c->c.getRunningProperty().get(), false);
|
boolean isRunning = Emulator.withComputer(c->c.getMotherboard().isRunning(), false);
|
||||||
if (!isRunning) return;
|
if (!isRunning) return;
|
||||||
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
GraphicsContext context = memoryViewCanvas.getGraphicsContext2D();
|
||||||
Set<MemoryCell> draw = new HashSet<>(redrawNodes);
|
|
||||||
redrawNodes.clear();
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
draw.stream().forEach((jace.cheat.MemoryCell cell) -> {
|
redrawNodes.values().stream().forEach((jace.cheat.MemoryCell cell) -> {
|
||||||
if (showValuesCheckbox.isSelected()) {
|
if (showValuesCheckbox.isSelected()) {
|
||||||
int val = cell.value.get() & 0x0ff;
|
int val = cell.value.get() & 0x0ff;
|
||||||
context.setFill(Color.rgb(val, val, val));
|
context.setFill(Color.rgb(val, val, val));
|
||||||
|
@ -450,10 +446,11 @@ public class MetacheatUI {
|
||||||
}
|
}
|
||||||
context.fillRect(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight());
|
context.fillRect(cell.getX(), cell.getY(), cell.getWidth(), cell.getHeight());
|
||||||
});
|
});
|
||||||
|
redrawNodes.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int FRAME_RATE = 1000 / 60;
|
public static int FRAME_RATE = 1000 / 30;
|
||||||
|
|
||||||
public void redrawMemoryView() {
|
public void redrawMemoryView() {
|
||||||
if (cheatEngine == null) {
|
if (cheatEngine == null) {
|
||||||
|
@ -468,8 +465,6 @@ public class MetacheatUI {
|
||||||
animationFuture.cancel(false);
|
animationFuture.cancel(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
animationFuture = animationTimer.scheduleAtFixedRate(this::processMemoryViewUpdates, FRAME_RATE, FRAME_RATE, TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
cheatEngine.initMemoryView();
|
cheatEngine.initMemoryView();
|
||||||
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
|
int pixelsPerBlock = 16 * MEMORY_BOX_TOTAL_SIZE;
|
||||||
memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock) * 16;
|
memoryViewColumns = (int) (memoryViewPane.getWidth() / pixelsPerBlock) * 16;
|
||||||
|
@ -490,13 +485,14 @@ public class MetacheatUI {
|
||||||
(int) (row * MEMORY_BOX_TOTAL_SIZE * drawScale),
|
(int) (row * MEMORY_BOX_TOTAL_SIZE * drawScale),
|
||||||
(int) (MEMORY_BOX_SIZE * drawScale),
|
(int) (MEMORY_BOX_SIZE * drawScale),
|
||||||
(int) (MEMORY_BOX_SIZE * drawScale));
|
(int) (MEMORY_BOX_SIZE * drawScale));
|
||||||
redrawNodes.add(cell);
|
redrawNodes.put(cell.address, cell);
|
||||||
}
|
}
|
||||||
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
|
MemoryCell.setListener((javafx.beans.value.ObservableValue<? extends jace.cheat.MemoryCell> prop, jace.cheat.MemoryCell oldCell, jace.cheat.MemoryCell newCell) -> {
|
||||||
redrawNodes.add(newCell);
|
redrawNodes.put(newCell.address, newCell);
|
||||||
});
|
});
|
||||||
|
|
||||||
setZoom(1/drawScale);
|
setZoom(1/drawScale);
|
||||||
|
animationFuture = animationTimer.scheduleAtFixedRate(this::processMemoryViewUpdates, FRAME_RATE, FRAME_RATE, TimeUnit.MILLISECONDS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
0-0,Firmware/Basic/Monitor
|
||||||
|
a3156625-1,Total Replay
|
||||||
|
158df73d-4,Miner 2049er
|
||||||
|
111cb7b9-5,Miner 2049er
|
||||||
|
d006d71b-6,A City Dies
|
||||||
|
d0d083aa-2,Alcazar (Title)
|
||||||
|
c05809d8-2,Alcazar (Menu)
|
||||||
|
6accc221-4,Alcazar (Game)
|
||||||
|
7381db02-4,Alien Downpour
|
||||||
|
580b57a0-5,Alien Downpour
|
||||||
|
f019024b-6,Alien Downpour (die)
|
||||||
|
2f1031b5-2,Alien Downpour (fail)
|
||||||
|
54d3700-3,Arctic Fox (Title)
|
||||||
|
b7fd2db6-13,Arctic Fox (Game)
|
||||||
|
d31a0d0a-14,Arctic Fox (Game)
|
||||||
|
82acd9ae-15,Arctic Fox (Game)
|
||||||
|
952fea92-16,Arctic Fox (Game)
|
||||||
|
bd7cf4f7-17,Arctic Fox (Game)
|
||||||
|
207242ca-2,Agent USA (Title)
|
||||||
|
9f9e6890-4,Agent USA (Menu)
|
||||||
|
536dad3-4,Agent USA (Menu)
|
||||||
|
90a1fd4f-2,Airheart (Title)
|
||||||
|
9a3b93f7-3,Airheart (Game)
|
||||||
|
6930a244-2,Apple Invader
|
||||||
|
aace1907-3,Apple Invader
|
||||||
|
c5c52757-2,Apple Invader (Title)
|
||||||
|
288ec83d-1,Apple Invader (Title)
|
||||||
|
bc3b2166-1,Arkanoid (Intro)
|
||||||
|
53a99672-7,Arkanoid (Demo)
|
||||||
|
87d4eab2-3,Arkanoid (Start)
|
||||||
|
cd93f077-3,Arkanoid (Game)
|
||||||
|
a6c1d770-3,Arkanoid (Game)
|
||||||
|
7b85b563-5,Arkanoid (Game)
|
||||||
|
53a99672-7,Arkanoid (Game)
|
||||||
|
6af90e52-1,Arkanoid (Game Over)
|
||||||
|
cde319e5-2,Montezuma's Revenge (Load)
|
||||||
|
eb28db32-3,Montezuma's Revenge (Title)
|
||||||
|
f447d42a-3,Montezuma's Revenge (Level Start 1 - Joystick)
|
||||||
|
312b8850-4,Montezuma's Revenge (Level Start 2 - Joystick)
|
||||||
|
73031104-5,Montezuma's Revenge (Level Start 3 - Joystick)
|
||||||
|
4b2cb3da-5,Montezuma's Revenge (Game 1 - Joystick)
|
||||||
|
72e913f2-3,Montezuma's Revenge (Game 2 - Joystick)
|
||||||
|
25e9bde4-4,Montezuma's Revenge (Game 3 - Joystick)
|
||||||
|
2e2db603-5,Montezuma's Revenge (Game 4 - Joystick)
|
||||||
|
160214dd-5,Montezuma's Revenge (Game 5 - Joystick)
|
||||||
|
43135e8-5,Montezuma's Revenge (Die)
|
||||||
|
b84a512-6,Montezuma's Revenge (Jump - Joystick)
|
||||||
|
d56c6cda-3,Montezuma's Revenge (Level Start 1 - Keyboard)
|
||||||
|
3cd3b2c5-4,Montezuma's Revenge (Level Start 2 - Keyboard)
|
||||||
|
23745a95-5,Montezuma's Revenge (Level Start 3 - Keyboard)
|
||||||
|
1b5bf84b-5,Montezuma's Revenge (Game - Keyboard)
|
||||||
|
b14ac573-6,Montezuma's Revenge (Jump - Keyboard)
|
||||||
|
f476b2d-2,Moon Patrol (Title)
|
||||||
|
4f94aa9-3,Moon Patrol (Menu)
|
||||||
|
396f7baf-3,Moon Patrol (Start 1)
|
||||||
|
6dfabc61-3,Moon Patrol (Start 2)
|
||||||
|
fb88733a-2,Moon Patrol (Start 3)
|
||||||
|
4e99aefb-5,Moon Patrol (Game 1)
|
||||||
|
dfd5fd5b-5,Moon Patrol (Game 2)
|
||||||
|
17e0326e-6,Moon Patrol (Game 3)
|
||||||
|
80243d6f-2,Moon Patrol (Game 5)
|
||||||
|
57a21d5d-6,Moon Patrol (Game - Shoot)
|
||||||
|
96130f7-6,Moon Patrol (Passed Pit or Checkpoint)
|
||||||
|
457104a-3,Moon Patrol (Die)
|
||||||
|
6a8bd750-2,Moon Patrol (Game Over)
|
||||||
|
1afccd0a-3,Moon Patrol (Bonus Screen)
|
|
@ -33,8 +33,9 @@ DEBUG = 0
|
||||||
decomp !zone {
|
decomp !zone {
|
||||||
jsr .chkdst
|
jsr .chkdst
|
||||||
ldy #0 ; In lit loop Y must be zero
|
ldy #0 ; In lit loop Y must be zero
|
||||||
|
sec
|
||||||
.fill1A jsr .getbt2
|
.fill1A jsr .getbt2
|
||||||
jmp .fill1B
|
bne .fill1B ; always taken
|
||||||
|
|
||||||
.incdst inc pDst+1
|
.incdst inc pDst+1
|
||||||
.chkdst ldx pDst+1
|
.chkdst ldx pDst+1
|
||||||
|
@ -174,19 +175,19 @@ decomp !zone {
|
||||||
bne .gshift ; always taken
|
bne .gshift ; always taken
|
||||||
|
|
||||||
; Get another 8 bits into our bit buffer. Destroys X. Preserves A. Requires Y=0.
|
; Get another 8 bits into our bit buffer. Destroys X. Preserves A. Requires Y=0.
|
||||||
|
; Carry is always set on entry, Z always clear on exit
|
||||||
; Alternately, use .getbt2 to preserve X and destroy A
|
; Alternately, use .getbt2 to preserve X and destroy A
|
||||||
.getbts tax
|
.getbts tax
|
||||||
.getbt2 lda (pSrc),y
|
.getbt2 lda (pSrc),y
|
||||||
inc pSrc
|
|
||||||
beq .src3A
|
|
||||||
.src3B sec
|
|
||||||
rol
|
rol
|
||||||
sta bits
|
sta bits
|
||||||
txa
|
txa
|
||||||
|
inc pSrc
|
||||||
|
beq .src3A
|
||||||
rts
|
rts
|
||||||
|
|
||||||
.src3A inc pSrc+1
|
.src3A inc pSrc+1
|
||||||
bne .src3B ; always taken
|
rts
|
||||||
|
|
||||||
} ; end of zone
|
} ; end of zone
|
||||||
|
|
||||||
|
|
|
@ -364,7 +364,7 @@ export asm memcpy(pSrc, pDst, len, auxWr)#0
|
||||||
inc pTmp+1
|
inc pTmp+1
|
||||||
bne .pglup ; always taken
|
bne .pglup ; always taken
|
||||||
.part:
|
.part:
|
||||||
cpx #0
|
txa
|
||||||
beq .done
|
beq .done
|
||||||
- lda (tmp),y
|
- lda (tmp),y
|
||||||
sta (pTmp),y
|
sta (pTmp),y
|
||||||
|
@ -390,8 +390,8 @@ export asm memset(pDst, val, len)#0
|
||||||
lda evalStkL,x ; len lo
|
lda evalStkL,x ; len lo
|
||||||
pha
|
pha
|
||||||
lda evalStkH,x ; len hi
|
lda evalStkH,x ; len hi
|
||||||
tax
|
|
||||||
beq +
|
beq +
|
||||||
|
tax
|
||||||
lda tmp
|
lda tmp
|
||||||
- sta (pTmp),y
|
- sta (pTmp),y
|
||||||
iny
|
iny
|
||||||
|
@ -420,10 +420,10 @@ export asm readAuxByte(ptr)#1
|
||||||
sta $10-1,y
|
sta $10-1,y
|
||||||
dey
|
dey
|
||||||
bne -
|
bne -
|
||||||
jmp $10
|
|
||||||
.rdauxb
|
|
||||||
sei ; prevent interrupts while in aux mem
|
sei ; prevent interrupts while in aux mem
|
||||||
sta setAuxRd
|
sta setAuxRd
|
||||||
|
jmp $10
|
||||||
|
.rdauxb
|
||||||
lda (pTmp),y
|
lda (pTmp),y
|
||||||
sta clrAuxRd
|
sta clrAuxRd
|
||||||
cli
|
cli
|
||||||
|
@ -462,19 +462,19 @@ end
|
||||||
export asm finishString(isPlural)#1
|
export asm finishString(isPlural)#1
|
||||||
!zone {
|
!zone {
|
||||||
+asmPlasmRet 1
|
+asmPlasmRet 1
|
||||||
|
ldy prevCSWL+ABS_OFFSET ; put the cout vector back to default
|
||||||
|
sty cswl
|
||||||
|
ldy prevCSWL+1+ABS_OFFSET ; put the cout vector back to default
|
||||||
|
sty cswh
|
||||||
|
ldy #0 ; dest offset in Y (will be incremented before store)
|
||||||
|
cpy inbuf
|
||||||
|
beq .done1 ; failsafe: handle zero-length string
|
||||||
tax ; test for isPlural == 0
|
tax ; test for isPlural == 0
|
||||||
beq +
|
beq +
|
||||||
lda #$40 ; for setting V later
|
lda #$40 ; for setting V later
|
||||||
+ sta tmp ; save isPlural flag
|
+ sta tmp ; save isPlural flag
|
||||||
lda prevCSWL+ABS_OFFSET ; put the cout vector back to default
|
|
||||||
sta cswl
|
|
||||||
lda prevCSWL+1+ABS_OFFSET ; put the cout vector back to default
|
|
||||||
sta cswh
|
|
||||||
clv ; V flag for prev-is-alpha
|
clv ; V flag for prev-is-alpha
|
||||||
ldy #0 ; dest offset in Y (will be incremented before store)
|
|
||||||
ldx #0 ; source offset in X (will be incremented before load)
|
ldx #0 ; source offset in X (will be incremented before load)
|
||||||
cpx inbuf
|
|
||||||
beq .done ; failsafe: handle zero-length string
|
|
||||||
.fetch
|
.fetch
|
||||||
inx
|
inx
|
||||||
lda inbuf,x ; get next input char
|
lda inbuf,x ; get next input char
|
||||||
|
@ -488,11 +488,11 @@ export asm finishString(isPlural)#1
|
||||||
|
|
||||||
dey ; undo copy of the paren
|
dey ; undo copy of the paren
|
||||||
stx tmp+1 ; save position in input
|
stx tmp+1 ; save position in input
|
||||||
dex ; needed for failsafe operation
|
|
||||||
bit tmp ; set copy flag (V) initially to same as isPlural flag
|
bit tmp ; set copy flag (V) initially to same as isPlural flag
|
||||||
.findsl ; see if there's a slash within the parens
|
.findsl ; see if there's a slash within the parens
|
||||||
inx
|
inx
|
||||||
cpx inbuf
|
cpx inbuf
|
||||||
|
bcs .done ; failsafe: handle missing end-paren
|
||||||
lda inbuf,x
|
lda inbuf,x
|
||||||
ora #$80 ; normalize hi-bit for comparisons below
|
ora #$80 ; normalize hi-bit for comparisons below
|
||||||
cmp #"/"
|
cmp #"/"
|
||||||
|
@ -503,11 +503,8 @@ export asm finishString(isPlural)#1
|
||||||
pha
|
pha
|
||||||
plp
|
plp
|
||||||
+ cmp #")" ; scan until ending paren
|
+ cmp #")" ; scan until ending paren
|
||||||
beq +
|
bne .findsl ; loop to scan next char
|
||||||
cpx inbuf
|
ldx tmp+1 ; get back to start of parens
|
||||||
bcc .findsl ; loop to scan next char
|
|
||||||
bcs .done ; failsafe: handle missing end-paren (always taken)
|
|
||||||
+ ldx tmp+1 ; get back to start of parens
|
|
||||||
; copy mode flag is now in V: if slash present, single=copy, plural=nocopy
|
; copy mode flag is now in V: if slash present, single=copy, plural=nocopy
|
||||||
; if no slash: single=nocopy, plural=copy
|
; if no slash: single=nocopy, plural=copy
|
||||||
.plup
|
.plup
|
||||||
|
@ -541,6 +538,7 @@ export asm finishString(isPlural)#1
|
||||||
|
|
||||||
.done
|
.done
|
||||||
sty inbuf ; save new length
|
sty inbuf ; save new length
|
||||||
|
.done1
|
||||||
lda #<inbuf ; return pointer to string
|
lda #<inbuf ; return pointer to string
|
||||||
ldy #>inbuf
|
ldy #>inbuf
|
||||||
rts
|
rts
|
||||||
|
@ -575,8 +573,8 @@ export asm blit(isAux, srcData, dstScreenPtr, nLines, lineSize)#0
|
||||||
lsr ; to carry bit
|
lsr ; to carry bit
|
||||||
bcc +
|
bcc +
|
||||||
ldy #15 ; put aux copy routine in zero page
|
ldy #15 ; put aux copy routine in zero page
|
||||||
- lda .cpaux + ABS_OFFSET,y
|
- ldx .cpaux + ABS_OFFSET,y
|
||||||
sta $10,y
|
stx $10,y
|
||||||
dey
|
dey
|
||||||
bpl -
|
bpl -
|
||||||
+ pla ; get line count
|
+ pla ; get line count
|
||||||
|
@ -694,8 +692,9 @@ export asm puts(str)#0
|
||||||
sta pTmp
|
sta pTmp
|
||||||
lda #'!'
|
lda #'!'
|
||||||
ldx #1
|
ldx #1
|
||||||
sty pTmp+1
|
tya
|
||||||
beq + ; safety: print '!' instead of null string
|
beq + ; safety: print '!' instead of null string
|
||||||
|
sty pTmp+1
|
||||||
ldy #0
|
ldy #0
|
||||||
lda (pTmp),y
|
lda (pTmp),y
|
||||||
tax
|
tax
|
||||||
|
@ -913,9 +912,8 @@ export asm rawDisplayStr(pStr)#0
|
||||||
lda (pTmp),y
|
lda (pTmp),y
|
||||||
sta tmp
|
sta tmp
|
||||||
- cpy tmp
|
- cpy tmp
|
||||||
bcc +
|
bcs ++
|
||||||
rts
|
iny
|
||||||
+ iny
|
|
||||||
lda (pTmp),y
|
lda (pTmp),y
|
||||||
ora #$80
|
ora #$80
|
||||||
cmp #"^"
|
cmp #"^"
|
||||||
|
@ -929,7 +927,8 @@ export asm rawDisplayStr(pStr)#0
|
||||||
+ sty tmp+1
|
+ sty tmp+1
|
||||||
jsr DisplayChar
|
jsr DisplayChar
|
||||||
ldy tmp+1
|
ldy tmp+1
|
||||||
bne -
|
bne - ; always taken
|
||||||
|
++rts
|
||||||
end
|
end
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -991,8 +990,8 @@ export asm streqi(a, b)#1
|
||||||
lda evalStkL+1,x
|
lda evalStkL+1,x
|
||||||
sta pTmp
|
sta pTmp
|
||||||
lda evalStkH+1,x
|
lda evalStkH+1,x
|
||||||
sta pTmp+1
|
|
||||||
beq .null
|
beq .null
|
||||||
|
sta pTmp+1
|
||||||
ldy #0
|
ldy #0
|
||||||
lda (tmp),y
|
lda (tmp),y
|
||||||
cmp (pTmp),y
|
cmp (pTmp),y
|
||||||
|
@ -1004,21 +1003,16 @@ export asm streqi(a, b)#1
|
||||||
+ tax ; count up to (verified same) length of the strings
|
+ tax ; count up to (verified same) length of the strings
|
||||||
- iny
|
- iny
|
||||||
lda (tmp),y
|
lda (tmp),y
|
||||||
cmp #('z'&$7F)+1 ; convert to upper case
|
eor (pTmp),y
|
||||||
bcs +
|
beq + ; matched
|
||||||
|
cmp #$20 ; check for case bit
|
||||||
|
bne .noteqi ; abort on alpha inequality
|
||||||
|
ora (tmp),y ; convert to lower case
|
||||||
|
cmp #('z'&$7F)+1
|
||||||
|
bcs .noteqi ; abort on inequality
|
||||||
cmp #'a'&$7F
|
cmp #'a'&$7F
|
||||||
bcc +
|
bcc .noteqi ; abort on inequality
|
||||||
sbc #$20
|
+ dex
|
||||||
+ sta ysav
|
|
||||||
lda (pTmp),y
|
|
||||||
cmp #('z'&$7F)+1 ; convert to upper case
|
|
||||||
bcs +
|
|
||||||
cmp #'a'&$7F
|
|
||||||
bcc +
|
|
||||||
sbc #$20
|
|
||||||
+ cmp ysav
|
|
||||||
bne .noteqi ; abort on inequality
|
|
||||||
dex
|
|
||||||
bne -
|
bne -
|
||||||
lda #1
|
lda #1
|
||||||
ldy #0 ; okay, they're equal. Return 1 (not just any char; so that PLASMA when...is can work)
|
ldy #0 ; okay, they're equal. Return 1 (not just any char; so that PLASMA when...is can work)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user