mid-kid
6 years ago
commit
d8fbf80a4b
15 changed files with 1889 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||
|
My resources used to beat https://zzazzdzz.github.io/fools2019/ |
||||
|
No writeups or explanations provided. |
@ -0,0 +1,98 @@ |
|||||
|
#include <stdlib.h> |
||||
|
#include <stdio.h> |
||||
|
#include <time.h> |
||||
|
#include <glib.h> |
||||
|
|
||||
|
int s03_A0F3 = 0x5D0B1C11; |
||||
|
int s03_A0F7 = 0x35E79125; |
||||
|
int s03_A0FB = 0x56596b10; |
||||
|
int s03_A0FF = 0x7FFFFB0A; |
||||
|
int s03_A103 = 0x1B080733; |
||||
|
|
||||
|
int s03_A107; |
||||
|
int s03_A10B; |
||||
|
int s03_A10D; |
||||
|
int s03_A10E; |
||||
|
|
||||
|
char buffer[0x200]; |
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
FILE *f = fopen("fools.sav", "r"); |
||||
|
if (!f) { |
||||
|
perror("fopen"); |
||||
|
exit(1); |
||||
|
} |
||||
|
fseek(f, 0x6567, SEEK_SET); |
||||
|
fread(buffer, 1, 0x200, f); |
||||
|
fclose(f); |
||||
|
|
||||
|
GHashTable *hashtable = g_hash_table_new(g_direct_hash, g_direct_equal); |
||||
|
|
||||
|
double start = clock(); |
||||
|
do { |
||||
|
gint lcg = s03_A0F3 & 0xFFFFFE00; |
||||
|
gint cur_lcg = GPOINTER_TO_INT(g_hash_table_lookup(hashtable, GINT_TO_POINTER(lcg))); |
||||
|
cur_lcg += 1; |
||||
|
g_hash_table_replace(hashtable, GINT_TO_POINTER(lcg), GINT_TO_POINTER(cur_lcg)); |
||||
|
|
||||
|
s03_A0F3 = (s03_A0F3 * s03_A0F7 + s03_A0FB) & 0xFFFFFFFF; |
||||
|
|
||||
|
if (s03_A0FF % 0x100000 == 0) { |
||||
|
double framespers = 0x100000 / ((double)(clock() - start) / CLOCKS_PER_SEC); |
||||
|
unsigned eta = (double)(s03_A0FF) / framespers; |
||||
|
fprintf(stderr, "Progress: %d (speed: %.2f iter/s, ETA: %02u:%02u:%02u)\n", |
||||
|
s03_A0FF, framespers, |
||||
|
eta / 60 / 60, (eta / 60) % 60, eta % 60); |
||||
|
start = clock(); |
||||
|
} |
||||
|
} while (--s03_A0FF); |
||||
|
|
||||
|
int count = 0; |
||||
|
|
||||
|
GHashTableIter iter; |
||||
|
gpointer key, value; |
||||
|
g_hash_table_iter_init(&iter, hashtable); |
||||
|
while (g_hash_table_iter_next(&iter, &key, &value)) { |
||||
|
count += GPOINTER_TO_INT(value) % 2; |
||||
|
} |
||||
|
|
||||
|
int i = 0; |
||||
|
start = clock(); |
||||
|
g_hash_table_iter_init(&iter, hashtable); |
||||
|
while (g_hash_table_iter_next(&iter, &key, &value)) { |
||||
|
if (GPOINTER_TO_INT(value) % 2 == 0) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
double framespers = 1 / ((double)(clock() - start) / CLOCKS_PER_SEC); |
||||
|
unsigned eta = (double)(count - i) / framespers; |
||||
|
fprintf(stderr, "Progress: %d/%d %.2f%% (speed: %.2f iter/s, ETA: %02u:%02u:%02u)\n", |
||||
|
i, count, (double)i / count * 100, framespers, |
||||
|
eta / 60 / 60, (eta / 60) % 60, eta % 60); |
||||
|
start = clock(); |
||||
|
i += 1; |
||||
|
|
||||
|
s03_A107 = s03_A103; |
||||
|
|
||||
|
s03_A10B = (GPOINTER_TO_INT(key) & 0xFF00) >> 8; |
||||
|
s03_A10D = (GPOINTER_TO_INT(key) & 0xFF0000) >> 16; |
||||
|
s03_A10E = (GPOINTER_TO_INT(key) & 0xFF000000) >> 24; |
||||
|
|
||||
|
int bufi = 0; |
||||
|
do { |
||||
|
s03_A10B = ((s03_A10B / 2) * s03_A10D + s03_A10E) & 0xFFFF; |
||||
|
buffer[bufi] ^= s03_A10B & 0xFF; |
||||
|
|
||||
|
if (++bufi >= 0x200) bufi = 0; |
||||
|
} while (--s03_A107); |
||||
|
} |
||||
|
|
||||
|
g_hash_table_destroy(hashtable); |
||||
|
|
||||
|
f = fopen("output.buf", "w"); |
||||
|
fwrite(buffer, 1, 0x200, f); |
||||
|
fclose(f); |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
# Seed values (break at s03_A13A to fetch them) |
||||
|
s03_A0F3 = 0x5D0B1C11 # Match |
||||
|
s03_A0F7 = 0x35E79125 # Match |
||||
|
s03_A0FB = 0x56596b10 # Match |
||||
|
s03_A0FF = 0x7FFFFB0A # Match |
||||
|
s03_A103 = 0x1b080733 # Match |
||||
|
|
||||
|
file = open("fools.sav", "rb") |
||||
|
file.seek(0x6567) |
||||
|
buf = bytearray(file.read(0x200)) |
||||
|
file.close() |
||||
|
|
||||
|
while s03_A0FF != 0: |
||||
|
s03_A107 = s03_A103 |
||||
|
|
||||
|
s03_A10B = (s03_A0F3 & 0xFF00) >> 8 |
||||
|
s03_A10D = (s03_A0F3 & 0xFF0000) >> 16 |
||||
|
s03_A10E = (s03_A0F3 & 0xFF000000) >> 24 |
||||
|
|
||||
|
print(s03_A0FF - i_out) |
||||
|
|
||||
|
bufi = 0 |
||||
|
i = 0 |
||||
|
while s03_A107 != 0: |
||||
|
s03_A10B = ((s03_A10B // 2) * s03_A10D + s03_A10E) & 0xFFFF |
||||
|
buf[bufi] ^= (s03_A10B) & 0xFF |
||||
|
|
||||
|
bufi += 1 |
||||
|
if bufi >= 0x200: |
||||
|
bufi = 0 |
||||
|
|
||||
|
s03_A107 -= 1 |
||||
|
|
||||
|
s03_A0F3 = (s03_A0F3 * s03_A0F7 + s03_A0FB) & 0xFFFFFFFF |
||||
|
|
||||
|
s03_A0FF -= 1 |
||||
|
|
||||
|
file = open("output.buffer", "wb").write(buf) |
@ -0,0 +1,222 @@ |
|||||
|
CopyDEtoHL_32bit: ; s03_A084 |
||||
|
; Copies value pointed to by de to hl |
||||
|
|
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
ret |
||||
|
|
||||
|
AddDEToHL_32bit: ; s03_A090 |
||||
|
; Adds value pointed to by de to value pointed to by hl |
||||
|
|
||||
|
ld a, [de] |
||||
|
add [hl] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
|
||||
|
ld a, [de] |
||||
|
adc [hl] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
|
||||
|
ld a, [de] |
||||
|
adc [hl] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
|
||||
|
ld a, [de] |
||||
|
adc [hl] |
||||
|
ld [hl], a |
||||
|
ret |
||||
|
|
||||
|
s03_A0A0: dl $FFFFFFFF |
||||
|
|
||||
|
DecHL_32bit: ; s03_A0A4 |
||||
|
; Decrements 32-bit value at hl, checks if result is 0 |
||||
|
|
||||
|
push hl |
||||
|
ld de, s03_A0A0 |
||||
|
call AddDEToHL_32bit |
||||
|
pop hl |
||||
|
|
||||
|
; Checks 4-byte value at hl is 0 |
||||
|
ld a, [hl+] |
||||
|
and a |
||||
|
ret nz |
||||
|
ld a, [hl+] |
||||
|
and a |
||||
|
ret nz |
||||
|
ld a, [hl+] |
||||
|
and a |
||||
|
ret nz |
||||
|
ld a, [hl+] |
||||
|
and a |
||||
|
ret |
||||
|
|
||||
|
Multiplier: ds 4 ; s03_A0B8 |
||||
|
CalcResult: ds 4 ; s03_A0BC |
||||
|
Clean32bit: dl $00000000 ; s03_A0C0 |
||||
|
|
||||
|
MulDEToHL_32bit: ; s03_A0C4 |
||||
|
; Multiplies value at de with value at hl, stores in hl |
||||
|
|
||||
|
push hl |
||||
|
|
||||
|
; Copy DE to the Multiplier |
||||
|
push hl |
||||
|
push de |
||||
|
ld hl, Multiplier |
||||
|
call CopyDEtoHL_32bit |
||||
|
pop de |
||||
|
pop hl |
||||
|
|
||||
|
; Clear the result value |
||||
|
push hl |
||||
|
ld hl, CalcResult |
||||
|
ld de, Clean32bit |
||||
|
call CopyDEtoHL_32bit |
||||
|
pop de |
||||
|
|
||||
|
; Add HL (now DE) Multiplier times to CalcResult |
||||
|
.loop |
||||
|
push de |
||||
|
ld hl, CalcResult |
||||
|
call AddDEToHL_32bit |
||||
|
pop de |
||||
|
push de |
||||
|
ld hl, Multiplier |
||||
|
call DecHL_32bit |
||||
|
pop de |
||||
|
jr nz, .loop |
||||
|
|
||||
|
; Copy the result back to HL |
||||
|
pop hl |
||||
|
ld de, CalcResult |
||||
|
jp CopyDEtoHL_32bit |
||||
|
|
||||
|
|
||||
|
s03_A0F3: ds 4 ; Initial value: $5D0B1C11 |
||||
|
s03_A0F7: dl $35E79125 |
||||
|
s03_A0FB: dl $56596b10 |
||||
|
s03_A0FF: ds 4 ; Initial value: $7FFFFB0A |
||||
|
|
||||
|
s03_A103: dl $1b080733 |
||||
|
s03_A107: ds 4 ; Initialized with A103 |
||||
|
|
||||
|
s03_A10B: dw |
||||
|
s03_A10D: db |
||||
|
s03_A10E: db |
||||
|
|
||||
|
s03_A10F: |
||||
|
; (u16)s03_A10B = ((u16)s03_A10B / 2) * s03_A10D + s03_A10E |
||||
|
|
||||
|
ld hl, s03_A10B |
||||
|
ld a, [hl+] |
||||
|
ld h, [hl] |
||||
|
ld l, a |
||||
|
|
||||
|
and a |
||||
|
srl h |
||||
|
rr l |
||||
|
|
||||
|
ld d, h |
||||
|
ld e, l |
||||
|
ld hl, 0 |
||||
|
ld a, [s03_A10D] |
||||
|
ld c, a |
||||
|
and a |
||||
|
jr z, .end |
||||
|
.loop |
||||
|
add hl, de |
||||
|
dec c |
||||
|
jr nz, .loop |
||||
|
.end |
||||
|
|
||||
|
ld a, [s03_A10E] |
||||
|
ld c, a |
||||
|
ld b, 0 |
||||
|
add hl, bc |
||||
|
|
||||
|
ld a, h |
||||
|
ld [s03_A10B + 1], a |
||||
|
ld a, l |
||||
|
ld [s03_A10B], a |
||||
|
ret |
||||
|
|
||||
|
s03_A13A: |
||||
|
; Main decryption routine |
||||
|
|
||||
|
.outer_loop |
||||
|
ld hl, s03_A107 |
||||
|
ld de, s03_A103 |
||||
|
call CopyDEtoHL_32bit |
||||
|
|
||||
|
; Initialize values |
||||
|
ld hl, s03_A0F3 + 1 |
||||
|
ld de, s03_A10B |
||||
|
ld a, [hl+] |
||||
|
ld [de], a |
||||
|
inc de ; s03_A10B + 1 |
||||
|
xor a |
||||
|
ld [de], a |
||||
|
inc de ; s03_A10D |
||||
|
ld a, [hl+] |
||||
|
ld [de], a |
||||
|
inc de ; s03_A10E |
||||
|
ld a, [hl] |
||||
|
ld [de], a |
||||
|
|
||||
|
ld hl, Buffer |
||||
|
ld bc, 0 |
||||
|
|
||||
|
; Problem with this routine: Writing to SRAM!!! |
||||
|
; This means that whatever is in hl's buffer is useless on next bootup, so we |
||||
|
; need to make sure to start from a clean save file. |
||||
|
|
||||
|
.loop ; s03_A15A |
||||
|
push hl |
||||
|
push bc |
||||
|
call s03_A10F ; (u16)s03_A10B = ((u16)s03_A10B / 2) * s03_A10D + s03_A10E |
||||
|
pop bc |
||||
|
pop hl |
||||
|
|
||||
|
; Exor the buffer |
||||
|
xor [hl] |
||||
|
ld [hl+], a |
||||
|
|
||||
|
; Reset HL to Buffer every $200 bytes |
||||
|
inc bc |
||||
|
ld a, b |
||||
|
cp $2 |
||||
|
jr nz, .s03_A16F |
||||
|
ld bc, 0 |
||||
|
ld hl, Buffer |
||||
|
.s03_A16F |
||||
|
|
||||
|
push hl |
||||
|
ld hl, s03_A107 |
||||
|
call DecHL_32bit |
||||
|
pop hl |
||||
|
jr nz, .loop |
||||
|
|
||||
|
ld hl, s03_A0F3 |
||||
|
ld de, s03_A0F7 |
||||
|
call MulDEToHL_32bit |
||||
|
ld hl, s03_A0F3 |
||||
|
ld de, s03_A0FB |
||||
|
call AddDEToHL_32bit |
||||
|
|
||||
|
ld hl, s03_A0FF |
||||
|
call DecHL_32bit |
||||
|
jr nz, .outer_loop |
||||
|
ret |
||||
|
|
||||
|
Buffer: ds $200 ; s03_A567 |
Binary file not shown.
@ -0,0 +1,86 @@ |
|||||
|
// Written by luckytyphlosion
|
||||
|
|
||||
|
#include <stdio.h> |
||||
|
#include <time.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
typedef unsigned int uint; |
||||
|
typedef unsigned short u16; |
||||
|
typedef unsigned char u8; |
||||
|
|
||||
|
#define _A0F4 (_A0F3 >> 8) & 0xff |
||||
|
#define _A0F5 (_A0F3 >> 16) & 0xff |
||||
|
#define _A0F6 (_A0F3 >> 24) & 0xff |
||||
|
#define TRUE 1 |
||||
|
#define FALSE 0 |
||||
|
|
||||
|
u8 sA567[] = {0x15, 0xc8, 0x7b, 0x6b, 0x7f, 0xa1, 0xa3, 0x29, 0xe8, 0x81, 0x1, 0x99, 0x9f, 0xeb, 0xf2, 0x80, 0x5f, 0xa3, 0x96, 0x7c, 0x17, 0xdb, 0xd2, 0x41, 0xa1, 0xbc, 0xbb, 0x13, 0xbc, 0xd8, 0xc3, 0x9, 0xf4, 0x2, 0x1b, 0x95, 0xf3, 0x72, 0x65, 0xdb, 0x6f, 0x82, 0x9e, 0x52, 0xd9, 0x89, 0xd8, 0xdf, 0x5a, 0xb0, 0x3, 0xf2, 0x9a, 0xe6, 0xef, 0x81, 0x32, 0xa5, 0x57, 0x60, 0xe0, 0xc8, 0x2d, 0x8c, 0x52, 0x63, 0x5d, 0xd8, 0xf, 0x72, 0xdf, 0xa1, 0x36, 0x1c, 0x3e, 0xc8, 0xc2, 0x4f, 0x1e, 0xfd, 0x1d, 0x11, 0xc, 0x74, 0x13, 0x21, 0x49, 0xad, 0xc0, 0xd9, 0xba, 0xda, 0xd, 0xe4, 0x6, 0x8e, 0x94, 0xe6, 0x25, 0x8b, 0xba, 0xc2, 0x2b, 0x92, 0xa, 0x90, 0xa1, 0x4a, 0x6, 0x53, 0x84, 0x79, 0xe5, 0xe7, 0xcf, 0x60, 0x74, 0xd2, 0x3b, 0x2a, 0xe0, 0x56, 0x32, 0xa6, 0x10, 0x69, 0x52, 0xf, 0xd3, 0x3d, 0x7f, 0xf3, 0x12, 0x6d, 0x0, 0x57, 0x41, 0x3f, 0x96, 0x3b, 0x8, 0xb7, 0x48, 0x72, 0xb2, 0x1e, 0x12, 0x57, 0x60, 0x95, 0x23, 0xc8, 0xab, 0x52, 0xc8, 0x3f, 0xc4, 0xc0, 0x50, 0xc1, 0xd3, 0x38, 0x28, 0x6e, 0x96, 0x6d, 0xdf, 0x8f, 0x41, 0x24, 0x21, 0x91, 0xf4, 0x64, 0x3e, 0xc9, 0xe6, 0xc7, 0x45, 0x26, 0xa1, 0x4c, 0xa, 0xd3, 0x2f, 0x8f, 0x77, 0x7d, 0x68, 0x86, 0x23, 0x43, 0xcf, 0xbf, 0xe1, 0xf4, 0xc8, 0x9e, 0x35, 0x5a, 0x11, 0x26, 0xb7, 0x9f, 0x23, 0xcd, 0x68, 0xa2, 0xb5, 0xca, 0xd3, 0x53, 0x95, 0xda, 0xb, 0x87, 0x15, 0xca, 0xe7, 0x73, 0xbd, 0x66, 0x39, 0x90, 0xc0, 0xa4, 0x94, 0x94, 0x3e, 0x61, 0x9e, 0xef, 0x89, 0x1e, 0x93, 0x13, 0xc1, 0xfa, 0xd9, 0xee, 0x5b, 0x27, 0x71, 0x16, 0xcd, 0xa2, 0xef, 0x49, 0xcc, 0xd6, 0x1d, 0x24, 0xa6, 0x3b, 0x89, 0x94, 0x58, 0x28, 0xd2, 0x83, 0x5b, 0x25, 0x8a, 0x5f, 0x25, 0xfe, 0xe3, 0x2d, 0xe8, 0x58, 0x5e, 0xbb, 0x9b, 0xd5, 0xe8, 0x46, 0xa5, 0xdc, 0xde, 0x8f, 0x97, 0x3, 0xf1, 0x16, 0x1, 0xfc, 0x2e, 0x3f, 0x47, 0x5b, 0xaf, 0x71, 0x2e, 0x7f, 0x19, 0xce, 0xe3, 0x7d, 0xe2, 0x49, 0x5e, 0x71, 0xa, 0x57, 0xe1, 0x98, 0xac, 0xdd, 0x7f, 0xfd, 0x5d, 0xae, 0xdc, 0x24, 0xc5, 0x30, 0x3b, 0x65, 0xc1, 0xd6, 0xf4, 0x62, 0xa0, 0xee, 0xbc, 0x86, 0x68, 0xb4, 0x5, 0x68, 0x1b, 0xdb, 0x5c, 0xa8, 0x25, 0x92, 0x70, 0xc8, 0xa5, 0xf6, 0x1a, 0x55, 0xad, 0xae, 0x44, 0x2a, 0x4a, 0x77, 0xca, 0x2d, 0x6b, 0xdd, 0x47, 0x51, 0x95, 0x58, 0xff, 0x75, 0xdd, 0x30, 0x81, 0x80, 0x1b, 0xdb, 0xc2, 0xa9, 0x29, 0xce, 0xa8, 0xd6, 0xd8, 0x8, 0xc1, 0x86, 0x1c, 0xec, 0xf, 0x63, 0x48, 0x38, 0x1b, 0xeb, 0x32, 0xe3, 0xa0, 0xe6, 0x28, 0x5e, 0xf4, 0xa, 0xa2, 0x2d, 0xf1, 0xb0, 0x61, 0xfc, 0xdd, 0x4c, 0x6b, 0x43, 0xe8, 0x82, 0x4, 0xe8, 0xf3, 0x3d, 0x43, 0xf5, 0x6d, 0x4e, 0x8a, 0x45, 0xc9, 0x6a, 0x96, 0x1d, 0x37, 0x93, 0x76, 0x53, 0x9e, 0x33, 0xa, 0xaf, 0x8, 0x3e, 0x80, 0xfc, 0xe7, 0xc5, 0x17, 0x69, 0xe7, 0x91, 0x55, 0x52, 0x4a, 0xa5, 0x51, 0x6, 0xa8, 0x3e, 0x82, 0x1d, 0xff, 0x27, 0x14, 0xee, 0x26, 0x39, 0x55, 0xc0, 0x8f, 0xd7, 0xf2, 0x47, 0x14, 0x9a, 0x54, 0x5e, 0xac, 0x9a, 0xc2, 0x93, 0xc0, 0x96, 0x60, 0x44, 0x11, 0x8, 0xed, 0x22, 0x20, 0x44, 0x77, 0xb3, 0xfc, 0x78, 0xe5, 0xda, 0xa, 0xc5, 0xa1, 0xbe, 0x64, 0x80, 0x25, 0x20, 0xa7, 0xfb, 0x3e, 0xdb, 0x26, 0x39, 0x99, 0x2a, 0xee, 0xa3, 0x36, 0x7b, 0xb6, 0x63, 0x24, 0xf6, 0xf6, 0x13, 0xe, 0x83, 0x86, 0x1f, 0x3a, 0xf}; |
||||
|
|
||||
|
u16 values[65536] = {0}; |
||||
|
u16 values_set[65536] = {0}; |
||||
|
int values_size = 0; |
||||
|
|
||||
|
int main(void) { |
||||
|
uint _A0F3 = 0x5d0b1c11; |
||||
|
const uint _A0F7 = 0x35e79125; |
||||
|
const uint _A0FB = 0x56596b10; |
||||
|
struct timespec start_time; |
||||
|
|
||||
|
for (int i = 0; i < 0x3ffffb0a; i++) { |
||||
|
_A0F3 = _A0F3 * _A0F7 + _A0FB; |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < 0x4f6; i++) { |
||||
|
u16 _A10B = _A0F4; |
||||
|
int _A10D = _A0F5; |
||||
|
int _A10E = _A0F6; |
||||
|
int data_count = 0; |
||||
|
int start_index = -1; |
||||
|
values_size = 0; |
||||
|
int sublcg_count = 0; |
||||
|
memset(values_set, 0xff, sizeof(values_set)); |
||||
|
while (TRUE) { |
||||
|
values[values_size++] = _A10B; |
||||
|
_A10B = (_A10B >> 1) * _A10D + _A10E; |
||||
|
if (values_set[_A10B] != 0xffff) { |
||||
|
start_index = values_set[_A10B]; |
||||
|
break; |
||||
|
} |
||||
|
values_set[_A10B] = values_size; |
||||
|
sA567[data_count++] ^= (_A10B & 0xff); |
||||
|
data_count = data_count & 0x1ff; |
||||
|
sublcg_count++; |
||||
|
} |
||||
|
int sublcg_index = start_index; |
||||
|
|
||||
|
int period = values_size - start_index; |
||||
|
while ((period & 1) == 0) { |
||||
|
period >>= 1; |
||||
|
} |
||||
|
|
||||
|
int num_xors_until_repeat = period * 512; |
||||
|
int num_repeat_iterations = (0x1b080733 - sublcg_count) / num_xors_until_repeat; |
||||
|
int remaining_sublcg_iterations = (0x1b080733 - sublcg_count) % num_xors_until_repeat; |
||||
|
if (num_repeat_iterations & 1 == 1) { |
||||
|
remaining_sublcg_iterations += num_xors_until_repeat; |
||||
|
} |
||||
|
|
||||
|
for (int j = 0; j < remaining_sublcg_iterations; j++) { |
||||
|
sA567[data_count++] ^= (values[sublcg_index++] & 0xff); |
||||
|
data_count = data_count & 0x1ff; |
||||
|
if (sublcg_index >= values_size) { |
||||
|
sublcg_index = start_index; |
||||
|
} |
||||
|
} |
||||
|
_A0F3 = _A0F3 * _A0F7 + _A0FB; |
||||
|
if (i % 10000 == 9999) { |
||||
|
struct timespec end_time; |
||||
|
clock_gettime(CLOCK_MONOTONIC, &end_time); |
||||
|
fprintf(stderr, "difftime: %f, iter: %u\n", 1000.0*end_time.tv_sec + 1e-6*end_time.tv_nsec - (1000.0*start_time.tv_sec + 1e-6*start_time.tv_nsec), i); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < 0x200; i++) { |
||||
|
printf("0x%02x, ", sA567[i]); |
||||
|
} |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
from sys import argv |
||||
|
from struct import unpack |
||||
|
|
||||
|
gadgets = {} |
||||
|
|
||||
|
for line in open("ropgadgets.txt"): |
||||
|
split = line.split("-") |
||||
|
if len(split) < 2: |
||||
|
continue |
||||
|
|
||||
|
addr = int(split[0][1:], 16) |
||||
|
cmd = "-".join(split[1:]).strip() |
||||
|
gadgets[addr] = cmd |
||||
|
|
||||
|
mem = open("fools.dump", "rb").read() |
||||
|
|
||||
|
addr = int(argv[1], 0) |
||||
|
|
||||
|
while True: |
||||
|
gadget = unpack("<H", mem[addr:addr+2])[0] |
||||
|
if gadget in gadgets: |
||||
|
print(" ", gadgets[gadget]) |
||||
|
else: |
||||
|
print(" dw $%04X" % gadget) |
||||
|
if gadget == 0x1708: |
||||
|
break |
||||
|
addr += 2 |
@ -0,0 +1,78 @@ |
|||||
|
#!/usr/bin/env python3 |
||||
|
|
||||
|
from sys import argv |
||||
|
from struct import unpack |
||||
|
|
||||
|
mem = open("fools.dump", "rb").read() |
||||
|
|
||||
|
addr = int(argv[1], 0) |
||||
|
|
||||
|
while True: |
||||
|
gadget = unpack("<B", mem[addr:addr+1])[0] |
||||
|
|
||||
|
if gadget == 0x01: |
||||
|
param = unpack("<H", mem[addr+1:addr+3])[0] |
||||
|
print(" ; sSaveSource = $%04X" % param) |
||||
|
print(" dbw $01, $%04X ; ROP_s02_AEF3" % param) |
||||
|
print() |
||||
|
addr += 3 |
||||
|
elif gadget == 0x02: |
||||
|
param = unpack("<B", mem[addr+1:addr+2])[0] |
||||
|
print(" ; sSaveBlockChecksum = $%02X" % param) |
||||
|
print(" dbb $02, $%02X ; ROP_s02_AF09" % param) |
||||
|
print() |
||||
|
addr += 2 |
||||
|
elif gadget == 0x03: |
||||
|
print(" ; w00_C800 = *(sSaveSource++)") |
||||
|
print(" db $03 ; ROP_s02_AF19") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x05: |
||||
|
print(" ; w00_C800 ^= func(s02_ADB1)") |
||||
|
print(" db $05 ; ROP_s02_AF3B") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x06: |
||||
|
print(" ; rotatebuffer(w00_C800)") |
||||
|
print(" db $06 ; ROP_s02_AF85") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x07: |
||||
|
param = unpack("<I", mem[addr+1:addr+5])[0] |
||||
|
print(" ; s02_ADB1 = $%08X" % param) |
||||
|
print(" dbl $07, $%08X ; ROP_s02_AFE3" % param) |
||||
|
print() |
||||
|
addr += 5 |
||||
|
elif gadget == 0x08: |
||||
|
print(" ; sSaveBlockChecksum += w00_C800") |
||||
|
print(" db $08 ; ROP_s02_B005") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x09: |
||||
|
print(" ; sSaveBlockChecksum ^= w00_C800") |
||||
|
print(" db $09 ; ROP_s02_B013") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x0B: |
||||
|
print(" ; w00_C800 = sSaveBlockChecksum") |
||||
|
print(" db $0B ; ROP_s02_B033") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x0C: |
||||
|
param1 = unpack("<H", mem[addr+1:addr+3])[0] |
||||
|
param2 = unpack("<B", mem[addr+3:addr+4])[0] |
||||
|
print(" dbwb $0C, $%03X, $%02X ; ROP_rept" % (param1, param2)) |
||||
|
print() |
||||
|
addr += 4 |
||||
|
elif gadget == 0x0D: |
||||
|
print(" ; *(sSaveSource++) = sSaveBlockChecksum") |
||||
|
print(" db $0D ; ROP_s02_B045") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
elif gadget == 0x0E: |
||||
|
print(" ; sSaveBlockChecksum = *sSaveSource") |
||||
|
print(" db $0E ; ROP_s02_B069") |
||||
|
print() |
||||
|
addr += 1 |
||||
|
else: |
||||
|
break |
@ -0,0 +1,997 @@ |
|||||
|
Text_WouldYouLikeToSaveTheGame EQU $5283 |
||||
|
Text_SavingDontTurnOffThePower EQU $5288 |
||||
|
SaveTheGame_yesorno EQU $4BAF |
||||
|
SaveMenu.refused EQU $4A4A |
||||
|
Text_WaitBGMap EQU $13B6 |
||||
|
SpeechTextBox EQU $103E |
||||
|
FarCall EQU $08 |
||||
|
FadeOutPalettes EQU $23:$4084 |
||||
|
LoadMapPalettes EQU $41:$47EB |
||||
|
ClearScreen EQU $0FDB |
||||
|
UpdateSprites EQU $1AD2 |
||||
|
GetSGBLayout EQU $3340 |
||||
|
SetPalettes EQU $32F9 |
||||
|
DelayFrame EQU $045A |
||||
|
DelayFrames EQU $0468 |
||||
|
PrintText EQU $1057 |
||||
|
Request1bpp EQU $0F1E |
||||
|
DoubleSpeed EQU $2FEF |
||||
|
hTransferVirtualOAM EQU $FFEC |
||||
|
rSTAT EQU $FF41 |
||||
|
CopyBytes EQU $3026 |
||||
|
|
||||
|
s02_9A12: db ; s02_9A12 |
||||
|
|
||||
|
SaveGame: ; s02_AD44 |
||||
|
push af |
||||
|
push bc |
||||
|
push de |
||||
|
push hl |
||||
|
ei |
||||
|
call Text_WaitBGMap |
||||
|
|
||||
|
ld a,[wSavingAllowed] |
||||
|
and a |
||||
|
jr z,.cantsave |
||||
|
|
||||
|
; Ask the player to save or some dumb shit idfk |
||||
|
ld hl,$B1E8 |
||||
|
ld a,$02 |
||||
|
ld [w01_DF34],a |
||||
|
call $A2A3 |
||||
|
ld bc,$0204 |
||||
|
ld hl,$A41A |
||||
|
ld de,Start |
||||
|
call $AB1F ; Get player input? |
||||
|
and a |
||||
|
jr z,.declined |
||||
|
|
||||
|
; Confirmed save |
||||
|
ld a,[wPartyCount] |
||||
|
cp a,$04 |
||||
|
jr c,.actuallysave |
||||
|
|
||||
|
; Too many party members yadda yadda |
||||
|
ld hl,$B323 |
||||
|
ld a,$02 |
||||
|
ld [w01_DF34],a |
||||
|
call $A2A3 |
||||
|
ld bc,$0204 |
||||
|
ld hl,$A41A |
||||
|
ld de,Start |
||||
|
call $AB1F |
||||
|
and a |
||||
|
jr z,$ADA7 |
||||
|
|
||||
|
.actuallysave ; s02_AD8F |
||||
|
ld a,BANK(FadeOutPalettes) |
||||
|
ld hl,FadeOutPalettes |
||||
|
rst FarCall |
||||
|
ld a,BANK(LoadMapPalettes) |
||||
|
ld hl,LoadMapPalettes |
||||
|
rst FarCall |
||||
|
jp SavingTheGame |
||||
|
|
||||
|
.cantsave ; s02_A9DC |
||||
|
ld hl,$B1A6 |
||||
|
ld a,$02 |
||||
|
ld [$DF34],a |
||||
|
call $A2A3 |
||||
|
|
||||
|
.declined ; s02_ADA7 |
||||
|
pop hl |
||||
|
pop de |
||||
|
pop bc |
||||
|
pop af |
||||
|
jp $0460 |
||||
|
|
||||
|
sSaveSource: dw ; s02_ADAE |
||||
|
sSaveBlockChecksum: db ; s02_ADB0 |
||||
|
s02_ADB1: dl ; s02_ADB1 |
||||
|
sBufferCarry: ; s02_ADB5 |
||||
|
sROPScriptBackup: dw ; s02_ADB6 |
||||
|
s02_ADB8: db ; s02_ADB8 |
||||
|
s02_ADB9: db ; s02_ADB9 |
||||
|
|
||||
|
ROPGadget_ldi_a_hl: ; s02_ADBA |
||||
|
ld a, [hl+] |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_ldd_a_hl: ; s02_ADBC |
||||
|
ld a, [hl-] |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_ld_hl_c: ; s02_ADBE |
||||
|
ld [hl], c |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_ld_b_hl: ; s02_ADC0 |
||||
|
ld b, [hl] |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_add_b: ; s02_ADC2 |
||||
|
add b |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_srl_a: ; s02_ADC4 |
||||
|
srl a |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_xor_hl: ; s02_ADC7 |
||||
|
xor [hl] |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_call_z: ; s02_ADC9 |
||||
|
ret z |
||||
|
pop hl |
||||
|
ret |
||||
|
|
||||
|
ROPGadget_variable: ; s02_ADCC |
||||
|
add [hl] |
||||
|
ret |
||||
|
|
||||
|
SavingTheGame: ; s02_ADCE |
||||
|
; Cleanup shit because well fuck nobody cares |
||||
|
call ClearScreen |
||||
|
call UpdateSprites |
||||
|
call UninstallVBlankHook ; Only interesting line in this entire blob of fuzz |
||||
|
ld b,$08 |
||||
|
call GetSGBLayout |
||||
|
call SetPalettes |
||||
|
ld hl,wMusicFadeID |
||||
|
ld [hl],$00 |
||||
|
dec hl |
||||
|
dec hl |
||||
|
ld [hl],$08 |
||||
|
ld c,$32 |
||||
|
call DelayFrames |
||||
|
ld a,$03 |
||||
|
ld [wOptions],a |
||||
|
ld a,$05 |
||||
|
rst $10 |
||||
|
ld hl,Text_SavingDontTurnOffThePower |
||||
|
call PrintText |
||||
|
ld de,$B400 |
||||
|
ld hl,$8C00 ; This graphic is probably a picture of a cucumber |
||||
|
ld bc,$0104 |
||||
|
call Request1bpp |
||||
|
call DelayFrame |
||||
|
|
||||
|
; Now THAT's more like it |
||||
|
ld de,ROPScript_SaveMain |
||||
|
di |
||||
|
call DoubleSpeed |
||||
|
call UpdateSaveSpinner |
||||
|
ld sp,SaveROPMain |
||||
|
ret |
||||
|
|
||||
|
ROP_SaveMain: ; s02_AE18 |
||||
|
ld a, [de] |
||||
|
inc de |
||||
|
add a |
||||
|
|
||||
|
ld bc, 0 |
||||
|
ld c, a |
||||
|
ld hl, .jmptable |
||||
|
add hl, bc |
||||
|
ldw hl, [hl] |
||||
|
.jmptable ; s02_AE2C |
||||
|
jp hl |
||||
|
dw ROP_SetAddr ; $01 |
||||
|
dw ROP_InitChecksum ; $02 |
||||
|
dw ROP_FetchByte ; $03 |
||||
|
dw ROP_end ; $04 |
||||
|
dw ROP_ApplyCrypto ; $05 |
||||
|
dw ROP_RotateBuffer ; $06 |
||||
|
dw ROP_InitCrypto ; $07 |
||||
|
dw ROP_AddChecksum ; $08 |
||||
|
dw ROP_XorChecksum ; $09 |
||||
|
dw $0000 ; $0A |
||||
|
dw ROP_WriteChecksumByte ; $0B |
||||
|
dw ROP_rept ; $0C |
||||
|
dw ROP_StoreByte ; $0D |
||||
|
dw ROP_LoadByte ; $0E |
||||
|
|
||||
|
ROP_end: ; s02_AE4A |
||||
|
ld bc, $0100 |
||||
|
ld de, $CB00 |
||||
|
ld hl, $AE58 |
||||
|
ld af, $FF00 |
||||
|
call CopyBytes |
||||
|
; Here's the destination of the copied code, |
||||
|
; it does some shit to copy the buffer back to the SRAM. |
||||
|
; I don't really care what it does. |
||||
|
|
||||
|
UpdateSaveSpinner: ; s02_AEDB |
||||
|
ld hl,s02_9A12 |
||||
|
ld b,$C0 |
||||
|
ld a,[s02_ADB9] |
||||
|
inc a |
||||
|
and a,%11 |
||||
|
ld [s02_ADB9],a |
||||
|
add b |
||||
|
ld b,a |
||||
|
|
||||
|
; Wait for HBlank |
||||
|
.loop ; s02_AEEB |
||||
|
ldh a,[rSTAT] |
||||
|
and a,%11 |
||||
|
jr nz,.loop |
||||
|
|
||||
|
ld [hl],b |
||||
|
ret |
||||
|
|
||||
|
ROP_SetAddr: ; s02_AEF3 |
||||
|
; sSaveSource = param |
||||
|
|
||||
|
ld hl, sSaveSource |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_InitChecksum: ; s02_AF09 |
||||
|
; sSaveBlockChecksum = param |
||||
|
|
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld a, [de] |
||||
|
inc de |
||||
|
ld [hl+], a |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_FetchByte: ; s02_AF19 |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
|
||||
|
; Fetch byte from pointer stored at sSaveSource |
||||
|
ld hl, sSaveSource |
||||
|
ldw hl, [hl] |
||||
|
ld a, [hl+] |
||||
|
|
||||
|
; Save incremented pointer back into sSaveSource |
||||
|
ld b, h |
||||
|
ld c, l |
||||
|
ld hl, sSaveSource |
||||
|
ld [hl], c |
||||
|
inc hl |
||||
|
ld [hl], b |
||||
|
|
||||
|
; Save byte into w00_C800 |
||||
|
ld hl, w00_C800 |
||||
|
ld [hl+], a |
||||
|
|
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_ApplyCrypto: ; s02_AF3B |
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
|
||||
|
; s02_ADB2 ^= (s02_ADB1 + 1) ^ s02_ADB4 |
||||
|
ld hl, s02_ADB1 |
||||
|
inc [hl] |
||||
|
ld b, [hl] ; s02_ADB1 |
||||
|
ld a, [hl+] |
||||
|
ld a, [hl+] |
||||
|
ld a, [hl+] |
||||
|
ld a, [hl-] ; s02_ADB4 |
||||
|
xor b |
||||
|
ld b, a |
||||
|
ld a, [hl-] |
||||
|
ld a, [hl-] ; s02_ADB2 |
||||
|
inc hl |
||||
|
xor b |
||||
|
ld [hl+], a ; s02_ADB2 |
||||
|
|
||||
|
; s02_ADB3 += s02_ADB2 |
||||
|
ld b, a |
||||
|
ld a, [hl-] ; s02_ADB3 |
||||
|
inc hl |
||||
|
add b |
||||
|
ld [hl+], a ; s02_ADB3 |
||||
|
|
||||
|
; s02_ADB4 = s02_ADB2 ^ (s02_ADB4 + (s02_ADB3 / 2)) |
||||
|
srl a |
||||
|
ld b, a |
||||
|
ld a, [hl-] ; s02_ADB4 |
||||
|
add b |
||||
|
ld b, a |
||||
|
ld a, [hl-] |
||||
|
ld a, [hl+] ; s02_ADB2 |
||||
|
xor b |
||||
|
inc hl |
||||
|
ld [hl+], a ; s02_ADB4 |
||||
|
|
||||
|
; w00_C800 ^= s02_ADB4 |
||||
|
ld hl, w00_C800 |
||||
|
xor [hl] |
||||
|
ld [hl+], a |
||||
|
|
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_RotateBuffer: ; s02_AF85 |
||||
|
; s02_ADB8 = ((s02_ADB8 + 1) | $C0) ^ $C0 |
||||
|
; s02_ADB8 = (s02_ADB8 + 1) & 0x3F |
||||
|
ld hl, s02_ADB8 |
||||
|
ld a, [hl-] |
||||
|
inc a |
||||
|
ld hl, $07FC |
||||
|
or [hl] |
||||
|
ld bc, $C000 |
||||
|
xor b |
||||
|
ld hl, s02_ADB8 |
||||
|
ld [hl+], a |
||||
|
|
||||
|
; Called every 64 times this function is ran |
||||
|
and a |
||||
|
call z, UpdateSaveSpinner |
||||
|
|
||||
|
; Save ROPScript pointer |
||||
|
ld hl, sROPScriptBackup |
||||
|
ld a, e |
||||
|
ld [hl+], a |
||||
|
ld [hl], d |
||||
|
|
||||
|
; Rotate the entire buffer, using sBufferCarry as carry |
||||
|
ld hl, w00_C800 |
||||
|
ld a, [hl+] |
||||
|
ld hl, sBufferCarry |
||||
|
ld [hl+], a |
||||
|
ld bc, $01B0 |
||||
|
ld de, w00_C800 |
||||
|
ld hl, w00_C800 + 1 |
||||
|
ld af, $FF00 |
||||
|
call CopyBytes ; bc bytes from hl to de |
||||
|
ld hl, sBufferCarry |
||||
|
ld a, [hl+] |
||||
|
ld hl, w00_C9AF |
||||
|
ld [hl+], a |
||||
|
|
||||
|
; Restore ROPScript pointer |
||||
|
ld hl, sROPScriptBackup |
||||
|
ld a, [hl+] |
||||
|
ld d, [hl] |
||||
|
ld e, a |
||||
|
|
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_InitCrypto: ; s02_AFE3 |
||||
|
; s02_ADB1 = param |
||||
|
|
||||
|
ld hl, s02_ADB1 |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld [hl+], a |
||||
|
inc de |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_AddChecksum: ; s02_B005 |
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
|
||||
|
ld hl, ROPGadget_variable |
||||
|
ld af, $8600 ; add [hl] |
||||
|
ld [hl+], a |
||||
|
ld hl, ROP_s02_B01B |
||||
|
jp hl |
||||
|
|
||||
|
ROP_XorChecksum: ; s02_B013 |
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
|
||||
|
ld hl, ROPGadget_variable |
||||
|
ld af, $AE00 ; xor [hl] |
||||
|
ld [hl+], a |
||||
|
|
||||
|
; fallthrough |
||||
|
|
||||
|
ROP_s02_B01B: ; s02_B01B |
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld a, [hl+] |
||||
|
ld hl, w00_C800 |
||||
|
add [hl]/xor [hl] ; Modified by caller |
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld [hl+], a |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_WriteChecksumByte: ; s02_B033 |
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
|
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld a, [hl+] |
||||
|
ld hl, w00_C800 |
||||
|
ld [hl+], a |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_StoreByte: ; s02_B045 |
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
|
||||
|
; *sSaveSource = sSaveBlockChecksum |
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld b, [hl] |
||||
|
ld hl, sSaveSource |
||||
|
ldw hl, [hl] |
||||
|
ld [hl], b |
||||
|
inc hl |
||||
|
|
||||
|
; sSaveSource = sSaveSource + 1 |
||||
|
ld b, h |
||||
|
ld c, l |
||||
|
ld hl, sSaveSource |
||||
|
ld [hl], c |
||||
|
inc hl |
||||
|
ld [hl], b |
||||
|
|
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_LoadByte: ; s02_B069 |
||||
|
; sSaveBlockChecksum = *sSaveSource |
||||
|
|
||||
|
ld hl, sSaveSource |
||||
|
ldw hl, [hl] |
||||
|
ld a, [hl+] |
||||
|
ld hl, sSaveBlockChecksum |
||||
|
ld [hl+], a |
||||
|
|
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROP_rept: ; s02_B07D |
||||
|
; do {} while(param[2]--); |
||||
|
|
||||
|
; Fetch jump pointer to bc |
||||
|
ld a, [de] |
||||
|
ld c, a |
||||
|
inc de |
||||
|
ld a, [de] |
||||
|
ld b, a |
||||
|
inc de |
||||
|
|
||||
|
; If param == 0, return |
||||
|
ld a, [de] |
||||
|
inc de |
||||
|
ld hl, ROP_SaveMain |
||||
|
and a |
||||
|
call z, (jp hl) |
||||
|
|
||||
|
; Decrement parameter, if 0, return |
||||
|
dec a |
||||
|
dec de |
||||
|
ld [de], a |
||||
|
inc de |
||||
|
ld hl, ROP_SaveMain |
||||
|
call z, (jp hl) |
||||
|
|
||||
|
; Jump to the script at bc |
||||
|
ld d, b |
||||
|
ld a, c |
||||
|
ld e, a |
||||
|
ld hl, ROP_SaveMain |
||||
|
jp hl |
||||
|
|
||||
|
ROPScript_SaveMain: ; s02_B0B3 |
||||
|
; ========================================================================== |
||||
|
; Start compiling data into save blob, and applying first crypto layer. |
||||
|
; Each "section" of the save blob has its own, fixed crypto seed and checksum. |
||||
|
; ========================================================================== |
||||
|
|
||||
|
; sSaveSource = $FCDF |
||||
|
dbw $01, $FCDF ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum = $7F |
||||
|
dbb $02, $7F ; ROP_InitChecksum |
||||
|
|
||||
|
; s02_ADB1 = $8C10E62F |
||||
|
dbl $07, $8C10E62F ; ROP_InitCrypto |
||||
|
|
||||
|
.s02_B0BD |
||||
|
; rept ($48) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B0BD, $48 ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $FA7A |
||||
|
dbw $01, $FA7A ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum = $C2 |
||||
|
dbb $02, $C2 ; ROP_InitChecksum |
||||
|
|
||||
|
; s02_ADB1 = $6AF528C2 |
||||
|
dbl $07, $6AF528C2 ; ROP_InitCrypto |
||||
|
|
||||
|
.s02_B0D5 |
||||
|
; rept ($14) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B0D5, $14 ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $F84E |
||||
|
dbw $01, $F84E ; ROP_SetAddr |
||||
|
|
||||
|
.s02_B0E2 |
||||
|
; rept ($03) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B0E2, $03 ; ROP_rept |
||||
|
|
||||
|
; sSaveSource = $F859 |
||||
|
dbw $01, $F859 ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum = $06 |
||||
|
dbb $02, $06 ; ROP_InitChecksum |
||||
|
|
||||
|
; s02_ADB1 = $EF7305A6 |
||||
|
dbl $07, $EF7305A6 ; ROP_InitCrypto |
||||
|
|
||||
|
.s02_B0F2 |
||||
|
; rept ($4C) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B0F2, $4C ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $DE41 |
||||
|
dbw $01, $DE41 ; ROP_SetAddr |
||||
|
|
||||
|
; s02_ADB1 = $2A7FEC38 |
||||
|
dbl $07, $2A7FEC38 ; ROP_InitCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum = $3C |
||||
|
dbb $02, $3C ; ROP_InitChecksum |
||||
|
|
||||
|
.s02_B10A |
||||
|
; rept ($21) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B10A, $21 ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $DE99 |
||||
|
dbw $01, $DE99 ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum = $E2 |
||||
|
dbb $02, $E2 ; ROP_InitChecksum |
||||
|
|
||||
|
; s02_ADB1 = $4BFC1115 |
||||
|
dbl $07, $4BFC1115 ; ROP_InitCrypto |
||||
|
|
||||
|
.s02_B11E |
||||
|
; rept ($40) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B11E, $40 ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; s02_ADB1 = $A23F387C |
||||
|
dbl $07, $A23F387C ; ROP_InitCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum = $16 |
||||
|
dbb $02, $16 ; ROP_InitChecksum |
||||
|
|
||||
|
; sSaveSource = $A003 |
||||
|
dbw $01, $A003 ; ROP_SetAddr |
||||
|
|
||||
|
.s02_B132 |
||||
|
; rept ($04) { |
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B132, $04 ; ROP_rept |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; ========================================================================== |
||||
|
; End compiling data into save blob. |
||||
|
; ========================================================================== |
||||
|
|
||||
|
|
||||
|
; ========================================================================== |
||||
|
; Apply second layer of crypto onto the save file as a whole. |
||||
|
; The seed for this crypto is based on random bytes, |
||||
|
; which are stored in the final blob as well. |
||||
|
; ========================================================================== |
||||
|
|
||||
|
; sSaveBlockChecksum = $00 |
||||
|
dbb $02, $00 ; ROP_InitChecksum |
||||
|
|
||||
|
; sSaveSource = $FFE1 |
||||
|
dbw $01, $FFE1 ; ROP_SetAddr |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; sSaveSource = $B16B |
||||
|
dbw $01, $B16B ; ROP_SetAddr |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $FFE2 |
||||
|
dbw $01, $FFE2 ; ROP_SetAddr |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; sSaveSource = $B16C |
||||
|
dbw $01, $B16C ; ROP_SetAddr |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $FF04 |
||||
|
dbw $01, $FF04 ; ROP_SetAddr |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; sSaveSource = $B16D |
||||
|
dbw $01, $B16D ; ROP_SetAddr |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $FF05 |
||||
|
dbw $01, $FF05 ; ROP_SetAddr |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; w00_C800 = sSaveBlockChecksum |
||||
|
db $0B ; ROP_WriteChecksumByte |
||||
|
|
||||
|
; sSaveSource = $B16E |
||||
|
dbw $01, $B16E ; ROP_SetAddr |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; NOTE: The parameter of this command is modified by the commands above. |
||||
|
; s02_ADB1 = $EFBEADDE |
||||
|
dbl $07, $EFBEADDE ; ROP_InitCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveBlockChecksum = $55 |
||||
|
dbb $02, $55 ; ROP_InitChecksum |
||||
|
|
||||
|
; sSaveSource = $F350 |
||||
|
dbw $01, $F350 ; ROP_SetAddr |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
.s02_B178 |
||||
|
; rept ($1AB) { |
||||
|
; sSaveSource = $F350 |
||||
|
dbw $01, $F350 ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum = *sSaveSource |
||||
|
db $0E ; ROP_LoadByte |
||||
|
|
||||
|
; sSaveBlockChecksum += w00_C800 |
||||
|
db $08 ; ROP_AddChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; sSaveBlockChecksum = *sSaveSource |
||||
|
db $0E ; ROP_LoadByte |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
; } |
||||
|
dbwb $0C, .s02_B178, $D5 ; ROP_rept |
||||
|
dbwb $0C, .s02_B178, $D6 ; ROP_rept |
||||
|
|
||||
|
; sSaveBlockChecksum = $CC |
||||
|
dbb $02, $CC ; ROP_InitChecksum |
||||
|
|
||||
|
; sSaveSource = $ADB1 |
||||
|
dbw $01, $ADB1 ; ROP_SetAddr |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveBlockChecksum ^= w00_C800 |
||||
|
db $09 ; ROP_XorChecksum |
||||
|
|
||||
|
; *(sSaveSource++) = sSaveBlockChecksum |
||||
|
db $0D ; ROP_StoreByte |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; sSaveSource = $F350 |
||||
|
dbw $01, $F350 ; ROP_SetAddr |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
; w00_C800 = *(sSaveSource++) |
||||
|
db $03 ; ROP_FetchByte |
||||
|
|
||||
|
; w00_C800 ^= func(s02_ADB1) |
||||
|
db $05 ; ROP_ApplyCrypto |
||||
|
|
||||
|
; rotatebuffer(w00_C800) |
||||
|
db $06 ; ROP_RotateBuffer |
||||
|
|
||||
|
|
||||
|
; Copy save blob from the buffer to final location in SRAM, and end. |
||||
|
db $04 ; ROP_end |
||||
|
|
||||
|
|
||||
|
; Temporary save location for the DelayFrame return pointer |
||||
|
sVBlankReturnPointer: dw ; s02_B4E6 |
||||
|
|
||||
|
VBlankHook_Save: ; s02_B673 |
||||
|
; Saving hook code |
||||
|
|
||||
|
; Check if the "P" tile is on the screen (part of "PLAYER") |
||||
|
ld a,[$C4CD] ; wTileMap + ??? |
||||
|
cp a,"P" ; $8F |
||||
|
ret nz |
||||
|
|
||||
|
; Check that we're trying to make a textbox for saving the game |
||||
|
ld hl,[sp+$12] |
||||
|
ldi a,[hl] |
||||
|
cp a,LOW(Text_WouldYouLikeToSaveTheGame) |
||||
|
ret nz |
||||
|
ldd a,[hl] |
||||
|
cp a,HIGH(Text_WouldYouLikeToSaveTheGame) |
||||
|
ret nz |
||||
|
|
||||
|
; Change that text pointer to an empty text box (only include the TX_END command) |
||||
|
ld [hl],LOW($0134) |
||||
|
inc hl |
||||
|
ld [hl],HIGH($0134) |
||||
|
|
||||
|
; Change the MapTextbox return address to skip to the end of SaveTheGame_yesorno |
||||
|
ld hl,sp+$16 |
||||
|
ld [hl],LOW(SaveTheGame_yesorno + 27) ; $4BCA |
||||
|
|
||||
|
; Change the SaveTheGame_yesorno return address to skip to SaveMenu.refused |
||||
|
inc hl |
||||
|
inc hl |
||||
|
ld [hl],LOW(SaveMenu.refused) |
||||
|
inc hl |
||||
|
ld [hl],HIGH(SaveMenu.refused) |
||||
|
|
||||
|
; Overwrite return pointer for the vblank hook |
||||
|
ld hl,SaveGame |
||||
|
ld a,l |
||||
|
ld [sVBlankReturnPointer],a |
||||
|
ld a,h |
||||
|
ld [sVBlankReturnPointer + 1],a |
||||
|
ld a,BANK(SaveGame) |
||||
|
ld [wVBlankReturnBank],a ; Overwrite return bank? |
||||
|
ret |
||||
|
|
||||
|
UninstallVBlankHook: ; s02_B711 |
||||
|
ld hl, hTransferVirtualOAM |
||||
|
ld [hl], $3E ; ld a, n8 |
||||
|
inc hl |
||||
|
ld [hl], $C4 |
||||
|
ret |
||||
|
|
||||
|
w00_C800: ds $1b0 ; w00_C800 |
||||
|
w00_C9AF: ; w00_C9AF |
||||
|
|
||||
|
wOptions: db ; w01_CFCC |
||||
|
wPartyCount: db ; w01_DCD7 |
||||
|
|
||||
|
w01_DF34: db |
||||
|
wVBlankReturnBank: db ; w01_DF35 |
||||
|
wSavingAllowed: db ; w01_DF3A |
Binary file not shown.
@ -0,0 +1,30 @@ |
|||||
|
|
||||
|
; Break for: |
||||
|
; BC=1A5 |
||||
|
; BC=1A6 |
||||
|
; BC=1A7 |
||||
|
; BC=1A8 |
||||
|
|
||||
|
; Hook this at 02:AF1F |
||||
|
; Unhook when 02:B13D is read (original: ADBA) |
||||
|
ld a, [$AD42] |
||||
|
ld c, a |
||||
|
ld a, [$AD43] |
||||
|
ld b, a |
||||
|
nop |
||||
|
ld a, c |
||||
|
ret |
||||
|
|
||||
|
; Hook this at the end of 02:AFDD |
||||
|
ld a, [$AD42] |
||||
|
ld c, a |
||||
|
ld a, [$AD43] |
||||
|
ld b, a |
||||
|
inc bc |
||||
|
ld a, c |
||||
|
ld [$AD42], a |
||||
|
ld a, b |
||||
|
ld [$AD43], a |
||||
|
|
||||
|
ld sp, $AE18 |
||||
|
ret |
Binary file not shown.
@ -0,0 +1,41 @@ |
|||||
|
$0394 - and a |
||||
|
$0831 - ld hl, n16 |
||||
|
$08F1 - ld bc, n16 |
||||
|
$0933 - xor b |
||||
|
$09A2 - ld bc, de, hl, af, n16 |
||||
|
$09A4 - ld hl, af, n16 |
||||
|
$0D8E - ld c, a |
||||
|
$106A - inc de |
||||
|
$106A - inc de |
||||
|
$1380 - dec de |
||||
|
$1447 - inc hl |
||||
|
$1489 - ld b, a |
||||
|
$1708 - jp hl |
||||
|
$1898 - ld a, [de] |
||||
|
$18D0 - ld a, e |
||||
|
$18DC - ld c, l |
||||
|
$1C85 - ldw hl, [hl] |
||||
|
$1D17 - add hl, bc |
||||
|
$1FA5 - ld e, a |
||||
|
$1FEE - ld [hl], b |
||||
|
$2250 - ld [hl+], a |
||||
|
$2CAD - ld a, c |
||||
|
$2DE0 - or [hl] |
||||
|
$2EC9 - dec a |
||||
|
$3351 - ld [hl], d |
||||
|
$37C2 - inc a |
||||
|
$3E3D - add a |
||||
|
$4128 - ld [de], a |
||||
|
$4404 - ld b, h |
||||
|
$4D6A - ld d, b |
||||
|
$50EC - ld d, [hl] |
||||
|
$65E1 - inc [hl] |
||||
|
$ADBA - ld a, [hl+] |
||||
|
$ADBC - ld a, [hl-] |
||||
|
$ADBE - ld [hl], c |
||||
|
$ADC0 - ld b, [hl] |
||||
|
$ADC2 - add b |
||||
|
$ADC4 - srl a |
||||
|
$ADC7 - xor [hl] |
||||
|
$ADC9 - call z, n16 |
||||
|
$ADCC - add [hl]/xor [hl] |
@ -0,0 +1,196 @@ |
|||||
|
#include <stdio.h> |
||||
|
|
||||
|
// Final buffer goes at 3:A100 of the save file
|
||||
|
|
||||
|
char buf[0x1b0]; |
||||
|
|
||||
|
int s02_ADB1; |
||||
|
|
||||
|
char s02_ADB1_b; |
||||
|
char s02_ADB2; |
||||
|
char s02_ADB3; |
||||
|
char s02_ADB4; |
||||
|
|
||||
|
char sSaveBlockChecksum; |
||||
|
|
||||
|
char func() |
||||
|
{ |
||||
|
s02_ADB1_b = (s02_ADB1 >> 0) & 0xFF; |
||||
|
s02_ADB2 = (s02_ADB1 >> 8) & 0xFF; |
||||
|
s02_ADB3 = (s02_ADB1 >> 16) & 0xFF; |
||||
|
s02_ADB4 = (s02_ADB1 >> 24) & 0xFF; |
||||
|
|
||||
|
s02_ADB2 ^= (s02_ADB1_b + 1) ^ s02_ADB4; |
||||
|
s02_ADB3 += s02_ADB2; |
||||
|
s02_ADB4 = s02_ADB2 ^ (s02_ADB4 + (s02_ADB3 / 2)); |
||||
|
|
||||
|
s02_ADB1 = (s02_ADB4 << 24) | (s02_ADB3 << 16) | (s02_ADB2 << 8) | s02_ADB1_b; |
||||
|
|
||||
|
return s02_ADB4; |
||||
|
} |
||||
|
|
||||
|
int main() |
||||
|
{ |
||||
|
int bufi = 0; |
||||
|
|
||||
|
// sSaveSource = $FCDF;
|
||||
|
sSaveBlockChecksum = 0x7F; |
||||
|
s02_ADB1 = 0x8C10E62F; |
||||
|
for (int i = 0; i < 0x48; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
bufi++; |
||||
|
|
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
sSaveBlockChecksum ^= buf[bufi]; |
||||
|
buf[bufi] ^= func(); |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
// sSaveSource = $FA7A;
|
||||
|
sSaveBlockChecksum = 0xC2; |
||||
|
s02_ADB1 = 0x6AF528C2; |
||||
|
for (int i = 0; i < 0x14; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum ^= buf[bufi]; |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
// sSaveSource = $F84E;
|
||||
|
for (int i = 0; i < 0x03; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
bufi++; |
||||
|
} |
||||
|
|
||||
|
// sSaveSource = $F859;
|
||||
|
sSaveBlockChecksum = 0x06; |
||||
|
s02_ADB1 = 0xEF7305A6; |
||||
|
for (int i = 0; i < 0x4C; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum ^= buf[bufi]; |
||||
|
bufi++; |
||||
|
|
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
// sSaveSource = $DE41;
|
||||
|
s02_ADB1 = 0x2A7FEC38; |
||||
|
sSaveBlockChecksum = 0x3C; |
||||
|
for (int i = 0; i < 0x21; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
buf[bufi] ^= func(); |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
// sSaveSource = $DE99;
|
||||
|
sSaveBlockChecksum = 0xE2; |
||||
|
s02_ADB1 = 0x4BFC1115; |
||||
|
for (int i = 0 ; i < 0x40; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
s02_ADB1 = 0xA23F387C; |
||||
|
sSaveBlockChecksum = 0x16; |
||||
|
// sSaveSource = $A003;
|
||||
|
for (int i = 0; i < 0x04; i++) { |
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
buf[bufi] ^= func(); |
||||
|
sSaveBlockChecksum ^= buf[bufi]; |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
bufi++; |
||||
|
} |
||||
|
buf[bufi] = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
sSaveBlockChecksum = 0x00; |
||||
|
|
||||
|
// sSaveSource = $FFE1;
|
||||
|
buf[bufi] = (char)(bufi & 0xFF); |
||||
|
sSaveBlockChecksum += buf[bufi]; |
||||
|
sSaveSource = 0xB16B; |
||||
|
*(sSaveSource++) = sSaveBlockChecksum; |
||||
|
bufi++; |
||||
|
|
||||
|
// sSaveSource = $FFE2;
|
||||
|
// buf[bufi] = *(sSaveSource++);
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// buf[bufi] = sSaveBlockChecksum;
|
||||
|
// sSaveSource = $B16C;
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
|
||||
|
// sSaveSource = $FF04;
|
||||
|
// buf[bufi] = *(sSaveSource++);
|
||||
|
// sSaveBlockChecksum += buf[bufi];
|
||||
|
// buf[bufi] = sSaveBlockChecksum;
|
||||
|
// sSaveSource = $B16D;
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// sSaveSource = $FF05;
|
||||
|
// buf[bufi] = *(sSaveSource++);
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// buf[bufi] = sSaveBlockChecksum;
|
||||
|
// sSaveSource = $B16E;
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// s02_ADB1 = $EFBEADDE;
|
||||
|
// bufi++;
|
||||
|
// bufi++;
|
||||
|
// sSaveBlockChecksum = $55;
|
||||
|
// sSaveSource = $F350;
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// rept ($1AB) {;
|
||||
|
// sSaveSource = $F350;
|
||||
|
// sSaveBlockChecksum = *sSaveSource;
|
||||
|
// sSaveBlockChecksum += buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// sSaveBlockChecksum = *sSaveSource;
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// buf[bufi] ^= func(s02_ADB1);
|
||||
|
// bufi++;
|
||||
|
// };
|
||||
|
|
||||
|
// sSaveBlockChecksum = $CC;
|
||||
|
// sSaveSource = $ADB1;
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// sSaveBlockChecksum ^= buf[bufi];
|
||||
|
// *(sSaveSource++) = sSaveBlockChecksum;
|
||||
|
// bufi++;
|
||||
|
// sSaveSource = $F350;
|
||||
|
// buf[bufi] = *(sSaveSource++);
|
||||
|
// buf[bufi] ^= func(s02_ADB1);
|
||||
|
// bufi++;
|
||||
|
// buf[bufi] = *(sSaveSource++);
|
||||
|
// buf[bufi] ^= func(s02_ADB1);
|
||||
|
// bufi++;
|
||||
|
} |
@ -0,0 +1,72 @@ |
|||||
|
# These are the patches I used to speed through the game. |
||||
|
# They include: |
||||
|
# - All pokemon's stats and HP are max when sent into battle |
||||
|
# - HP bars deplete instantly (to avoid destiny bond softlocking the game...) |
||||
|
# - No trainers can spot you (used to solve PK1 mostly) |
||||
|
|
||||
|
diff --git a/Makefile b/Makefile
|
||||
|
index e213bf63c..812cb9799 100644
|
||||
|
--- a/Makefile
|
||||
|
+++ b/Makefile
|
||||
|
@@ -89,6 +89,7 @@ endif
|
||||
|
pokecrystal.gbc: $(crystal_obj) pokecrystal.link |
||||
|
$(RGBLINK) -n pokecrystal.sym -m pokecrystal.map -l pokecrystal.link -o $@ $(crystal_obj) |
||||
|
$(RGBFIX) -Cjv -i BYTE -k 01 -l 0x33 -m 0x10 -p 0 -r 3 -t PM_CRYSTAL $@ |
||||
|
+ dd bs=1 if=baserom.gbc of=pokecrystal.gbc count=2 conv=notrunc skip=334 seek=334
|
||||
|
tools/sort_symfile.sh pokecrystal.sym |
||||
|
|
||||
|
pokecrystal11.gbc: $(crystal11_obj) pokecrystal.link |
||||
|
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
|
||||
|
index 38abbb51f..f752e4d46 100644
|
||||
|
--- a/engine/battle/core.asm
|
||||
|
+++ b/engine/battle/core.asm
|
||||
|
@@ -3884,11 +3884,13 @@ InitBattleMon:
|
||||
|
ld bc, MON_NAME_LENGTH |
||||
|
call CopyBytes |
||||
|
ld hl, wBattleMonAttack |
||||
|
- ld de, wPlayerStats
|
||||
|
+ ld a, $ff
|
||||
|
ld bc, PARTYMON_STRUCT_LENGTH - MON_ATK |
||||
|
- call CopyBytes
|
||||
|
- call ApplyStatusEffectOnPlayerStats
|
||||
|
- call BadgeStatBoosts
|
||||
|
+ call ByteFill
|
||||
|
+ ld a, $ff
|
||||
|
+ ld [wBattleMonHP], a
|
||||
|
+ nop
|
||||
|
+ nop
|
||||
|
ret |
||||
|
|
||||
|
BattleCheckPlayerShininess: |
||||
|
diff --git a/engine/overworld/events.asm b/engine/overworld/events.asm
|
||||
|
index a84d72db4..9d1dd8d44 100644
|
||||
|
--- a/engine/overworld/events.asm
|
||||
|
+++ b/engine/overworld/events.asm
|
||||
|
@@ -294,8 +294,10 @@ PlayerEvents:
|
||||
|
CheckTrainerBattle_GetPlayerEvent: |
||||
|
nop |
||||
|
nop |
||||
|
- call CheckTrainerBattle
|
||||
|
- jr nc, .nope
|
||||
|
+ nop
|
||||
|
+ nop
|
||||
|
+ nop
|
||||
|
+ jr .nope
|
||||
|
|
||||
|
ld a, PLAYEREVENT_SEENBYTRAINER |
||||
|
scf |
||||
|
diff --git a/engine/pokemon/health.asm b/engine/pokemon/health.asm
|
||||
|
index d11a073b5..0cd97d237 100644
|
||||
|
--- a/engine/pokemon/health.asm
|
||||
|
+++ b/engine/pokemon/health.asm
|
||||
|
@@ -104,7 +104,9 @@ ComputeHPBarPixels:
|
||||
|
ret |
||||
|
|
||||
|
AnimateHPBar: |
||||
|
- call WaitBGMap
|
||||
|
+ ret
|
||||
|
+ ret
|
||||
|
+ ret
|
||||
|
call _AnimateHPBar |
||||
|
call WaitBGMap |
||||
|
ret |
Loading…
Reference in new issue