Added Beyond Wolfenstein cheats

This commit is contained in:
Brendan Robert 2018-05-26 00:47:57 -05:00
parent d4073b9096
commit 1f2eff2e42
2 changed files with 180 additions and 64 deletions

View File

@ -1326,6 +1326,9 @@ public class MOS65C02 extends CPU {
*/ */
StringBuilder out = new StringBuilder(o.getCommand().toString()); StringBuilder out = new StringBuilder(o.getCommand().toString());
out.append(" ").append(format); out.append(" ").append(format);
if (o.getMode().isIndirect()) {
out.append(" >> $").append(Integer.toHexString(o.getMode().getCalculator().calculateAddress(this)));
}
return out.toString(); return out.toString();
} }
private boolean pageBoundaryPenalty = false; private boolean pageBoundaryPenalty = false;

View File

@ -16,6 +16,7 @@
package jace.cheat; package jace.cheat;
import jace.EmulatorUILogic; import jace.EmulatorUILogic;
import jace.apple2e.MOS65C02;
import jace.config.ConfigurableField; import jace.config.ConfigurableField;
import jace.core.Computer; import jace.core.Computer;
import jace.core.RAMEvent; import jace.core.RAMEvent;
@ -29,78 +30,124 @@ import javafx.scene.input.MouseEvent;
*/ */
public class WolfensteinCheats extends Cheats { public class WolfensteinCheats extends Cheats {
// Specific to Wolfenstein
static final int KEYS = 0x04359;
static final int GRENADES = 0x04348;
// Object types
static final int CHEST = 48;
static final int SS = 32;
// Specific to Beyond Wolfenstein
static final int MARKS = 0x0434b;
static final int PASSES = 0x04360;
static final int CLOSET_CONTENTS_CMP = 0x05FB9; // Only locks by type, so mess up the check
// Object types
static final int CLOSET = 32;
static final int ALARM = 48;
static final int SEATED_GUARD = 80;
static final int BW_DOOR = 96;
// Same in both Wolfenstein and Beyond Wolfenstein
static final int PLAYER_LOCATION = 0x04343;
static final int BULLETS = 0x04347;
// Object types
static final int CORPSE = 64;
static final int GUARD = 16;
static final int DOOR = 80;
static final int NOTHING = 0;
public WolfensteinCheats(Computer computer) { public WolfensteinCheats(Computer computer) {
super(computer); super(computer);
} }
private EventHandler<MouseEvent> mouseListener = this::processMouseEvent; private EventHandler<MouseEvent> mouseListener = this::processMouseEvent;
@ConfigurableField(category = "Hack", name = "Beyond Wolfenstein", defaultValue = "false", description = "Make sure cheats work with Beyond Wolfenstein")
public static boolean _isBeyondWolfenstein = false;
@ConfigurableField(category = "Hack", name = "Mouse", defaultValue = "false", description = "Left click kills/opens, Right click teleports") @ConfigurableField(category = "Hack", name = "Mouse (1+2)", defaultValue = "false", description = "Left click kills/opens, Right click teleports")
public static boolean mouseMode = true; public static boolean mouseMode = true;
@ConfigurableField(category = "Hack", name = "Ammo", defaultValue = "false", description = "All the bullets and grenades you'll need") @ConfigurableField(category = "Hack", name = "Ammo (1+2)", defaultValue = "false", description = "All the bullets and grenades you'll need")
public static boolean ammo = true; public static boolean ammo = true;
@ConfigurableField(category = "Hack", name = "Uniform", defaultValue = "false", description = "PUT SOME CLOTHES ON!") @ConfigurableField(category = "Hack", name = "Rich (2)", defaultValue = "false", description = "All the money")
public static boolean rich = true;
@ConfigurableField(category = "Hack", name = "Uniform (1)", defaultValue = "false", description = "PUT SOME CLOTHES ON!")
public static boolean uniform = true; public static boolean uniform = true;
@ConfigurableField(category = "Hack", name = "Protection", defaultValue = "false", description = "Bulletproof") @ConfigurableField(category = "Hack", name = "Vest (1)", defaultValue = "false", description = "Bulletproof vest")
public static boolean vest = true; public static boolean vest = true;
@ConfigurableField(category = "Hack", name = "Skeleton Key", defaultValue = "false", description = "Open all things") @ConfigurableField(category = "Hack", name = "Skeleton Key (1+2)", defaultValue = "false", description = "Open all things")
public static boolean skeletonKey = true; public static boolean skeletonKey = true;
@ConfigurableField(category = "Hack", name = "Fast Open", defaultValue = "false", description = "Open all things quickly") @ConfigurableField(category = "Hack", name = "Fast Open (1)", defaultValue = "false", description = "Open all things quickly")
public static boolean fastOpen = true; public static boolean fastOpen = true;
@ConfigurableField(category = "Hack", name = "All dead", defaultValue = "false", description = "Everything is dead") @ConfigurableField(category = "Hack", name = "All dead (1+2)", defaultValue = "false", description = "Everything is dead")
public static boolean allDead = false; public static boolean allDead = true;
@ConfigurableField(category = "Hack", name = "Sleepy Time", defaultValue = "false", description = "Nobody move, nobody get hurt") @ConfigurableField(category = "Hack", name = "Sleepy Time (1+2)", defaultValue = "false", description = "Nobody move, nobody get hurt")
public static boolean sleepyTime = false; public static boolean sleepyTime = false;
@ConfigurableField(category = "Hack", name = "Legendary", defaultValue = "false", description = "All of them are SS guards!") @ConfigurableField(category = "Hack", name = "Legendary (1)", defaultValue = "false", description = "All of them are SS guards!")
public static boolean legendary = false; public static boolean legendary = false;
@Override @Override
public void registerListeners() { public void registerListeners() {
if (_isBeyondWolfenstein) {
// Only work in Beyond Wolfenstein
if (rich) {
forceValue(MARKS, 255);
}
} else {
// Only work in the first Wolfenstein game
if (uniform) {
forceValue(255, 0x04349);
}
if (vest) {
forceValue(255, 0x0434A);
}
if (fastOpen) {
addCheat(RAMEvent.TYPE.WRITE, this::fastOpenHandler, 0x04351);
addCheat(RAMEvent.TYPE.WRITE, this::fastOpenHandler, 0x0587B);
}
}
if (ammo) { if (ammo) {
forceValue(10, 0x04347); forceValue(10, BULLETS);
forceValue(9, 0x04348); if (!_isBeyondWolfenstein) {
} forceValue(9, GRENADES);
if (uniform) { }
forceValue(255, 0x04349);
}
if (vest) {
forceValue(255, 0x0434A);
} }
if (skeletonKey) { if (skeletonKey) {
forceValue(255, 0x04359); if (_isBeyondWolfenstein) {
} forceValue(255, PASSES);
if (fastOpen) { forceValue(64, CLOSET_CONTENTS_CMP); // Fake it out so it thinks all doors are unlocked
addCheat(RAMEvent.TYPE.WRITE, this::fastOpenHandler, 0x04351); } else {
addCheat(RAMEvent.TYPE.WRITE, this::fastOpenHandler, 0x0587B); forceValue(255, KEYS);
}
} }
if (allDead) { if (allDead) {
for (int i = 0x04080; i < 0x04100; i += 0x010) { for (int i = 0x04080; i < 0x04100; i += 0x010) {
addCheat(RAMEvent.TYPE.READ, this::allDead, i); addCheat(RAMEvent.TYPE.READ, this::allDead, i);
} }
} }
if (sleepyTime) { if (sleepyTime) {
for (int i = 0x04080; i < 0x04100; i += 0x010) { for (int i = 0x04080; i < 0x04100; i += 0x010) {
forceValue(0, i+2); forceValue(0, i + 2);
forceValue(0, i+3); forceValue(0, i + 3);
// This makes them shout ACHTUNG over and over again... so don't do that. // This makes them shout ACHTUNG over and over again... so don't do that.
// forceValue(144, i+12); // forceValue(144, i+12);
forceValue(0, i+12); forceValue(0, i + 12);
} }
} }
if (legendary) { if (legendary) {
for (int i = 0x04080; i < 0x04100; i += 0x010) { for (int i = 0x04080; i < 0x04100; i += 0x010) {
addCheat(RAMEvent.TYPE.READ, this::legendaryMode, i); addCheat(RAMEvent.TYPE.READ, this::legendaryMode, i);
} }
} }
if (mouseMode) { if (mouseMode) {
EmulatorUILogic.addMouseListener(mouseListener); EmulatorUILogic.addMouseListener(mouseListener);
} else { } else {
@ -114,20 +161,40 @@ public class WolfensteinCheats extends Cheats {
evt.setNewValue(1); evt.setNewValue(1);
} }
} }
private boolean isFinalRoom() {
for (int i = 0x04080; i < 0x04100; i += 0x010) {
int objectType = computer.getMemory().readRaw(i) & 0x0ff;
if (objectType == BW_DOOR) {
return true;
}
}
return false;
}
private void allDead(RAMEvent evt) { private void allDead(RAMEvent evt) {
int type = evt.getNewValue(); int type = evt.getNewValue();
if (type == 16 || type == 32) { if (_isBeyondWolfenstein) {
evt.setNewValue(64); if (type == GUARD) {
} evt.setNewValue(CORPSE);
} else if (type == SEATED_GUARD && !isFinalRoom()) {
computer.getMemory().write(evt.getAddress() + 4, (byte) 4, false, false);
}
} else {
if (type == GUARD || type == SS) {
evt.setNewValue(CORPSE);
}
}
} }
private int debugTicks = 0;
private void legendaryMode(RAMEvent evt) { private void legendaryMode(RAMEvent evt) {
int type = evt.getNewValue(); int type = evt.getNewValue();
if (type == 16) { if (type == 16) {
evt.setNewValue(32); evt.setNewValue(32);
} }
} }
private void processMouseEvent(MouseEvent evt) { private void processMouseEvent(MouseEvent evt) {
if (evt.isPrimaryButtonDown() || evt.isSecondaryButtonDown()) { if (evt.isPrimaryButtonDown() || evt.isSecondaryButtonDown()) {
@ -152,30 +219,70 @@ public class WolfensteinCheats extends Cheats {
System.out.print("Location " + enemyLocation); System.out.print("Location " + enemyLocation);
String type = ""; String type = "";
boolean isAlive = false; boolean isAlive = false;
switch (computer.getMemory().readRaw(i) & 0x0ff) { boolean isSeatedGuard = false;
case 16: if (_isBeyondWolfenstein) {
type = "soldier"; switch (computer.getMemory().readRaw(i) & 0x0ff) {
isAlive = true; case GUARD:
break; type = "guard";
case 32: isAlive = true;
type = "SS"; break;
isAlive = true; case SEATED_GUARD:
break; type = "seated guard";
case 48: isAlive = true;
type = "chest"; isSeatedGuard = true;
break; break;
case 64: case CLOSET:
type = "corpse"; type = "closet";
break; break;
case 80: case CORPSE:
type = "door"; type = "corpse";
break; break;
default: case NOTHING:
type = "unknown type " + (computer.getMemory().readRaw(i) & 0x0ff); type = "nothing";
break;
default:
type = "unknown type " + (computer.getMemory().readRaw(i) & 0x0ff);
}
} else {
switch (computer.getMemory().readRaw(i) & 0x0ff) {
case GUARD:
type = "guard";
isAlive = true;
break;
case SS:
type = "SS";
isAlive = true;
break;
case CHEST:
type = "chest";
break;
case CORPSE:
type = "corpse";
break;
case DOOR:
type = "door";
break;
case NOTHING:
type = "nothing";
break;
default:
type = "unknown type " + (computer.getMemory().readRaw(i) & 0x0ff);
}
} }
System.out.println(" is a " + type); System.out.println(" is a " + type);
for (int j = 0x00; j < 0x0f; j++) {
int val = computer.getMemory().readRaw(i + j) & 0x0ff;
System.out.print(Integer.toHexString(val) + " ");
}
System.out.println();
if (isAlive && location == enemyLocation) { if (isAlive && location == enemyLocation) {
computer.getMemory().write(i, (byte) 64, false, true); if (isSeatedGuard) {
computer.getMemory().write(i + 4, (byte) 4, false, false);
} else {
computer.getMemory().write(i, (byte) CORPSE, false, true);
}
System.out.println("*BLAM*"); System.out.println("*BLAM*");
} }
} }
@ -200,6 +307,12 @@ public class WolfensteinCheats extends Cheats {
@Override @Override
public void tick() { public void tick() {
if (debugTicks > 0) {
debugTicks--;
if (debugTicks == 0) {
computer.getCpu().setTraceEnabled(false);
}
}
} }
/** /**