diff --git a/bin/DMGTRIS.GBC b/bin/DMGTRIS.GBC index 96dc7ec..4ada00d 100644 Binary files a/bin/DMGTRIS.GBC and b/bin/DMGTRIS.GBC differ diff --git a/bin/DMGTRIS.pocket b/bin/DMGTRIS.pocket index 39c94f8..2404940 100644 Binary files a/bin/DMGTRIS.pocket and b/bin/DMGTRIS.pocket differ diff --git a/src/bankid.asm b/src/bankid.asm index c1c40cd..4d71c05 100644 --- a/src/bankid.asm +++ b/src/bankid.asm @@ -19,29 +19,50 @@ IF !DEF(BANKID_ASM) DEF BANKID_ASM EQU 1 -SECTION "Bank ID 0", ROM0[$0] - REPT 7 - rst $00 - ENDR - db $00 +INCLUDE "globals.asm" -SECTION "Bank ID 1", ROMX[$4000], BANK[1] - REPT 7 - rst $00 - ENDR - db $01 -SECTION "Bank ID 2", ROMX[$4000], BANK[2] - REPT 7 - rst $00 - ENDR - db $02 +SECTION "Bank ID BANK_MAIN", ROM0[$0] +REPT 7 + rst $00 +ENDR +db BANK_MAIN -SECTION "Bank ID 3", ROMX[$4000], BANK[3] - REPT 7 - rst $00 - ENDR - db $03 +SECTION "Bank ID BANK_OTHER", ROMX[$4000], BANK[BANK_OTHER] +REPT 7 + rst $00 +ENDR +db BANK_OTHER + +SECTION "Bank ID BANK_SFX", ROMX[$4000], BANK[BANK_SFX] +REPT 7 + rst $00 +ENDR +db BANK_SFX + +SECTION "Bank ID BANK_MUSIC", ROMX[$4000], BANK[BANK_MUSIC] +REPT 7 + rst $00 +ENDR +db BANK_MUSIC + +SECTION "Bank ID BANK_TITLE", ROMX[$4000], BANK[BANK_TITLE] +REPT 7 + rst $00 +ENDR +db BANK_TITLE + +SECTION "Bank ID BANK_GAMEPLAY", ROMX[$4000], BANK[BANK_GAMEPLAY] +REPT 7 + rst $00 +ENDR +db BANK_GAMEPLAY + +SECTION "Bank ID BANK_GAMEPLAY_BIG", ROMX[$4000], BANK[BANK_GAMEPLAY_BIG] +REPT 7 + rst $00 +ENDR +db BANK_GAMEPLAY_BIG ENDC diff --git a/src/banking.asm b/src/banking.asm index 1a621f2..16f7255 100644 --- a/src/banking.asm +++ b/src/banking.asm @@ -22,23 +22,37 @@ DEF BANKING_ASM EQU 1 INCLUDE "globals.asm" -SECTION "High Banking Variables", HRAM -hBankBackup: ds 1 +SECTION "Banking Variables", WRAM0 +wBankBackup: ds 4 SECTION "Switch Bank", ROM0[$08] - ; Saves the current bank and switches to the bank in b. + ; Pushes the current bank to the stach, switches to bank in B. RSTSwitchBank:: + ld a, [wBankBackup+2] + ld [wBankBackup+3], a + ld a, [wBankBackup+1] + ld [wBankBackup+2], a + ld a, [wBankBackup+0] + ld [wBankBackup+1], a ld a, [rBANKID] - ldh [hBankBackup], a + ld [wBankBackup+0], a ld a, b ld [rROMB0], a ret -SECTION "Restore Bank", ROM0[$18] - ; Restore the bank previously saved. The current one is not saved. +SECTION "Restore Bank", ROM0[$28] + ; Pops a bank from the stack ans switches to it. RSTRestoreBank:: - ld a, [hBankBackup] + ld a, [wBankBackup+0] + ld b, a + ld a, [wBankBackup+1] + ld [wBankBackup+0], a + ld a, [wBankBackup+2] + ld [wBankBackup+1], a + ld a, [wBankBackup+3] + ld [wBankBackup+2], a + ld a, b ld [rROMB0], a ret diff --git a/src/constants.asm b/src/constants.asm deleted file mode 100644 index 553dd2a..0000000 --- a/src/constants.asm +++ /dev/null @@ -1,940 +0,0 @@ -; DMGTRIS -; Copyright (C) 2023 - Randy Thiemann - -; This program is free software: you can redistribute it and/or modify -; it under the terms of the GNU General Public License as published by -; the Free Software Foundation, either version 3 of the License, or -; (at your option) any later version. - -; This program is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. - -; You should have received a copy of the GNU General Public License -; along with this program. If not, see . - - -IF !DEF(CONSTANTS_ASM) -DEF CONSTANTS_ASM EQU 1 - -CHARMAP " ", 1 -CHARMAP "0", 66 -CHARMAP "1", 67 -CHARMAP "2", 68 -CHARMAP "3", 69 -CHARMAP "4", 70 -CHARMAP "5", 71 -CHARMAP "6", 72 -CHARMAP "7", 73 -CHARMAP "8", 74 -CHARMAP "9", 75 -CHARMAP "A", 76 -CHARMAP "B", 77 -CHARMAP "C", 78 -CHARMAP "D", 79 -CHARMAP "E", 80 -CHARMAP "F", 81 -CHARMAP "G", 82 -CHARMAP "H", 83 -CHARMAP "I", 84 -CHARMAP "J", 85 -CHARMAP "K", 86 -CHARMAP "L", 87 -CHARMAP "M", 88 -CHARMAP "N", 89 -CHARMAP "O", 90 -CHARMAP "P", 91 -CHARMAP "Q", 92 -CHARMAP "R", 93 -CHARMAP "S", 94 -CHARMAP "T", 95 -CHARMAP "U", 96 -CHARMAP "V", 97 -CHARMAP "W", 98 -CHARMAP "X", 99 -CHARMAP "Y", 100 -CHARMAP "Z", 101 -CHARMAP "!", 102 -CHARMAP "?", 103 -CHARMAP "[", 129 -CHARMAP "]", 130 -CHARMAP "/", 128 -CHARMAP "-", 127 -CHARMAP "#", 126 -CHARMAP ".", 216 -CHARMAP ":", 222 - - -SECTION "Static Data", ROMX, BANK[1] -sLeady:: db " READY? " -sGo:: db " GO " -sPause:: - db "P A U S E " - db " P A U S E" -sOption0:: - db "NORM" - db " INV" -sOption1:: - db "TGM1" - db "TGM2" - db "TGM3" - db "HELL" - db " NES" -sOption2:: - db "ARS1" - db "ARS2" - db " NES" -sOption3:: - db "FIRM" - db "SNIC" - db "HARD" - db "LOCK" - db "NONE" -sOption4:: - db "DMGT" - db "TGM1" - db "TGM3" - db "DEAT" - db "SHIR" - db "CHIL" -sOption5:: - db " NO" - db " YES" -sDisabled:: - db "----" - -sEasterM0:: db $C4, $C6, $C8, $CA, $CC -sEasterM1:: db $C5, $C7, $C9, $CB, $CD -sEasterC0:: db $CE, $D0, $C8, $CA, $CC, $72, $74, $76, $78, $7A, $D6, $D7 -sEasterC1:: db $CF, $D1, $C9, $CB, $CD, $73, $75, $77, $79, $7B, $01, $01 -sEasterA0:: db $D2, $D4, $C8, $CA, $CC, $72, $74, $76, $78, $7A, $D6, $D7 -sEasterA1:: db $D3, $D5, $C9, $CB, $CD, $73, $75, $77, $79, $7B, $01, $01 -sEasterS0:: db $F7, $F9, $C8, $CA, $CC -sEasterS1:: db $F8, $FA, $C9, $CB, $CD - -sPieceXOffsets:: ; How to draw each piece. X-offsets of the sprites. - db 0, 8, 16, 24 ; I - db 0, 8, 8, 16 ; Z - db 0, 8, 8, 16 ; S - db 0, 8, 16, 16 ; J - db 0, 0, 8, 16 ; L - db 8, 8, 16, 16 ; O - db 0, 8, 8, 16 ; T - -sPieceYOffsets:: ; How to draw each piece. Y-offsets of the sprites. - db 0, 0, 0, 0 ; I - db 0, 0, 7, 7 ; Z - db 7, 7, 0, 0 ; S - db 0, 0, 0, 7 ; J - db 7, 0, 0, 0 ; L - db 0, 7, 0, 7 ; O - db 0, 0, 7, 0 ; T - -; Speed curve data is defined as follows: -; N blocks of: -; dw BCD_START_LEVEL, START_LEVEL, BCD_NEXT_100_LEVEL_BREAKPOINT -; db GRID_CELLS_PER_MOVE_ON_OVERFLOW, INCREMENT_PER_FRAME (0 means overflow each frame) -; db NORMAL_ARE, LINE_ARE, DAS, LOCK_DELAY, CLEAR_DELAY -; -; Followed by one single: -; dw $FFFF -sDMGTSpeedCurve:: ; Speed curve of the game. - dw $0000, 0, $0100 ; Level 0000 - db 1, 16 - db 25, 15, 14, 30, 40 - - dw $0015, 15, $0100 ; Level 0015 - db 1, 17 - db 25, 15, 14, 30, 40 - - dw $0030, 30, $0100 ; Level 0030 - db 1, 18 - db 25, 15, 14, 30, 40 - - dw $0040, 40, $0100 ; Level 0040 - db 1, 20 - db 25, 15, 14, 30, 40 - - dw $0050, 50, $0100 ; Level 0050 - db 1, 21 - db 25, 15, 14, 30, 40 - - dw $0060, 60, $0100 ; Level 0060 - db 1, 23 - db 25, 15, 14, 30, 40 - - dw $0070, 70, $0100 ; Level 0070 - db 1, 26 - db 25, 15, 14, 30, 40 - - dw $0080, 80, $0100 ; Level 0080 - db 1, 28 - db 25, 15, 14, 30, 40 - - dw $0090, 90, $0100 ; Level 0090 - db 1, 32 - db 25, 15, 14, 30, 40 - - dw $0100, 100, $0200 ; Level 0100 - db 1, 37 - db 25, 15, 14, 30, 40 - - dw $0150, 150, $0200 ; Level 0150 - db 1, 43 - db 25, 15, 14, 30, 40 - - dw $0200, 200, $0300 ; Level 0200 - db 1, 51 - db 25, 15, 14, 30, 40 - - dw $0225, 225, $0300 ; Level 0225 - db 1, 64 - db 25, 15, 14, 30, 40 - - dw $0250, 250, $0300 ; Level 0250 - db 1, 85 - db 25, 15, 14, 30, 40 - - dw $0275, 275, $0300 ; Level 0275 - db 1, 128 - db 25, 15, 14, 30, 40 - - dw $0300, 300, $0400 ; Level 0300 - db 1, $00 - db 25, 7, 14, 30, 32 - - dw $0350, 350, $0350 ; Level 0350 - db 2, $00 - db 25, 7, 14, 30, 32 - - dw $0400, 400, $0400 ; Level 0400 - db 3, $00 - db 25, 7, 14, 30, 32 - - dw $0450, 450, $0500 ; Level 0450 - db 4, $00 - db 25, 7, 14, 30, 32 - - dw $0475, 475, $0500 ; Level 0475 - db 5, $00 - db 25, 7, 14, 30, 32 - - dw $0500, 500, $0600 ; Level 0500 - db 20, $00 - db 25, 6, 14, 30, 24 - - dw $0600, 600, $0700 ; Level 0600 - db 20, $00 - db 25, 6, 8, 30, 24 - - dw $0700, 700, $0800 ; Level 0700 - db 20, $00 - db 20, 6, 8, 30, 24 - - dw $0900, 900, $1000 ; Level 0900 - db 20, $00 - db 16, 4, 6, 25, 16 - - dw $1100, 1100, $1200 ; Level 1100 - db 20, $00 - db 12, 4, 6, 25, 16 - - dw $1200, 1200, $1300 ; Level 1200 - db 20, $00 - db 12, 4, 6, 25, 8 - - dw $1300, 1300, $1400 ; Level 1300 - db 20, $00 - db 10, 4, 6, 20, 7 - - dw $1400, 1400, $1500 ; Level 1400 - db 20, $00 - db 10, 4, 6, 18, 6 - - dw $1500, 1500, $1600 ; Level 1500 - db 20, $00 - db 8, 4, 4, 16, 5 - - dw $1600, 1600, $1700 ; Level 1600 - db 20, $00 - db 8, 4, 4, 14, 4 - - dw $1700, 1700, $1800 ; Level 1700 - db 20, $00 - db 6, 4, 4, 12, 3 - - dw $1800, 1800, $1900 ; Level 1800 - db 20, $00 - db 6, 4, 4, 10, 3 - - dw $1900, 1900, $2000 ; Level 1900 - db 20, $00 - db 4, 4, 4, 8, 3 - - dw $2000, 2000, $2100 ; Level 2000 - db 20, $00 - db 4, 4, 3, 8, 3 - - dw $2500, 2500, $2600 ; Level 2500 - db 20, $00 - db 2, 2, 1, 8, 2 - - dw $3000, 3000, $3100 ; Level 3000 - db 20, $00 - db 1, 1, 1, 8, 1 - - dw $4000, 4000, $4100 ; Level 4000 - db 20, $00 - db 1, 1, 1, 6, 1 - - dw $5000, 5000, $5100 ; Level 5000 - db 20, $00 - db 1, 1, 1, 4, 1 - - dw $6666, 6666, $6700 ; Level 6666 - db 20, $00 - db 1, 1, 1, 2, 1 - - dw $9999, 9999, $9999 ; Level 9999 - db 20, $00 - db 1, 1, 1, 1, 1 - -sDMGTSpeedCurveEnd:: - dw $FFFF ; End. - -sTGM1SpeedCurve:: - dw $0000, 0, $0100 - db 1, 4 - db 30, 30, 16, 30, 41 - - dw $0030, 30, $0100 - db 1, 6 - db 30, 30, 16, 30, 41 - - dw $0035, 35, $0100 - db 1, 8 - db 30, 30, 16, 30, 41 - - dw $0040, 40, $0100 - db 1, 10 - db 30, 30, 16, 30, 41 - - dw $0050, 50, $0100 - db 1, 12 - db 30, 30, 16, 30, 41 - - dw $0060, 60, $0100 - db 1, 16 - db 30, 30, 16, 30, 41 - - dw $0070, 70, $0100 - db 1, 32 - db 30, 30, 16, 30, 41 - - dw $0080, 80, $0100 - db 1, 48 - db 30, 30, 16, 30, 41 - - dw $0090, 90, $0100 - db 1, 64 - db 30, 30, 16, 30, 41 - - dw $0100, 100, $0200 - db 1, 80 - db 30, 30, 16, 30, 41 - - dw $0120, 120, $0200 - db 1, 96 - db 30, 30, 16, 30, 41 - - dw $0140, 140, $0200 - db 1, 112 - db 30, 30, 16, 30, 41 - - dw $0160, 160, $0200 - db 1, 128 - db 30, 30, 16, 30, 41 - - dw $0170, 170, $0200 - db 1, 144 - db 30, 30, 16, 30, 41 - - dw $0200, 200, $0300 - db 1, 4 - db 30, 30, 16, 30, 41 - - dw $0220, 220, $0300 - db 1, 32 - db 30, 30, 16, 30, 41 - - dw $0230, 230, $0300 - db 1, 64 - db 30, 30, 16, 30, 41 - - dw $0233, 233, $0300 - db 1, 96 - db 30, 30, 16, 30, 41 - - dw $0236, 236, $0300 - db 1, 128 - db 30, 30, 16, 30, 41 - - dw $0239, 239, $0300 - db 1, 160 - db 30, 30, 16, 30, 41 - - dw $0243, 243, $0300 - db 1, 192 - db 30, 30, 16, 30, 41 - - dw $0247, 239, $0300 - db 1, 224 - db 30, 30, 16, 30, 41 - - dw $0251, 251, $0300 - db 1, $00 - db 30, 30, 16, 30, 41 - - dw $0300, 300, $0400 - db 2, $00 - db 30, 30, 16, 30, 41 - - dw $0330, 330, $0400 - db 3, $00 - db 30, 30, 16, 30, 41 - - dw $0360, 360, $0400 - db 4, $00 - db 30, 30, 16, 30, 41 - - dw $0400, 400, $0500 - db 5, $00 - db 30, 30, 16, 30, 41 - - dw $0420, 420, $0500 - db 4, $00 - db 30, 30, 16, 30, 41 - - dw $0450, 450, $0500 - db 3, $00 - db 30, 30, 16, 30, 41 - - dw $0500, 500, $0600 - db 20, $00 - db 30, 30, 16, 30, 41 - -sTGM1SpeedCurveEnd:: - dw $FFFF - - -sCHILSpeedCurve:: - dw $0000, 0, $0100 - db 1, 5 - db 10, 10, 16, 25, 17 - - dw $0100, 100, $0200 - db 1, 6 - db 10, 10, 16, 25, 17 - - dw $0200, 200, $0300 - db 1, 7 - db 10, 10, 16, 25, 17 - - dw $0300, 300, $0400 - db 1, 8 - db 10, 10, 16, 25, 17 - - dw $0400, 400, $0500 - db 1, 9 - db 10, 10, 16, 25, 17 - - dw $0500, 500, $0600 - db 1, 11 - db 10, 10, 16, 25, 17 - - dw $0600, 600, $0700 - db 1, 14 - db 10, 10, 16, 25, 17 - - dw $0700, 700, $0800 - db 1, 20 - db 10, 10, 16, 25, 17 - - dw $0800, 800, $0900 - db 1, 32 - db 10, 10, 16, 25, 17 - - dw $0900, 900, $1000 - db 1, 43 - db 10, 10, 16, 25, 17 - - dw $1000, 1000, $1100 - db 1, 51 - db 10, 10, 16, 25, 17 - - dw $1300, 1300, $1400 - db 1, 64 - db 10, 10, 16, 25, 17 - - dw $1600, 1600, $1700 - db 1, 85 - db 10, 10, 16, 25, 17 - - dw $1900, 1900, $2000 - db 1, 128 - db 10, 10, 16, 25, 17 - - dw $2900, 2900, $3000 - db 1, $00 - db 10, 10, 16, 25, 17 - - dw $3333, 3333, $3400 - db 2, $00 - db 10, 10, 12, 25, 17 - - dw $4444, 4444, $4500 - db 3, $00 - db 10, 10, 12, 25, 17 - - dw $5555, 5555, $5600 - db 4, $00 - db 10, 10, 12, 25, 17 - - dw $6666, 6666, $6700 - db 5, $00 - db 10, 10, 12, 25, 17 - - dw $7777, 7777, $7800 - db 20, $00 - db 10, 10, 8, 25, 17 - - dw $8888, 8888, $8900 - db 20, $00 - db 10, 10, 6, 18, 17 - - dw $9999, 9999, $9999 - db 20, $00 - db 5, 5, 6, 14, 10 - -sCHILSpeedCurveEnd:: - dw $FFFF - - -sTGM3SpeedCurve:: - dw $0000, 0, $0100 - db 1, 4 - db 27, 27, 16, 30, 40 - - dw $0030, 30, $0100 - db 1, 6 - db 27, 27, 16, 30, 40 - - dw $0035, 35, $0100 - db 1, 8 - db 27, 27, 16, 30, 40 - - dw $0040, 40, $0100 - db 1, 10 - db 27, 27, 16, 30, 40 - - dw $0050, 50, $0100 - db 1, 12 - db 27, 27, 16, 30, 40 - - dw $0060, 60, $0100 - db 1, 16 - db 27, 27, 16, 30, 40 - - dw $0070, 70, $0100 - db 1, 32 - db 27, 27, 16, 30, 40 - - dw $0080, 80, $0100 - db 1, 48 - db 27, 27, 16, 30, 40 - - dw $0090, 90, $0100 - db 1, 64 - db 27, 27, 16, 30, 40 - - dw $0100, 100, $0200 - db 1, 80 - db 27, 27, 16, 30, 40 - - dw $0120, 120, $0200 - db 1, 96 - db 27, 27, 16, 30, 40 - - dw $0140, 140, $0200 - db 1, 112 - db 27, 27, 16, 30, 40 - - dw $0160, 160, $0200 - db 1, 128 - db 27, 27, 16, 30, 40 - - dw $0170, 170, $0200 - db 1, 144 - db 27, 27, 16, 30, 40 - - dw $0200, 200, $0300 - db 1, 4 - db 27, 27, 16, 30, 40 - - dw $0220, 220, $0300 - db 1, 32 - db 27, 27, 16, 30, 40 - - dw $0230, 230, $0300 - db 1, 64 - db 27, 27, 16, 30, 40 - - dw $0233, 233, $0300 - db 1, 96 - db 27, 27, 16, 30, 40 - - dw $0236, 236, $0300 - db 1, 128 - db 27, 27, 16, 30, 40 - - dw $0239, 239, $0300 - db 1, 160 - db 27, 27, 16, 30, 40 - - dw $0243, 243, $0300 - db 1, 192 - db 27, 27, 16, 30, 40 - - dw $0247, 239, $0300 - db 1, 224 - db 27, 27, 16, 30, 40 - - dw $0251, 251, $0300 - db 1, $00 - db 27, 27, 16, 30, 40 - - dw $0300, 300, $0400 - db 2, $00 - db 27, 27, 16, 30, 40 - - dw $0330, 330, $0400 - db 3, $00 - db 27, 27, 16, 30, 40 - - dw $0360, 360, $0400 - db 4, $00 - db 27, 27, 16, 30, 40 - - dw $0400, 400, $0500 - db 5, $00 - db 27, 27, 16, 30, 40 - - dw $0420, 420, $0500 - db 4, $00 - db 27, 27, 16, 30, 40 - - dw $0450, 450, $0500 - db 3, $00 - db 27, 27, 16, 30, 40 - - dw $0500, 500, $0600 - db 20, $00 - db 27, 27, 10, 30, 25 - - dw $0600, 600, $0700 - db 20, $00 - db 27, 18, 10, 30, 16 - - dw $0700, 700, $0800 - db 20, $00 - db 18, 14, 10, 30, 12 - - dw $0800, 800, $0900 - db 20, $00 - db 14, 8, 10, 30, 6 - - dw $0900, 900, $1000 - db 20, $00 - db 14, 8, 8, 17, 6 - - dw $1000, 1000, $1100 - db 20, $00 - db 8, 8, 8, 17, 6 - - dw $1100, 1000, $1200 - db 20, $00 - db 7, 7, 8, 15, 6 - - dw $1200, 1000, $1300 - db 20, $00 - db 6, 6, 8, 15, 6 - -sTGM3SpeedCurveEnd:: - dw $FFFF - -sDEATSpeedCurve:: - dw $0000, 0, $0100 - db 20, $00 - db 18, 14, 12, 30, 12 - - dw $0100, 0, $0200 - db 20, $00 - db 14, 8, 12, 26, 6 - - dw $0200, 0, $0300 - db 20, $00 - db 14, 8, 11, 22, 6 - - dw $0300, 0, $0400 - db 20, $00 - db 8, 8, 10, 18, 6 - - dw $0400, 0, $0500 - db 20, $00 - db 7, 7, 8, 15, 5 - - dw $0500, 0, $0600 - db 20, $00 - db 6, 6, 8, 15, 4 - -sDEATSpeedCurveEnd:: - dw $FFFF - -sSHIRSpeedCurve:: - dw $0000, 0, $0100 - db 20, $00 - db 12, 8, 10, 18, 6 - - dw $0100, 100, $0200 - db 20, $00 - db 12, 7, 8, 18, 5 - - dw $0200, 200, $0300 - db 20, $00 - db 12, 6, 8, 17, 4 - - dw $0300, 300, $0400 - db 20, $00 - db 6, 6, 8, 15, 4 - - dw $0500, 500, $0600 - db 20, $00 - db 6, 5, 6, 13, 3 - - dw $1100, 1100, $1200 - db 20, $00 - db 6, 5, 6, 10, 3 - - dw $1200, 1200, $1300 - db 20, $00 - db 6, 5, 6, 8, 3 - -sSHIRSpeedCurveEnd:: - dw $FFFF - -sPieceFastRotationStates:: - ; I - db 14, 1, 1, 1 - db 2, 14, 14, 14 - db 14, 1, 1, 1 - db 2, 14, 14, 14 - - ; Z - db 14, 1, 14, 1 - db 2, 13, 1, 13 - db 14, 1, 14, 1 - db 2, 13, 1, 13 - - ; S - db 15, 1, 12, 1 - db 0, 14, 1, 14 - db 15, 1, 12, 1 - db 0, 14, 1, 14 - - ; J - db 14, 1, 1, 14 - db 1, 1, 13, 14 - db 14, 14, 1, 1 - db 1, 14, 13, 1 - - ; L - db 14, 1, 1, 12 - db 1, 14, 14, 1 - db 16, 12, 1, 1 - db 0, 1, 14, 14 - - ; O - db 15, 1, 13, 1 - db 15, 1, 13, 1 - db 15, 1, 13, 1 - db 15, 1, 13, 1 - - ; T - db 14, 1, 1, 13 - db 1, 14, 1, 13 - db 15, 13, 1, 1 - db 1, 13, 1, 14 - -sPieceRotationStates:: ; How each piece is rotated. - ; I - db %0000 - db %1111 - db %0000 - db %0000 - - db %0010 - db %0010 - db %0010 - db %0010 - - db %0000 - db %1111 - db %0000 - db %0000 - - db %0010 - db %0010 - db %0010 - db %0010 - - ; Z - db %0000 - db %1100 - db %0110 - db %0000 - - db %0010 - db %0110 - db %0100 - db %0000 - - db %0000 - db %1100 - db %0110 - db %0000 - - db %0010 - db %0110 - db %0100 - db %0000 - - ; S - db %0000 - db %0110 - db %1100 - db %0000 - - db %1000 - db %1100 - db %0100 - db %0000 - - db %0000 - db %0110 - db %1100 - db %0000 - - db %1000 - db %1100 - db %0100 - db %0000 - - ; J - db %0000 - db %1110 - db %0010 - db %0000 - - db %0110 - db %0100 - db %0100 - db %0000 - - db %0000 - db %1000 - db %1110 - db %0000 - - db %0100 - db %0100 - db %1100 - db %0000 - - ; L - db %0000 - db %1110 - db %1000 - db %0000 - - db %0100 - db %0100 - db %0110 - db %0000 - - db %0000 - db %0010 - db %1110 - db %0000 - - db %1100 - db %0100 - db %0100 - db %0000 - - ; O - db %0000 - db %0110 - db %0110 - db %0000 - - db %0000 - db %0110 - db %0110 - db %0000 - - db %0000 - db %0110 - db %0110 - db %0000 - - db %0000 - db %0110 - db %0110 - db %0000 - - ; T - db %0000 - db %1110 - db %0100 - db %0000 - - db %0100 - db %0110 - db %0100 - db %0000 - - db %0000 - db %0100 - db %1110 - db %0000 - - db %0100 - db %1100 - db %0100 - db %0000 - -sTGM3Bag:: - db 0, 0, 0, 0, 0 - db 1, 1, 1, 1, 1 - db 2, 2, 2, 2, 2 - db 3, 3, 3, 3, 3 - db 4, 4, 4, 4, 4 - db 5, 5, 5, 5, 5 - db 6, 6, 6, 6, 6 - -sTGM3Droughts:: - db 0, 0, 0, 0, 0, 0, 0 - - -ENDC diff --git a/src/field.asm b/src/field.asm index dc63a97..c3c4a28 100644 --- a/src/field.asm +++ b/src/field.asm @@ -61,7 +61,64 @@ hBravo: ds 1 hShouldLockIfGrounded: ds 1 -SECTION "Field Functions", ROM0 +SECTION "Field Function Unbanked", ROM0 + ; Blits the field onto the tile map. + ; On the GBC, this chain calls into a special version that takes + ; advantage of the GBC's CPU. +BlitField:: + ld a, [wInitialA] + cp a, $11 + jp z, GBCBlitField + + ; What to copy + ld de, wField + 40 + ; Where to put it + ld hl, FIELD_TOP_LEFT + ; How much to increment hl after each row + ld bc, 32-10 + + ; The first 14 rows can be blitted without checking for vram access. + REPT 14 + REPT 10 + ld a, [de] + ld [hl+], a + inc de + ENDR + add hl, bc + ENDR + +: ldh a, [rLY] + cp a, 0 + jr nz, :- + + ; The last 6 rows need some care. + REPT 6 + ; Wait until start of drawing, then insert 35 nops. +: ldh a, [rSTAT] + and a, 3 + cp a, 3 + jr nz, :- + REPT 35 + nop + ENDR + + ; Blit a line. + REPT 10 + ld a, [de] + ld [hl+], a + inc de + ENDR + + ; Increment HL so that the next line can be blitted. + add hl, bc + ENDR + + ; This function is actually called as the vblank handler for the gameplay state. + ; This is why it jumps straight back to the event loop. + jp EventLoop + + +SECTION "Field Function Banked Gameplay", ROMX, BANK[BANK_GAMEPLAY] ; Initializes the field completely blank. ; Initializes the combo counter to 1. ; Initializes the bravo counter to 0. @@ -149,63 +206,6 @@ FromShadowField: jr nz, .outer ret - - ; Blits the field onto the tile map. - ; On the GBC, this chain calls into a special version that takes - ; advantage of the GBC's CPU. -BlitField:: - ld a, [wInitialA] - cp a, $11 - jp z, GBCBlitField - - ; What to copy - ld de, wField + 40 - ; Where to put it - ld hl, FIELD_TOP_LEFT - ; How much to increment hl after each row - ld bc, 32-10 - - ; The first 14 rows can be blitted without checking for vram access. - REPT 14 - REPT 10 - ld a, [de] - ld [hl+], a - inc de - ENDR - add hl, bc - ENDR - -: ldh a, [rLY] - cp a, 0 - jr nz, :- - - ; The last 6 rows need some care. - REPT 6 - ; Wait until start of drawing, then insert 35 nops. -: ldh a, [rSTAT] - and a, 3 - cp a, 3 - jr nz, :- - REPT 35 - nop - ENDR - - ; Blit a line. - REPT 10 - ld a, [de] - ld [hl+], a - inc de - ENDR - - ; Increment HL so that the next line can be blitted. - add hl, bc - ENDR - - ; This function is actually called as the vblank handler for the gameplay state. - ; This is why it jumps straight back to the event loop. - jp EventLoop - - ; The current piece ID is used to get the offset into the rotation states ; corresponding to that piece's zero rotation. SetPieceData: @@ -2159,4 +2159,2073 @@ ClearLines: ret +SECTION "Field Function Banked Gameplay Big", ROMX, BANK[BANK_GAMEPLAY_BIG] + ; Initializes the field completely blank. + ; Initializes the combo counter to 1. + ; Initializes the bravo counter to 0. + ; Initializes the shadow field. +BigFieldInit:: + xor a, a + ldh [hBravo], a + ld a, 1 + ldh [hComboCt], a + ld hl, wField + ld bc, 10*24 + ld d, TILE_BLANK + call UnsafeMemSet + ld hl, wShadowField + ld bc, 14*26 + ld d, $FF + jp UnsafeMemSet + + ; Fills the field with the empty tile. +BigFieldClear:: + ld hl, wField + ld bc, 10*24 + ld d, 0 + call UnsafeMemSet + DEF row = 0 + REPT 14 + ld hl, wField + (row*10) + ld bc, 5 + ld d, TILE_FIELD_EMPTY + call UnsafeMemSet + DEF row += 1 + ENDR + ret + + + ; Backs up the field. + ; This backup field is used for pausing the game. +BigToBackupField:: + ld de, wField + ld hl, wBackupField + ld bc, 10*24 + jp UnsafeMemCopy + + + ; Restores the backup of the field for ending pause mode. +BigFromBackupField:: + ld hl, wField + ld de, wBackupField + ld bc, 10*24 + jp UnsafeMemCopy + + + ; Copies the field to the shadow field. + ; This shadow field is used to calculate whether or not the piece can fit. +BigToShadowField:: + ld hl, wField + ld de, wShadowField+2 + ld c, 24 +.outer + ld b, 10 +.inner + ld a, [hl+] + ld [de], a + inc de + dec b + jr nz, .inner + inc de + inc de + inc de + inc de + dec c + jr nz, .outer + ret + + + ; Restores the shadow field to the main field. +BigFromShadowField: + ld hl, wField + ld de, wShadowField+2 + ld c, 24 +.outer + ld b, 10 +.inner + ld a, [de] + ld [hl+], a + inc de + dec b + jr nz, .inner + inc de + inc de + inc de + inc de + dec c + jr nz, .outer + ret + + ; The current piece ID is used to get the offset into the rotation states + ; corresponding to that piece's zero rotation. +BigSetPieceData: + ldh a, [hCurrentPiece] + sla a + sla a + sla a + sla a + ld c, a + ld b, 0 + + ld hl, sBigPieceRotationStates + add hl, bc + ld a, l + ldh [hPieceDataBase], a + ld a, h + ldh [hPieceDataBase+1], a + + ld hl, sBigPieceFastRotationStates + add hl, bc + ld a, l + ldh [hPieceDataBaseFast], a + ld a, h + ldh [hPieceDataBaseFast+1], a + ret + + + ; The rotation state is a further offset of 4 bytes. +BigSetPieceDataOffset: + ldh a, [hCurrentPieceRotationState] + sla a + sla a + ldh [hPieceDataOffset], a + ret + + + ; Converts piece Y in B and a piece X in A to a pointer to the shadow field in HL. +BigXYToSFieldPtr: + ld hl, wShadowField + ld de, 14 + inc a + inc b +: dec b + jr z, :+ + add hl, de + jr :- +: dec a + ret z + inc hl + jr :- + ret + + + ; Converts piece Y in B and a piece X in A to a pointer to the field in HL. +BigXYToFieldPtr: + ld hl, wField-2 + ld de, 10 + inc a + inc b +: dec b + jr z, :+ + add hl, de + jr :- +: dec a + ret z + inc hl + jr :- + ret + + + ; This function makes HL point to the correct offset into the rotation data. + ; This version of the data is used for thorough checking (T, J, and L have + ; a middle column exception.) +BigGetPieceData: + ldh a, [hPieceDataBase] + ld l, a + ldh a, [hPieceDataBase+1] + ld h, a + ldh a, [hPieceDataOffset] + ld c, a + ld b, 0 + add hl, bc + ret + + + ; Same as the above but for the fast data. This data is used when the exact + ; cell that failed isn't important. +BigGetPieceDataFast: + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hPieceDataOffset] + ld c, a + xor a, a + ld b, a + add hl, bc + ret + + + ; Checks if the piece can fit at the current position. + ; HL should point to the piece's rotation state data. + ; DE should be pointing to the right place in the SHADOW field. + ; This will return with $FF in A if the piece fits, or with the + ; exact cell that caused the first failure in A. +BigCanPieceFit: + xor a, a + ld b, a + + ; Row 1 + bit 3, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 2, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 1, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 0, [hl] + jr z, .r1end + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz + +.r1end + REPT 11 + inc de + ENDR + + ; Row 2 + inc b + inc hl + bit 3, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 2, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 1, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 0, [hl] + jr z, .r2end + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz + +.r2end + REPT 11 + inc de + ENDR + + ; Row 3 + inc b + inc hl + bit 3, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 2, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 1, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 0, [hl] + jr z, .r3end + ld a, [de] + cp a, TILE_FIELD_EMPTY + ret nz + +.r3end + REPT 11 + inc de + ENDR + + ; Row 4 + inc b + inc hl + bit 3, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 2, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 1, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz +: inc de + inc b + bit 0, [hl] + jr z, :+ + ld a, [de] + cp a, TILE_FIELD_EMPTY + ld a, b + ret nz + + ; If we got here, the piece can fit. +: ld a, $FF + ret + + + ; Checks if the piece can fit at the current position, but fast. + ; HL should point to the piece's fast rotation state data. + ; DE should be pointing to the right place in the SHADOW field. + ; This will return with $FF in A if the piece fits, or with a non-$FF + ; value if it doesn't. +BigCanPieceFitFast: + ld a, [hl+] + add a, e + ld e, a + adc a, d + sub e + ld d, a + ld a, [de] + cp a, TILE_FIELD_EMPTY + jr z, :+ + xor a, a + ret +: ld a, [hl+] + add a, e + ld e, a + adc a, d + sub e + ld d, a + ld a, [de] + cp a, TILE_FIELD_EMPTY + jr z, :+ + xor a, a + ret +: ld a, [hl+] + add a, e + ld e, a + adc a, d + sub e + ld d, a + ld a, [de] + cp a, TILE_FIELD_EMPTY + jr z, :+ + xor a, a + ret +: ld a, [hl+] + add a, e + ld e, a + adc a, d + sub e + ld d, a + ld a, [de] + cp a, TILE_FIELD_EMPTY + jr z, :+ + xor a, a + ret +: ld a, $FF + ret + + + ; This function will draw the piece even if it can't fit. + ; We use this to draw a final failed spawn before going game + ; over. +BigForceSpawnPiece:: + call BigSetPieceData + call BigSetPieceDataOffset + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToFieldPtr + ld d, h + ld e, l + call BigGetPieceData + ld b, GAME_OVER_OTHER + push hl + push de + pop hl + pop de + jp BigDrawPiece + + + ; Initialize the state for a new piece and attempts to spawn it. + ; On return, A will be $FF if the piece fit. +BigTrySpawnPiece:: + ; Always reset these for a new piece. + xor a, a + ldh [hStalePiece], a + ldh [hDownFrames], a + ldh [hAwardDownBonus], a + ldh [hLockDelayForce], a + ldh [hShouldLockIfGrounded], a + ldh [hGravityCtr], a + ldh [hGrounded], a + ldh a, [hCurrentLockDelay] + ldh [hCurrentLockDelayRemaining], a + ld a, $FF + ldh [hRemainingDelay], a + ld a, DELAY_STATE_DETERMINE_DELAY + ld [wDelayState], a + + ; Point the piece data to the correct piece. + call BigSetPieceData + call BigSetPieceDataOffset + + ; Get the piece's spawn position. + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + + ; Check if the piece can spawn. + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + + ; A will be $FF if the piece can fit. + cp a, $FF + ret z + + ; Otherwise, try in this order: 0, 1, 3, 2 + ldh a, [hCurrentPieceRotationState] + ldh [hWantRotation], a + + ; Try rotation state 0. +.try0 + cp a, 0 + jr z, .try1 + xor a, a + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call XYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + ret z + + ; Try rotation state 1. +.try1 + ldh a, [hWantRotation] + cp a, 1 + jr z, .try3 + ld a, 1 + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + ret z + + ; Try rotation state 3. +.try3 + ldh a, [hWantRotation] + cp a, 3 + jr z, .try2 + ld a, 3 + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + ret z + + ; Try rotation state 2. +.try2 + ld a, 2 + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + jp BigCanPieceFitFast + + + ; Draws the piece onto the field. + ; B is the tile. + ; DE should point to the piece's rotation state data. + ; HL should be pointing to the right place in the NORMAL field. +BigDrawPiece: + ld a, [de] + inc de + + bit 3, a + jr z, :+ + ld [hl], b +: inc hl + bit 2, a + jr z, :+ + ld [hl], b +: inc hl + bit 1, a + jr z, :+ + ld [hl], b +: inc hl + bit 0, a + jr z, .r1end2 + ld [hl], b + +.r1end2 + REPT 7 + inc hl + ENDR + ld a, [de] + inc de + + bit 3, a + jr z, :+ + ld [hl], b +: inc hl + bit 2, a + jr z, :+ + ld [hl], b +: inc hl + bit 1, a + jr z, :+ + ld [hl], b +: inc hl + bit 0, a + jr z, .r2end2 + ld [hl], b + +.r2end2 + REPT 7 + inc hl + ENDR + ld a, [de] + inc de + + bit 3, a + jr z, :+ + ld [hl], b +: inc hl + bit 2, a + jr z, :+ + ld [hl], b +: inc hl + bit 1, a + jr z, :+ + ld [hl], b +: inc hl + bit 0, a + jr z, .r3end2 + ld [hl], b + +.r3end2 + REPT 7 + inc hl + ENDR + ld a, [de] + inc de + + bit 3, a + jr z, :+ + ld [hl], b +: inc hl + bit 2, a + jr z, :+ + ld [hl], b +: inc hl + bit 1, a + jr z, :+ + ld [hl], b +: inc hl + bit 0, a + ret z + ld [hl], b + ret + + +BigFindMaxG: + ; Find the deepest the piece can go. + ; We cache this pointer, cause it otherwise takes too much time. + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + + push hl + ld a, 1 + ldh [hActualG], a +.try + ld de, 14 + pop hl + add hl, de + push hl + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + jr nz, .found + ldh a, [hActualG] + inc a + ldh [hActualG], a + jr .try + +.found + pop hl + ldh a, [hActualG] + dec a + ldh [hActualG], a + ret + + + ; This is the main function that will process input, gravity, and locking. + ; It should be ran once per frame as long as lock delay is greater than 0. +BigFieldProcess:: + ; ************************************************************** + ; SETUP + ; Wipe out the piece. + ldh a, [hCurrentPieceY] + ldh [hYPosAtStartOfFrame], a + call BigFromShadowField + + ; Cleanup from last frame. + ldh a, [hCurrentPieceX] + ldh [hWantX], a + ldh a, [hCurrentPieceRotationState] + ldh [hWantRotation], a + + ; Is this the first frame of the piece? +.firstframe + ldh a, [hStalePiece] + cp a, 0 + jr nz, .handleselect + ld a, $FF + ldh [hStalePiece], a + jp .skipmovement + + + ; ************************************************************** + ; HANDLE SELECT + ; Check if we're about to hold. Return if so. +.handleselect + ldh a, [hSelectState] + cp a, 1 + jr nz, .wantrotccw + ldh a, [hHoldSpent] + cp a, $FF + ret nz + + + ; ************************************************************** + ; HANDLE ROTATION + ; Want rotate CCW? +.wantrotccw + ld a, [wSwapABState] + cp a, 0 + jr z, .ldb1 +.lda1 + ldh a, [hAState] + jr .cp1 +.ldb1 + ldh a, [hBState] +.cp1 + cp a, 1 + jr nz, .wantrotcw + ldh a, [hWantRotation] + inc a + and a, $03 + ldh [hWantRotation], a + jr .tryrot + + ; Want rotate CW? +.wantrotcw + ld a, [wSwapABState] + cp a, 0 + jr z, .lda2 +.ldb2 + ldh a, [hBState] + jr .cp2 +.lda2 + ldh a, [hAState] +.cp2 + cp a, 1 + jp nz, .norot + ldh a, [hWantRotation] + dec a + and a, $03 + ldh [hWantRotation], a + + ; Try the rotation. +.tryrot + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBase] + ld l, a + ldh a, [hPieceDataBase+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFit ; This does have to be the "slow" version. + cp a, $FF + jr nz, .maybekick + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hLockDelayForce] ; Set the forced lock delay to 2 if it's 1. + cp a, 1 + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; Try kicks if the piece isn't I or O. And in the case of J L and T, only if the blocked side is the left or right. +.maybekick + ld c, a + ; No kicks for NES mode. + ld a, [wRotModeState] + cp a, ROT_MODE_NES + jp z, .norot + + ldh a, [hCurrentPiece] + ; O pieces never kick, obviously. + cp a, PIECE_O + jp z, .norot + + ; S/Z always kick. + cp a, PIECE_S + jr z, .trykickright + cp a, PIECE_Z + jr z, .trykickright + + ; I piece only kicks in ARS2 + cp a, PIECE_I + jr nz, :+ + ld a, [wRotModeState] + cp a, ROT_MODE_ARSTI + jp nz, .norot + ldh a, [hWantRotation] + bit 0, a + jp nz, .checki + jr .trykickright + + ; T/L/J only kick if not through the middle axis. +: ld a, c + cp a, 1 + jp z, .maybetgm3rot + cp a, 5 + jr z, .maybetgm3rot + cp a, 9 + jr z, .maybetgm3rot + + ; A step to the right. +.trykickright + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + inc a + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jr nz, .trykickleft + ldh a, [hCurrentPieceX] + inc a + ldh [hCurrentPieceX], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hLockDelayForce] ; Set the forced lock delay to 2 if it's 1. + cp a, 1 + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; And a step to the left. +.trykickleft + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + dec a + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jr nz, .maybetgm3rot + ldh a, [hCurrentPieceX] + dec a + ldh [hCurrentPieceX], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hLockDelayForce] ; Set the forced lock delay to 2 if it's 1. + cp a, 1 + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; In ARS2 mode, there are a few other kicks possible. +.maybetgm3rot + ld a, [wRotModeState] + cp a, ROT_MODE_ARSTI + jp nz, .norot + + ; In the case of a T piece, try the space above. +.checkt + ldh a, [hCurrentPiece] + cp a, PIECE_T + jr nz, .checki + + ldh a, [hCurrentPieceY] + dec a + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jp nz, .norot + ldh a, [hCurrentPieceY] + dec a + ldh [hCurrentPieceY], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call SetPieceDataOffset + ldh a, [hLockDelayForce] ; Set lock delay forcing to 1 if it's 0. + cp a, 0 + jr nz, :+ + inc a + ldh [hLockDelayForce], a + jp .norot +: cp a, 1 ; Or to 2 if it's 1. + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; In the case of an I piece... +.checki + ldh a, [hCurrentPiece] + cp a, PIECE_I + jp nz, .norot + + ; What direction do we want to end up? + ldh a, [hWantRotation] + bit 0, a + jp z, .tryiright2 ; Flat? Sideways kicks are fine. + ; Upright? Only up kicks. + + ; Are we grounded? Don't kick if we aren't. + ldh a, [hActualG] + cp a, 0 + jp nz, .norot + + ; Try up once. +.tryiup1 + ldh a, [hCurrentPieceY] + dec a + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jr nz, .tryiup2 + ldh a, [hCurrentPieceY] + dec a + ldh [hCurrentPieceY], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call SetPieceDataOffset + ldh a, [hLockDelayForce] ; Set lock delay forcing to 1 if it's 0. + cp a, 0 + jr nz, :+ + inc a + ldh [hLockDelayForce], a + jp .norot +: cp a, 1 ; Or to 2 if it's 1. + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; Try up twice. +.tryiup2 + ldh a, [hCurrentPieceY] + dec a + dec a + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jr nz, .norot + ldh a, [hCurrentPieceY] + dec a + dec a + ldh [hCurrentPieceY], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call BigSetPieceDataOffset + ldh a, [hLockDelayForce] ; Set lock delay forcing to 1 if it's 0. + cp a, 0 + jr nz, :+ + inc a + ldh [hLockDelayForce], a + jp .norot +: cp a, 1 ; Or to 2 if it's 1. + jp nz, .norot + inc a + ldh [hLockDelayForce], a + jp .norot + + ; Try right twice. +.tryiright2 + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + inc a + inc a + call XYToSFieldPtr + ld d, h + ld e, l + ldh a, [hPieceDataBaseFast] + ld l, a + ldh a, [hPieceDataBaseFast+1] + ld h, a + ldh a, [hWantRotation] + sla a + sla a + push bc + ld c, a + xor a, a + ld b, a + add hl, bc + pop bc + call BigCanPieceFitFast + cp a, $FF + jr nz, .norot + ldh a, [hCurrentPieceX] + inc a + inc a + ldh [hCurrentPieceX], a + ldh a, [hWantRotation] + ldh [hCurrentPieceRotationState], a + call SetPieceDataOffset + ldh a, [hLockDelayForce] ; Set the forced lock delay to 2 if it's 1. + cp a, 1 + jp nz, .norot + inc a + ldh [hLockDelayForce], a + + + ; ************************************************************** + ; HANDLE MOVEMENT + ; Do we want to move left? +.norot + ldh a, [hLeftState] ; Check if held for 1 frame. If so we move. + cp a, 1 + jr z, .doleft + cp a, 0 ; We never want to move if the button wasn't held. + jr z, .wantright + ld b, a + ldh a, [hGrounded] ; If we're grounded, assume some urgency in getting DAS charged, charge at twice the rate. + cp a, $FF + jr nz, .checkdasleft + inc b + ld a, b + ldh [hLeftState], a +.checkdasleft + ldh a, [hCurrentDAS] + ld c, a + ld a, b + cp a, c + jr c, .wantright +.doleft + ldh a, [hWantX] + dec a + ldh [hWantX], a + jr .trymove + + ; Do we want to move right? +.wantright + ldh a, [hRightState] ; Check if held for 1 frame. If so we move. + cp a, 1 + jr z, .doright + cp a, 0 ; We never want to move if the button wasn't held. + jr z, .donemanipulating + ld b, a + ldh a, [hGrounded] ; If we're grounded, assume some urgency in getting DAS charged, charge at twice the rate. + cp a, $FF + jr nz, .checkdasright + inc b + ld a, b + ldh [hRightState], a +.checkdasright + ldh a, [hCurrentDAS] + ld c, a + ld a, b + cp a, c + jr c, .donemanipulating +.doright + ldh a, [hWantX] + inc a + ldh [hWantX], a + + ; Try the movement. +.trymove + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hWantX] + call BigXYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + jr nz, .donemanipulating + ldh a, [hWantX] + ldh [hCurrentPieceX], a + + + ; ************************************************************** + ; HANDLE MAXIMUM FALL + ; This little maneuver is going to cost us 51 years. +.skipmovement +.donemanipulating +: call BigFindMaxG + + + ; ************************************************************** + ; HANDLE UP + ; Assume 1G or lower. + ld a, 1 + ldh [hWantedG], a + + ; Is a hard/sonic drop requested? Skip if in 20G mode. + ldh a, [hCurrentIntegerGravity] + cp a, 20 + jr z, .postdrop + ldh a, [hUpState] + cp a, 1 + jr nz, .postdrop + + ; What kind, if any? + ld a, [wDropModeState] + cp a, DROP_MODE_NONE + jr z, .postdrop + cp a, DROP_MODE_LOCK + jr z, .harddrop + cp a, DROP_MODE_HARD + jr z, .harddrop + + ; Sonic drop. +.sonicdrop + ld a, [wDropModeState] + cp a, DROP_MODE_SNIC + jr z, :+ + ld a, $FF + ldh [hShouldLockIfGrounded], a +: ld a, $FF + ldh [hAwardDownBonus], a + ld a, 20 + ldh [hWantedG], a + jr .grav + + ; Hard drop. +.harddrop + ld a, $FF + ldh [hAwardDownBonus], a + ld a, 20 + ldh [hWantedG], a + ld b, a + ldh a, [hActualG] + cp a, b + jr nc, :+ + ld b, a +: ldh a, [hCurrentPieceY] + add a, b + ldh [hCurrentPieceY], a + xor a, a + ldh [hCurrentLockDelayRemaining], a + ld a, SFX_LOCK + call SFXTriggerNoise + jp .draw + + ; If we press down, we want to do a soft drop. +.postdrop + ldh a, [hDownState] + cp a, 0 + jr z, :+ + ldh a, [hDownFrames] + inc a + ldh [hDownFrames], a + ld a, $FF + ldh [hGravityCtr], a + ld a, [wDropModeState] + cp a, DROP_MODE_HARD + jr nz, :+ + ld a, $FF + ldh [hShouldLockIfGrounded], a + + ; Gravity? +: ldh a, [hCurrentFractionalGravity] + cp a, $00 ; 0 is the sentinel value that should be interpreted as "every frame" + jr z, :+ + ld b, a + ldh a, [hGravityCtr] + add a, b + ldh [hGravityCtr], a + jr nc, .nograv +: ldh a, [hCurrentIntegerGravity] + ldh [hWantedG], a + + ; Can we drop the full requested distance? +.grav + ldh a, [hWantedG] + ld b, a + ldh a, [hActualG] + cp a, b + jr c, .smallg + + ; Yes. Do it. +.bigg + ldh a, [hWantedG] + ld b, a + ldh a, [hCurrentPieceY] + add a, b + ldh [hCurrentPieceY], a + jr .postgrav + + ; No. Smaller distance. +.smallg + ldh a, [hActualG] + ld b, a + ldh a, [hCurrentPieceY] + add a, b + ldh [hCurrentPieceY], a + + + ; ************************************************************** + ; HANDLE LOCKING + ; Are we grounded? +.postgrav +.nograv + xor a, a + ldh [hGrounded], a + ldh a, [hYPosAtStartOfFrame] + ld b, a + ldh a, [hCurrentPieceY] + cp a, b + jr z, .noreset + ldh a, [hCurrentLockDelay] + ldh [hCurrentLockDelayRemaining], a +.noreset + ldh a, [hCurrentPieceY] + inc a + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToSFieldPtr + ld d, h + ld e, l + call BigGetPieceDataFast + call BigCanPieceFitFast + cp a, $FF + jp z, .notgrounded + + ; We're grounded. +.grounded + ld a, $FF + ldh [hGrounded], a + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hYPosAtStartOfFrame] + cp a, b + jr z, .postcheckforfirmdropsound ; Never play the sound if we didn't change rows. + ldh a, [hDownState] + cp a, 0 + jr nz, .postcheckforfirmdropsound ; Don't play the sound if we're holding down. + + ; Play the firm drop sound, and also reset the lock delay since the piece stepped down. +.playfirmdropsound + ld a, SFX_LAND + call SFXTriggerNoise + + ; If the down button is held, lock. +.postcheckforfirmdropsound + ldh a, [hDownState] + cp a, 0 + jr z, .neutralcheck + + ; Don't lock on down for hard drop mode immediately. + ld a, [wDropModeState] + cp a, DROP_MODE_HARD + jr nz, :+ + ld a, $FF + ldh [hShouldLockIfGrounded], a + jr .dontforcelock + + ; Lock on down in modes <20G. +: ldh a, [hCurrentIntegerGravity] + cp a, 20 + jr nz, .forcelock + + ; In 20G mode, only lock if down has been pressed for exactly 1 frame. + ldh a, [hDownState] + cp a, 1 + jr z, .forcelock + jr .dontforcelock + + ; If the down button is not held, check if we're neutral and if that should lock. +.neutralcheck + ldh a, [hShouldLockIfGrounded] + cp a, 0 + jr z, .dontforcelock + + ; Check for neutral. + ldh a, [hUpState] + cp a, 0 + jr nz, .dontforcelock + ldh a, [hLeftState] + cp a, 0 + jr nz, .dontforcelock + ldh a, [hRightState] + cp a, 0 + jr nz, .dontforcelock + + ; Lock on neutral for a few modes. + ld a, [wDropModeState] + cp a, DROP_MODE_FIRM + jr z, .forcelock + cp a, DROP_MODE_HARD + jr z, .forcelock + jr .dontforcelock + + ; Set the lock delay to 0 and save it. +.forcelock + xor a, a + ldh [hCurrentLockDelayRemaining], a + jr .dolock + + ; Load the lock delay. + ; Decrement it by one and save it. +.dontforcelock + ldh a, [hCurrentLockDelayRemaining] + dec a + ldh [hCurrentLockDelayRemaining], a + + ; Are we out of lock delay? +.checklockdelay + cp a, 0 + jr nz, .checkfortgm3lockexception ; If not, check if the TGM3 exception applies. + jr .dolock ; Otherwise, lock! + + ; TGM3 sometimes forces a piece to immediately lock. +.checkfortgm3lockexception + ldh a, [hLockDelayForce] + cp a, 2 + jr nz, .draw ; It's not forced, so go to drawing. + xor a, a ; It is forced, so force it! + ldh [hCurrentLockDelayRemaining], a + + ; Play the locking sound and draw the piece. +.dolock + ld a, SFX_LOCK + call SFXTriggerNoise + jr .draw + + ; If we weren't grounded, reset the lock force. +.notgrounded + xor a, a + ldh [hShouldLockIfGrounded], a + + + ; ************************************************************** + ; HANDLE DRAWING + ; Draw the piece. +.draw + ; If the piece is locked, skip the ghost piece. + ldh a, [hCurrentLockDelayRemaining] + cp a, 0 + jr z, .postghost + + ; If the gravity is <= 1G, draw a ghost piece. + ldh a, [hWantedG] + cp a, 1 + jr nz, .postghost + ld a, [wInitialA] ; Let's not do the flickering on the GBC. + cp a, $11 + jr z, .ghost + ldh a, [hEvenFrame] + cp a, 1 + jr nz, .postghost + +.ghost + ldh a, [hYPosAtStartOfFrame] + ld b, a + ldh a, [hActualG] + add a, b + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToFieldPtr + ld d, h + ld e, l + call BigGetPieceData + ld a, TILE_GHOST + ld b, a + push hl + push de + pop hl + pop de + call BigDrawPiece + +.postghost + ; If the lock delay is at the highest value, draw the piece normally. + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0 + add a, b + ldh [hWantedTile], a + ldh a, [hCurrentLockDelay] + ld b, a + ldh a, [hCurrentLockDelayRemaining] + cp a, b + jr z, .drawpiece + + ; If the lock delay is 0, draw the piece in the final color. + ldh a, [hWantedTile] + add a, 7 + ldh [hWantedTile], a + ldh a, [hCurrentLockDelayRemaining] + cp a, 0 + jr z, .drawpiece + + ; If we're not grounded, draw the piece normally. + ldh a, [hWantedTile] + sub a, 7 + ldh [hWantedTile], a + ldh a, [hGrounded] + cp a, $FF + jr nz, .drawpiece + + ; Otherwise, look it up. + call BigGetTileShade + +.drawpiece + ldh a, [hCurrentPieceY] + ld b, a + ldh a, [hCurrentPieceX] + call BigXYToFieldPtr + ld d, h + ld e, l + call BigGetPieceData + ldh a, [hWantedTile] + ld b, a + push hl + push de + pop hl + pop de + call BigDrawPiece + ret + + ; Performs a lookup to see how "locked" the piece is. +BigGetTileShade: + ldh a, [hCurrentLockDelay] + cp a, 30 + jr nc, .max30 + cp a, 20 + jr nc, .max20 + cp a, 10 + jr nc, .max10 + jr .max0 + ret +.max30 + ldh a, [hCurrentLockDelayRemaining] + cp a, 4 + ret c + cp a, 8 + jp c, .s6 + cp a, 12 + jr c, .s5 + cp a, 16 + jr c, .s4 + cp a, 20 + jr c, .s3 + cp a, 24 + jr c, .s2 + cp a, 28 + jr c, .s1 + jr .s0 +.max20 + ldh a, [hCurrentLockDelayRemaining] + cp a, 2 + ret c + cp a, 5 + jr c, .s6 + cp a, 7 + jr c, .s5 + cp a, 10 + jr c, .s4 + cp a, 12 + jr c, .s3 + cp a, 15 + jr c, .s2 + cp a, 17 + jr c, .s1 + jr .s0 +.max10 + ldh a, [hCurrentLockDelayRemaining] + cp a, 1 + ret c + cp a, 2 + jr c, .s6 + cp a, 3 + jr c, .s5 + cp a, 5 + jr c, .s4 + cp a, 6 + jr c, .s3 + cp a, 7 + jr c, .s2 + cp a, 8 + jr c, .s1 + jr .s0 +.max0 + jr .s4 +.s0 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0 + add a, b + ldh [hWantedTile], a + ret +.s1 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(2*7) + add a, b + ldh [hWantedTile], a + ret +.s2 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(3*7) + add a, b + ldh [hWantedTile], a + ret +.s3 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(4*7) + add a, b + ldh [hWantedTile], a + ret +.s4 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(5*7) + add a, b + ldh [hWantedTile], a + ret +.s5 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(6*7) + add a, b + ldh [hWantedTile], a + ret +.s6 + ldh a, [hCurrentPiece] + ld b, TILE_PIECE_0+(7*7) + add a, b + ldh [hWantedTile], a + ret + + + ; This is called every frame after a piece has been locked until the delay state ends. + ; Lines are cleared, levels and score are awarded, and ARE time is waited out. +BigFieldDelay:: + ; Switch on the delay state. + ld a, [wDelayState] + cp DELAY_STATE_DETERMINE_DELAY + jr z, .determine + cp DELAY_STATE_LINE_PRE_CLEAR + jr z, .prelineclear + cp DELAY_STATE_LINE_CLEAR + jp z, .lineclear + cp DELAY_STATE_PRE_ARE + jp z, .preare + jp .are + + + ; Check if there were line clears. + ; If so, we need to do a line clear delay. + ; Otherwise, we skip to ARE delay. +.determine + ; Increment bravo by 4. + ldh a, [hBravo] + add a, 4 + ldh [hBravo], a + + ; Are there line clears? + call BigToShadowField + call BigFindClearedLines + ldh a, [hClearedLines] + ld b, a + ldh a, [hClearedLines+1] + ld c, a + ldh a, [hClearedLines+2] + ld d, a + ldh a, [hClearedLines+3] + and a, b + and a, c + and a, d + cp a, $FF + jr z, .skip + ld a, DELAY_STATE_LINE_PRE_CLEAR ; If there were line clears, do a line clear delay, then a LINE_ARE delay. + ld [wDelayState], a + ldh a, [hCurrentLineClearDelay] + ldh [hRemainingDelay], a + call BigMarkClear + jp .prelineclear +.skip + ld a, DELAY_STATE_PRE_ARE ; If there were no line clears, do an ARE delay. + ld [wDelayState], a + ldh a, [hCurrentARE] + ldh [hRemainingDelay], a + jp .preare + + + ; Pre-line clear delay. + ; If we had line clears, immediately hand out the score and the levels. +.prelineclear: + ld a, DELAY_STATE_LINE_CLEAR + ld [wDelayState], a + + ldh a, [hLineClearCt] + cp a, 0 + jr z, .lineclear ; If not, just skip the phase. + + ; There were line clears! Clear the level counter breakpoint. + xor a, a + ldh [hRequiresLineClear], a + + ; Decrement bravo by 10 for each line clear. + ldh a, [hLineClearCt] + ld b, a + ldh a, [hBravo] +: sub a, 10 + dec b + jr nz, :- + ldh [hBravo], a + + ; Increment the level counter by the amount of lines. +.applylines + ldh a, [hLineClearCt] + ld e, a + call LevelUp + + ; Score the line clears. + ; Get the new level. + ldh a, [hLevel] + ld l, a + ldh a, [hLevel+1] + ld h, a + + ; Divide by 4. + srl h + rr l + srl h + rr l + + ; Add 1. + inc hl + + ; Add soft drop points. + ldh a, [hDownFrames] + ld c, a + xor a, a + ld b, a + + ; Lock bonus? + ldh a, [hAwardDownBonus] + cp a, $FF + jr nz, .premultiplier + ld a, 10 + add a, c + ld c, a + + ; Final total pre-multipliers. +.premultiplier + add hl, bc + + ; Copy the running total for multiplication. + ld b, h + ld c, l + + ; Do we have a bravo? x4 if so. +.bravo + ldh a, [hBravo] + cp a, 0 + jr nz, .lineclears + add hl, bc + jr c, .forcemax + add hl, bc + jr c, .forcemax + add hl, bc + jr c, .forcemax + ld b, h + ld c, l + + ; x line clears +.lineclears + ldh a, [hLineClearCt] + dec a + jr z, .combo +: add hl, bc + jr c, .forcemax + dec a + jr nz, :- + ld b, h + ld c, l + + ; x combo +.combo + ldh a, [hComboCt] + dec a + jr z, .applyscore +: add hl, bc + jr c, .forcemax + dec a + jr nz, :- + jr .applyscore + + ; Overflow = 65535 +.forcemax + ld a, $FF + ld h, a + ld l, a + + ; And apply the score. +.applyscore + ld a, l + ldh [hScoreIncrement], a + ld a, h + ldh [hScoreIncrement+1], a + call IncreaseScore + + ; Update the combo counter. + ldh a, [hLineClearCt] + ld b, a + ldh a, [hComboCt] ; Old combo count. + add b ; + lines + add b ; + lines + sub 2 ; - 2 + ldh [hComboCt], a + + + ; Line clear delay. + ; Count down the delay. If we're out of delay, clear the lines and go to LINE_ARE. +.lineclear + ldh a, [hRemainingDelay] + dec a + ldh [hRemainingDelay], a + cp a, 0 + ret nz + + call BigClearLines + ld a, SFX_LINE_CLEAR + call SFXTriggerNoise + +: ldh a, [hCurrentLineARE] + ldh [hRemainingDelay], a + + + ; Pre-ARE delay. +.preare: + ld a, DELAY_STATE_ARE + ld [wDelayState], a + + ; Copy over the newly cleaned field. + call BigToShadowField + + ; Don't do anything if there were line clears + ldh a, [hLineClearCt] + cp a, 0 + jr nz, .are + + ; Otherwise, reset the combo. + ld a, 1 + ldh [hComboCt], a + + ; ARE delay. + ; Count down the delay. If it hits 0, award levels and score if necessary, then end the delay phase. +.are + ldh a, [hRemainingDelay] + dec a + ldh [hRemainingDelay], a + cp a, 0 + ret nz + + ; Add one level if we're not at a breakpoint. + ldh a, [hRequiresLineClear] + cp a, $FF + jr z, :+ + ld e, 1 + call LevelUp + + ; Cycle the RNG. +: ldh a, [hNextPiece] + ldh [hCurrentPiece], a + call GetNextPiece + + ; Kill the sound for the next piece. + jp SFXKill + + + ; Shifts B into the line clear list. + ; Also increments the line clear count. +BigAppendClearedLine: + ldh a, [hLineClearCt] + inc a + ldh [hLineClearCt], a + ldh a, [hClearedLines+2] + ldh [hClearedLines+3], a + ldh a, [hClearedLines+1] + ldh [hClearedLines+2], a + ldh a, [hClearedLines] + ldh [hClearedLines+1], a + ld a, b + ldh [hClearedLines], a + ret + + + ; Scans the field for lines that are completely filled with non-empty spaces. + ; Every time one is found, it is added to a list. +BigFindClearedLines: + xor a, a + ldh [hLineClearCt], a + ld a, $FF + ld c, 0 + ldh [hClearedLines], a + ldh [hClearedLines+1], a + ldh [hClearedLines+2], a + ldh [hClearedLines+3], a + + DEF row = 13 + REPT 14 + ld hl, wShadowField+2+(row*14) + ld b, 11 +: ld a, [hl+] + dec b + cp a, $FF + jr z, :+ + cp a, TILE_FIELD_EMPTY + jr nz, :- +: xor a, a + cp a, b + jr nz, .next\@ + ld b, 13-row + call BigAppendClearedLine + inc c + ld a, 4 + cp a, c + ret z + DEF row -= 1 +.next\@ + ENDR + + ret + + ; Goes through the list of cleared lines and marks those lines with the "line clear" tile. +BigMarkClear: + ldh a, [hClearedLines] + cp a, $FF + ret z + ld hl, wField+(14*10) +: ld bc, -10 + add hl, bc + dec a + cp a, $FF + jr nz, :- + ld bc, 5 + ld d, TILE_CLEARING + call UnsafeMemSet + + ldh a, [hClearedLines+1] + cp a, $FF + ret z + ld hl, wField+(14*10) +: ld bc, -10 + add hl, bc + dec a + cp a, $FF + jr nz, :- + ld bc, 5 + ld d, TILE_CLEARING + call UnsafeMemSet + + ldh a, [hClearedLines+2] + cp a, $FF + ret z + ld hl, wField+(14*10) +: ld bc, -10 + add hl, bc + dec a + cp a, $FF + jr nz, :- + ld bc, 5 + ld d, TILE_CLEARING + call UnsafeMemSet + + ldh a, [hClearedLines+3] + cp a, $FF + ret z + ld hl, wField+(14*10) +: ld bc, -10 + add hl, bc + dec a + cp a, $FF + jr nz, :- + ld bc, 5 + ld d, TILE_CLEARING + jp UnsafeMemSet + + + ; Once again, scans the field for cleared lines, but this time removes them. +BigClearLines: + ld de, 0 + + DEF row = 23 + REPT 23 + ; Check if the row begins with a clearing tile. + ld hl, wField+(row*10) + ld a, [hl] + cp a, TILE_CLEARING + + ; If it does, increment the clearing counter, but skip this line. + jr nz, .clear\@ + inc de + inc de + inc de + inc de + inc de + inc de + inc de + inc de + inc de + inc de + jr .r\@ + +.clear\@ + ; If there's 0 lines that need to be moved down, skip this line. + xor a, a + cp a, e + jr z, .r\@ + + ; Otherwise... + ld bc, wField+(row*10) + add hl, de +: ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc + ld a, [bc] + ld [hl+], a + inc bc +.r\@ + DEF row -= 1 + ENDR + + ; Make sure there's no garbage in the top de lines. +.fixgarbo + ld hl, wField +: xor a, a + or a, d + or a, e + ret z + ld a, TILE_FIELD_EMPTY + ld [hl+], a + ld [hl+], a + ld [hl+], a + ld [hl+], a + ld [hl+], a + ld a, 0 + ld [hl+], a + ld [hl+], a + ld [hl+], a + ld [hl+], a + ld [hl+], a + dec de + dec de + dec de + dec de + dec de + dec de + dec de + dec de + dec de + dec de + jr :- + ret + + ENDC diff --git a/src/include/globals.asm b/src/include/globals.asm index c2ba887..953b7ac 100644 --- a/src/include/globals.asm +++ b/src/include/globals.asm @@ -23,6 +23,55 @@ INCLUDE "hardware.inc" INCLUDE "structs.asm" +; Set up charmap. +CHARMAP " ", 1 +CHARMAP "0", 66 +CHARMAP "1", 67 +CHARMAP "2", 68 +CHARMAP "3", 69 +CHARMAP "4", 70 +CHARMAP "5", 71 +CHARMAP "6", 72 +CHARMAP "7", 73 +CHARMAP "8", 74 +CHARMAP "9", 75 +CHARMAP "A", 76 +CHARMAP "B", 77 +CHARMAP "C", 78 +CHARMAP "D", 79 +CHARMAP "E", 80 +CHARMAP "F", 81 +CHARMAP "G", 82 +CHARMAP "H", 83 +CHARMAP "I", 84 +CHARMAP "J", 85 +CHARMAP "K", 86 +CHARMAP "L", 87 +CHARMAP "M", 88 +CHARMAP "N", 89 +CHARMAP "O", 90 +CHARMAP "P", 91 +CHARMAP "Q", 92 +CHARMAP "R", 93 +CHARMAP "S", 94 +CHARMAP "T", 95 +CHARMAP "U", 96 +CHARMAP "V", 97 +CHARMAP "W", 98 +CHARMAP "X", 99 +CHARMAP "Y", 100 +CHARMAP "Z", 101 +CHARMAP "!", 102 +CHARMAP "?", 103 +CHARMAP "[", 129 +CHARMAP "]", 130 +CHARMAP "/", 128 +CHARMAP "-", 127 +CHARMAP "#", 126 +CHARMAP ".", 216 +CHARMAP ":", 222 + + ; Waits for PPU mode to be 0 or 1. ; We don't wait for 2 because it's super short and impractical to do much of anything in. MACRO wait_vram @@ -87,11 +136,14 @@ MACRO lb ENDM -; Magic bytes for save files. -DEF SAVE_MAGIC_0 EQU "D" -DEF SAVE_MAGIC_1 EQU "M" -DEF SAVE_MAGIC_2 EQU "G" -DEF SAVE_MAGIC_3 EQU "5" +; Bank names +DEF BANK_MAIN EQU 0 +DEF BANK_OTHER EQU 1 +DEF BANK_SFX EQU 2 +DEF BANK_MUSIC EQU 3 +DEF BANK_TITLE EQU 4 +DEF BANK_GAMEPLAY EQU 5 +DEF BANK_GAMEPLAY_BIG EQU 6 ; Some useful palettes. DEF PALETTE_REGULAR EQU %11100100 @@ -231,6 +283,8 @@ DEF LEADY_TIME EQU 80 DEF GO_TIME EQU 40 DEF PIECE_SPAWN_X EQU 5 DEF PIECE_SPAWN_Y EQU 3 +DEF PIECE_SPAWN_X_BIG EQU 3 +DEF PIECE_SPAWN_Y_BIG EQU 3 DEF ROTATION_STATE_DEF EQU 0 DEF ROTATION_STATE_CW EQU 1 DEF ROTATION_STATE_180 EQU 2 @@ -239,6 +293,7 @@ DEF ROTATION_STATE_CCW EQU 3 ; Game states. (Let these increase by 3) DEF STATE_TITLE EQU 0 DEF STATE_GAMEPLAY EQU 3 +DEF STATE_GAMEPLAY_BIG EQU 6 ; Other DEF STACK_SIZE EQU 64 diff --git a/src/level.asm b/src/level.asm index b3d03c1..ce9456a 100644 --- a/src/level.asm +++ b/src/level.asm @@ -43,6 +43,10 @@ hPrevHundreds:: ds 1 SECTION "Level Functions", ROM0 ; Loads the initial state of the speed curve. LevelInit:: + ; Bank to speed curve data. + ld b, BANK_OTHER + rst RSTSwitchBank + xor a, a ldh [hRequiresLineClear], a @@ -98,6 +102,9 @@ LevelInit:: and a, $0F ldh [hNLevel], a + ; Restore the bank before returning. + rst RSTRestoreBank + jp DoSpeedUp @@ -303,6 +310,10 @@ LevelUp:: ; Iterates over the speed curve and loads the new constants. DoSpeedUp: + ; Bank to speed curve data. + ld b, BANK_OTHER + rst RSTSwitchBank + ; Load curve ptr. ldh a, [hSpeedCurvePtr] ld l, a @@ -344,12 +355,12 @@ DoSpeedUp: ; Do we want to force 20G? ld a, [wAlways20GState] cp a, 0 - ret z + jp z, RSTRestoreBank ld a, 20 ldh [hCurrentIntegerGravity], a ld a, $00 ldh [hCurrentFractionalGravity], a - ret + jp RSTRestoreBank ENDC diff --git a/src/main.asm b/src/main.asm index b7000d4..e1f5f54 100644 --- a/src/main.asm +++ b/src/main.asm @@ -20,9 +20,7 @@ DEF MAIN_ASM EQU 1 INCLUDE "globals.asm" -INCLUDE "res/tiles.inc" -INCLUDE "res/gameplay_map.inc" -INCLUDE "res/title_map.inc" +INCLUDE "res/other_data.inc" SECTION "High Globals", HRAM @@ -85,13 +83,13 @@ Main:: ld [rRAMG], a xor a, a ld [rRAMB], a - ld a, BANK("Static Data") + ld a, BANK_OTHER ld [rROMB0], a ; We use a single set of tiles for the entire game, so we copy it at the start. - ld de, Tiles + ld de, sTiles ld hl, _VRAM - ld bc, TilesEnd - Tiles + ld bc, sTilesEnd - sTiles call SafeMemCopy ; Clear OAM. @@ -138,6 +136,7 @@ EventLoop:: .eventloopjumps jp TitleEventLoopHandler jp GamePlayEventLoopHandler + jp GamePlayBigEventLoopHandler EventLoopPostHandler:: ; Wait for vblank. @@ -157,6 +156,7 @@ EventLoopPostHandler:: .vblankjumps jp TitleVBlankHandler jp BlitField + jp BlitField ; The VBlank Handler is expected to end with jp EventLoop. diff --git a/src/res/gameplay_map.inc b/src/res/gameplay_big_data.inc similarity index 55% rename from src/res/gameplay_map.inc rename to src/res/gameplay_big_data.inc index 885f03a..e4c24f4 100644 --- a/src/res/gameplay_map.inc +++ b/src/res/gameplay_big_data.inc @@ -15,12 +15,232 @@ ; along with this program. If not, see . -IF !DEF(GAMEPLAY_MAP_INC) -DEF GAMEPLAY_MAP_INC EQU 1 +IF !DEF(GAMEPLAY_BIG_MAP_INC) +DEF GAMEPLAY_BIG_MAP_INC EQU 1 -SECTION "Gameplay Tilemap", ROMX, BANK[1] -GameplayTilemap:: +INCLUDE "globals.asm" + + +SECTION "Gameplay Big Static Data", ROMX, BANK[BANK_GAMEPLAY_BIG] +sBigLeady:: db " READY? " + +sBigGo:: db " GO " + +sBigPause:: + db "P A U S E " + db " P A U S E" + +sBigPieceXOffsets:: ; How to draw each piece. X-offsets of the sprites. + db 0, 8, 16, 24 ; I + db 0, 8, 8, 16 ; Z + db 0, 8, 8, 16 ; S + db 0, 8, 16, 16 ; J + db 0, 0, 8, 16 ; L + db 8, 8, 16, 16 ; O + db 0, 8, 8, 16 ; T + +sBigPieceYOffsets:: ; How to draw each piece. Y-offsets of the sprites. + db 0, 0, 0, 0 ; I + db 0, 0, 7, 7 ; Z + db 7, 7, 0, 0 ; S + db 0, 0, 0, 7 ; J + db 7, 0, 0, 0 ; L + db 0, 7, 0, 7 ; O + db 0, 0, 7, 0 ; T + +sBigPieceFastRotationStates:: + ; I + db 14, 1, 1, 1 + db 2, 14, 14, 14 + db 14, 1, 1, 1 + db 2, 14, 14, 14 + + ; Z + db 14, 1, 14, 1 + db 2, 13, 1, 13 + db 14, 1, 14, 1 + db 2, 13, 1, 13 + + ; S + db 15, 1, 12, 1 + db 0, 14, 1, 14 + db 15, 1, 12, 1 + db 0, 14, 1, 14 + + ; J + db 14, 1, 1, 14 + db 1, 1, 13, 14 + db 14, 14, 1, 1 + db 1, 14, 13, 1 + + ; L + db 14, 1, 1, 12 + db 1, 14, 14, 1 + db 16, 12, 1, 1 + db 0, 1, 14, 14 + + ; O + db 15, 1, 13, 1 + db 15, 1, 13, 1 + db 15, 1, 13, 1 + db 15, 1, 13, 1 + + ; T + db 14, 1, 1, 13 + db 1, 14, 1, 13 + db 15, 13, 1, 1 + db 1, 13, 1, 14 + +sBigPieceRotationStates:: ; How each piece is rotated. + ; I + db %0000 + db %1111 + db %0000 + db %0000 + + db %0010 + db %0010 + db %0010 + db %0010 + + db %0000 + db %1111 + db %0000 + db %0000 + + db %0010 + db %0010 + db %0010 + db %0010 + + ; Z + db %0000 + db %1100 + db %0110 + db %0000 + + db %0010 + db %0110 + db %0100 + db %0000 + + db %0000 + db %1100 + db %0110 + db %0000 + + db %0010 + db %0110 + db %0100 + db %0000 + + ; S + db %0000 + db %0110 + db %1100 + db %0000 + + db %1000 + db %1100 + db %0100 + db %0000 + + db %0000 + db %0110 + db %1100 + db %0000 + + db %1000 + db %1100 + db %0100 + db %0000 + + ; J + db %0000 + db %1110 + db %0010 + db %0000 + + db %0110 + db %0100 + db %0100 + db %0000 + + db %0000 + db %1000 + db %1110 + db %0000 + + db %0100 + db %0100 + db %1100 + db %0000 + + ; L + db %0000 + db %1110 + db %1000 + db %0000 + + db %0100 + db %0100 + db %0110 + db %0000 + + db %0000 + db %0010 + db %1110 + db %0000 + + db %1100 + db %0100 + db %0100 + db %0000 + + ; O + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + ; T + db %0000 + db %1110 + db %0100 + db %0000 + + db %0100 + db %0110 + db %0100 + db %0000 + + db %0000 + db %0100 + db %1110 + db %0000 + + db %0100 + db %1100 + db %0100 + db %0000 + +sBigGameplayTileMap:: DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 DB $01,$03,$09,$01,$01,$01,$01,$01,$01,$09 DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 @@ -87,7 +307,7 @@ GameplayTilemap:: DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $02,$00,$00,$00,$00,$00,$00,$00,$00,$00 DB $00,$03,$09,$01,$01,$01,$01,$01,$01,$09 -GameplayTilemapEnd:: +sBigGameplayTileMapEnd:: ENDC diff --git a/src/res/gameplay_data.inc b/src/res/gameplay_data.inc new file mode 100644 index 0000000..dc42834 --- /dev/null +++ b/src/res/gameplay_data.inc @@ -0,0 +1,325 @@ +; DMGTRIS +; Copyright (C) 2023 - Randy Thiemann + +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. + +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. + +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . + + +IF !DEF(GAMEPLAY_MAP_INC) +DEF GAMEPLAY_MAP_INC EQU 1 + + +INCLUDE "globals.asm" + + +SECTION "Gameplay Static Data", ROMX, BANK[BANK_GAMEPLAY] +sLeady:: db " READY? " + +sGo:: db " GO " + +sPause:: + db "P A U S E " + db " P A U S E" + +sPieceXOffsets:: ; How to draw each piece. X-offsets of the sprites. + db 0, 8, 16, 24 ; I + db 0, 8, 8, 16 ; Z + db 0, 8, 8, 16 ; S + db 0, 8, 16, 16 ; J + db 0, 0, 8, 16 ; L + db 8, 8, 16, 16 ; O + db 0, 8, 8, 16 ; T + +sPieceYOffsets:: ; How to draw each piece. Y-offsets of the sprites. + db 0, 0, 0, 0 ; I + db 0, 0, 7, 7 ; Z + db 7, 7, 0, 0 ; S + db 0, 0, 0, 7 ; J + db 7, 0, 0, 0 ; L + db 0, 7, 0, 7 ; O + db 0, 0, 7, 0 ; T + +sPieceFastRotationStates:: + ; I + db 14, 1, 1, 1 + db 2, 14, 14, 14 + db 14, 1, 1, 1 + db 2, 14, 14, 14 + + ; Z + db 14, 1, 14, 1 + db 2, 13, 1, 13 + db 14, 1, 14, 1 + db 2, 13, 1, 13 + + ; S + db 15, 1, 12, 1 + db 0, 14, 1, 14 + db 15, 1, 12, 1 + db 0, 14, 1, 14 + + ; J + db 14, 1, 1, 14 + db 1, 1, 13, 14 + db 14, 14, 1, 1 + db 1, 14, 13, 1 + + ; L + db 14, 1, 1, 12 + db 1, 14, 14, 1 + db 16, 12, 1, 1 + db 0, 1, 14, 14 + + ; O + db 15, 1, 13, 1 + db 15, 1, 13, 1 + db 15, 1, 13, 1 + db 15, 1, 13, 1 + + ; T + db 14, 1, 1, 13 + db 1, 14, 1, 13 + db 15, 13, 1, 1 + db 1, 13, 1, 14 + +sPieceRotationStates:: ; How each piece is rotated. + ; I + db %0000 + db %1111 + db %0000 + db %0000 + + db %0010 + db %0010 + db %0010 + db %0010 + + db %0000 + db %1111 + db %0000 + db %0000 + + db %0010 + db %0010 + db %0010 + db %0010 + + ; Z + db %0000 + db %1100 + db %0110 + db %0000 + + db %0010 + db %0110 + db %0100 + db %0000 + + db %0000 + db %1100 + db %0110 + db %0000 + + db %0010 + db %0110 + db %0100 + db %0000 + + ; S + db %0000 + db %0110 + db %1100 + db %0000 + + db %1000 + db %1100 + db %0100 + db %0000 + + db %0000 + db %0110 + db %1100 + db %0000 + + db %1000 + db %1100 + db %0100 + db %0000 + + ; J + db %0000 + db %1110 + db %0010 + db %0000 + + db %0110 + db %0100 + db %0100 + db %0000 + + db %0000 + db %1000 + db %1110 + db %0000 + + db %0100 + db %0100 + db %1100 + db %0000 + + ; L + db %0000 + db %1110 + db %1000 + db %0000 + + db %0100 + db %0100 + db %0110 + db %0000 + + db %0000 + db %0010 + db %1110 + db %0000 + + db %1100 + db %0100 + db %0100 + db %0000 + + ; O + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + db %0000 + db %0110 + db %0110 + db %0000 + + ; T + db %0000 + db %1110 + db %0100 + db %0000 + + db %0100 + db %0110 + db %0100 + db %0000 + + db %0000 + db %0100 + db %1110 + db %0000 + + db %0100 + db %1100 + db %0100 + db %0000 + +sTGM3Bag:: + db 0, 0, 0, 0, 0 + db 1, 1, 1, 1, 1 + db 2, 2, 2, 2, 2 + db 3, 3, 3, 3, 3 + db 4, 4, 4, 4, 4 + db 5, 5, 5, 5, 5 + db 6, 6, 6, 6, 6 + +sTGM3Droughts:: + db 0, 0, 0, 0, 0, 0, 0 + +sGameplayTileMap:: + DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 + DB $01,$03,$09,$01,$01,$01,$01,$01,$01,$09 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$02,$01,$01,$01,$01,$01,$01,$01 + DB $01,$01,$01,$03,$09,$59,$50,$63,$5F,$01 + DB $01,$09,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$02,$01,$01,$01,$01,$01 + DB $01,$01,$01,$01,$01,$03,$09,$01,$01,$01 + DB $01,$01,$01,$09,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$02,$01,$01,$01 + DB $01,$01,$01,$01,$01,$01,$01,$03,$09,$01 + DB $01,$01,$01,$01,$01,$09,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$02,$01 + DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$03 + DB $09,$01,$01,$01,$01,$01,$01,$09,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 + DB $01,$03,$09,$01,$01,$01,$01,$01,$01,$09 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$02,$01,$01,$01,$01,$01,$01,$01 + DB $01,$01,$01,$03,$08,$06,$06,$06,$06,$06 + DB $06,$07,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$02,$01,$01,$01,$01,$01 + DB $01,$01,$01,$01,$01,$03,$09,$53,$5A,$57 + DB $4F,$01,$01,$09,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$02,$01,$01,$01 + DB $01,$01,$01,$01,$01,$01,$01,$03,$09,$01 + DB $01,$01,$01,$01,$01,$09,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$02,$01 + DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$03 + DB $09,$01,$01,$01,$01,$01,$01,$09,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 + DB $01,$03,$09,$01,$01,$01,$01,$01,$01,$09 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$02,$01,$01,$01,$01,$01,$01,$01 + DB $01,$01,$01,$03,$09,$01,$01,$01,$01,$01 + DB $01,$09,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$02,$01,$01,$01,$01,$01 + DB $01,$01,$01,$01,$01,$03,$08,$06,$06,$06 + DB $06,$06,$06,$07,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$02,$01,$01,$01 + DB $01,$01,$01,$01,$01,$01,$01,$03,$09,$5E + DB $4E,$5A,$5D,$50,$01,$09,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$02,$01 + DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$03 + DB $09,$01,$01,$01,$01,$01,$01,$09,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $02,$01,$01,$01,$01,$01,$01,$01,$01,$01 + DB $01,$03,$08,$06,$06,$06,$06,$06,$06,$07 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$02,$01,$01,$01,$01,$01,$01,$01 + DB $01,$01,$01,$03,$09,$57,$50,$61,$50,$57 + DB $01,$09,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$02,$01,$01,$01,$01,$01 + DB $01,$01,$01,$01,$01,$03,$09,$01,$01,$01 + DB $01,$01,$01,$09,$00,$00,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$02,$01,$01,$01 + DB $01,$01,$01,$01,$01,$01,$01,$03,$09,$01 + DB $05,$05,$05,$05,$01,$09,$00,$00,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$02,$01 + DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$03 + DB $09,$01,$01,$01,$01,$01,$01,$09,$00,$00 + DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $02,$00,$00,$00,$00,$00,$00,$00,$00,$00 + DB $00,$03,$09,$01,$01,$01,$01,$01,$01,$09 +sGameplayTileMapEnd:: + + +ENDC diff --git a/src/res/music_data.inc b/src/res/music_data.inc index 4a97a81..77d09cb 100644 --- a/src/res/music_data.inc +++ b/src/res/music_data.inc @@ -18,7 +18,11 @@ IF !DEF(MUSIC_DATA_INC) DEF MUSIC_DATA_INC EQU 1 -SECTION "Music Data", ROMX, BANK[3] + +INCLUDE "globals.asm" + + +SECTION "Music Data", ROMX, BANK[BANK_MUSIC] sMusicMenu:: db REG_NR12_CH1_VOLEV, $00, REG_NR14_CH1_FRQHI, $80, REG_NR22_CH2_VOLEV, $00, REG_NR24_CH2_FRQHI, $80 diff --git a/src/res/tiles.inc b/src/res/other_data.inc similarity index 66% rename from src/res/tiles.inc rename to src/res/other_data.inc index 43c152b..d9e8bec 100644 --- a/src/res/tiles.inc +++ b/src/res/other_data.inc @@ -18,8 +18,614 @@ IF !DEF(TILES_INC) DEF TILES_INC EQU 1 -SECTION "Tile data", ROMX, BANK[1] -Tiles:: + +INCLUDE "globals.asm" + + +SECTION "Tile data", ROMX, BANK[BANK_OTHER] +; Speed curve data is defined as follows: +; N blocks of: +; dw BCD_START_LEVEL, START_LEVEL, BCD_NEXT_100_LEVEL_BREAKPOINT +; db GRID_CELLS_PER_MOVE_ON_OVERFLOW, INCREMENT_PER_FRAME (0 means overflow each frame) +; db NORMAL_ARE, LINE_ARE, DAS, LOCK_DELAY, CLEAR_DELAY +; +; Followed by one single: +; dw $FFFF +sDMGTSpeedCurve:: ; Speed curve of the game. + dw $0000, 0, $0100 ; Level 0000 + db 1, 16 + db 25, 15, 14, 30, 40 + + dw $0015, 15, $0100 ; Level 0015 + db 1, 17 + db 25, 15, 14, 30, 40 + + dw $0030, 30, $0100 ; Level 0030 + db 1, 18 + db 25, 15, 14, 30, 40 + + dw $0040, 40, $0100 ; Level 0040 + db 1, 20 + db 25, 15, 14, 30, 40 + + dw $0050, 50, $0100 ; Level 0050 + db 1, 21 + db 25, 15, 14, 30, 40 + + dw $0060, 60, $0100 ; Level 0060 + db 1, 23 + db 25, 15, 14, 30, 40 + + dw $0070, 70, $0100 ; Level 0070 + db 1, 26 + db 25, 15, 14, 30, 40 + + dw $0080, 80, $0100 ; Level 0080 + db 1, 28 + db 25, 15, 14, 30, 40 + + dw $0090, 90, $0100 ; Level 0090 + db 1, 32 + db 25, 15, 14, 30, 40 + + dw $0100, 100, $0200 ; Level 0100 + db 1, 37 + db 25, 15, 14, 30, 40 + + dw $0150, 150, $0200 ; Level 0150 + db 1, 43 + db 25, 15, 14, 30, 40 + + dw $0200, 200, $0300 ; Level 0200 + db 1, 51 + db 25, 15, 14, 30, 40 + + dw $0225, 225, $0300 ; Level 0225 + db 1, 64 + db 25, 15, 14, 30, 40 + + dw $0250, 250, $0300 ; Level 0250 + db 1, 85 + db 25, 15, 14, 30, 40 + + dw $0275, 275, $0300 ; Level 0275 + db 1, 128 + db 25, 15, 14, 30, 40 + + dw $0300, 300, $0400 ; Level 0300 + db 1, $00 + db 25, 7, 14, 30, 32 + + dw $0350, 350, $0350 ; Level 0350 + db 2, $00 + db 25, 7, 14, 30, 32 + + dw $0400, 400, $0400 ; Level 0400 + db 3, $00 + db 25, 7, 14, 30, 32 + + dw $0450, 450, $0500 ; Level 0450 + db 4, $00 + db 25, 7, 14, 30, 32 + + dw $0475, 475, $0500 ; Level 0475 + db 5, $00 + db 25, 7, 14, 30, 32 + + dw $0500, 500, $0600 ; Level 0500 + db 20, $00 + db 25, 6, 14, 30, 24 + + dw $0600, 600, $0700 ; Level 0600 + db 20, $00 + db 25, 6, 8, 30, 24 + + dw $0700, 700, $0800 ; Level 0700 + db 20, $00 + db 20, 6, 8, 30, 24 + + dw $0900, 900, $1000 ; Level 0900 + db 20, $00 + db 16, 4, 6, 25, 16 + + dw $1100, 1100, $1200 ; Level 1100 + db 20, $00 + db 12, 4, 6, 25, 16 + + dw $1200, 1200, $1300 ; Level 1200 + db 20, $00 + db 12, 4, 6, 25, 8 + + dw $1300, 1300, $1400 ; Level 1300 + db 20, $00 + db 10, 4, 6, 20, 7 + + dw $1400, 1400, $1500 ; Level 1400 + db 20, $00 + db 10, 4, 6, 18, 6 + + dw $1500, 1500, $1600 ; Level 1500 + db 20, $00 + db 8, 4, 4, 16, 5 + + dw $1600, 1600, $1700 ; Level 1600 + db 20, $00 + db 8, 4, 4, 14, 4 + + dw $1700, 1700, $1800 ; Level 1700 + db 20, $00 + db 6, 4, 4, 12, 3 + + dw $1800, 1800, $1900 ; Level 1800 + db 20, $00 + db 6, 4, 4, 10, 3 + + dw $1900, 1900, $2000 ; Level 1900 + db 20, $00 + db 4, 4, 4, 8, 3 + + dw $2000, 2000, $2100 ; Level 2000 + db 20, $00 + db 4, 4, 3, 8, 3 + + dw $2500, 2500, $2600 ; Level 2500 + db 20, $00 + db 2, 2, 1, 8, 2 + + dw $3000, 3000, $3100 ; Level 3000 + db 20, $00 + db 1, 1, 1, 8, 1 + + dw $4000, 4000, $4100 ; Level 4000 + db 20, $00 + db 1, 1, 1, 6, 1 + + dw $5000, 5000, $5100 ; Level 5000 + db 20, $00 + db 1, 1, 1, 4, 1 + + dw $6666, 6666, $6700 ; Level 6666 + db 20, $00 + db 1, 1, 1, 2, 1 + + dw $9999, 9999, $9999 ; Level 9999 + db 20, $00 + db 1, 1, 1, 1, 1 + +sDMGTSpeedCurveEnd:: + dw $FFFF ; End. + +sTGM1SpeedCurve:: + dw $0000, 0, $0100 + db 1, 4 + db 30, 30, 16, 30, 41 + + dw $0030, 30, $0100 + db 1, 6 + db 30, 30, 16, 30, 41 + + dw $0035, 35, $0100 + db 1, 8 + db 30, 30, 16, 30, 41 + + dw $0040, 40, $0100 + db 1, 10 + db 30, 30, 16, 30, 41 + + dw $0050, 50, $0100 + db 1, 12 + db 30, 30, 16, 30, 41 + + dw $0060, 60, $0100 + db 1, 16 + db 30, 30, 16, 30, 41 + + dw $0070, 70, $0100 + db 1, 32 + db 30, 30, 16, 30, 41 + + dw $0080, 80, $0100 + db 1, 48 + db 30, 30, 16, 30, 41 + + dw $0090, 90, $0100 + db 1, 64 + db 30, 30, 16, 30, 41 + + dw $0100, 100, $0200 + db 1, 80 + db 30, 30, 16, 30, 41 + + dw $0120, 120, $0200 + db 1, 96 + db 30, 30, 16, 30, 41 + + dw $0140, 140, $0200 + db 1, 112 + db 30, 30, 16, 30, 41 + + dw $0160, 160, $0200 + db 1, 128 + db 30, 30, 16, 30, 41 + + dw $0170, 170, $0200 + db 1, 144 + db 30, 30, 16, 30, 41 + + dw $0200, 200, $0300 + db 1, 4 + db 30, 30, 16, 30, 41 + + dw $0220, 220, $0300 + db 1, 32 + db 30, 30, 16, 30, 41 + + dw $0230, 230, $0300 + db 1, 64 + db 30, 30, 16, 30, 41 + + dw $0233, 233, $0300 + db 1, 96 + db 30, 30, 16, 30, 41 + + dw $0236, 236, $0300 + db 1, 128 + db 30, 30, 16, 30, 41 + + dw $0239, 239, $0300 + db 1, 160 + db 30, 30, 16, 30, 41 + + dw $0243, 243, $0300 + db 1, 192 + db 30, 30, 16, 30, 41 + + dw $0247, 239, $0300 + db 1, 224 + db 30, 30, 16, 30, 41 + + dw $0251, 251, $0300 + db 1, $00 + db 30, 30, 16, 30, 41 + + dw $0300, 300, $0400 + db 2, $00 + db 30, 30, 16, 30, 41 + + dw $0330, 330, $0400 + db 3, $00 + db 30, 30, 16, 30, 41 + + dw $0360, 360, $0400 + db 4, $00 + db 30, 30, 16, 30, 41 + + dw $0400, 400, $0500 + db 5, $00 + db 30, 30, 16, 30, 41 + + dw $0420, 420, $0500 + db 4, $00 + db 30, 30, 16, 30, 41 + + dw $0450, 450, $0500 + db 3, $00 + db 30, 30, 16, 30, 41 + + dw $0500, 500, $0600 + db 20, $00 + db 30, 30, 16, 30, 41 + +sTGM1SpeedCurveEnd:: + dw $FFFF + + +sCHILSpeedCurve:: + dw $0000, 0, $0100 + db 1, 5 + db 10, 10, 16, 25, 17 + + dw $0100, 100, $0200 + db 1, 6 + db 10, 10, 16, 25, 17 + + dw $0200, 200, $0300 + db 1, 7 + db 10, 10, 16, 25, 17 + + dw $0300, 300, $0400 + db 1, 8 + db 10, 10, 16, 25, 17 + + dw $0400, 400, $0500 + db 1, 9 + db 10, 10, 16, 25, 17 + + dw $0500, 500, $0600 + db 1, 11 + db 10, 10, 16, 25, 17 + + dw $0600, 600, $0700 + db 1, 14 + db 10, 10, 16, 25, 17 + + dw $0700, 700, $0800 + db 1, 20 + db 10, 10, 16, 25, 17 + + dw $0800, 800, $0900 + db 1, 32 + db 10, 10, 16, 25, 17 + + dw $0900, 900, $1000 + db 1, 43 + db 10, 10, 16, 25, 17 + + dw $1000, 1000, $1100 + db 1, 51 + db 10, 10, 16, 25, 17 + + dw $1300, 1300, $1400 + db 1, 64 + db 10, 10, 16, 25, 17 + + dw $1600, 1600, $1700 + db 1, 85 + db 10, 10, 16, 25, 17 + + dw $1900, 1900, $2000 + db 1, 128 + db 10, 10, 16, 25, 17 + + dw $2900, 2900, $3000 + db 1, $00 + db 10, 10, 16, 25, 17 + + dw $3333, 3333, $3400 + db 2, $00 + db 10, 10, 12, 25, 17 + + dw $4444, 4444, $4500 + db 3, $00 + db 10, 10, 12, 25, 17 + + dw $5555, 5555, $5600 + db 4, $00 + db 10, 10, 12, 25, 17 + + dw $6666, 6666, $6700 + db 5, $00 + db 10, 10, 12, 25, 17 + + dw $7777, 7777, $7800 + db 20, $00 + db 10, 10, 8, 25, 17 + + dw $8888, 8888, $8900 + db 20, $00 + db 10, 10, 6, 18, 17 + + dw $9999, 9999, $9999 + db 20, $00 + db 5, 5, 6, 14, 10 + +sCHILSpeedCurveEnd:: + dw $FFFF + + +sTGM3SpeedCurve:: + dw $0000, 0, $0100 + db 1, 4 + db 27, 27, 16, 30, 40 + + dw $0030, 30, $0100 + db 1, 6 + db 27, 27, 16, 30, 40 + + dw $0035, 35, $0100 + db 1, 8 + db 27, 27, 16, 30, 40 + + dw $0040, 40, $0100 + db 1, 10 + db 27, 27, 16, 30, 40 + + dw $0050, 50, $0100 + db 1, 12 + db 27, 27, 16, 30, 40 + + dw $0060, 60, $0100 + db 1, 16 + db 27, 27, 16, 30, 40 + + dw $0070, 70, $0100 + db 1, 32 + db 27, 27, 16, 30, 40 + + dw $0080, 80, $0100 + db 1, 48 + db 27, 27, 16, 30, 40 + + dw $0090, 90, $0100 + db 1, 64 + db 27, 27, 16, 30, 40 + + dw $0100, 100, $0200 + db 1, 80 + db 27, 27, 16, 30, 40 + + dw $0120, 120, $0200 + db 1, 96 + db 27, 27, 16, 30, 40 + + dw $0140, 140, $0200 + db 1, 112 + db 27, 27, 16, 30, 40 + + dw $0160, 160, $0200 + db 1, 128 + db 27, 27, 16, 30, 40 + + dw $0170, 170, $0200 + db 1, 144 + db 27, 27, 16, 30, 40 + + dw $0200, 200, $0300 + db 1, 4 + db 27, 27, 16, 30, 40 + + dw $0220, 220, $0300 + db 1, 32 + db 27, 27, 16, 30, 40 + + dw $0230, 230, $0300 + db 1, 64 + db 27, 27, 16, 30, 40 + + dw $0233, 233, $0300 + db 1, 96 + db 27, 27, 16, 30, 40 + + dw $0236, 236, $0300 + db 1, 128 + db 27, 27, 16, 30, 40 + + dw $0239, 239, $0300 + db 1, 160 + db 27, 27, 16, 30, 40 + + dw $0243, 243, $0300 + db 1, 192 + db 27, 27, 16, 30, 40 + + dw $0247, 239, $0300 + db 1, 224 + db 27, 27, 16, 30, 40 + + dw $0251, 251, $0300 + db 1, $00 + db 27, 27, 16, 30, 40 + + dw $0300, 300, $0400 + db 2, $00 + db 27, 27, 16, 30, 40 + + dw $0330, 330, $0400 + db 3, $00 + db 27, 27, 16, 30, 40 + + dw $0360, 360, $0400 + db 4, $00 + db 27, 27, 16, 30, 40 + + dw $0400, 400, $0500 + db 5, $00 + db 27, 27, 16, 30, 40 + + dw $0420, 420, $0500 + db 4, $00 + db 27, 27, 16, 30, 40 + + dw $0450, 450, $0500 + db 3, $00 + db 27, 27, 16, 30, 40 + + dw $0500, 500, $0600 + db 20, $00 + db 27, 27, 10, 30, 25 + + dw $0600, 600, $0700 + db 20, $00 + db 27, 18, 10, 30, 16 + + dw $0700, 700, $0800 + db 20, $00 + db 18, 14, 10, 30, 12 + + dw $0800, 800, $0900 + db 20, $00 + db 14, 8, 10, 30, 6 + + dw $0900, 900, $1000 + db 20, $00 + db 14, 8, 8, 17, 6 + + dw $1000, 1000, $1100 + db 20, $00 + db 8, 8, 8, 17, 6 + + dw $1100, 1000, $1200 + db 20, $00 + db 7, 7, 8, 15, 6 + + dw $1200, 1000, $1300 + db 20, $00 + db 6, 6, 8, 15, 6 + +sTGM3SpeedCurveEnd:: + dw $FFFF + +sDEATSpeedCurve:: + dw $0000, 0, $0100 + db 20, $00 + db 18, 14, 12, 30, 12 + + dw $0100, 0, $0200 + db 20, $00 + db 14, 8, 12, 26, 6 + + dw $0200, 0, $0300 + db 20, $00 + db 14, 8, 11, 22, 6 + + dw $0300, 0, $0400 + db 20, $00 + db 8, 8, 10, 18, 6 + + dw $0400, 0, $0500 + db 20, $00 + db 7, 7, 8, 15, 5 + + dw $0500, 0, $0600 + db 20, $00 + db 6, 6, 8, 15, 4 + +sDEATSpeedCurveEnd:: + dw $FFFF + +sSHIRSpeedCurve:: + dw $0000, 0, $0100 + db 20, $00 + db 12, 8, 10, 18, 6 + + dw $0100, 100, $0200 + db 20, $00 + db 12, 7, 8, 18, 5 + + dw $0200, 200, $0300 + db 20, $00 + db 12, 6, 8, 17, 4 + + dw $0300, 300, $0400 + db 20, $00 + db 6, 6, 8, 15, 4 + + dw $0500, 500, $0600 + db 20, $00 + db 6, 5, 6, 13, 3 + + dw $1100, 1100, $1200 + db 20, $00 + db 6, 5, 6, 10, 3 + + dw $1200, 1200, $1300 + db 20, $00 + db 6, 5, 6, 8, 3 + +sSHIRSpeedCurveEnd:: + dw $FFFF + +sTiles:: DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF DB $00,$00,$00,$00,$00,$00,$00,$00 @@ -532,7 +1138,7 @@ Tiles:: DB $8A,$8A,$8A,$8A,$E4,$E4,$00,$00 DB $00,$00,$62,$62,$94,$94,$88,$88 DB $94,$94,$62,$62,$00,$00,$00,$00 -TilesEnd:: +sTilesEnd:: ENDC diff --git a/src/res/sfx_data.inc b/src/res/sfx_data.inc index bdf9b84..b359c5a 100644 --- a/src/res/sfx_data.inc +++ b/src/res/sfx_data.inc @@ -1,7 +1,11 @@ IF !DEF(SFX_DATA_INC) DEF SFX_DATA_INC EQU 1 -SECTION "SFX Data", ROMX, BANK[2] + +INCLUDE "globals.asm" + + +SECTION "SFX Data", ROMX, BANK[BANK_SFX] ; These sound effects can contain any channel. sSFXPieceI:: db REG_NR12_CH1_VOLEV, $F0, REG_NR22_CH2_VOLEV, $F0, REG_NR11_CH1_LENDT, $BF, REG_NR11_CH1_LENDT, $BF diff --git a/src/res/title_map.inc b/src/res/title_data.inc similarity index 79% rename from src/res/title_map.inc rename to src/res/title_data.inc index 2ff17c3..de405ce 100644 --- a/src/res/title_map.inc +++ b/src/res/title_data.inc @@ -19,8 +19,61 @@ IF !DEF(TITLE_MAP_INC) DEF TITLE_MAP_INC EQU 1 -SECTION "Title Screen Tilemap", ROMX, BANK[1] -TitleScreenTilemap:: +INCLUDE "globals.asm" + + +SECTION "Title Screen Static Data", ROMX, BANK[BANK_TITLE] +sEasterM0:: db $C4, $C6, $C8, $CA, $CC +sEasterM1:: db $C5, $C7, $C9, $CB, $CD + +sEasterC0:: db $CE, $D0, $C8, $CA, $CC, $72, $74, $76, $78, $7A, $D6, $D7 +sEasterC1:: db $CF, $D1, $C9, $CB, $CD, $73, $75, $77, $79, $7B, $01, $01 + +sEasterA0:: db $D2, $D4, $C8, $CA, $CC, $72, $74, $76, $78, $7A, $D6, $D7 +sEasterA1:: db $D3, $D5, $C9, $CB, $CD, $73, $75, $77, $79, $7B, $01, $01 + +sEasterS0:: db $F7, $F9, $C8, $CA, $CC +sEasterS1:: db $F8, $FA, $C9, $CB, $CD + +sOption0:: + db "NORM" + db " INV" + +sOption1:: + db "TGM1" + db "TGM2" + db "TGM3" + db "HELL" + db " NES" + +sOption2:: + db "ARS1" + db "ARS2" + db " NES" + +sOption3:: + db "FIRM" + db "SNIC" + db "HARD" + db "LOCK" + db "NONE" + +sOption4:: + db "DMGT" + db "TGM1" + db "TGM3" + db "DEAT" + db "SHIR" + db "CHIL" + +sOption5:: + db " NO" + db " YES" + +sDisabled:: + db "----" + +sTitleScreenTileMap:: DB $C3,$5B,$4C,$59,$4F,$5A,$5D,$4C,$01,$59 DB $5A,$61,$4C,$01,$01,$FB,$FC,$FD,$FE,$FF DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$01 @@ -89,7 +142,7 @@ TitleScreenTilemap:: DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$01 DB $01,$01,$01,$01,$01,$01,$01,$01,$01,$01 DB $01,$01 -TitleScreenTilemapEnd:: +sTitleScreenTileMapEnd:: ENDC diff --git a/src/rng.asm b/src/rng.asm index c50c297..6ed5116 100644 --- a/src/rng.asm +++ b/src/rng.asm @@ -58,6 +58,8 @@ RNGInit:: ldh [hRNGSeed+3], a ; TGM3 vars + ld b, BANK_GAMEPLAY + rst RSTSwitchBank ld de, sTGM3Bag ld hl, wTGM3Bag ld bc, 35 @@ -66,6 +68,7 @@ RNGInit:: ld hl, wTGM3Droughts ld bc, 7 call UnsafeMemCopy + rst RSTRestoreBank ; Start with a random non-S/Z piece held. : call Next7Piece diff --git a/src/sfx.asm b/src/sfx.asm index 3bc1413..0713e2b 100644 --- a/src/sfx.asm +++ b/src/sfx.asm @@ -421,7 +421,8 @@ SFXPlayNoise:: ; Bail if it's null ret z - ld b, BANK("SFX Data") + ; Bank to sound effects. + ld b, BANK_SFX rst RSTSwitchBank ; Get the register to write to @@ -469,10 +470,10 @@ SFXPlay:: ldh a, [hPlayQueue] cp a, MUSIC_MENU jr nz, :+ - ld b, BANK("Music Data") + ld b, BANK_MUSIC rst RSTSwitchBank jr .play -: ld b, BANK("SFX Data") +: ld b, BANK_SFX rst RSTSwitchBank ; Load the playhead position into HL. diff --git a/src/sprites.asm b/src/sprites.asm index 143988d..f715ec4 100644 --- a/src/sprites.asm +++ b/src/sprites.asm @@ -176,8 +176,18 @@ ApplyNext:: sub a, 7 ; X positions + ld b, a + ldh a, [hGameState] + cp a, STATE_GAMEPLAY_BIG + ld a, b + jr nz, .regular + ld hl, sBigPieceXOffsets + ld de, sBigPieceYOffsets + jr .postoffsets +.regular ld hl, sPieceXOffsets ld de, sPieceYOffsets +.postoffsets cp 0 jr z, .skipoffn .getoffn @@ -296,8 +306,18 @@ ApplyHold:: ; X positions .x + ld b, a + ldh a, [hGameState] + cp a, STATE_GAMEPLAY_BIG + ld a, b + jr nz, .regular + ld hl, sBigPieceXOffsets + ld de, sBigPieceYOffsets + jr .postoffsets +.regular ld hl, sPieceXOffsets ld de, sPieceYOffsets +.postoffsets cp 0 jr z, .skipoffh .getoffh diff --git a/src/state_gameplay.asm b/src/state_gameplay.asm index 6f72bb6..e174984 100644 --- a/src/state_gameplay.asm +++ b/src/state_gameplay.asm @@ -20,6 +20,8 @@ DEF STATE_GAMEPLAY_ASM EQU 1 INCLUDE "globals.asm" +INCLUDE "res/gameplay_data.inc" +INCLUDE "res/gameplay_big_data.inc" DEF MODE_LEADY EQU 0 @@ -47,9 +49,43 @@ hPrePause: ds 1 hRequestedJingle: ds 1 -SECTION "Gameplay Functions", ROM0 - ; Change to game play mode. The event loop will call the event loop and vblank handlers for this mode after this returns. +SECTION "Gameplay Function Trampolines", ROM0 + ; Trampolines to the banked function. SwitchToGameplay:: + ld b, BANK_GAMEPLAY + rst RSTSwitchBank + call SwitchToGameplayB + rst RSTRestoreBank + jp EventLoopPostHandler + + ; Trampolines to the banked function. +SwitchToGameplayBig:: + ld b, BANK_GAMEPLAY_BIG + rst RSTSwitchBank + call SwitchToGameplayBigB + rst RSTRestoreBank + jp EventLoopPostHandler + + ; Banks and jumps to the actual handler. +GamePlayEventLoopHandler:: + ld b, BANK_GAMEPLAY + rst RSTSwitchBank + call GamePlayEventLoopHandlerB + rst RSTRestoreBank + jp EventLoopPostHandler + + ; Banks and jumps to the actual handler. +GamePlayBigEventLoopHandler:: + ld b, BANK_GAMEPLAY_BIG + rst RSTSwitchBank + call GamePlayBigEventLoopHandlerB + rst RSTRestoreBank + jp EventLoopPostHandler + + +SECTION "Gameplay Function Banked", ROMX, BANK[BANK_GAMEPLAY] + ; Change to game play mode. The event loop will call the event loop and vblank handlers for this mode after this returns. +SwitchToGameplayB: ; Turn the screen off if it's on. ldh a, [rLCDC] and LCDCF_ON @@ -59,9 +95,9 @@ SwitchToGameplay:: ldh [rLCDC], a ; Load the gameplay tilemap. -: ld de, GameplayTilemap +: ld de, sGameplayTileMap ld hl, $9800 - ld bc, GameplayTilemapEnd - GameplayTilemap + ld bc, sGameplayTileMapEnd - sGameplayTileMap call UnsafeMemCopy ; Clear OAM. @@ -115,7 +151,7 @@ SwitchToGameplay:: ; Main gameplay event loop. -GamePlayEventLoopHandler:: +GamePlayEventLoopHandlerB:: ; What mode are we in? ld hl, .modejumps ldh a, [hMode] @@ -577,9 +613,7 @@ drawStaticInfo: ld de, hNLevel call ApplyNumbers - call GBCGameplayProcess - - jp EventLoopPostHandler + jp GBCGameplayProcess ; Do the hold action. @@ -657,4 +691,612 @@ DoHold: ret + +SECTION "Gameplay Function Big Banked", ROMX, BANK[BANK_GAMEPLAY_BIG] +; Change to game play mode. The event loop will call the event loop and vblank handlers for this mode after this returns. +SwitchToGameplayBigB: + ; Turn the screen off if it's on. + ldh a, [rLCDC] + and LCDCF_ON + jr z, :+ ; Screen is already off. + wait_vram + xor a, a + ldh [rLCDC], a + + ; Load the gameplay tilemap. +: ld de, sBigGameplayTileMap + ld hl, $9800 + ld bc, sBigGameplayTileMapEnd - sBigGameplayTileMap + call UnsafeMemCopy + + ; Clear OAM. + call ClearOAM + call SetNumberSpritePositions + call ApplyTells + + ; Set up the palettes. + ld a, PALETTE_REGULAR + set_bg_palette + set_obj0_palette + ld a, PALETTE_LIGHTER_1 + set_obj1_palette + + ; Initialize the RNG. + call RNGInit + + ; Initialize the score, level and field. + call ScoreInit + call LevelInit + call BigFieldInit + + ; We don't start with hold spent. + xor a, a + ldh [hHoldSpent], a + + ; Leady mode. + ld a, MODE_LEADY + ldh [hMode], a + ld a, LEADY_TIME + ldh [hModeCounter], a + + ; GBC init + call GBCGameplayInit + + ; Install the event loop handlers. + ld a, STATE_GAMEPLAY_BIG + ldh [hGameState], a + + ; And turn the LCD back on before we start. + ld a, LCDCF_ON | LCDCF_BGON | LCDCF_OBJON | LCDCF_BLK01 + ldh [rLCDC], a + + ; Music end + call SFXKill + + ; Make sure the first game loop starts just like all the future ones. + wait_vblank + wait_vblank_end + ret + + ; Main gameplay event loop. +GamePlayBigEventLoopHandlerB: + ; What mode are we in? + ld hl, .modejumps + ldh a, [hMode] + ld b, 0 + ld c, a + add hl, bc + jp hl + +.modejumps + jp .leadyMode + jp .goMode + jp .postGoMode + jp .prefetchedPieceMode + jp .spawnPieceMode + jp .pieceInMotionMode + jp .delayMode + jp .gameOverMode + jp .preGameOverMode + jp .pauseMode + + + ; Draw "READY" and wait a bit. +.leadyMode + ldh a, [hModeCounter] + cp a, LEADY_TIME + jr nz, :+ + call SFXKill + ld a, SFX_READYGO + call SFXEnqueue + ldh a, [hModeCounter] +: dec a + jr nz, :+ + ld a, MODE_GO + ldh [hMode], a + ld a, GO_TIME +: ldh [hModeCounter], a + ld de, sBigLeady + ld hl, wField+(14*10) + ld bc, 10 + call UnsafeMemCopy + jp .drawStaticInfo + + + ; Draw "GO" and wait a bit. +.goMode + ldh a, [hModeCounter] + dec a + jr nz, :+ + ld a, MODE_POSTGO + ldh [hMode], a + xor a, a +: ldh [hModeCounter], a + ld de, sBigGo + ld hl, wField+(14*10) + ld bc, 10 + call UnsafeMemCopy + jp .drawStaticInfo + + + ; Clear the field, fetch the piece, ready for gameplay. +.postGoMode + ld a, MODE_PREFETCHED_PIECE + ldh [hMode], a + call BigFieldClear + call BigToShadowField + ldh a, [hNextPiece] + ldh [hCurrentPiece], a + call GetNextPiece + jp .drawStaticInfo + + + ; Fetch the next piece. +.prefetchedPieceMode + ; A piece will spawn in the middle, at the top of the screen, not rotated by default. + ld a, $FF + ldh [hRequestedJingle], a + ld a, PIECE_SPAWN_X_BIG + ldh [hCurrentPieceX], a + ld a, PIECE_SPAWN_Y_BIG + ldh [hCurrentPieceY], a + xor a, a ; ROTATION_STATE_DEF + ldh [hCurrentPieceRotationState], a + ldh [hHoldSpent], a + + ; Check if IHS is requested. + ; Apply the hold if so. +.checkIHS + ldh a, [hSelectState] + cp a, 0 + jr z, .loaddefaultjingle + call BigDoHold + jr .postjingle + + ; Enqueue the jingle. +.loaddefaultjingle + ldh a, [hNextPiece] + ldh [hRequestedJingle], a + + ; Check if IRS is requested. + ; Apply the rotation if so. +.checkIRSA + ld a, [wSwapABState] + cp a, 0 + jr z, .lda1 +.ldb1 + ldh a, [hBState] + cp a, 0 + jr z, .checkIRSB + ld a, $FF + ldh [hBState], a + jr .cp1 +.lda1 + ldh a, [hAState] + cp a, 0 + jr z, .checkIRSB + ld a, $FF + ldh [hAState], a +.cp1 + ld a, ROTATION_STATE_CCW + ldh [hCurrentPieceRotationState], a + ldh a, [hNextPiece] + ld b, a + ld a, SFX_IRS + or a, b + ldh [hRequestedJingle], a + jr .postjingle + +.checkIRSB + ld a, [wSwapABState] + cp a, 0 + jr z, .ldb2 +.lda2 + ldh a, [hAState] + cp a, 0 + jr z, .postjingle + ld a, $FF + ldh [hAState], a + jr .cp2 +.ldb2 + ldh a, [hBState] + cp a, 0 + jr z, .postjingle + ld a, $FF + ldh [hBState], a +.cp2 + ld a, ROTATION_STATE_CW + ldh [hCurrentPieceRotationState], a + ldh a, [hNextPiece] + ld b, a + ld a, SFX_IRS + or a, b + ldh [hRequestedJingle], a + jr .postjingle + +.postjingle + ld a, MODE_SPAWN_PIECE + ldh [hMode], a + ; State falls through to the next. + + + ; Spawn the piece. +.spawnPieceMode + call BigTrySpawnPiece + cp a, $FF + jr z, :+ + ld a, MODE_PRE_GAME_OVER + ldh [hMode], a + jp .drawStaticInfo +: ld a, MODE_PIECE_IN_MOTION + ldh [hMode], a + + ; Play the next jingle... maybe! + ldh a, [hHoldSpent] + cp a, $FF + jr z, .pieceInMotionMode + ldh a, [hRequestedJingle] + cp a, $FF + jr z, .pieceInMotionMode + call SFXEnqueue + + + ; This mode lasts for as long as the piece is in motion. + ; Field will let us know when it has locked in place. +.pieceInMotionMode + ldh a, [hStartState] + cp a, 1 + jr nz, :+ + call BigToBackupField + ldh a, [hMode] + ldh [hPrePause], a + ld a, MODE_PAUSED + ldh [hMode], a + jp .drawStaticInfo + +: call BigFieldProcess + + ; Do we hold? + ldh a, [hSelectState] + cp a, 1 + jr nz, :+ + ldh a, [hHoldSpent] + cp a, $FF + jr z, :+ + ; Reset position and rotation. + ld a, PIECE_SPAWN_X_BIG + ldh [hCurrentPieceX], a + ld a, PIECE_SPAWN_Y_BIG + ldh [hCurrentPieceY], a + xor a, a ; ROTATION_STATE_DEF + ldh [hCurrentPieceRotationState], a + call BigDoHold + ld a, MODE_SPAWN_PIECE + ldh [hMode], a + + ; Do we go into delay state? +: ldh a, [hCurrentLockDelayRemaining] + cp a, 0 + jr nz, :+ + ld a, MODE_DELAY + ldh [hMode], a + ; No fall through this time. + +: jp .drawStaticInfo + + +.delayMode + ldh a, [hStartState] + cp a, 1 + jr nz, :+ + call BigToBackupField + ldh a, [hMode] + ldh [hPrePause], a + ld a, MODE_PAUSED + ldh [hMode], a + jp .drawStaticInfo + +: call BigFieldDelay + + ldh a, [hRemainingDelay] + cp a, 0 + jr nz, :+ + ld a, MODE_PREFETCHED_PIECE + ldh [hMode], a + +: jp .drawStaticInfo + + +.preGameOverMode + ; Spawn the failed piece. + call BigForceSpawnPiece + + ; Draw the field in grey. + ; Yes. This really unrolls the loop that many times. + ld hl, wField+(4*10) + REPT 60 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty1\@ + ld a, GAME_OVER_OTHER+1 + ld [hl+], a + jr .skip1\@ +.notempty1\@ + ld a, GAME_OVER_OTHER + ld [hl+], a +.skip1\@ + ENDR + DEF off = 0 + REPT 10 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty2\@ + ld a, GAME_OVER_R10+10+off + ld [hl+], a + jr .skip2\@ +.notempty2\@ + ld a, GAME_OVER_R10+off + ld [hl+], a +.skip2\@ + DEF off += 1 + ENDR + REPT 10 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty3\@ + ld a, GAME_OVER_OTHER+1 + ld [hl+], a + jr .skip3\@ +.notempty3\@ + ld a, GAME_OVER_OTHER + ld [hl+], a +.skip3\@ + ENDR + DEF off = 0 + REPT 10 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty4\@ + ld a, GAME_OVER_R12+10+off + ld [hl+], a + jr .skip4\@ +.notempty4\@ + ld a, GAME_OVER_R12+off + ld [hl+], a +.skip4\@ + DEF off += 1 + ENDR + REPT 10 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty5\@ + ld a, GAME_OVER_OTHER+1 + ld [hl+], a + jr .skip5\@ +.notempty5\@ + ld a, GAME_OVER_OTHER + ld [hl+], a +.skip5\@ + ENDR + DEF off = 0 + REPT 10 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty6\@ + ld a, GAME_OVER_R14+10+off + ld [hl+], a + jr .skip6\@ +.notempty6\@ + ld a, GAME_OVER_R14+off + ld [hl+], a +.skip6\@ + DEF off += 1 + ENDR + REPT 90 + ld a, [hl] + cp a, TILE_FIELD_EMPTY + jr nz, .notempty7\@ + ld a, GAME_OVER_OTHER+1 + ld [hl+], a + jr .skip7\@ +.notempty7\@ + ld a, GAME_OVER_OTHER + ld [hl+], a +.skip7\@ + ENDR + + ld a, MODE_GAME_OVER + ldh [hMode], a + + +.gameOverMode + ; Retry? + ldh a, [hAState] + cp a, 1 + jr nz, :+ + call RNGInit + call ScoreInit + call LevelInit + call BigFieldInit + xor a, a + ldh [hHoldSpent], a + ld a, MODE_LEADY + ldh [hMode], a + ld a, LEADY_TIME + ldh [hModeCounter], a + jp .drawStaticInfo + + ; Quit +: ldh a, [hBState] + cp a, 1 + jp nz, .drawStaticInfo + call SwitchToTitle + jp EventLoopPostHandler + + +.pauseMode + ; Quick reset. + ldh a, [hAState] + cp a, 0 + jr z, :+ + ldh a, [hBState] + cp a, 0 + jr z, :+ + ldh a, [hSelectState] + cp a, 0 + jr z, :+ + call SwitchToTitle + jp EventLoopPostHandler + + ; Unpause +: ldh a, [hStartState] + cp a, 1 + jr nz, :+ + call BigFromBackupField + ldh a, [hPrePause] + ldh [hMode], a + jr .drawStaticInfo + + ; Draw PAUSE all over the field. +: ld de, sBigPause + ld hl, wField+(4*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(6*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(8*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(10*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(12*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(14*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(16*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(18*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(20*10) + ld bc, 20 + call UnsafeMemCopy + ld de, sBigPause + ld hl, wField+(22*10) + ld bc, 20 + call UnsafeMemCopy + jr .drawStaticInfo + + + ; Always draw the score, level, next piece, and held piece. +.drawStaticInfo +: ldh a, [hNextPiece] + call ApplyNext + + ldh a, [hHeldPiece] + call ApplyHold + + ld hl, wSPRScore1 + ld de, hScore + call ApplyNumbers + + ld hl, wSPRCLevel1 + ld de, hCLevel + call ApplyNumbers + + ld hl, wSPRNLevel1 + ld de, hNLevel + call ApplyNumbers + + jp GBCGameplayProcess + + + ; Do the hold action. +BigDoHold: + ; Mark hold as spent. + ld a, $FF + ldh [hHoldSpent], a + + ; Check if IRS is requested. + ; Apply the rotation if so. +.checkIRSHA + ld a, [wSwapABState] + cp a, 0 + jr z, .lda3 +.ldb3 + ldh a, [hBState] + cp a, 0 + jr z, .checkIRSHB + ld a, $FF + ldh [hBState], a + jr .cp3 +.lda3 + ldh a, [hAState] + cp a, 0 + jr z, .checkIRSHB + ld a, $FF + ldh [hAState], a +.cp3 + ld a, ROTATION_STATE_CCW + ldh [hCurrentPieceRotationState], a + call SFXKill + ld a, SFX_IRS | SFX_IHS + call SFXEnqueue + jr .doHoldOperation + +.checkIRSHB + ld a, [wSwapABState] + cp a, 0 + jr z, .ldb4 +.lda4 + ldh a, [hAState] + cp a, 0 + jr z, .noRotation + ld a, $FF + ldh [hAState], a + jr .cp4 +.ldb4 + ldh a, [hBState] + cp a, 0 + jr z, .noRotation + ld a, $FF + ldh [hBState], a +.cp4 + ld a, ROTATION_STATE_CW + ldh [hCurrentPieceRotationState], a + call SFXKill + ld a, SFX_IRS | SFX_IHS + call SFXEnqueue + jr .doHoldOperation + +.noRotation + call SFXKill + ld a, SFX_IHS + call SFXEnqueue + xor a, a ; ROTATION_STATE_DEF + ldh [hCurrentPieceRotationState], a + +.doHoldOperation + ldh a, [hHeldPiece] + ld b, a + ldh a, [hCurrentPiece] + ldh [hHeldPiece], a + ld a, b + ldh [hCurrentPiece], a + ret + + ENDC diff --git a/src/state_title.asm b/src/state_title.asm index 4b2aa02..3cba7b8 100644 --- a/src/state_title.asm +++ b/src/state_title.asm @@ -20,15 +20,99 @@ DEF STATE_TITLE_ASM EQU 1 INCLUDE "globals.asm" +INCLUDE "res/title_data.inc" SECTION "Title Variables", WRAM0 wSelected:: ds 1 -SECTION "Title Functions", ROM0 - ; Change to title mode. The event loop will call the event loop and vblank handlers for this mode after this returns. +SECTION "Title Function Trampolines", ROM0 + ; Trampolines to the banked function. SwitchToTitle:: + ld b, BANK_TITLE + rst RSTSwitchBank + call SwitchToTitleB + rst RSTRestoreBank + jp EventLoopPostHandler + + ; Banks and jumps to the actual handler. +TitleEventLoopHandler:: + ld b, BANK_TITLE + rst RSTSwitchBank + call TitleEventLoopHandlerB + rst RSTRestoreBank + jp EventLoopPostHandler + + ; Banks and jumps to the actual handler. +TitleVBlankHandler:: + ld b, BANK_TITLE + rst RSTSwitchBank + call TitleVBlankHandlerB + rst RSTRestoreBank + jp EventLoop + +DrawOption6: + ld b, BANK_OTHER + rst RSTSwitchBank + + ldh a, [hStartSpeed] + ld l, a + ldh a, [hStartSpeed+1] + ld h, a + ld a, [hl] + swap a + and a, $0F + ld b, a + ld a, TILE_0 + add a, b + ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+2 + ld [hl], a + + ldh a, [hStartSpeed] + ld l, a + ldh a, [hStartSpeed+1] + ld h, a + ld a, [hl] + and a, $0F + ld b, a + ld a, TILE_0 + add a, b + ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+3 + ld [hl], a + + ldh a, [hStartSpeed] + ld l, a + ldh a, [hStartSpeed+1] + ld h, a + inc hl + ld a, [hl] + swap a + and a, $0F + ld b, a + ld a, TILE_0 + add a, b + ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+0 + ld [hl], a + + ldh a, [hStartSpeed] + ld l, a + ldh a, [hStartSpeed+1] + ld h, a + inc hl + ld a, [hl] + and a, $0F + ld b, a + ld a, TILE_0 + add a, b + ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+1 + ld [hl], a + + jp RSTRestoreBank + + +SECTION "Title Functions Banked", ROMX, BANK[BANK_TITLE] +SwitchToTitleB: ; Turn the screen off if it's on. ldh a, [rLCDC] and LCDCF_ON @@ -38,9 +122,9 @@ SwitchToTitle:: ldh [rLCDC], a ; Load the gameplay tilemap. -: ld de, TitleScreenTilemap +: ld de, sTitleScreenTileMap ld hl, $9800 - ld bc, TitleScreenTilemapEnd - TitleScreenTilemap + ld bc, sTitleScreenTileMapEnd - sTitleScreenTileMap call UnsafeMemCopy ; Title screen easter egg. @@ -136,9 +220,8 @@ SwitchToTitle:: wait_vblank_end ret - ; Handles title screen input. -TitleEventLoopHandler:: +TitleEventLoopHandlerB: call GBCTitleProcess ; Start game? @@ -152,8 +235,10 @@ TitleEventLoopHandler:: or a, c cp a, 1 jr nz, .up - call SwitchToGameplay - jp EventLoopPostHandler + ldh a, [hSelectState] + cp a, 0 + jp z, SwitchToGameplay + jp SwitchToGameplayBig ; Change menu selection? .up @@ -165,10 +250,10 @@ TitleEventLoopHandler:: jr z, :+ dec a ld [wSelected], a - jp EventLoopPostHandler + ret : ld a, TITLE_OPTIONS-1 ld [wSelected], a - jp EventLoopPostHandler + ret .down ldh a, [hDownState] @@ -179,10 +264,10 @@ TitleEventLoopHandler:: jr z, :+ inc a ld [wSelected], a - jp EventLoopPostHandler + ret : xor a, a ld [wSelected], a - jp EventLoopPostHandler + ret .left ldh a, [hLeftState] @@ -194,7 +279,8 @@ TitleEventLoopHandler:: and 3 cp a, 3 jr nz, .right - jp DecrementOption + call DecrementOption + ret .right ldh a, [hRightState] @@ -206,10 +292,10 @@ TitleEventLoopHandler:: and 3 cp a, 3 jr nz, .done - jp IncrementOption + call IncrementOption .done - jp EventLoopPostHandler + ret ; Decrements the currently selected option. @@ -224,11 +310,11 @@ DecrementOption: dec a ld [wSwapABState], a ld [rSwapABState], a - jp EventLoopPostHandler + ret : ld a, BUTTON_MODE_COUNT-1 ld [wSwapABState], a ld [rSwapABState], a - jp EventLoopPostHandler + ret .opt1 cp a, 1 @@ -239,11 +325,11 @@ DecrementOption: dec a ld [wRNGModeState], a ld [rRNGModeState], a - jp EventLoopPostHandler + ret : ld a, RNG_MODE_COUNT-1 ld [wRNGModeState], a ld [rRNGModeState], a - jp EventLoopPostHandler + ret .opt2 cp a, 2 @@ -254,11 +340,11 @@ DecrementOption: dec a ld [wRotModeState], a ld [rRotModeState], a - jp EventLoopPostHandler + ret : ld a, ROT_MODE_COUNT-1 ld [wRotModeState], a ld [rRotModeState], a - jp EventLoopPostHandler + ret .opt3 cp a, 3 @@ -269,11 +355,11 @@ DecrementOption: dec a ld [wDropModeState], a ld [rDropModeState], a - jp EventLoopPostHandler + ret : ld a, DROP_MODE_COUNT-1 ld [wDropModeState], a ld [rDropModeState], a - jp EventLoopPostHandler + ret .opt4 cp a, 4 @@ -285,12 +371,12 @@ DecrementOption: ld [wSpeedCurveState], a ld [rSpeedCurveState], a call InitSpeedCurve - jp EventLoopPostHandler + ret : ld a, SCURVE_COUNT-1 ld [wSpeedCurveState], a ld [rSpeedCurveState], a call InitSpeedCurve - jp EventLoopPostHandler + ret .opt5 cp a, 5 @@ -301,15 +387,14 @@ DecrementOption: dec a ld [wAlways20GState], a ld [rAlways20GState], a - jp EventLoopPostHandler + ret : ld a, HIG_MODE_COUNT-1 ld [wAlways20GState], a ld [rAlways20GState], a - jp EventLoopPostHandler + ret .opt6 jr DecrementLevel - jp EventLoopPostHandler ; Decrements start level. @@ -327,7 +412,7 @@ DecrementLevel: ld a, h ldh [hStartSpeed+1], a ld [rSelectedStartLevel+1], a - jp CheckLevelRange + ret ; Increments the selected option. @@ -342,11 +427,11 @@ IncrementOption: inc a ld [wSwapABState], a ld [rSwapABState], a - jp EventLoopPostHandler + ret : xor a, a ld [wSwapABState], a ld [rSwapABState], a - jp EventLoopPostHandler + ret .opt1 cp a, 1 @@ -357,11 +442,11 @@ IncrementOption: inc a ld [wRNGModeState], a ld [rRNGModeState], a - jp EventLoopPostHandler + ret : xor a, a ld [wRNGModeState], a ld [rRNGModeState], a - jp EventLoopPostHandler + ret .opt2 cp a, 2 @@ -372,11 +457,11 @@ IncrementOption: inc a ld [wRotModeState], a ld [rRotModeState], a - jp EventLoopPostHandler + ret : xor a, a ld [wRotModeState], a ld [rRotModeState], a - jp EventLoopPostHandler + ret .opt3 cp a, 3 @@ -387,11 +472,11 @@ IncrementOption: inc a ld [wDropModeState], a ld [rDropModeState], a - jp EventLoopPostHandler + ret : xor a, a ld [wDropModeState], a ld [rDropModeState], a - jp EventLoopPostHandler + ret .opt4 cp a, 4 @@ -403,12 +488,12 @@ IncrementOption: ld [wSpeedCurveState], a ld [rSpeedCurveState], a call InitSpeedCurve - jp EventLoopPostHandler + ret : xor a, a ld [wSpeedCurveState], a ld [rSpeedCurveState], a call InitSpeedCurve - jp EventLoopPostHandler + ret .opt5 cp a, 5 @@ -419,15 +504,14 @@ IncrementOption: inc a ld [wAlways20GState], a ld [rAlways20GState], a - jp EventLoopPostHandler + ret : xor a, a ld [wAlways20GState], a ld [rAlways20GState], a - jp EventLoopPostHandler + ret .opt6 jr IncrementLevel - jp EventLoopPostHandler ; Increments start level. @@ -557,11 +641,11 @@ CheckLevelRange: ldh [hStartSpeed+1], a .notatstart - jp EventLoopPostHandler + ret ; Handles the display of the menu. -TitleVBlankHandler:: +TitleVBlankHandlerB: call ToATTR ld a, TILE_UNSELECTED @@ -707,58 +791,7 @@ TitleVBlankHandler:: ; Draw option 6. .opt6 - ldh a, [hStartSpeed] - ld l, a - ldh a, [hStartSpeed+1] - ld h, a - ld a, [hl] - swap a - and a, $0F - ld b, a - ld a, TILE_0 - add a, b - ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+2 - ld [hl], a - - ldh a, [hStartSpeed] - ld l, a - ldh a, [hStartSpeed+1] - ld h, a - ld a, [hl] - and a, $0F - ld b, a - ld a, TILE_0 - add a, b - ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+3 - ld [hl], a - - ldh a, [hStartSpeed] - ld l, a - ldh a, [hStartSpeed+1] - ld h, a - inc hl - ld a, [hl] - swap a - and a, $0F - ld b, a - ld a, TILE_0 - add a, b - ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+0 - ld [hl], a - - ldh a, [hStartSpeed] - ld l, a - ldh a, [hStartSpeed+1] - ld h, a - inc hl - ld a, [hl] - and a, $0F - ld b, a - ld a, TILE_0 - add a, b - ld hl, TITLE_OPTION_6+TITLE_OPTION_OFFSET+1 - ld [hl], a - jp EventLoop + jp DrawOption6 ENDC