dmgtris/src/level.asm

729 lines
13 KiB
NASM
Raw Normal View History

2023-10-21 15:28:38 +00:00
; DMGTRIS
; Copyright (C) 2023 - Randy Thiemann <randy.thiemann@gmail.com>
; 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 <https://www.gnu.org/licenses/>.
2023-10-13 09:20:28 +00:00
IF !DEF(LEVEL_ASM)
DEF LEVEL_ASM EQU 1
2023-10-16 05:47:11 +00:00
INCLUDE "globals.asm"
2023-10-21 18:49:52 +00:00
SECTION "High Level Variables", HRAM
hCurrentDAS:: ds 1
hCurrentARE:: ds 1
2023-10-26 12:29:06 +00:00
hCurrentLineARE:: ds 1
hCurrentLockDelay:: ds 1
hCurrentLineClearDelay:: ds 1
hCurrentIntegerGravity:: ds 1
hCurrentFractionalGravity:: ds 1
hNextSpeedUp:: ds 2
hSpeedCurvePtr:: ds 2
2023-10-21 14:31:26 +00:00
hStartSpeed:: ds 2
hRequiresLineClear:: ds 1
2023-10-20 15:25:42 +00:00
hLevel:: ds 2
2023-10-21 18:49:52 +00:00
hCLevel:: ds 4
hNLevel:: ds 6 ; The extra 2 bytes will be clobbered by the sprite drawing functions.
hPrevHundreds:: ds 1
2023-11-08 21:35:08 +00:00
SECTION "Level Variables", WRAM0
wBoneActivationLevel: ds 2
wInvisActivationLevel: ds 2
wKillScreenActivationLevel: ds 2
2023-11-08 23:27:44 +00:00
wKillScreenActivationLevelBCD: ds 2
2023-11-09 19:56:44 +00:00
wLastLockLevel: ds 2
wStaffRollDuration:: ds 2
2023-11-08 21:35:08 +00:00
wBonesActive:: ds 1
wInvisActive:: ds 1
2023-11-08 22:36:10 +00:00
wKillScreenActive:: ds 1
2023-11-08 23:10:25 +00:00
wLockLevel:: ds 1
2023-11-09 19:56:44 +00:00
wShouldGoStaffRoll:: ds 1
wNoMoreLocks:: ds 1
2023-11-08 21:35:08 +00:00
2023-10-13 09:20:28 +00:00
SECTION "Level Functions", ROM0
2023-10-27 19:37:32 +00:00
; Loads the initial state of the speed curve.
2023-10-13 09:20:28 +00:00
LevelInit::
2023-10-28 17:04:55 +00:00
; Bank to speed curve data.
ld b, BANK_OTHER
rst RSTSwitchBank
2023-10-13 09:20:28 +00:00
xor a, a
ldh [hRequiresLineClear], a
2023-11-08 21:35:08 +00:00
ld [wBonesActive], a
ld [wInvisActive], a
2023-11-08 22:36:10 +00:00
ld [wKillScreenActive], a
2023-11-08 23:10:25 +00:00
ld [wLockLevel], a
2023-11-09 19:56:44 +00:00
ld [wShouldGoStaffRoll], a
ld [wNoMoreLocks], a
2023-10-21 14:31:26 +00:00
ldh a, [hStartSpeed]
ld l, a
ldh a, [hStartSpeed+1]
ld h, a
; CLevel
ld a, [hl+]
ld b, a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hCLevel+3], a
2023-10-21 14:31:26 +00:00
ld a, b
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hCLevel+2], a
2023-10-21 14:31:26 +00:00
ld a, [hl+]
ld b, a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hCLevel+1], a
2023-10-21 14:31:26 +00:00
ld a, b
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hCLevel], a
2023-10-21 14:31:26 +00:00
ld a, l
ldh [hSpeedCurvePtr], a
ld a, h
ldh [hSpeedCurvePtr+1], a
2023-10-21 14:31:26 +00:00
; Binary level.
ld a, [hl+]
ldh [hLevel], a
ld a, [hl+]
ldh [hLevel+1], a
; NLevel
ld a, [hl+]
ld b, a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hNLevel+3], a
2023-10-21 14:31:26 +00:00
ld a, b
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hNLevel+2], a
2023-10-21 14:31:26 +00:00
ld a, [hl+]
ld b, a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hNLevel+1], a
2023-10-21 14:31:26 +00:00
ld a, b
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ldh [hNLevel], a
2023-10-21 14:31:26 +00:00
2023-11-08 21:35:08 +00:00
; Get special data.
call SpecialLevelInit
2023-10-28 17:04:55 +00:00
; Restore the bank before returning.
rst RSTRestoreBank
2023-10-27 19:37:32 +00:00
jp DoSpeedUp
2023-11-08 21:35:08 +00:00
SpecialLevelInit:
ld a, [wSpeedCurveState]
ld b, a
add a, b
add a, b
ld b, 0
ld c, a
ld hl, .jumps
add hl, bc
jp hl
.jumps
jp .dmgt
jp .tgm1
jp .tgm3
jp .deat
jp .shir
jp .chil
jp .myco
.dmgt
ld hl, sDMGTSpeedCurveSpecialData
jr .loaddata
.tgm1
ld hl, sTGM1SpeedCurveSpecialData
jr .loaddata
.tgm3
ld hl, sTGM3SpeedCurveSpecialData
jr .loaddata
.deat
ld hl, sDEATSpeedCurveSpecialData
jr .loaddata
.shir
ld hl, sSHIRSpeedCurveSpecialData
jr .loaddata
.chil
ld hl, sCHILSpeedCurveSpecialData
jr .loaddata
.myco
ld hl, sMYCOSpeedCurveSpecialData
jr .loaddata
.loaddata
ld a, [hl+]
ld [wBoneActivationLevel], a
ld a, [hl+]
ld [wBoneActivationLevel+1], a
ld a, [hl+]
ld [wInvisActivationLevel], a
ld a, [hl+]
ld [wInvisActivationLevel+1], a
ld a, [hl+]
ld [wKillScreenActivationLevel], a
2023-11-08 23:27:44 +00:00
ld a, [hl+]
2023-11-08 21:35:08 +00:00
ld [wKillScreenActivationLevel+1], a
2023-11-08 23:27:44 +00:00
ld a, [hl+]
ld [wKillScreenActivationLevelBCD], a
2023-11-09 19:56:44 +00:00
ld a, [hl+]
2023-11-08 23:27:44 +00:00
ld [wKillScreenActivationLevelBCD+1], a
2023-11-09 19:56:44 +00:00
ld a, [hl+]
ld [wLastLockLevel], a
ld a, [hl+]
ld [wLastLockLevel+1], a
ld a, [hl+]
ld [wStaffRollDuration], a
ld a, [hl]
ld [wStaffRollDuration+1], a
2023-11-08 21:35:08 +00:00
ret
; Increment level and speed up if necessary. Level increment in E.
; Levels may only increment by single digits.
LevelUp::
2023-11-08 23:10:25 +00:00
; Return if our level is hard locked.
ld a, [wLockLevel]
cp a, $FF
ret z
; Return if we're maxed out.
2023-10-21 18:49:52 +00:00
ld hl, hCLevel
ld a, $09
and a, [hl]
inc hl
and a, [hl]
inc hl
and a, [hl]
inc hl
and a, [hl]
ld c, [hl]
cp a, $09
ret z
2023-10-20 15:25:42 +00:00
; Binary addition
ldh a, [hLevel]
ld l, a
ldh a, [hLevel+1]
ld h, a
ld a, e
add a, l
ld l, a
adc a, h
2023-10-24 20:21:48 +00:00
sub a, l
2023-10-20 15:25:42 +00:00
ldh [hLevel+1], a
2023-10-24 20:21:48 +00:00
ld a, l
2023-10-20 15:25:42 +00:00
ldh [hLevel], a
2023-10-18 09:59:22 +00:00
; Save the current hundred digit.
2023-10-21 18:49:52 +00:00
ldh a, [hCLevel+1]
ldh [hPrevHundreds], a
2023-10-18 07:31:08 +00:00
; Increment LSD.
2023-10-18 07:31:08 +00:00
.doit
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+3
ld a, [hl]
add a, e
ld [hl], a
cp a, $0A
jr c, .checknlevel
sub a, 10
ld [hl], a
; Carry the one...
dec hl
ld a, [hl]
inc a
ld [hl], a
cp a, $0A
jr c, .checknlevel
xor a, a
ld [hl], a
; Again...
dec hl
ld a, [hl]
inc a
ld [hl], a
cp a, $0A
jr c, .checknlevel
xor a, a
ld [hl], a
; Once more...
dec hl
ld a, [hl]
inc a
ld [hl], a
cp a, $0A
jr c, .checknlevel
; We're maxed out. Both levels should be set to 9999.
ld a, 9
2023-10-21 18:49:52 +00:00
ldh [hCLevel], a
ldh [hCLevel+1], a
ldh [hCLevel+2], a
ldh [hCLevel+3], a
2023-10-24 20:21:48 +00:00
ld hl, 9999
ld a, l
ldh [hLevel], a
ld a, h
ldh [hLevel+1], a
call DoSpeedUp
2023-11-08 21:35:08 +00:00
call CheckSpecialLevelConditions
call SFXKill
2023-11-01 20:24:22 +00:00
ld a, SFX_RANKGM
2023-10-27 19:37:32 +00:00
jp SFXEnqueue
.checknlevel
; Make wNLevel make sense.
2023-10-21 18:49:52 +00:00
ld hl, hCLevel
ld a, $09
and a, [hl]
inc hl
and a, [hl]
cp a, $09
; If wCLevel begins 99, wNLevel should be 9999.
jr nz, :+
ld a, 9
2023-10-21 18:49:52 +00:00
ldh [hNLevel], a
ldh [hNLevel+1], a
ldh [hNLevel+2], a
ldh [hNLevel+3], a
; If the last two digits of wCLevel are 98, play the bell.
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+2
ld a, [hl+]
cp a, 9
jr nz, .checkspeedup
ld a, [hl]
cp a, 8
jr nz, .checkspeedup
2023-10-17 11:56:00 +00:00
ld a, $FF
ldh [hRequiresLineClear], a
2023-10-24 11:35:51 +00:00
ld a, SFX_LEVELLOCK
call SFXEnqueue
2023-10-18 09:59:22 +00:00
jr .leveljinglemaybe
; Otherwise check the second digit of wCLevel.
2023-10-21 18:49:52 +00:00
: ld hl, hCLevel+1
ld a, [hl]
; If it's 9, wNLevel should be y0xx. With y being the first digit of wCLevel+1
cp a, 9
jr nz, :+
2023-10-21 18:49:52 +00:00
ld hl, hNLevel+1
xor a, a
ld [hl], a
2023-10-21 18:49:52 +00:00
ld hl, hCLevel
ld a, [hl]
inc a
2023-10-21 18:49:52 +00:00
ld hl, hNLevel
ld [hl], a
jr .bellmaybe
; Otherwise just set the second digit of wNLevel to the second digit of wCLevel + 1.
2023-10-21 18:49:52 +00:00
: ld hl, hCLevel+1
ld a, [hl]
inc a
2023-10-21 18:49:52 +00:00
ld hl, hNLevel+1
ld [hl], a
.bellmaybe
; If the last two digits of wCLevel are 99, play the bell.
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+2
ld a, [hl+]
and a, [hl]
cp a, 9
2023-10-18 09:59:22 +00:00
jr nz, .leveljinglemaybe
2023-11-09 19:56:44 +00:00
ld a, [wNoMoreLocks]
cp a, $FF
jr z, .checkspeedup
2023-10-17 11:56:00 +00:00
ld a, $FF
ldh [hRequiresLineClear], a
2023-10-24 11:35:51 +00:00
ld a, SFX_LEVELLOCK
call SFXEnqueue
2023-10-18 09:59:22 +00:00
.leveljinglemaybe
2023-10-21 18:49:52 +00:00
ldh a, [hPrevHundreds]
2023-10-18 09:59:22 +00:00
ld b, a
2023-10-21 18:53:54 +00:00
ldh a, [hCLevel+1]
2023-10-18 09:59:22 +00:00
cp a, b
jr z, .checkspeedup
2023-10-24 11:35:51 +00:00
ld a, SFX_LEVELUP
2023-10-18 09:59:22 +00:00
call SFXEnqueue
.checkspeedup
2023-11-08 21:35:08 +00:00
call CheckSpecialLevelConditions
ldh a, [hNextSpeedUp]
and a, $F0
jr z, :+
2023-10-18 09:59:22 +00:00
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ld hl, hCLevel
cp a, [hl]
2023-10-24 03:08:38 +00:00
jr z, :+
ret nc
: ldh a, [hNextSpeedUp]
and a, $0F
jr z, :+
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+1
cp a, [hl]
jr z, :+
ret nc
: ldh a, [hNextSpeedUp+1]
and a, $F0
jr z, :+
2023-10-18 09:59:22 +00:00
swap a
and a, $0F
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+2
cp a, [hl]
jr z, :+
ret nc
: ldh a, [hNextSpeedUp+1]
and a, $0F
2023-10-27 19:37:32 +00:00
jr z, DoSpeedUp
2023-10-21 18:49:52 +00:00
ld hl, hCLevel+3
cp a, [hl]
2023-10-27 19:37:32 +00:00
jr z, DoSpeedUp
ret nc ; This can fall through to the next function here. This is intentional.
2023-10-27 19:37:32 +00:00
; Iterates over the speed curve and loads the new constants.
DoSpeedUp:
2023-10-28 17:04:55 +00:00
; Bank to speed curve data.
ld b, BANK_OTHER
rst RSTSwitchBank
; Load curve ptr.
ldh a, [hSpeedCurvePtr]
ld l, a
ldh a, [hSpeedCurvePtr+1]
ld h, a
2023-10-21 14:31:26 +00:00
; There's 4 bytes we don't care about.
inc hl
inc hl
inc hl
inc hl
; Get all the new data.
ld a, [hl+]
ldh [hCurrentIntegerGravity], a
ld a, [hl+]
ldh [hCurrentFractionalGravity], a
ld a, [hl+]
ldh [hCurrentARE], a
ld a, [hl+]
2023-10-26 12:29:06 +00:00
ldh [hCurrentLineARE], a
ld a, [hl+]
ldh [hCurrentDAS], a
ld a, [hl+]
ldh [hCurrentLockDelay], a
ld a, [hl+]
ldh [hCurrentLineClearDelay], a
ld a, [hl+]
ldh [hNextSpeedUp+1], a
ld a, [hl+]
ldh [hNextSpeedUp], a
; Save the new pointer.
ld a, l
ldh [hSpeedCurvePtr], a
ld a, h
ldh [hSpeedCurvePtr+1], a
2023-10-23 10:16:16 +00:00
; Do we want to force 20G?
ld a, [wAlways20GState]
cp a, 0
2023-10-28 17:04:55 +00:00
jp z, RSTRestoreBank
2023-10-23 10:16:16 +00:00
ld a, 20
ldh [hCurrentIntegerGravity], a
2023-10-27 01:24:30 +00:00
ld a, $00
ldh [hCurrentFractionalGravity], a
2023-10-28 17:04:55 +00:00
jp RSTRestoreBank
2023-10-13 09:20:28 +00:00
2023-11-08 21:35:08 +00:00
CheckSpecialLevelConditions:
2023-11-09 19:56:44 +00:00
; Is our nlevel > our kill screen?
ld hl, wKillScreenActivationLevelBCD+1
ld a, [hl]
swap a
and a, $0F
ld b, a
ldh a, [hNLevel]
cp a, b
jr c, .nooverride
jr nz, .override
ld a, [hl-]
and a, $0F
ld b, a
ldh a, [hNLevel+1]
cp a, b
jr c, .nooverride
jr nz, .override
ld a, [hl]
swap a
and a, $0F
ld b, a
ldh a, [hNLevel+2]
cp a, b
jr c, .nooverride
jr nz, .override
ld a, [hl]
and a, $0F
ld b, a
ldh a, [hNLevel+3]
cp a, b
jr c, .nooverride
.override
ld hl, wKillScreenActivationLevelBCD
ld a, [hl]
and a, $0F
ldh [hNLevel+3], a
ld a, [hl+]
swap a
and a, $0F
ldh [hNLevel+2], a
ld a, [hl]
and a, $0F
ldh [hNLevel+1], a
ld a, [hl]
swap a
and a, $0F
ldh [hNLevel], a
2023-11-08 21:35:08 +00:00
; Get our level in bc
2023-11-09 19:56:44 +00:00
.nooverride
2023-11-08 21:35:08 +00:00
ldh a, [hLevel]
ld c, a
ldh a, [hLevel+1]
ld b, a
2023-11-09 19:56:44 +00:00
; Do we need to do a special lock?
.speciallock
ld hl, wLastLockLevel
ld a, [hl+]
cp a, $FF ; $FF means never.
jp z, .bones
; Load the level, binary in de.
ld e, a
ld d, [hl]
; Check if BC == DE...
ld a, b
cp a, d
jr nz, .bones
ld a, c
cp a, e
jr nz, .bones
; Jingle and level lock.
ld a, $FF
ldh [hRequiresLineClear], a
ld [wNoMoreLocks], a
ld a, SFX_LEVELLOCK
push bc
call SFXEnqueue
pop bc
2023-11-08 21:35:08 +00:00
; Bones?
.bones
ld hl, wBoneActivationLevel
ld a, [hl+]
cp a, $FF ; $FF means never.
jp z, .invis
; Load the level, binary in de.
ld e, a
ld d, [hl]
; Check if BC >= DE...
; Skip if B < D.
ld a, b
cp a, d
jr c, .invis
; We can confidently enter the bone zone if B > D.
jr nz, .enterthebonezone
; If B == D, we need to check C and E...
; Skip if C < E. Otherwise enter the bone zone.
ld a, c
cp a, e
jr c, .invis
.enterthebonezone
ld a, $FF
ld [wBonesActive], a
; Invis?
.invis
ld hl, wInvisActivationLevel
ld a, [hl+]
cp a, $FF ; $FF means never.
jp z, .killscreen
; Load the level, binary in de.
ld e, a
ld d, [hl]
; Check if BC >= DE...
; Skip if B < D.
ld a, b
cp a, d
jr c, .killscreen
; We can confidently vanish if B > D.
jr nz, .vanishoxyaction
; If B == D, we need to check C and E...
; Skip if C < E. Otherwise vanish.
ld a, c
cp a, e
jr c, .killscreen
.vanishoxyaction
ld a, $FF
ld [wInvisActive], a
; Kill screen?
.killscreen
ld hl, wKillScreenActivationLevel
ld a, [hl+]
cp a, $FF
ret z
; Load the level, binary in de.
ld e, a
ld d, [hl]
; Check if BC >= DE...
; Ret if B < D.
ld a, b
cp a, d
ret c
; We can confidently rip if B > D.
jr nz, .rip
; If B == D, we need to check C and E...
; Skip if C < E. Otherwise rip.
ld a, c
cp a, e
ret c
.rip
2023-11-09 19:56:44 +00:00
call SFXKill
2023-11-08 22:36:10 +00:00
ld a, $FF
ld [wKillScreenActive], a
2023-11-08 23:27:44 +00:00
ld hl, wKillScreenActivationLevelBCD
ld a, [hl]
and a, $0F
ldh [hCLevel+3], a
ldh [hNLevel+3], a
ld a, [hl+]
swap a
and a, $0F
ldh [hCLevel+2], a
ldh [hNLevel+2], a
ld a, [hl]
and a, $0F
ldh [hCLevel+1], a
ldh [hNLevel+1], a
ld a, [hl]
swap a
and a, $0F
ldh [hCLevel], a
ldh [hNLevel], a
ld a, $FF
ld [wLockLevel], a
2023-11-09 19:56:44 +00:00
; Since we triggered a kill screen, does this mean the game now just ends, or do we transition to the staff roll?
.staffroll
ld hl, wStaffRollDuration
ld a, [hl+]
cp a, $FF
jr z, .justkill
; Yes, tell the game that we should go to staff roll instead.
ld a, $FF
ld [wShouldGoStaffRoll], a
ret
.justkill
ld a, 1
ldh [hCurrentARE], a
ldh [hCurrentLineARE], a
ldh [hCurrentDAS], a
ldh [hCurrentLockDelay], a
ldh [hCurrentLineClearDelay], a
ld a, 20
ldh [hCurrentIntegerGravity], a
xor a, a
ldh [hCurrentFractionalGravity], a
2023-11-08 22:36:10 +00:00
ret
TriggerKillScreen::
2023-11-09 19:56:44 +00:00
call SFXKill
2023-11-08 22:36:10 +00:00
ld a, 1
ldh [hCurrentARE], a
ldh [hCurrentLineARE], a
ldh [hCurrentDAS], a
ldh [hCurrentLockDelay], a
ldh [hCurrentLineClearDelay], a
ld a, 20
ldh [hCurrentIntegerGravity], a
xor a, a
ldh [hCurrentFractionalGravity], a
ld [wKillScreenActivationLevel], a
ld [wKillScreenActivationLevel+1], a
ld a, $FF
ld [wKillScreenActive], a
2023-11-08 21:35:08 +00:00
ret
2023-10-13 09:20:28 +00:00
ENDC