-
Notifications
You must be signed in to change notification settings - Fork 2
/
hack.asm
2543 lines (2298 loc) · 64.6 KB
/
hack.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
arch snes.cpu
// LoROM org macro - see bass's snes-cpu.asm "seek" macro
macro reorg n
org ((({n}) & 0x7f0000) >> 1) | (({n}) & 0x7fff)
base {n}
endmacro
// Warn if the current address is greater than the specified value.
macro warnpc n
{#}:
if {#} > {n}
warning "warnpc assertion failure"
endif
endmacro
// Allows saving the current location and seeking somewhere else.
define savepc push origin, base
define loadpc pull base, origin
// Warn if the expression is false.
macro static_assert n
if ({n}) == 0
warning "static assertion failure"
endif
endmacro
// Copy the original ROM
{reorg $808000}
incbin "Rockman X (J) (V1.0) [!].smc"
// Version tags
eval version_major 2
eval version_minor 3
eval version_revision 2
// Constants
eval stage_intro 0
eval stage_sigma1 9
eval stage_sigma2 10
eval stage_sigma3 11
eval stage_sigma4 12
eval game_config_size $17
eval magic_sram_tag_lo $4143 // Combined, these say "CATS"
eval magic_sram_tag_hi $5354
eval magic_config_tag_lo $4643 // Combined, these say "CFG4"
eval magic_config_tag_hi $3447
// RAM addresses
eval title_screen_option $7E003C
eval controller_1_current $7E00A7
eval controller_1_previous $7E00A9
eval controller_1_new $7E00AB
eval controller_2_current $7E00AD
eval controller_2_previous $7E00AF
eval controller_2_new $7E00B1
eval screen_control_shadow $7E00B3
eval nmi_control_shadow $7E00C2
eval hdma_control_shadow $7E00C3
eval rng_value $7E0BA6
eval controller_1_disable $7E1F48
eval state_vars $7E1F70
eval current_level $7E1F7A
eval life_count $7E1F80
eval midpoint_flag $7E1F81
eval weapon_power $7E1F85
eval intro_completed $7E1F9B
eval config_selected_option $7EFF80
eval config_data $7EFFC0
eval config_shot $7EFFC0
eval config_jump $7EFFC1
eval config_dash $7EFFC2
eval config_select_l $7EFFC3
eval config_select_r $7EFFC4
eval config_menu $7EFFC5
eval config_bgm $7EFFC8
eval config_se $7EFFC9
eval config_sound $7EFFCA
eval spc_state_shadow $7EFFFE
// Temporary storage for load process. Overlaps game use.
eval load_temporary_rng $7F0000
// ROM addresses
eval rom_play_music $80878B
eval rom_play_sound $8088B6
eval rom_rtl_instruction $808798 // last instruction of rom_play_sound
eval rom_rts_instruction $8087D0 // last instruction of some part of rom_play_music
eval rom_nmi_after_pushes $808173
eval rom_nmi_after_controller $8081DD
eval rom_config_loop $80EAAA
eval rom_config_button $80EB55
eval rom_config_stereo $80EBE8
eval rom_config_bgm $80EC30
eval rom_config_se $80EC74
eval rom_config_exit $80ECC0
eval rom_rng_next $849086
eval rom_string_table $86910B
eval rom_string_table_unused $869193 // first unused string in rom_string_table
eval rom_string_table_end $8691F5 // one past the end of rom_string_table
eval rom_default_config $86EE23
eval rom_bank84_string_table $84FF00 // where to put the master string table (free space in ROM)
eval rom_bank84_string_table_max $850000 // warn if table goes past here
// Constants derived from ROM addresses
eval num_used_string_table ({rom_string_table_unused} - {rom_string_table}) / 2
// SRAM addresses for saved states
eval sram_start $700000
eval sram_wram_7E0000 $710000
eval sram_wram_7E8000 $720000
eval sram_wram_7F0000 $730000
eval sram_wram_7F8000 $740000
eval sram_vram_0000 $750000
eval sram_vram_8000 $760000
eval sram_cgram $772000
eval sram_oam $772200
eval sram_dma_bank $770000
eval sram_validity $774000
eval sram_saved_sp $774004
eval sram_vm_return $774006
eval sram_previous_command $774008
// SRAM addresses for general config. These are at lower addresses to support
// emulators and cartridges that don't support 256 KB of SRAM.
eval sram_config_valid $700100
eval sram_config_game $700104 // Main game config. game_config_size bytes.
eval sram_config_extra {sram_config_game} + {game_config_size}
eval sram_config_category {sram_config_extra} + 0
eval sram_config_route {sram_config_extra} + 1
eval sram_config_midpointsoff {sram_config_extra} + 2
eval sram_config_keeprng {sram_config_extra} + 3
eval sram_config_musicoff {sram_config_extra} + 4
eval sram_config_godmode {sram_config_extra} + 5
eval sram_config_fixdrop {sram_config_extra} + 6
eval sram_config_delay {sram_config_extra} + 7
eval sram_config_extra_size 8 // adjust this as more are added
eval sram_size $080000
// Header edits
{savepc}
// Change SRAM size to 256 KB
{reorg $80FFD8}
db $08
{loadpc}
// Init hook
{savepc}
{reorg $808012}
jml init_hook
{loadpc}
// Disable protection routines (needed because we add SRAM)
// Thanks to devin of The Cutting Room Floor for documenting these checks.
{savepc}
{reorg $81816F}
lda.b #$01
nop
nop
{reorg $81852A}
lda.b #$01
nop
nop
{reorg $849D0B}
lda.b #$01
nop
nop
{reorg $84A471} // $84A3BF checks for patches near here
lda.b #$01
nop
nop
// Patching check for the 84A471 check above.
// Break this only for the performance increase, since we modify
// this routine elsewhere.
{reorg $84A3BF}
rtl
// Mirroring checks. Doubt we need to patch these.
//{reorg $81824A}
//bra $81824F
//{reorg $849FC3}
//bra $849FC8
{loadpc}
// Disable stage intros.
{savepc}
// bne 9597 -> bra 9597
{reorg $8095A2}
bra $809597
{loadpc}
// Disable interstage password screen.
{savepc}
// Always use password screen state 3, which is used to exit to stage select.
// States are offsets into a jump table, so they're multiplied by 2.
{reorg $80EFC2}
ldx.b #3 * 2
{loadpc}
// Disable ending - return to stage select after Sigma 4.
{savepc}
// Make check for completing Sigma 4 fail.
{reorg $809C01}
bra $809C06
{loadpc}
// Stage select hack
{savepc}
{reorg $80BFED}
stage_choice_hack:
// We come in when the user chooses an option in stage select.
// A=00 through 0F, where A=(x * 4) + y, with x and y in 0-3.
tax
lda.l .stage_map, x
// We're about to overwrite this memory, so we can use it as temporary
// storage for these coming lookups.
sta.w {state_vars}
stz.w {state_vars} + 1 // for 16-bit adc below
php
rep #$30
pha
phx
phy
// Convert route to index into state_table_lookup.
sep #$20
// Category times 5.
lda.l {sram_config_category}
asl
asl // clears carry since category is small
adc.l {sram_config_category} // carry still clear
// Plus route.
adc.l {sram_config_route}
// Multiply by 2 because each pointer is a word.
asl
rep #$21 // clear carry
and.w #$00FF
tax
lda.l state_table_lookup, x
// After finding the right table, add 2 times the level.
adc.w {state_vars}
adc.w {state_vars}
tax
// Is select being held?
sep #$20
lda.w {controller_1_current}+1
and.b #$20
beq .not_holding_select
// Read the second element of the table when holding select.
inx
.not_holding_select:
// Get the table index byte.
lda.l state_bank & $FF0000, x
// Copy the state variables in.
// Multiply by 48 = 3 * 16. Do the math with the * 3 first because we
// only have 1 byte of temporary storage.
sta.b $02 // the replaced code zeros this anyway; see below.
asl // clears carry because number is small enough (max is $0C)
adc.b $02
// The multiply by 3 won't overflow into the high byte (A was less than
// $55), but this multiply by 16 can.
rep #$30
and.w #$00FF
asl
asl
asl
asl // clears carry because number is small enough (max is $0FF0)
// memcpy the state variables we want.
adc.w #state_table_base
tax
.state_vars_copy:
sep #$20
ldy.w #{state_vars}
// For some reason, I couldn't get mvn to work!
lda.b #$30
sta.b $02
.copy_loop:
lda.l state_table_base & $FF0000, x
sta 0, y
inx
iny
dec.b $02
bne .copy_loop
rep #$20
// Restore state.
ply
plx
pla
plp
// Replaced code to trigger starting a level.
inc.b $01
inc.b $01
stz.b $02
inc.b $15
rts
.stage_map:
db 9, 1, 8, 10
db 3, 0, 0, 4
db 5, 0, 0, 7
db 11, 6, 2, 12
{loadpc}
// Infinite lives hack
{savepc}
{reorg $809B40}
patch_infinite_lives:
bra .nextline
.nextline:
lda.w {life_count}
{loadpc}
// Start at stage select instead of intro
{savepc}
{reorg $8094EF}
patch_skip_intro:
// Replaces "stz". A is already $10, conveniently =)
sta.w {intro_completed}
{loadpc}
// Show all stages as highlighted regardless of game state
{savepc}
{reorg $80C141}
patch_always_unbeaten:
and.b #$00
{loadpc}
// Set stage select cursor according to previous level.
{savepc}
{reorg $80BD16}
// Don't set Launch Octopus as selected level if previous level was intro.
// Done by deleting code.
patch_fix_stage_select_cursor:
bra .always
// Old code
lda.b #1
sta.w {current_level}
.always:
// Delete check for Sigma levels; handle Sigma levels normally.
ldx.b $1E
bra .always2
lda.b #9
.always2:
// Load correct coordinates for the map ID, with Sigma levels and intro.
sta.b $1D // not sure what this does
nop // remove decrement!
tax
lda.w stage_select_inverse_x, x
sta.b $04
lda.w stage_select_inverse_y, x
sta.b $07
{loadpc}
// Title screen text edits:
// Add "Practice Edition".
// Change "Game Start" to "Practice".
// Remove "Password".
{savepc}
{reorg $869349}
patch_main_menu_text:
macro optionset label, attrib1, attrib2
db .edition_{label}_end - .edition_{label}_begin, $38
dw $138E >> 1
.edition_{label}_begin:
db "- Practice Edition -"
.edition_{label}_end:
db .option1_{label}_end - .option1_{label}_begin, {attrib1}
dw $1514 >> 1
.option1_{label}_begin:
db "PRACTICE"
.option1_{label}_end:
db .option2_{label}_end - .option2_{label}_begin, {attrib2}
dw $1614 >> 1
.option2_{label}_begin:
db "OPTION MODE"
.option2_{label}_end:
endmacro
.optionset1:
{optionset s1, $24, $20}
db 0
.optionset2:
{optionset s2, $20, $24}
db 0
{reorg $86912B}
dw .optionset1
dw .optionset1
dw .optionset2
{loadpc}
// Change intro text =^-^=
{savepc}
{reorg $84CE10}
db "ROCKMAN X PRACTICE EDITION"
db $80, $87, $0A
db "Ver. "
db $30 + {version_major}, '.', $30 + {version_minor}, $30 + {version_revision}
db " "
{reorg $84CE4B}
db "2014-2018 "
{reorg $84CE5C}
db "Myria and Total"
{loadpc}
// Make the useless hidden "PASS WORD" option unavailable.
{savepc}
// The original code handles both Up and Down button presses on the title
// screen separately, obviously. But we only have two options, indexes 0
// and 2, so we can just XOR by 2. Note that Select is treated as Down.
{reorg $80925C}
bit.b #$2C
beq $80928B
lda.b {title_screen_option}
eor.b #$02
bra $809276
{loadpc}
// Make "ESCAPE.U" always work
{savepc}
{reorg $80C950}
escape_u_hack:
lda.w {current_level}
bra .nextline1 // replace
.nextline1:
cmp.b #{stage_sigma1}
bra .nextline2
.nextline2:
asl
tax
lda.w {weapon_power} + 1, x
lda.b #$40
bra .nextline3
.nextline3:
rts
{loadpc}
// Make the four corners of stage select all be Sigma.
// stage_select_render_hook later in this file puts the numbers 1-4 on top
// of the Sigma icons.
{savepc}
// Redirect tilemaps for Stage/Map/Spec at those for Sigma icon.
{reorg $869B00 + 4}
dw $E990
{reorg $869B07 + 4}
dw $E990
{reorg $869B0E + 4}
dw $E990
{reorg $869B15 + 4}
dw $E990
{reorg $869B1C + 4}
dw $E990
{reorg $869B23 + 4}
dw $E990
// Show Storm Eagle's stage picture as his "alive" state. We need this
// because the state of RAM at this point is him dead.
{reorg $869B7E + 4}
dw $E510
// Always show Sigma in lower right, and switch palette from Rockman X
// to the Sigma icon palette.
{reorg $80BDC5}
nop
nop
// Show Sigma even though "show Sigma" flag in RAM is clear.
{reorg $80C10C}
nop
nop
// When highlighting the corners, show Sigma in the middle.
// When highlighting the middle, show the city.
{reorg $869BE3}
db $12, $0A, $10, $12
db $0D, $07, $07, $0E
db $0F, $07, $07, $11
db $12, $0B, $0C, $12
// Palette map table for the same.
{reorg $869C13}
db $6F, $67, $6C, $6F
db $68, $C8, $C8, $6A
db $6B, $C8, $C8, $6E
db $6F, $6D, $69, $6F
// The indexes above are double before calling $828011, but this doubling
// is done as 8-bit. We need the full 16-bit result in order to get the
// "city" palette working.
{reorg $80C131}
jmp palette_multiply_hack
// Same hack, but for when returning to the character selection screen
// from within a stage.
{reorg $80BDFF}
// JSR instead of JMP because we don't RTS right afterward.
jsr palette_multiply_hack
nop
nop
nop
{loadpc}
// *** START OF BANK 80 HACKS ***
// Added code/data
{reorg $80FBD0}
// Hook end of stage select BG3 tilemap rendering so we can change the stage select screen.
{savepc}
{reorg $80B2F8}
// jmp instead of jml because our code is in the same bank.
jmp stage_select_render_hook
{loadpc}
stage_select_render_hook:
// At entry, A = 8-bit, X/Y = 16-bit.
// Deleted code
stx.b $F8
stz.b $F4
// Is this rendering from bank A2?
// "A" register destroyed by original code when we return.
lda.b $F5 + 2
cmp.b #$A2
bne .not_stage_select
// Did this just render the BG3 tilemap of stage select?
lda.b $F5 + 0
ora.b $F5 + 1
bne .not_stage_select
// A2:C672 = end of compressed BG3 stage select tilemap.
cpy.w #$C672
bne .not_stage_select
// OK, this is what we wanted to hook.
// NOTE: We don't need to restore A back to 8-bit, because 8080F8 does sep #$30.
rep #$20
lda.w #$3431 // ASCII character "1" in yellow palette
sta.l $7F0190
inc
sta.l $7F01B4
inc
sta.l $7F0610
inc
sta.l $7F0634
lda.l {sram_config_category}
and.w #$00FF
bne .skip_hold_select_message
phx
phy
ldx.w #0
.string_loop:
lda.l .stage_select_text_begin, x
tay
txa
asl
tax
tya
and.w #$00FF
ora.w #$3400
sta.l $7F06C8, x
txa
lsr
tax
inx
cpx.w #.stage_select_text_end - .stage_select_text_begin
bne .string_loop
ply
plx
.skip_hold_select_message:
.not_stage_select:
// jmp instead of jml because our code is in the same bank.
jmp $8080F8
.stage_select_text_begin:
db "HOLD SELECT FOR REVISITS"
.stage_select_text_end:
// The indexes above are double before calling $828011, but this doubling
// is done as 8-bit. We need the full 16-bit result in order to get the
// "city" palette working.
palette_multiply_hack:
// Switch to 16-bit for this.
rep #$30
// The high byte of A is set to random crap at this point.
and.w #$00FF
// Double here and put into Y.
asl
tay
// Call the routine, then return ourselves (we were jumped to, not called).
jsl $828011
// Need to set A/X/Y back to 8-bit before we return, though.
sep #$30
rts
// Hack draw_string to use our custom table.
{savepc}
{reorg $8089CA}
jmp draw_string_hack
{loadpc}
draw_string_hack:
// This assumes that bank doesn't change.
{warnpc $80FFFF}
// Overwritten code
sep #$30
sta.b $02
and.b #$7F // might change this if we need more than 127 strings
asl
tay
// Is this one of our extra strings?
cpy.b #{num_used_string_table} * 2
bcc .old_table
// Switch to the other bank.
phb
pea ({rom_bank84_string_table} >> 16) * $0101
plb
plb
// Refer to the new table instead.
lda {rom_bank84_string_table} - ({num_used_string_table} * 2), y
sta.b $10
lda {rom_bank84_string_table} - ({num_used_string_table} * 2) + 1, y
sta.b $11
// Return to original code.
plb
jmp $8089DC
.old_table:
// Use the original code.
jmp $8089D2
// Warn if the above code overflows the area we have it.
{warnpc $80FF80}
// *** END OF BANK 80 HACKS ***
// *** START OF BANK 86 HACKS ***
// Added data that must be in bank $86.
{reorg $86FA60}
// These tables convert from stage number to X/Y cursor coordinates for stage select.
stage_select_inverse_x:
db 1, 1, 2, 0, 3, 0, 1, 3, 2, 0, 3, 0, 3
stage_select_inverse_y:
db 1, 0, 3, 1, 1, 2, 3, 2, 0, 0, 0, 3, 3
// Configuration screen text hacks.
config_screen_moves:
{savepc}
// Move existing strings
// First group
// JUMP (normal)
{reorg $869588}
dw $1282 >> 1
// JUMP (highlighted)
{reorg $869591}
dw $1282 >> 1
// SHOT (normal)
{reorg $86959A}
dw $1242 >> 1
// SHOT (highlighted)
{reorg $8695A3}
dw $1242 >> 1
// SELECT_R (normal)
{reorg $8695C6}
dw $1342 >> 1
// SELECT_R (highlighted)
{reorg $8695D3}
dw $1342 >> 1
// MENU (normal)
{reorg $8695E0}
dw $1382 >> 1
// MENU (highlighted)
{reorg $8695E9}
dw $1382 >> 1
// EXIT (normal)
{reorg $8695F2}
dw $15EC >> 1
// EXIT (highlighted)
{reorg $8695FB}
dw $15EC >> 1
// BGM (normal)
{reorg $869604}
dw $1642 >> 1
// BGM (highlighted)
{reorg $86960C}
dw $1642 >> 1
// S.E. (normal)
{reorg $869614}
dw $1682 >> 1
// S.E. (highlighted)
{reorg $86961D}
dw $1682 >> 1
// DASH (normal)
{reorg $869626}
dw $12C2 >> 1
// DASH (highlighted)
{reorg $86962F}
dw $12C2 >> 1
// Second group
// " STEREO " (normal)
{reorg $86989F}
dw $14D4 >> 1
// Also overwrite string to move spaces
db "STEREO "
// " STEREO " (highlighted)
{reorg $8698AC}
dw $14D4 >> 1
// Also overwrite string to move spaces
db "STEREO "
// "MONAURAL" (normal)
{reorg $8698B9}
dw $14D4 >> 1
// Also overwrite string to rename "MONO"
db "MONO "
// "MONAURAL" (highlighted)
{reorg $8698C6}
dw $14D4 >> 1
// Also overwrite string to rename "MONO"
db "MONO "
// Button names
{reorg $80ECE3}
lda.w #$1254 >> 1
{reorg $80ECF3}
lda.w #$1294 >> 1
{reorg $80ED03}
lda.w #$12D4 >> 1
{reorg $80ED13}
lda.w #$1314 >> 1
{reorg $80ED23}
lda.w #$1354 >> 1
{reorg $80ED33}
lda.w #$1394 >> 1
{reorg $86BCE8}
// Left-align button names
db "B Y A X L R SELECTSTART * "
// Song number after "BGM".
{reorg $80EDB9}
lda.w #$1654 >> 1
// Effect number after "S.E."
{reorg $80EDFB}
lda.w #$1694 >> 1
// Change "SELECT_L" to "SEL_L".
{reorg $8695AA}
db .select_l1_end - .select_l1_begin, $20
dw $1302 >> 1
.select_l1_begin:
db "SEL_L"
.select_l1_end:
db 0
{reorg $8695B7}
db .select_l2_end - .select_l2_begin, $2C
dw $1302 >> 1
.select_l2_begin:
db "SEL_L"
.select_l2_end:
db 0
// Change "SELECT_R" to "SEL_R".
{reorg $8695C4}
db .select_r1_end - .select_r1_begin, $20
dw $1342 >> 1
.select_r1_begin:
db "SEL_R"
.select_r1_end:
db 0
{reorg $8695D1}
db .select_r2_end - .select_r2_begin, $2C
dw $1342 >> 1
.select_r2_begin:
db "SEL_R"
.select_r2_end:
db 0
{loadpc}
// Macros for creating new option strings.
macro option_string label, string, vramaddr, attribute, terminator
{label}:
db {label}_end - {label}_begin, {attribute}
dw {vramaddr} >> 1
{label}_begin:
db {string}
{label}_end:
if {terminator}
db 0
endif
endmacro
macro option_string_pair label, string, vramaddr
{option_string {label}_normal, {string}, {vramaddr}, $20, 1}
{option_string {label}_highlighted, {string}, {vramaddr}, $2C, 1}
endmacro
// Option category titles.
{savepc}
{reorg $869143}
dw string_option_titles
{loadpc}
string_option_titles:
{option_string .key_config, "KEY CONFIG", $11C6, $38, 0}
{option_string .sound_mode, "SOUND MODE", $1446, $38, 0}
{option_string .sound_test, "SOUND TEST", $15C6, $38, 0}
{option_string .route, "ROUTE", $11EA, $38, 0}
{option_string .misc, "MISC.", $13AA, $38, 0}
db 0
// Extra strings we're adding.
{option_string_pair string_category, "CATEGORY", $1264}
{option_string string_anypercent, "ANY`", $1276, $20, 1}
{option_string string_100percent, "100`", $1276, $20, 1}
{option_string_pair string_mammoth, "MAMMOTH", $12A4}
{option_string string_mammoth_5th, "5TH ", $12B6, $20, 1}
{option_string string_mammoth_6th, "6TH ", $12B6, $20, 1}
{option_string string_mammoth_7th, "7TH ", $12B6, $20, 1}
{option_string string_mammoth_8th, "8TH ", $12B6, $20, 1}
{option_string_pair string_empty_route2, " ", $12E4}
{option_string string_empty_route2_setting, " ", $12F6, $20, 1}
{option_string_pair string_ice, "ICE... ", $12A4}
{option_string string_iceless, "LESS", $12B6, $20, 1}
{option_string string_iceful, "FUL ", $12B6, $20, 1}
{option_string_pair string_water, "WATER...", $12E4}
{option_string string_waterless, "LESS", $12F6, $20, 1}
{option_string string_waterful, "FUL ", $12F6, $20, 1}
{option_string string_chameleon_3rd, "C3RD", $12F6, $20, 1}
{option_string_pair string_output, "OUTPUT", $14C2}
{option_string_pair string_music, "MUSIC", $1502}
{option_string string_music_on, "ON ", $1514, $20, 1}
{option_string string_music_off, "OFF", $1514, $20, 1}
{option_string_pair string_midpoints, "MIDPOINT", $1424}
{option_string string_midpoints_on, "ON ", $1436, $20, 1}
{option_string string_midpoints_off, "OFF", $1436, $20, 1}
{option_string_pair string_keeprng, "KEEP RNG", $1464}
{option_string string_keeprng_on, "ON ", $1476, $20, 1}
{option_string string_keeprng_off, "OFF", $1476, $20, 1}
{option_string_pair string_godmode, "GODMODE", $14A4}
{option_string string_godmode_on, "ON ", $14B6, $20, 1}
{option_string string_godmode_off, "OFF", $14B6, $20, 1}
{option_string_pair string_fixdrop, "FIX DROP", $14E4}
{option_string string_fixdrop_on, "ON ", $14F6, $20, 1}
{option_string string_fixdrop_off, "OFF", $14F6, $20, 1}
{option_string_pair string_delay, "DELAY", $1524}
{option_string string_delay_00f, "00 F", $1536, $20, 1}
{option_string string_delay_30f, "30 F", $1536, $20, 1}
{option_string string_delay_60f, "60 F", $1536, $20, 1}
{option_string string_delay_90f, "90 F", $1536, $20, 1}
// I'm too lazy to rework the compressed font, so I use this to overwrite
// the ` character in VRAM. The field used for the "attribute" of the
// "text" just becomes the high byte of each pair of bytes.
macro tilerow vrambase, rownum, col7, col6, col5, col4, col3, col2, col1, col0
db 1, (({col7} & 2) << 6) | (({col6} & 2) << 5) | (({col5} & 2) << 4) | (({col4} & 2) << 3) | (({col3} & 2) << 2) | (({col2} & 2) << 1) | ({col1} & 2) | (({col0} & 2) >> 1)
dw (({vrambase}) + (({rownum}) * 2)) >> 1
db (({col7} & 1) << 7) | (({col6} & 1) << 6) | (({col5} & 1) << 5) | (({col4} & 1) << 4) | (({col3} & 1) << 3) | (({col2} & 1) << 2) | (({col1} & 1) << 1) | ({col0} & 1)
endmacro
string_percent_sign_bitmap:
{tilerow $0600, 0, 0,2,3,0,0,0,2,3}
{tilerow $0600, 1, 2,3,2,3,0,2,3,0}
{tilerow $0600, 2, 3,1,3,0,1,3,0,0}
{tilerow $0600, 3, 0,3,0,1,3,0,0,0}
{tilerow $0600, 4, 0,0,1,3,0,1,3,0}
{tilerow $0600, 5, 0,2,3,0,2,3,2,3}
{tilerow $0600, 6, 2,3,0,0,3,2,3,0}
{tilerow $0600, 7, 3,0,0,0,0,3,0,0}
db 0
// New additions to string table. This table has reserved entries not being used.
{savepc}
{reorg {rom_bank84_string_table}}
string_table:
macro stringtableentry label
.idcalc_{label}:
dw (string_{label}) & $FFFF
eval stringid_{label} ((string_table.idcalc_{label} - string_table) / 2) + {num_used_string_table}
endmacro
{stringtableentry percent_sign_bitmap}
{stringtableentry 100percent}
{stringtableentry anypercent}
{stringtableentry ice_normal}
{stringtableentry ice_highlighted}
{stringtableentry iceless}
{stringtableentry iceful}
{stringtableentry water_normal}
{stringtableentry water_highlighted}
{stringtableentry waterful}
{stringtableentry waterless}
{stringtableentry chameleon_3rd}
{stringtableentry mammoth_normal}
{stringtableentry mammoth_highlighted}
{stringtableentry mammoth_5th}
{stringtableentry mammoth_6th}
{stringtableentry mammoth_7th}
{stringtableentry mammoth_8th}
{stringtableentry empty_route2_normal}
{stringtableentry empty_route2_highlighted}
{stringtableentry empty_route2_setting}
{stringtableentry output_normal}
{stringtableentry output_highlighted}
{stringtableentry category_normal}
{stringtableentry category_highlighted}
{stringtableentry midpoints_normal}
{stringtableentry midpoints_highlighted}
{stringtableentry midpoints_on} // on, off -> option inverted
{stringtableentry midpoints_off}
{stringtableentry keeprng_normal}
{stringtableentry keeprng_highlighted}
{stringtableentry keeprng_off}
{stringtableentry keeprng_on}
{stringtableentry music_normal}
{stringtableentry music_highlighted}
{stringtableentry music_on} // on, off -> option inverted
{stringtableentry music_off}
{stringtableentry godmode_normal}
{stringtableentry godmode_highlighted}
{stringtableentry godmode_off}
{stringtableentry godmode_on}
{stringtableentry fixdrop_normal}
{stringtableentry fixdrop_highlighted}
{stringtableentry fixdrop_off}
{stringtableentry fixdrop_on}
{stringtableentry delay_normal}
{stringtableentry delay_highlighted}
{stringtableentry delay_00f}
{stringtableentry delay_30f}
{stringtableentry delay_60f}
{stringtableentry delay_90f}
{warnpc {rom_bank84_string_table_max}}
{loadpc}
// Hack initial config menu routine to add more strings.
{savepc}
{reorg $80EA5C}
jml config_menu_start_hook
{loadpc}
config_menu_start_hook:
// We enter with A/X/Y 8-bit and bank set to $86 (our code bank)
// Deleted code. We need to do this first, or 8100 fails.
lda.b #7
tsb.w $7E00A2
ldx.b #0
.string_loop:
lda.w config_menu_extra_string_table, x
phx
beq .string_flush
cmp.b #$FF
beq .special
jsl trampoline_8089CA
bra .string_next
.special:
// Call a function
inx
clc // having carry clear is convenient for these functions
jsr (config_menu_extra_string_table, x)
jsl trampoline_8089CA
plx
inx
inx
bra .special_resume
.string_flush:
jsl trampoline_808100
.string_next:
plx
.special_resume: // save 1 byte by using the extra inx here
inx