mirror of
https://github.com/badvision/lawless-legends.git
synced 2024-07-05 01:28:57 +00:00
Merge branch 'master' of github.com:badvision/lawless-legends
This commit is contained in:
commit
234e013047
@ -125,6 +125,16 @@ public class MapEditor extends Editor<Map, MapEditor.DrawMode> implements EventH
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
public void moveMapByY(int amt) {
|
||||
getCurrentMap().shift(0, amt);
|
||||
redraw();
|
||||
}
|
||||
|
||||
public void moveMapByX(int amt) {
|
||||
getCurrentMap().shift(amt, 0);
|
||||
redraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildEditorUI(Pane tileEditorAnchorPane) {
|
||||
anchorPane = tileEditorAnchorPane;
|
||||
|
@ -98,6 +98,9 @@ public class DataUtilities {
|
||||
private static void logScripts(Scripts scripts, PrintWriter logger) {
|
||||
if (scripts != null && scripts.getScript() != null || !scripts.getScript().isEmpty()) {
|
||||
scripts.getScript().forEach((script) -> {
|
||||
if (script.getBlock() == null) {
|
||||
return;
|
||||
}
|
||||
Queue<Block> evaluateStack = new ArrayDeque<>();
|
||||
evaluateStack.add(script.getBlock());
|
||||
int blockCount = 0;
|
||||
|
@ -38,30 +38,30 @@ import org.badvision.outlaweditor.ui.UIAction;
|
||||
* @author brobert
|
||||
*/
|
||||
public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable {
|
||||
|
||||
|
||||
public static final long serialVersionUID = 6486309334559843742L;
|
||||
Map backingMap;
|
||||
boolean backingMapStale;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
|
||||
public TileMap(Map m) {
|
||||
backingMapStale = false;
|
||||
width = 0;
|
||||
height = 0;
|
||||
loadFromMap(m);
|
||||
}
|
||||
|
||||
|
||||
public static final double SATURATION = 0.70;
|
||||
public static final double VALUE = 1.0;
|
||||
public static double HUE = 180;
|
||||
private final java.util.Map<Integer, List<Script>> locationScripts = new HashMap<>();
|
||||
private final java.util.Map<Script, Color> scriptColors = new HashMap<>();
|
||||
|
||||
|
||||
public Optional<Color> getScriptColor(Script s) {
|
||||
return Optional.ofNullable(scriptColors.get(s));
|
||||
}
|
||||
|
||||
|
||||
public List<Script> getLocationScripts(int x, int y) {
|
||||
List<Script> list = locationScripts.get(getMortonNumber(x, y));
|
||||
if (list != null) {
|
||||
@ -70,15 +70,18 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void putLocationScript(int x, int y, Script s) {
|
||||
if (x < 0 || y < 0) {
|
||||
return;
|
||||
}
|
||||
LocationTrigger trigger = new Script.LocationTrigger();
|
||||
trigger.setX(x);
|
||||
trigger.setY(y);
|
||||
s.getLocationTrigger().add(trigger);
|
||||
registerLocationScript(x, y, s);
|
||||
}
|
||||
|
||||
|
||||
public void removeLocationScripts(int x, int y) {
|
||||
int loc = getMortonNumber(x, y);
|
||||
List<Script> scripts = locationScripts.get(loc);
|
||||
@ -92,7 +95,7 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
locationScripts.remove(loc);
|
||||
ApplicationState.getInstance().getController().redrawScripts();
|
||||
}
|
||||
|
||||
|
||||
private void registerLocationScript(int x, int y, Script s) {
|
||||
if (!scriptColors.containsKey(s)) {
|
||||
scriptColors.put(s, Color.hsb(HUE, SATURATION, 0.75 + Math.cos(HUE / Math.PI / 2.0) / 8.0));
|
||||
@ -107,7 +110,7 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
list.add(s);
|
||||
ApplicationState.getInstance().getController().redrawScripts();
|
||||
}
|
||||
|
||||
|
||||
private int getMortonNumber(int x, int y) {
|
||||
int morton = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
@ -117,7 +120,7 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
}
|
||||
return morton;
|
||||
}
|
||||
|
||||
|
||||
public Tile get(int x, int y) {
|
||||
if (size() <= y || get(y) == null) {
|
||||
return null;
|
||||
@ -127,8 +130,11 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
}
|
||||
return get(y).get(x);
|
||||
}
|
||||
|
||||
|
||||
public void put(int x, int y, Tile t) {
|
||||
if (x < 0 || y < 0) {
|
||||
return;
|
||||
}
|
||||
width = Math.max(x + 1, width);
|
||||
height = Math.max(y + 1, height);
|
||||
for (int i = size(); i <= y; i++) {
|
||||
@ -144,11 +150,11 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
row.set(x, t);
|
||||
backingMapStale = true;
|
||||
}
|
||||
|
||||
|
||||
public Map getBackingMap() {
|
||||
return backingMap;
|
||||
}
|
||||
|
||||
|
||||
public void updateBackingMap() {
|
||||
ObjectFactory f = new ObjectFactory();
|
||||
backingMap.getChunk().clear();
|
||||
@ -170,9 +176,10 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
backingMap.getChunk().add(c);
|
||||
backingMapStale = false;
|
||||
}
|
||||
|
||||
|
||||
private void loadFromMap(Map m) {
|
||||
clear();
|
||||
locationScripts.clear();
|
||||
width = 0;
|
||||
height = 0;
|
||||
Set<Tile> unknownTiles = new HashSet<>();
|
||||
@ -220,20 +227,40 @@ public class TileMap extends ArrayList<ArrayList<Tile>> implements Serializable
|
||||
backingMapStale = false;
|
||||
}
|
||||
public static String NULL_TILE_ID = "_";
|
||||
|
||||
|
||||
public static boolean isNullTile(String tileId) {
|
||||
return tileId.equalsIgnoreCase(NULL_TILE_ID);
|
||||
}
|
||||
|
||||
|
||||
public void clearScriptTriggersFromMap(Script script) {
|
||||
script.getLocationTrigger().clear();
|
||||
locationScripts.values().stream().filter((scripts) -> !(scripts == null)).forEach((scripts) -> {
|
||||
scripts.remove(script);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void removeScriptFromMap(Script script) {
|
||||
clearScriptTriggersFromMap(script);
|
||||
backingMap.getScripts().getScript().remove(script);
|
||||
}
|
||||
|
||||
public void shift(int xAmt, int yAmt) {
|
||||
Scripts scripts = backingMap.getScripts();
|
||||
if (scripts != null) {
|
||||
List<Script> allScripts = new ArrayList<>(scripts.getScript());
|
||||
allScripts.forEach(
|
||||
s -> s.getLocationTrigger().forEach(
|
||||
l -> {
|
||||
l.setX(l.getX() + xAmt);
|
||||
l.setY(l.getY() + yAmt);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
backingMap.getChunk().forEach(c -> {
|
||||
c.setX(c.getX() + xAmt);
|
||||
c.setY(c.getY() + yAmt);
|
||||
});
|
||||
loadFromMap(backingMap);
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,9 @@ public abstract class MapEditorTabController {
|
||||
// Handler for Button[Button[id=null, styleClass=button moveButton]] onAction
|
||||
@FXML
|
||||
abstract public void scrollMapUp(ActionEvent event);
|
||||
|
||||
@FXML
|
||||
abstract public void showShiftUI(ActionEvent event);
|
||||
|
||||
public void initalize() {
|
||||
assert mapEditorAnchorPane != null : "fx:id=\"mapEditorAnchorPane\" was not injected: check your FXML file 'mapEditorTab.fxml'.";
|
||||
|
@ -13,8 +13,6 @@ import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.ComboBoxListCell;
|
||||
@ -22,6 +20,7 @@ import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javax.xml.bind.JAXBException;
|
||||
@ -330,7 +329,30 @@ public class MapEditorTabControllerImpl extends MapEditorTabController {
|
||||
}
|
||||
redrawMapScripts();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void showShiftUI(ActionEvent evt) {
|
||||
Dialog dialog = new Dialog();
|
||||
dialog.setTitle("Shift map");
|
||||
dialog.setOnCloseRequest(v->dialog.close());
|
||||
dialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
|
||||
GridPane pane = new GridPane();
|
||||
Button moveUp = new Button("↑");
|
||||
moveUp.setOnMouseClicked(v->getCurrentEditor().moveMapByY(-1));
|
||||
pane.add(moveUp, 1, 0);
|
||||
Button moveDown = new Button("↓");
|
||||
moveDown.setOnMouseClicked(v->getCurrentEditor().moveMapByY(1));
|
||||
pane.add(moveDown, 1, 2);
|
||||
Button moveLeft = new Button("←");
|
||||
moveLeft.setOnMouseClicked(v->getCurrentEditor().moveMapByX(-1));
|
||||
pane.add(moveLeft, 0, 1);
|
||||
Button moveRight = new Button("→");
|
||||
moveRight.setOnMouseClicked(v->getCurrentEditor().moveMapByX(1));
|
||||
pane.add(moveRight, 2, 1);
|
||||
dialog.getDialogPane().setContent(pane);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebuildMapSelectors() {
|
||||
Map m = mapSelect.getSelectionModel().getSelectedItem();
|
||||
|
@ -16,7 +16,7 @@
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0" prefHeight="480.0" prefWidth="677.0" stylesheets="@styles/applicationui.css" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.MapEditorTabControllerImpl">
|
||||
<AnchorPane id="mapsTab" minHeight="0.0" minWidth="0.0" prefHeight="480.0" prefWidth="677.0" stylesheets="@styles/applicationui.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.MapEditorTabControllerImpl">
|
||||
<children>
|
||||
<VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
@ -44,6 +44,7 @@
|
||||
</items>
|
||||
</Menu>
|
||||
<MenuItem mnemonicParsing="false" onAction="#mapTogglePanZoom" text="Toggle pan/zoom controls" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#showShiftUI" text="Shift Map" />
|
||||
</items>
|
||||
</MenuButton>
|
||||
<Label fx:id="cursorInfo" text="CursorInfo" />
|
||||
|
12
Platform/Apple/tools/jace/8bitbunch.xml
Normal file
12
Platform/Apple/tools/jace/8bitbunch.xml
Normal file
File diff suppressed because one or more lines are too long
@ -234,7 +234,11 @@ public class JaceUIController {
|
||||
}
|
||||
});
|
||||
speedSlider.valueProperty().addListener((val, oldValue, newValue) -> setSpeed(newValue.doubleValue()));
|
||||
Platform.runLater(() -> speedSlider.setValue(Emulator.logic.speedSetting));
|
||||
Platform.runLater(() -> {
|
||||
speedSlider.setValue(Emulator.logic.speedSetting);
|
||||
// Kind of redundant but make sure speed is properly set as if the user did it
|
||||
setSpeed(Emulator.logic.speedSetting);
|
||||
});
|
||||
}
|
||||
|
||||
private void connectButtons(Node n) {
|
||||
@ -253,7 +257,7 @@ public class JaceUIController {
|
||||
Emulator.logic.speedSetting = (int) speed;
|
||||
double speedRatio = convertSpeedToRatio(speed);
|
||||
if (speedRatio > 100.0) {
|
||||
Emulator.computer.getMotherboard().maxspeed = true;
|
||||
Emulator.computer.getMotherboard().setMaxSpeed(true);
|
||||
Motherboard.cpuPerClock = 3;
|
||||
} else {
|
||||
if (speedRatio > 25) {
|
||||
@ -261,8 +265,8 @@ public class JaceUIController {
|
||||
} else {
|
||||
Motherboard.cpuPerClock = 1;
|
||||
}
|
||||
Emulator.computer.getMotherboard().maxspeed = false;
|
||||
Emulator.computer.getMotherboard().speedRatio = (int) (speedRatio * 100);
|
||||
Emulator.computer.getMotherboard().setMaxSpeed(false);
|
||||
Emulator.computer.getMotherboard().setSpeedInPercentage((int) (speedRatio * 100));
|
||||
}
|
||||
Emulator.computer.getMotherboard().reconfigure();
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ public class MetaCheat extends Cheats {
|
||||
}
|
||||
|
||||
int fadeCounter = 0;
|
||||
int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().cyclesPerSecond / 60);
|
||||
int FADE_TIMER_VALUE = (int) (Emulator.computer.getMotherboard().getSpeedInHz() / 60);
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
|
@ -65,6 +65,9 @@ public class Motherboard extends TimedDevice {
|
||||
if (oldMotherboard != null) {
|
||||
miscDevices.addAll(oldMotherboard.miscDevices);
|
||||
speaker = oldMotherboard.speaker;
|
||||
accelorationRequestors.addAll(oldMotherboard.accelorationRequestors);
|
||||
setSpeedInHz(oldMotherboard.getSpeedInHz());
|
||||
setMaxSpeed(oldMotherboard.isMaxSpeed());
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +150,7 @@ public class Motherboard extends TimedDevice {
|
||||
resume();
|
||||
}
|
||||
}
|
||||
static HashSet<Object> accelorationRequestors = new HashSet<>();
|
||||
HashSet<Object> accelorationRequestors = new HashSet<>();
|
||||
|
||||
public void requestSpeed(Object requester) {
|
||||
accelorationRequestors.add(requester);
|
||||
|
@ -21,24 +21,25 @@ package jace.core;
|
||||
import jace.config.ConfigurableField;
|
||||
|
||||
/**
|
||||
* A timed device is a device which executes so many ticks in a given time
|
||||
* interval. This is the core of the emulator timing mechanics.
|
||||
* A timed device is a device which executes so many ticks in a given time interval. This is the core of the emulator
|
||||
* timing mechanics.
|
||||
*
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
|
||||
*/
|
||||
public abstract class TimedDevice extends Device {
|
||||
|
||||
/**
|
||||
* Creates a new instance of TimedDevice
|
||||
*
|
||||
* @param computer
|
||||
*/
|
||||
public TimedDevice(Computer computer) {
|
||||
super(computer);
|
||||
setSpeed(cyclesPerSecond);
|
||||
setSpeedInHz(cyclesPerSecond);
|
||||
}
|
||||
@ConfigurableField(name = "Speed", description = "(Percentage)")
|
||||
public int speedRatio = 100;
|
||||
public long cyclesPerSecond = defaultCyclesPerSecond();
|
||||
private long cyclesPerSecond = defaultCyclesPerSecond();
|
||||
@ConfigurableField(name = "Max speed")
|
||||
public boolean maxspeed = false;
|
||||
|
||||
@ -114,13 +115,44 @@ public abstract class TimedDevice extends Device {
|
||||
long cyclesPerInterval; // How many cycles to wait until a pause interval
|
||||
long nextSync; // When was the last pause?
|
||||
|
||||
public final void setSpeed(long cyclesPerSecond) {
|
||||
public final int getSpeedRatio() {
|
||||
return speedRatio;
|
||||
}
|
||||
|
||||
public final void setMaxSpeed(boolean enabled) {
|
||||
maxspeed = enabled;
|
||||
if (!enabled) {
|
||||
disableTempMaxSpeed();
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isMaxSpeed() {
|
||||
return maxspeed;
|
||||
}
|
||||
|
||||
public final long getSpeedInHz() {
|
||||
return cyclesPerInterval * 100L;
|
||||
}
|
||||
|
||||
public final void setSpeedInHz(long cyclesPerSecond) {
|
||||
// System.out.println("Raw set speed for " + getName() + " to " + cyclesPerSecond + "hz");
|
||||
speedRatio = (int) Math.round(cyclesPerSecond * 100.0 / defaultCyclesPerSecond());
|
||||
cyclesPerInterval = cyclesPerSecond / 100L;
|
||||
nanosPerInterval = (long) (cyclesPerInterval * NANOS_PER_SECOND / cyclesPerSecond);
|
||||
// System.out.println("Will pause " + nanosPerInterval + " nanos every " + cyclesPerInterval + " cycles");
|
||||
cycleTimer = 0;
|
||||
resetSyncTimer();
|
||||
}
|
||||
|
||||
public final void setSpeedInPercentage(int ratio) {
|
||||
// System.out.println("Setting " + getName() + " speed ratio to " + speedRatio);
|
||||
cyclesPerSecond = defaultCyclesPerSecond() * ratio / 100;
|
||||
if (cyclesPerSecond == 0) {
|
||||
cyclesPerSecond = defaultCyclesPerSecond();
|
||||
}
|
||||
setSpeedInHz(cyclesPerSecond);
|
||||
}
|
||||
|
||||
long skip = 0;
|
||||
long wait = 0;
|
||||
|
||||
@ -171,11 +203,6 @@ public abstract class TimedDevice extends Device {
|
||||
|
||||
@Override
|
||||
public void reconfigure() {
|
||||
cyclesPerSecond = defaultCyclesPerSecond() * speedRatio / 100;
|
||||
if (cyclesPerSecond == 0) {
|
||||
cyclesPerSecond = defaultCyclesPerSecond();
|
||||
}
|
||||
setSpeed(cyclesPerSecond);
|
||||
}
|
||||
|
||||
public abstract long defaultCyclesPerSecond();
|
||||
|
@ -1,45 +1,48 @@
|
||||
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.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_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);
|
||||
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);
|
||||
}
|
||||
// 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();
|
||||
@ -54,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++) {
|
||||
@ -79,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package jace.lawless;
|
||||
|
||||
import jace.Emulator;
|
||||
import jace.LawlessLegends;
|
||||
import jace.apple2e.RAM128k;
|
||||
import jace.apple2e.VideoNTSC;
|
||||
import jace.core.Computer;
|
||||
@ -15,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,
|
||||
@ -61,9 +65,30 @@ public class LawlessVideo extends VideoNTSC {
|
||||
super(computer);
|
||||
}
|
||||
|
||||
public static void setEngine(RenderEngine e) {
|
||||
public void setEngine(RenderEngine e) {
|
||||
activeEngine = e;
|
||||
// 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];
|
||||
@ -83,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) {
|
||||
@ -103,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) {
|
||||
|
Loading…
Reference in New Issue
Block a user