Compare commits
9 Commits
67f7232046
...
9f0c43af18
Author | SHA1 | Date |
---|---|---|
Peter Ferrie | 9f0c43af18 | |
Brendan Robert | b3ec0df929 | |
Brendan Robert | 25d5f293e8 | |
Brendan Robert | 90771cb31e | |
Brendan Robert | e8c6fb3efe | |
Peter Ferrie | d4d3c59b8c | |
Peter Ferrie | c540527370 | |
Peter Ferrie | 3f359cf3ff | |
Peter Ferrie | b258ed441a |
|
@ -68,3 +68,6 @@ error_stack.txt
|
|||
# Ignore NetBeans project files
|
||||
Platform/Apple/tools/jace/nb-configuration.xml
|
||||
Platform/Apple/tools/jace/nbactions.xml
|
||||
|
||||
# Ignore temporary pom files
|
||||
Platform/Apple/tools/jace/runPom.xml
|
||||
|
|
|
@ -167,7 +167,6 @@ public class LawlessLegends extends Application {
|
|||
resetEmulator();
|
||||
configureEmulatorForGame();
|
||||
bootWatchdog();
|
||||
// Emulator.getComputer().getCpu().trace=true;
|
||||
} else {
|
||||
startListener.unregister();
|
||||
}
|
||||
|
|
|
@ -123,5 +123,5 @@ public class Motherboard extends IndependentTimedDevice {
|
|||
if (accelorationRequestors.remove(requester) && accelorationRequestors.isEmpty()) {
|
||||
disableTempMaxSpeed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,10 @@ public abstract class TimedDevice extends Device {
|
|||
}
|
||||
}
|
||||
|
||||
public final boolean isMaxSpeedEnabled() {
|
||||
return maxspeed;
|
||||
}
|
||||
|
||||
public final boolean isMaxSpeed() {
|
||||
return forceMaxspeed || maxspeed;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -18,7 +19,10 @@ import java.util.regex.Pattern;
|
|||
import jace.Emulator;
|
||||
import jace.apple2e.VideoDHGR;
|
||||
import jace.cheat.Cheats;
|
||||
import jace.core.Computer;
|
||||
import jace.core.Motherboard;
|
||||
import jace.core.RAMEvent;
|
||||
import jace.core.TimedDevice;
|
||||
import javafx.util.Duration;
|
||||
|
||||
/**
|
||||
|
@ -48,6 +52,7 @@ public class LawlessHacks extends Cheats {
|
|||
addCheat("Lawless Text Speedup", RAMEvent.TYPE.EXECUTE, this::fastText, 0x0ee00, 0x0ee00 + 0x0f00);
|
||||
addCheat("Lawless Text Enhancement", RAMEvent.TYPE.WRITE, this::enhanceText, 0x02000, 0x03fff);
|
||||
addCheat("Lawless Legends Music Commands", RAMEvent.TYPE.WRITE, (e) -> playSound(e.getNewValue()), SFX_TRIGGER);
|
||||
addCheat("Lawless Adjust Animation Speed", RAMEvent.TYPE.READ, this::adjustAnimationSpeed, 0x0c000, 0x0c010);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,12 +81,27 @@ public class LawlessHacks extends Cheats {
|
|||
}
|
||||
|
||||
// Enhance text rendering by forcing the text to be pure B&W
|
||||
Map<Integer, Integer> detectedEntryPoints = new TreeMap<>();
|
||||
long lastStatus = 0;
|
||||
private void enhanceText(RAMEvent e) {
|
||||
if (!e.isMainMemory()) {
|
||||
return;
|
||||
}
|
||||
int pc = Emulator.withComputer(c->c.getCpu().getProgramCounter(), 0);
|
||||
boolean drawingText = pc == 0x0ee46 || pc > 0x0f300;
|
||||
boolean drawingText = (pc >= 0x0ee00 && pc <= 0x0f0c0) || pc > 0x0f100;
|
||||
if (DEBUG) {
|
||||
if (drawingText) {
|
||||
detectedEntryPoints.put(pc, detectedEntryPoints.getOrDefault(pc, 0) + 1);
|
||||
}
|
||||
if ((System.currentTimeMillis() - lastStatus) >= 10000) {
|
||||
lastStatus = System.currentTimeMillis();
|
||||
System.out.println("---text entry points---");
|
||||
detectedEntryPoints.forEach((addr, count) -> {
|
||||
System.out.println(Integer.toHexString(addr) + ": " + count);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Emulator.withVideo(v -> {
|
||||
if (v instanceof LawlessVideo) {
|
||||
LawlessVideo video = (LawlessVideo) v;
|
||||
|
@ -98,6 +118,45 @@ public class LawlessHacks extends Cheats {
|
|||
});
|
||||
}
|
||||
|
||||
private Map<Integer, Integer> keyReadAddresses = new TreeMap<>();
|
||||
long lastKeyStatus = 0;
|
||||
long lastKnownSpeed = -1;
|
||||
boolean isCurrentlyMaxSpeed = false;
|
||||
private void adjustAnimationSpeed(RAMEvent e) {
|
||||
int pc = Emulator.withComputer(c->c.getCpu().getProgramCounter(), 0);
|
||||
if (DEBUG) {
|
||||
keyReadAddresses.put(pc, keyReadAddresses.getOrDefault(pc, 0) + 1);
|
||||
if ((System.currentTimeMillis() - lastKeyStatus) >= 10000) {
|
||||
lastKeyStatus = System.currentTimeMillis();
|
||||
System.out.println("---keyin points---");
|
||||
keyReadAddresses.forEach((addr, count) -> {
|
||||
System.out.println(Integer.toHexString(addr) + ": " + count);
|
||||
});
|
||||
}
|
||||
}
|
||||
Motherboard m = Emulator.withComputer(Computer::getMotherboard, null);
|
||||
long currentSpeed = m.getSpeedInHz();
|
||||
if (pc == 0x0D5FE) {
|
||||
long slowerSpeed = (long) (TimedDevice.NTSC_1MHZ * 1.5);
|
||||
// We are waiting for a key in portait mode, slow to 1.5x
|
||||
if (currentSpeed > slowerSpeed || m.isMaxSpeedEnabled()) {
|
||||
lastKnownSpeed = currentSpeed;
|
||||
isCurrentlyMaxSpeed = m.isMaxSpeedEnabled();
|
||||
m.setSpeedInHz(slowerSpeed);
|
||||
m.setMaxSpeed(false);
|
||||
m.cancelSpeedRequest(this);
|
||||
}
|
||||
} else {
|
||||
// We're in some other mode, go back the default speed
|
||||
if (currentSpeed < lastKnownSpeed || isCurrentlyMaxSpeed) {
|
||||
m.setSpeedInHz(lastKnownSpeed);
|
||||
m.setMaxSpeed(isCurrentlyMaxSpeed);
|
||||
isCurrentlyMaxSpeed = false;
|
||||
lastKnownSpeed = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final String SCORE_NONE = "none";
|
||||
public static final String SCORE_COMMON = "common";
|
||||
public static final String SCORE_ORCHESTRAL = "8-bit orchestral samples";
|
||||
|
|
|
@ -33,8 +33,9 @@ DEBUG = 0
|
|||
decomp !zone {
|
||||
jsr .chkdst
|
||||
ldy #0 ; In lit loop Y must be zero
|
||||
sec
|
||||
.fill1A jsr .getbt2
|
||||
jmp .fill1B
|
||||
bne .fill1B ; always taken
|
||||
|
||||
.incdst inc pDst+1
|
||||
.chkdst ldx pDst+1
|
||||
|
@ -174,19 +175,19 @@ decomp !zone {
|
|||
bne .gshift ; always taken
|
||||
|
||||
; 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
|
||||
.getbts tax
|
||||
.getbt2 lda (pSrc),y
|
||||
inc pSrc
|
||||
beq .src3A
|
||||
.src3B sec
|
||||
rol
|
||||
sta bits
|
||||
txa
|
||||
inc pSrc
|
||||
beq .src3A
|
||||
rts
|
||||
|
||||
.src3A inc pSrc+1
|
||||
bne .src3B ; always taken
|
||||
rts
|
||||
|
||||
} ; end of zone
|
||||
|
||||
|
|
|
@ -364,7 +364,7 @@ export asm memcpy(pSrc, pDst, len, auxWr)#0
|
|||
inc pTmp+1
|
||||
bne .pglup ; always taken
|
||||
.part:
|
||||
cpx #0
|
||||
txa
|
||||
beq .done
|
||||
- lda (tmp),y
|
||||
sta (pTmp),y
|
||||
|
@ -390,8 +390,8 @@ export asm memset(pDst, val, len)#0
|
|||
lda evalStkL,x ; len lo
|
||||
pha
|
||||
lda evalStkH,x ; len hi
|
||||
tax
|
||||
beq +
|
||||
tax
|
||||
lda tmp
|
||||
- sta (pTmp),y
|
||||
iny
|
||||
|
@ -420,10 +420,10 @@ export asm readAuxByte(ptr)#1
|
|||
sta $10-1,y
|
||||
dey
|
||||
bne -
|
||||
jmp $10
|
||||
.rdauxb
|
||||
sei ; prevent interrupts while in aux mem
|
||||
sta setAuxRd
|
||||
jmp $10
|
||||
.rdauxb
|
||||
lda (pTmp),y
|
||||
sta clrAuxRd
|
||||
cli
|
||||
|
@ -462,19 +462,19 @@ end
|
|||
export asm finishString(isPlural)#1
|
||||
!zone {
|
||||
+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
|
||||
beq +
|
||||
lda #$40 ; for setting V later
|
||||
+ 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
|
||||
ldy #0 ; dest offset in Y (will be incremented before store)
|
||||
ldx #0 ; source offset in X (will be incremented before load)
|
||||
cpx inbuf
|
||||
beq .done ; failsafe: handle zero-length string
|
||||
.fetch
|
||||
inx
|
||||
lda inbuf,x ; get next input char
|
||||
|
@ -488,11 +488,11 @@ export asm finishString(isPlural)#1
|
|||
|
||||
dey ; undo copy of the paren
|
||||
stx tmp+1 ; save position in input
|
||||
dex ; needed for failsafe operation
|
||||
bit tmp ; set copy flag (V) initially to same as isPlural flag
|
||||
.findsl ; see if there's a slash within the parens
|
||||
inx
|
||||
cpx inbuf
|
||||
bcs .done ; failsafe: handle missing end-paren
|
||||
lda inbuf,x
|
||||
ora #$80 ; normalize hi-bit for comparisons below
|
||||
cmp #"/"
|
||||
|
@ -503,11 +503,8 @@ export asm finishString(isPlural)#1
|
|||
pha
|
||||
plp
|
||||
+ cmp #")" ; scan until ending paren
|
||||
beq +
|
||||
cpx inbuf
|
||||
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
|
||||
bne .findsl ; loop to scan next char
|
||||
ldx tmp+1 ; get back to start of parens
|
||||
; copy mode flag is now in V: if slash present, single=copy, plural=nocopy
|
||||
; if no slash: single=nocopy, plural=copy
|
||||
.plup
|
||||
|
@ -541,6 +538,7 @@ export asm finishString(isPlural)#1
|
|||
|
||||
.done
|
||||
sty inbuf ; save new length
|
||||
.done1
|
||||
lda #<inbuf ; return pointer to string
|
||||
ldy #>inbuf
|
||||
rts
|
||||
|
@ -575,8 +573,8 @@ export asm blit(isAux, srcData, dstScreenPtr, nLines, lineSize)#0
|
|||
lsr ; to carry bit
|
||||
bcc +
|
||||
ldy #15 ; put aux copy routine in zero page
|
||||
- lda .cpaux + ABS_OFFSET,y
|
||||
sta $10,y
|
||||
- ldx .cpaux + ABS_OFFSET,y
|
||||
stx $10,y
|
||||
dey
|
||||
bpl -
|
||||
+ pla ; get line count
|
||||
|
@ -694,8 +692,9 @@ export asm puts(str)#0
|
|||
sta pTmp
|
||||
lda #'!'
|
||||
ldx #1
|
||||
sty pTmp+1
|
||||
tya
|
||||
beq + ; safety: print '!' instead of null string
|
||||
sty pTmp+1
|
||||
ldy #0
|
||||
lda (pTmp),y
|
||||
tax
|
||||
|
@ -913,9 +912,8 @@ export asm rawDisplayStr(pStr)#0
|
|||
lda (pTmp),y
|
||||
sta tmp
|
||||
- cpy tmp
|
||||
bcc +
|
||||
rts
|
||||
+ iny
|
||||
bcs ++
|
||||
iny
|
||||
lda (pTmp),y
|
||||
ora #$80
|
||||
cmp #"^"
|
||||
|
@ -929,7 +927,8 @@ export asm rawDisplayStr(pStr)#0
|
|||
+ sty tmp+1
|
||||
jsr DisplayChar
|
||||
ldy tmp+1
|
||||
bne -
|
||||
bne - ; always taken
|
||||
++rts
|
||||
end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -991,8 +990,8 @@ export asm streqi(a, b)#1
|
|||
lda evalStkL+1,x
|
||||
sta pTmp
|
||||
lda evalStkH+1,x
|
||||
sta pTmp+1
|
||||
beq .null
|
||||
sta pTmp+1
|
||||
ldy #0
|
||||
lda (tmp),y
|
||||
cmp (pTmp),y
|
||||
|
@ -1004,21 +1003,16 @@ export asm streqi(a, b)#1
|
|||
+ tax ; count up to (verified same) length of the strings
|
||||
- iny
|
||||
lda (tmp),y
|
||||
cmp #('z'&$7F)+1 ; convert to upper case
|
||||
bcs +
|
||||
eor (pTmp),y
|
||||
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
|
||||
bcc +
|
||||
sbc #$20
|
||||
+ 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
|
||||
bcc .noteqi ; abort on inequality
|
||||
+ dex
|
||||
bne -
|
||||
lda #1
|
||||
ldy #0 ; okay, they're equal. Return 1 (not just any char; so that PLASMA when...is can work)
|
||||
|
|
Loading…
Reference in New Issue