-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathactpract_usa.asm
More file actions
2456 lines (2217 loc) · 47.8 KB
/
actpract_usa.asm
File metadata and controls
2456 lines (2217 loc) · 47.8 KB
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
; ActRaiser Practice ROM
; Osteoclave
; 2023-08-16 - Migration from xkas v14 to asar 1.81
; 2020-10-03 - Original version, assembled using xkas v14
asar 1.81
math pri on
math round off
check title "ACTRAISER-USA "
arch 65816
lorom
bank noassume
; SNES registers
incsrc registers.asm
; Vanilla constants
!DMA_CHANNEL_4 = $10
!JOYPAD_B = $8000
!JOYPAD_SELECT = $2000
!JOYPAD_START = $1000
!JOYPAD_UP = $0800
!JOYPAD_DOWN = $0400
!JOYPAD_LEFT = $0200
!JOYPAD_RIGHT = $0100
; Vanilla variables
!currentMap = $18
!changeMap = $1A
!currentHealth = $1D
!maximumHealth = $1E
!playerX = $80
!playerY = $82
!frameCounter = $88
!scheduledHDMA = $92
!vramWriteSource = $D0
!vramWriteDest = $D3
!vramWriteSize = $D5
!swordUpgrade = $E4
!discardInput = $F4
!ignoreInput = $F6
!equippedMagic = $02AC
!rng = $02D1
!deathFlag = $032C
!respawnX = $032E
!respawnY = $0330
!pauseStatus = $0332
!difficulty = $0349
!tilemapBG3 = $7FB000
; Vanilla labels
ShortRandom = $0084C0
CountdownTick = $02BC82
PrintText = $02BF60
UpdateHUD = $02C206
MagicIcons = $06A400
; New variables
; In vanilla, 7E024C-0281 contains the "offering" inventories for each town.
; The practice ROM never enters town-building mode, so we can repurpose this
; memory safely.
!menuCursor = $024C
!heldButton = $024E
!heldCounter = $0250
!countdownOff = $0252
!memoryViewerOn = $0253
; Cached values for the memory viewer
!cacheXH = $0254
!cacheXL = $0255
!cacheYH = $0256
!cacheYL = $0257
!cacheR = $0258
!cacheFH = $0259
!cacheIH = $025A
!cacheIL = $025B
; Joypad input bits, sorted for the input viewer
!inputUDLR = $025C
!inputEL = $025E
!inputTR = $0260
!inputBYAX = $0262
; More new variables
!magicIcon = $0264
!onExitAction = $0266
!currentRoom = $0268
!selectedRoom = $026A
!spcLock = $026C
; "On room load" actions
!autoSetHealth = $026D
!autoSwordUpgrade = $026E
!autoSimDifficulty = $026F
!endOfActRefill = $0270
; New constants
; Number of items in the various selectable menus.
!MENU_LENGTH = 11
!MAGIC_LENGTH = 5
!AUTO_HEALTH_LENGTH = 25
!ON_EXIT_LENGTH = 3
!ROOMS_LENGTH = 55
; Number of eligible destinations when the on-exit action is "RANDOM".
; This is less than the total number of rooms because we don't want
; checkpoints or at-boss spawn points to be eligible destinations.
!DESTINATIONS_LENGTH = 48
; Repeat delay and repeat rate for held buttons.
!REPEAT_DELAY = 15
!REPEAT_RATE = 6
; Windowing registers: Don't invert the windows.
org $02C6CB
lda #$22
; Windowing registers: Disable window 1 on BG3.
org $02C6D0
stz !W34SEL
; Windowing registers: Set window 1's range to zero.
org $02C6D6
lda #$FF
org $02C6DB
lda #$00
; Look for map metadata at 0xF8000 instead of 0x28000.
org $02BE28
lda #$1F
; Insert new text for the title screen.
org $02A9A7
NewTitleScreenText:
db "^ PRACTICE", $0D
db $0D
db " v0.7, 2023-09-22", $0D
db " by Osteoclave"
db $00
; Force the title screen menu to only have one option. (This normally
; happens when there's no save data, and only "START" is displayed.)
org $02A70D
nop
nop
; Print the new text instead of "START" for that one menu option.
org $02A711
lda #$110B
ldy.w #NewTitleScreenText
; Always enter Professional Mode from the title screen menu.
org $008040
nop
nop
; Update the HUD to use the modified font's tiles.
org $028E7E
; First row
dw $0015, $0016, $0017, $0018, $0019, $001A ; "[ACT]"
dw $0C5B, $005D, $0030, $0030, $0000 ; Heart icon and lives remaining
dw $0401, $0402, $0403, $0404 ; "TIME"
dw $0030, $0030, $0030, $0000, $0000, $0000 ; Time remaining and spacer
dw $0405, $0406, $0407, $0408, $0404 ; "SCORE"
dw $0030, $0030, $0030, $0030, $0030, $0000 ; Score
; Second row
dw $0409, $040A, $040B, $040C, $040D, $040E ; "PLAYER"
dw $081B, $081B, $081B, $081B, $081B, $081B ; Health meter
dw $081B, $081B, $081B, $081B, $081B, $081B
dw $0000, $0000, $0000 ; Spacer
dw $005C, $005C, $005C, $005C, $005C, $005C ; MP scrolls
dw $005C, $005C, $005C, $005C, $0000
; Third row ("ENEMY", only visible during boss fights)
org $00A4D3
lda #$240F
; Health meters (player and enemy)
org $02C38F
lda #$1B
org $02C3A5
lda #$1C
org $02C3B3
lda #$1D
org $02C3C4
lda #$1E
org $02C3D3
lda #$1F
; MP scrolls
org $02C2E2
lda #$205C
; Always show 99 lives remaining at the top of the screen.
org $02C28E
lda #$39
org $02C29E
lda #$39
; Upon death, don't restore health: "OnRoomLoad" takes care of that now.
org $0082AB
nop
nop
; Upon death, don't reduce the number of lives remaining.
org $0082B0
nop
nop
nop
; Take control of the countdown timer.
org $0080A0
jsl NewCountdownTick
org $0080DB
jsl NewCountdownTick
; If you have no magic equipped, display the empty-box icon.
org $02BCDB
lda #$0005
; Allow magic to be used at will: no MP required, no MP cost.
org $009E03
bra $03
org $009E0A
nop
nop
; Always show ten MP scrolls at the top of the screen.
org $02C2DC
nop
nop
; Prevent the Magical Stardust spell from doing double damage.
; During object creation, if:
; - The game is in Professional Mode
; - Certain flags on the new object are clear
; - The new object's attack power is equal to one
; Then the new object's attack power is increased to two.
; The other spells are not affected by this boost: Magical Fire and Magical
; Aura both have one of the relevant flags set, and Magical Light's attack
; power is already 2, so it's not eligible.
; Anyway. Let's add some code to keep the attack power of meteors at one.
org $009F7B
lda #$FFA0
org $00FFA0
lda #$0001
sta $002A,x
lda #$A0E8
sta $0012,x
jmp $A0E8
; Merge the 02/BB4C and 02/BC27 functions.
; "JSL $02BB4C" is always followed by "JSL $02BC27", and 02/BB4C is located
; immediately before 02/BC27 in the ROM. If we replace the RTL at the end of
; 02/BB4C with a NOP, we can execute both functions with just "JSL $02BB4C".
; "JSL $02BC27" can then be replaced with a JSL to new code.
; (Specifically, new code to update the memory viewer.)
org $02BC26
nop
org $008098
jsl UpdateMemoryViewer
org $0080D3
jsl UpdateMemoryViewer
; This JSL is executed during room transitions (both fade-out and fade-in).
; BG3 gets cleared during room transitions, and "UpdateMemoryViewer" only
; draws the values that have changed (intentional time-saving behaviour).
; So calling "UpdateMemoryViewer" here could result in a partially-drawn
; memory viewer when the new room loads.
; To avoid that, we use "ForceUpdateMemoryViewer" instead.
org $008304
jsl ForceUpdateMemoryViewer
; When updating the BG3 tilemap in VRAM, include the memory viewer.
org $02AF13
jmp $FF80
org $02FF80
; The accumulator is 8-bit and holds the value of $F1 here.
beq +
; If $F1 is nonzero, we're copying the full BG3 tilemap to VRAM. This will
; copy the memory viewer as well, so we don't need to do anything.
jmp $AF16
+
lda !memoryViewerOn
beq +
ldx #$5B41
stx !VMADDL
ldx #$B682
stx !A1T0L
ldx #$003C
stx !DAS0L
lda #$01
sta !MDMAEN
+
rts
; Skip the "descending ball of light brings statue to life" animation.
org $02AB0D
stz $00FC
; Replace the existing Start-button pause handler.
org $008066
jsl NewPauseHandler
; Perform the "on room load" actions when loading a room. These actions
; happen on all room loads: manual loading, exiting a room, death, etc.
org $00826C
jsl OnRoomLoad
; Always use the respawn coordinates if they're set, not just after a death.
org $009380
nop
nop
; In the event of player death, respawn on the same map.
org $02BD61
nop
nop
lda !currentMap+1
; When fading out the current music in the middle of a stage (e.g. before or
; after a boss battle), acquire a lock to prevent the practice menu from
; being opened.
; We do this because when the practice menu is opened, it sends a command to
; the SPC700 to pause the currently playing music. Normally that doesn't
; cause any problems, but when the SPC700 is in the middle of some other
; communication, an unexpected command can throw things off and cause the
; game to freeze.
org $00A3FE
jsl AcquireSpcLock
org $00A410
jsl ReleaseSpcLock
; On room exit, load the next room according to the current on-exit action.
; 102
org $00B030
jsl LoadNextRoom
rts
; 103
org $00B03B
jsl LoadNextRoom
rts
; 202
org $00B92B
jsl LoadNextRoom
rts
; 203
org $00B939
jsl LoadNextRoom
rts
; 204
org $00B947
jsl LoadNextRoom
rts
; 205
org $00B955
jsl LoadNextRoom
rts
; 206
org $00B963
jsl LoadNextRoom
rts
; 207
org $00B971
jsl LoadNextRoom
rts
; 301
org $00C15E
jsl LoadNextRoom
rts
; 303
org $00C16C
jsl LoadNextRoom
rts
; 304
org $00C186
jsl LoadNextRoom
rts
; 305
org $00C19C
jsl LoadNextRoom
rts
; 401
org $00CDEB
jsl LoadNextRoom
rts
; 402
org $00CDF9
jsl LoadNextRoom
rts
; 404
org $00CE0F
jsl LoadNextRoom
rts
; 405
org $00CE1D
jsl LoadNextRoom
rts
; 406
org $00CE33
jsl LoadNextRoom
rts
; 501
org $00E6C6
jsl LoadNextRoom
rts
; 502
org $00E6D4
jsl LoadNextRoom
rts
; 504
org $00E6EA
jsl LoadNextRoom
rts
; 505 = The room-with-two-exits in the Marahna temple (a special case)
org $00E6F8
lda !playerX
cmp #$0180
bcc +
cmp #$02E0
bcs +
rts
+
jsl LoadNextRoom
rts
; 506 and 507
org $00E71C
jsl LoadNextRoom
rts
; 601
org $00E766
jsl LoadNextRoom
rts
; 602
org $00E774
jsl LoadNextRoom
rts
; 603
org $00E78A
jsl LoadNextRoom
rts
; 605
org $00E7A0
jsl LoadNextRoom
rts
; 606
org $00E7AB
jsl LoadNextRoom
rts
; 607
org $00E7B6
jsl LoadNextRoom
rts
; Upon completing an Act, don't increment the "Acts completed" counter. Load
; the next room according to the current on-exit action.
org $008788
jsl LoadNextRoom
bra $0A
; When completing an Act on Sim difficulty, don't do the score count-up.
org $00A205
nop
nop
; When completing an Act on Sim difficulty, don't return to sim mode.
org $00A2CF
nop
nop
; Upon defeating a boss in the boss rush, don't increment the "bosses
; defeated in the boss rush" counter. Load the next room according to the
; current on-exit action.
org $00FEEC
jsl LoadNextRoom
bra $08
org $00FF00
bra $05
; Prevent animated tiles from glitching.
org $0289E2
db $08
org $028A6E
db $02
org $028AA6
db $02
org $028B32
db $08
org $028B6A
db $04
org $028B86
db $04
org $028BA2
db $04
org $028C2E
db $08
org $028C4A
db $08
org $028C9E
db $08
org $028CBA
db $08
org $028CF2
db $04
org $028D0E
db $04
org $028D2A
db $04
org $028D9A
db $08
org $028DB6
db $08
org $028DEE
db $08
org $028E0A
db $08
; The random-number generation function lives in bank 00 and ends with a
; short return (RTS). We want to generate random numbers from outside that
; bank, so let's create a helper function in bank 00 that ends with a long
; return (RTL).
org $00FFB0
LongRandom:
jsr ShortRandom
rtl
; Use the modified font.
org $17ECFB
incbin actraiser_font_modified_compressed.bin
warnpc $17F7A2
; Updated map metadata: each map now loads all of its required assets.
org $1F8000
incsrc map_metadata_usa.asm
; The following three functions are called as part of the game loop, so we
; want them to be as lean as possible to minimize added lag.
; All of them expect the accumulator to be 8-bit when they are called.
NewCountdownTick:
lda !countdownOff
bne +
jml CountdownTick
+
rtl
UpdateMemoryViewer:
lda !memoryViewerOn
beq +
jsr DrawMemoryViewer
+
rtl
ForceUpdateMemoryViewer:
lda !memoryViewerOn
beq +
jsr InvalidateCache
jsr DrawMemoryViewer
+
rtl
InvalidateCache:
; Player's X coordinate, high byte
lda !playerX+1
eor #$FF
sta !cacheXH
; Player's X coordinate, low byte
lda !playerX
eor #$FF
sta !cacheXL
; Player's Y coordinate, high byte
lda !playerY+1
eor #$FF
sta !cacheYH
; Player's Y coordinate, low byte
lda !playerY
eor #$FF
sta !cacheYL
; RNG state
lda !rng
eor #$FF
sta !cacheR
; Frame counter, high byte
lda !frameCounter+1
eor #$FF
sta !cacheFH
; Frame counter, low byte = Not cached (changes every frame)
; Joypad input, high byte
lda !JOY1H
eor #$FF
sta !cacheIH
; Joypad input, low byte
lda !JOY1L
eor #$FF
sta !cacheIL
rts
DrawMemoryViewer:
php
rep #$20
pha
; Draw the labels if they're absent (e.g. erased by room transition)
lda #$2458
cmp !tilemapBG3+(26<<6)+(1<<1)
beq +
sta !tilemapBG3+(26<<6)+(1<<1)
lda #$2459
sta !tilemapBG3+(26<<6)+(8<<1)
lda #$2452
sta !tilemapBG3+(26<<6)+(20<<1)
lda #$2446
sta !tilemapBG3+(26<<6)+(25<<1)
+
sep #$20
; Player's X coordinate, high byte
ldx.w #3<<1
lda !playerX+1
cmp !cacheXH
beq +
sta !cacheXH
jsr DrawByte
+
; Player's X coordinate, low byte
ldx.w #5<<1
lda !playerX
cmp !cacheXL
beq +
sta !cacheXL
jsr DrawByte
+
; Player's Y coordinate, high byte
ldx.w #10<<1
lda !playerY+1
cmp !cacheYH
beq +
sta !cacheYH
jsr DrawByte
+
; Player's Y coordinate, low byte
ldx.w #12<<1
lda !playerY
cmp !cacheYL
beq +
sta !cacheYL
jsr DrawByte
+
; RNG state
ldx.w #22<<1
lda !rng
cmp !cacheR
beq +
sta !cacheR
jsr DrawByte
+
; Frame counter, high byte
ldx.w #27<<1
lda !frameCounter+1
cmp !cacheFH
beq +
sta !cacheFH
jsr DrawByte
+
; Frame counter, low byte
; This is not cached because it's expected to change every frame
ldx.w #29<<1
lda !frameCounter
jsr DrawByte
; Has the joypad input changed?
lda !JOY1H
cmp !cacheIH
bne .InputChanged
lda !JOY1L
cmp !cacheIL
beq .InputUnchanged
.InputChanged:
stz !inputBYAX
stz !inputEL
stz !inputTR
; Joypad input, high byte
lda !JOY1H
sta !cacheIH
and #$0F
sta !inputUDLR
lda !JOY1H
asl
rol !inputBYAX
asl
rol !inputBYAX
asl
rol !inputEL
asl
rol !inputTR
; Joypad input, low byte
lda !JOY1L
sta !cacheIL
asl
rol !inputBYAX
asl
rol !inputBYAX
asl
rol !inputEL
asl
rol !inputTR
; Draw the input display
rep #$20
lda !inputUDLR
ora #$2880
sta !tilemapBG3+(26<<6)+(15<<1)
lda !inputEL
ora #$287C
sta !tilemapBG3+(26<<6)+(16<<1)
lda !inputTR
ora #$687C
sta !tilemapBG3+(26<<6)+(17<<1)
lda !inputBYAX
ora #$2890
sta !tilemapBG3+(26<<6)+(18<<1)
.InputUnchanged:
rep #$20
pla
plp
rts
DrawByte:
; First digit
pha
lsr
lsr
lsr
lsr
ora #$30
sta !tilemapBG3+(26<<6),x
inx
inx
pla
; Second digit
and #$0F
ora #$30
sta !tilemapBG3+(26<<6),x
inx
inx
rts
EraseMemoryViewer:
lda #$00
sta !tilemapBG3+(26<<6)+(1<<1)
sta !tilemapBG3+(26<<6)+(3<<1)
sta !tilemapBG3+(26<<6)+(4<<1)
sta !tilemapBG3+(26<<6)+(5<<1)
sta !tilemapBG3+(26<<6)+(6<<1)
sta !tilemapBG3+(26<<6)+(8<<1)
sta !tilemapBG3+(26<<6)+(10<<1)
sta !tilemapBG3+(26<<6)+(11<<1)
sta !tilemapBG3+(26<<6)+(12<<1)
sta !tilemapBG3+(26<<6)+(13<<1)
sta !tilemapBG3+(26<<6)+(15<<1)
sta !tilemapBG3+(26<<6)+(16<<1)
sta !tilemapBG3+(26<<6)+(17<<1)
sta !tilemapBG3+(26<<6)+(18<<1)
sta !tilemapBG3+(26<<6)+(20<<1)
sta !tilemapBG3+(26<<6)+(22<<1)
sta !tilemapBG3+(26<<6)+(23<<1)
sta !tilemapBG3+(26<<6)+(25<<1)
sta !tilemapBG3+(26<<6)+(27<<1)
sta !tilemapBG3+(26<<6)+(28<<1)
sta !tilemapBG3+(26<<6)+(29<<1)
sta !tilemapBG3+(26<<6)+(30<<1)
rts
AcquireSpcLock:
sep #$20
lda #$01
sta !spcLock
lda #$F1
rtl
ReleaseSpcLock:
sep #$20
stz !spcLock
lda #$F1
rtl
NewPauseHandler:
lda !pauseStatus
bmi .Done
bne .Paused
lda !JOY1H
bit.b #!JOYPAD_START>>8
beq .Done
; Don't open the practice menu if other code has acquired spcLock
lda !spcLock
bne .Done
; Open the practice menu
jsr PracticeMenu
rtl
.Paused:
; Stay in the "paused" state until the Start button has been released
lda !JOY1H
bit.b #!JOYPAD_START>>8
bne .Done
stz !pauseStatus
.Done:
rtl
PracticeMenu:
; Switch to bank 1F
; The "PrintText" function's "text pointer" argument is a short pointer,
; so we have to set the data bank register to make it read from the
; correct bank.
phb
lda #$1F
pha
plb
; Enter the "paused" state
inc !pauseStatus
; Pause the music
lda #$F2
sta !APUIO0
; Draw the window
lda #$01
sta !DMAP4
lda #$26
sta !BBAD4
ldx.w #WindowData
stx !A1T4L
lda.b #WindowData>>16
sta !A1B4
lda #!DMA_CHANNEL_4
tsb !scheduledHDMA
; Set initial menu variables
rep #$20
stz !menuCursor
stz !heldButton
stz !heldCounter
lda !equippedMagic
and #$00FF
sta !magicIcon
lda !currentRoom
sta !selectedRoom
; Draw the menu
jsr DrawMenu
; Wait for the Start button to be released
lda #!JOYPAD_START
jsr WaitForKeyup
.Loop:
; Practice menu behaviour: Select button
lda #!JOYPAD_SELECT
bit !JOY1L
beq +
pha
sep #$20
lda #!DMA_CHANNEL_4
trb !scheduledHDMA
rep #$20
jsr EraseMenu
pla
jsr WaitForKeyup
sep #$20
lda #!DMA_CHANNEL_4
tsb !scheduledHDMA
rep #$20
jsr DrawMenu
+
; Practice menu behaviour: Start button
lda #!JOYPAD_START
bit !JOY1L
beq +
jmp .Break
+
; Practice menu behaviour: Up button
lda #!JOYPAD_UP
jsr CheckButton
bcc ++
lda !menuCursor
dec
bpl +
lda.w #!MENU_LENGTH-1
+
sta !menuCursor
jmp .RedrawMenu
++
; If the Up button is being held, and we're here because the button is
; in cooldown, skip to the next frame.
bit !JOY1L
beq +
jmp .NextFrame
+
; Practice menu behaviour: Down button
lda #!JOYPAD_DOWN
jsr CheckButton
bcc ++
lda !menuCursor
inc
cmp.w #!MENU_LENGTH
bcc +
lda.w #0
+
sta !menuCursor
jmp .RedrawMenu
++
; If the Down button is being held, and we're here because the button is
; in cooldown, skip to the next frame.
bit !JOY1L
beq +
jmp .NextFrame
+
; Menu option behaviour
lda !menuCursor
.ResumeGame:
cmp.w #0
bne .AdjustHealth
lda #!JOYPAD_B
bit !JOY1L
beq +
; Prevent this B-press from making the player jump
trb !ignoreInput
jmp .Break
+
jmp .NextFrame
.AdjustHealth:
cmp.w #1
bne .ToggleCountdown
; Adjust health behaviour: B button
lda #!JOYPAD_B
bit !JOY1L
beq +
pha
sep #$20
lda !maximumHealth
sta !currentHealth
rep #$20
jsl UpdateHUD
pla
jsr WaitForKeyup
jmp .NextFrame
+
; Adjust health behaviour: Left button
lda #!JOYPAD_LEFT
jsr CheckButton
bcc ++
sep #$20
lda !currentHealth
cmp #$02
bcc +
dec
sta !currentHealth
+
rep #$20
jsl UpdateHUD
jmp .NextFrame
++
; Adjust health behaviour: Right button
lda #!JOYPAD_RIGHT
jsr CheckButton
bcc ++
sep #$20
lda !currentHealth
cmp !maximumHealth
bcs +
inc
sta !currentHealth
+
rep #$20
jsl UpdateHUD
++