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