Compare commits

..

No commits in common. "4fa9f68107a7c88cf7a138b55955ce4cf903d3e8" and "e9c84abc9e300a6acd5e8c8b2f0ff6506a43294b" have entirely different histories.

19 changed files with 281 additions and 340 deletions

Binary file not shown.

Binary file not shown.

View File

@ -25,7 +25,7 @@ INCLUDE "globals.asm"
SECTION "High Banking Variables", HRAM
hBankBackup: ds 1
; 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, and 0x38
SECTION "Switch Bank", ROM0[$08]
; Saves the current bank and switches to the bank in b.
RSTSwitchBank::

View File

@ -23,7 +23,6 @@ INCLUDE "globals.asm"
SECTION "DMG Intro Effect", ROM0
; Does a small effect on boot with the nintendo logo.
DoDMGEffect::
ld a, [wInitialA]
cp a, $11

View File

@ -62,10 +62,6 @@ hShouldLockIfGrounded: ds 1
SECTION "Field Functions", ROM0
; Initializes the field completely blank.
; Initializes the combo counter to 1.
; Initializes the bravo counter to 0.
; Initializes the shadow field.
FieldInit::
xor a, a
ldh [hBravo], a
@ -73,14 +69,14 @@ FieldInit::
ldh [hComboCt], a
ld hl, wField
ld bc, 10*24
ld d, TILE_BLANK
ld d, 1
call UnsafeMemSet
ld hl, wShadowField
ld bc, 14*26
ld d, $FF
jp UnsafeMemSet
; Fills the field with the empty tile.
FieldClear::
ld hl, wField
ld bc, 10*24
@ -88,16 +84,13 @@ FieldClear::
jp UnsafeMemSet
; Backs up the field.
; This backup field is used for pausing the game.
ToBackupField::
ld de, wField
ld hl, wBackupField
ld de, wField
ld bc, 10*24
jp UnsafeMemCopy
; Restores the backup of the field for ending pause mode.
FromBackupField::
ld hl, wField
ld de, wBackupField
@ -105,8 +98,6 @@ FromBackupField::
jp UnsafeMemCopy
; Copies the field to the shadow field.
; This shadow field is used to calculate whether or not the piece can fit.
ToShadowField::
ld hl, wField
ld de, wShadowField+2
@ -128,7 +119,6 @@ ToShadowField::
ret
; Restores the shadow field to the main field.
FromShadowField:
ld hl, wField
ld de, wShadowField+2
@ -150,10 +140,9 @@ FromShadowField:
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.
; This routine will copy wField onto the screen.
BlitField::
; Hold on, are we on a gbc?
ld a, [wInitialA]
cp a, $11
jp z, GBCBlitField
@ -201,39 +190,39 @@ BlitField::
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.
; This has to finish just before the first LCDC interrupt of the frame or stuff will break in weird ways.
jp EventLoop
; The current piece ID is used to get the offset into the rotation states
; corresponding to that piece's zero rotation.
SetPieceData:
ldh a, [hCurrentPiece]
sla a
sla a
sla a
sla a
ld c, a
ld b, 0
ld hl, sPieceRotationStates
add hl, bc
ld a, l
ld de, 16
: cp a, 0
jr z, :+
add hl, de
dec a
jr :-
: ld a, l
ldh [hPieceDataBase], a
ld a, h
ldh [hPieceDataBase+1], a
ldh a, [hCurrentPiece]
ld hl, sPieceFastRotationStates
add hl, bc
ld a, l
ld de, 16
: cp a, 0
jr z, :+
add hl, de
dec a
jr :-
: ld a, l
ldh [hPieceDataBaseFast], a
ld a, h
ldh [hPieceDataBaseFast+1], a
ret
; The rotation state is a further offset of 4 bytes.
SetPieceDataOffset:
ldh a, [hCurrentPieceRotationState]
sla a
@ -259,6 +248,7 @@ XYToSFieldPtr:
ret
; Converts piece Y in B and a piece X in A to a pointer to the field in HL.
XYToFieldPtr:
ld hl, wField-2
@ -276,9 +266,6 @@ XYToFieldPtr:
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.)
GetPieceData:
ldh a, [hPieceDataBase]
ld l, a
@ -286,13 +273,12 @@ GetPieceData:
ld h, a
ldh a, [hPieceDataOffset]
ld c, a
ld b, 0
xor a, a
ld b, a
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.
GetPieceDataFast:
ldh a, [hPieceDataBaseFast]
ld l, a
@ -305,12 +291,61 @@ GetPieceDataFast:
add hl, bc
ret
; Checks if the piece can fit at the current position, but fast.
; HL should point to the piece's rotation state data.
; DE should be pointing to the right place in the SHADOW field.
CanPieceFitFast:
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
; 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.
CanPieceFit:
xor a, a
ld b, a
@ -468,63 +503,6 @@ CanPieceFit:
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.
CanPieceFitFast:
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.
ForceSpawnPiece::
call SetPieceData
call SetPieceDataOffset
@ -535,7 +513,8 @@ ForceSpawnPiece::
ld d, h
ld e, l
call GetPieceData
ld b, GAME_OVER_OTHER
ld a, GAME_OVER_OTHER
ld b, a
push hl
push de
pop hl
@ -543,8 +522,6 @@ ForceSpawnPiece::
jp DrawPiece
; Initialize the state for a new piece and attempts to spawn it.
; On return, A will be $FF if the piece fit.
TrySpawnPiece::
; Always reset these for a new piece.
xor a, a
@ -731,8 +708,6 @@ FindMaxG:
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.
FieldProcess::
; **************************************************************
; SETUP
@ -861,7 +836,7 @@ FieldProcess::
cp a, PIECE_Z
jr z, .trykickright
; I piece only kicks in ARS2
; I piece only kicks in TGM3/TGW3/EASY/EAWY
cp a, PIECE_I
jr nz, :+
ld a, [wRotModeState]
@ -957,7 +932,7 @@ FieldProcess::
ldh [hLockDelayForce], a
jp .norot
; In ARS2 mode, there are a few other kicks possible.
; In TGM3, TGW3, EASY, and EAWY modes, there are a few other kicks possible.
.maybetgm3rot
ld a, [wRotModeState]
cp a, ROT_MODE_ARSTI
@ -1253,7 +1228,6 @@ FieldProcess::
ld a, $FF
ldh [hAwardDownBonus], a
ld a, 20
ldh [hWantedG], a
ld b, a
ldh a, [hActualG]
cp a, b
@ -1286,7 +1260,7 @@ FieldProcess::
; Gravity?
: ldh a, [hCurrentFractionalGravity]
cp a, $00 ; 0 is the sentinel value that should be interpreted as "every frame"
cp a, $00
jr z, :+
ld b, a
ldh a, [hGravityCtr]
@ -1469,7 +1443,7 @@ FieldProcess::
ldh a, [hWantedG]
cp a, 1
jr nz, .postghost
ld a, [wInitialA] ; Let's not do the flickering on the GBC.
ld a, [wInitialA]
cp a, $11
jr z, .ghost
ldh a, [hEvenFrame]
@ -1507,22 +1481,20 @@ FieldProcess::
cp a, b
jr z, .drawpiece
; If we're not grounded, draw the piece normally.
ldh a, [hGrounded]
cp a, $FF
jr nz, .drawpiece
; If the lock delay is 0, draw the piece in the final color.
ldh a, [hWantedTile]
add a, 7
ldh a, [hCurrentPiece]
ld b, TILE_PIECE_0+7
add a, b
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 GetTileShade
@ -1543,7 +1515,7 @@ FieldProcess::
call DrawPiece
ret
; Performs a lookup to see how "locked" the piece is.
GetTileShade:
ldh a, [hCurrentLockDelay]
cp a, 30
@ -1651,8 +1623,6 @@ GetTileShade:
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.
FieldDelay::
; Switch on the delay state.
ld a, [wDelayState]
@ -1691,7 +1661,7 @@ FieldDelay::
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 a, DELAY_STATE_LINE_PRE_CLEAR ; If there were line clears, do a line clear delay, then an ARE delay.
ld [wDelayState], a
ldh a, [hCurrentLineClearDelay]
ldh [hRemainingDelay], a
@ -1834,7 +1804,7 @@ FieldDelay::
; Line clear delay.
; Count down the delay. If we're out of delay, clear the lines and go to LINE_ARE.
; Count down the delay. If we're out of delay, clear the lines and go to ARE.
.lineclear
ldh a, [hRemainingDelay]
dec a
@ -1888,12 +1858,12 @@ FieldDelay::
ldh [hCurrentPiece], a
call GetNextPiece
; Kill the sound for the next piece.
jp SFXKill
call SFXKill
ret
; Shifts B into the line clear list.
; Also increments the line clear count.
AppendClearedLine:
ldh a, [hLineClearCt]
inc a
@ -1909,8 +1879,6 @@ AppendClearedLine:
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.
FindClearedLines:
xor a, a
ldh [hLineClearCt], a
@ -1946,7 +1914,7 @@ FindClearedLines:
ret
; Goes through the list of cleared lines and marks those lines with the "line clear" tile.
MarkClear:
ldh a, [hClearedLines]
cp a, $FF
@ -1998,10 +1966,10 @@ MarkClear:
jr nz, :-
ld bc, 10
ld d, TILE_CLEARING
jp UnsafeMemSet
call UnsafeMemSet
ret
; Once again, scans the field for cleared lines, but this time removes them.
ClearLines:
ld de, 0

View File

@ -38,11 +38,9 @@ DEF R3 EQU %0000000000011111
SECTION "GBC Shadow Tilemap", WRAM0, ALIGN[8]
wShadowTilemap:: ds 32*32
SECTION "GBC Shadow Tile Attributes", WRAM0, ALIGN[8]
wShadowTileAttrs:: ds 32*32
SECTION "GBC Variables", WRAM0
wOuterReps:: ds 1
wInnerReps:: ds 1
@ -50,7 +48,6 @@ wTitlePal:: ds 1
SECTION "GBC Functions", ROM0
; Copies the shadow tile attribute map to vram using instant HDMA.
ToATTR::
ld a, [wInitialA]
cp a, $11
@ -74,7 +71,38 @@ ToATTR::
ret
; Sets up GBC registers for the title state.
ToVRAM::
; Bank 1
ld a, 1
ldh [rVBK], a
ld a, HIGH(wShadowTileAttrs)
ldh [rHDMA1], a
ld a, LOW(wShadowTileAttrs)
ldh [rHDMA2], a
ld a, HIGH($9800)
ldh [rHDMA3], a
ld a, LOW($9800)
ldh [rHDMA4], a
ld a, 40
ldh [rHDMA5], a
; Bank 0
ld a, 0
ldh [rVBK], a
ld a, HIGH(wShadowTilemap)
ldh [rHDMA1], a
ld a, LOW(wShadowTilemap)
ldh [rHDMA2], a
ld a, HIGH($9800)
ldh [rHDMA3], a
ld a, LOW($9800)
ldh [rHDMA4], a
ld a, 39 | $80
ldh [rHDMA5], a
jp EventLoop
GBCTitleInit::
ld a, [wInitialA]
cp a, $11
@ -356,7 +384,7 @@ GBCTitleInit::
ld [wTitlePal], a
ret
; Sets the GBC registers for the gameplay state.
GBCGameplayInit::
ld a, [wInitialA]
cp a, $11
@ -650,7 +678,6 @@ GBCGameplayInit::
ret
; Additional GBC effects for the title screen process state.
GBCTitleProcess::
ld a, [wInitialA]
cp a, $11
@ -698,10 +725,10 @@ GBCTitleProcess::
ld a, 3
ld d, a
ld bc, 32
jp UnsafeMemSet
call UnsafeMemSet
ret
; Additional GBC effects for the gameplay process state.
GBCGameplayProcess::
ld a, [wInitialA]
cp a, $11
@ -919,38 +946,8 @@ GBCGameplayProcess::
ret
; Copies the shadow tile maps to VRAM using HDMA. The attributes are copied using instant mode
; The tile data is done using hblank mode.
GBCBlitField::
ToVRAM::
; Bank 1
ld a, 1
ldh [rVBK], a
ld a, HIGH(wShadowTileAttrs)
ldh [rHDMA1], a
ld a, LOW(wShadowTileAttrs)
ldh [rHDMA2], a
ld a, HIGH($9800)
ldh [rHDMA3], a
ld a, LOW($9800)
ldh [rHDMA4], a
ld a, 40
ldh [rHDMA5], a
; Bank 0
ld a, 0
ldh [rVBK], a
ld a, HIGH(wShadowTilemap)
ldh [rHDMA1], a
ld a, LOW(wShadowTilemap)
ldh [rHDMA2], a
ld a, HIGH($9800)
ldh [rHDMA3], a
ld a, LOW($9800)
ldh [rHDMA4], a
ld a, 39 | $80
ldh [rHDMA5], a
jp EventLoop
jp ToVRAM
ENDC

View File

@ -35,7 +35,6 @@ hSelectState:: ds 1
SECTION "Input Functions", ROM0
; Zeroes out all button states.
InputInit::
xor a, a
ldh [hUpState], a
@ -49,9 +48,6 @@ InputInit::
ret
; Gets the current state of all buttons.
; Held buttons are incremented. Buttons that aren't held are reset to 0.
; Left/Right cause Up/Down to be reset as well.
GetInput::
; Get the button state.
.btns

View File

@ -27,13 +27,12 @@ hLCDCCtr:: ds 1
SECTION "Interrupt Initialization Functions", ROM0
; Zeroes out the interrupt counter.
IntrInit::
xor a, a
ldh [hLCDCCtr], a
ret
; Sets up the STAT interrupt.
InitializeLCDCInterrupt::
ld a, STATF_LYC
ldh [rSTAT], a
@ -50,8 +49,6 @@ InitializeLCDCInterrupt::
SECTION "LCDC Interrupt", ROM0[INT_HANDLER_STAT]
; This interrupt handler will be called every 7 scanlines, scrolling up the tile map by 1 line. This has the
; effect of making the tiles appear as 8x7 pixels, and making 20 rows fit on the screen.
LCDCInterrupt:
push af
push hl

View File

@ -41,11 +41,22 @@ hPrevHundreds:: ds 1
SECTION "Level Functions", ROM0
; Loads the initial state of the speed curve.
LevelInit::
xor a, a
ldh [hLevel], a
ldh [hLevel+1], a
ldh [hCLevel], a
ldh [hCLevel+1], a
ldh [hCLevel+2], a
ldh [hCLevel+3], a
ldh [hNLevel], a
ldh [hNLevel+2], a ; Note +1 is inited later.
ldh [hNLevel+3], a
ldh [hRequiresLineClear], a
ld a, 1
ldh [hNLevel+1], a
ldh a, [hStartSpeed]
ld l, a
ldh a, [hStartSpeed+1]
@ -98,8 +109,8 @@ LevelInit::
and a, $0F
ldh [hNLevel], a
jp DoSpeedUp
call DoSpeedUp
ret
; Increment level and speed up if necessary. Level increment in E.
; Levels may only increment by single digits.
@ -188,7 +199,8 @@ LevelUp::
ldh [hLevel+1], a
call DoSpeedUp
ld a, SFX_RANKUP
jp SFXEnqueue
call SFXEnqueue
ret
.checknlevel
; Make wNLevel make sense.
@ -294,14 +306,16 @@ LevelUp::
: ldh a, [hNextSpeedUp+1]
and a, $0F
jr z, DoSpeedUp
jr z, :+
ld hl, hCLevel+3
cp a, [hl]
jr z, DoSpeedUp
ret nc ; This can fall through to the next function here. This is intentional.
jr z, :+
ret nc
: call DoSpeedUp
ret
; Iterates over the speed curve and loads the new constants.
DoSpeedUp:
; Load curve ptr.
ldh a, [hSpeedCurvePtr]

View File

@ -39,6 +39,10 @@ wAlways20GState:: ds 1
wInitialA:: ds 1
wInitialB:: ds 1
wInitialC:: ds 1
wInitialD:: ds 1
wInitialE:: ds 1
wInitialH:: ds 1
wInitialL:: ds 1
SECTION "Stack", WRAM0
@ -48,7 +52,6 @@ wStackEnd::
SECTION "Code Entry Point", ROM0
; Main entry point. Does some set up and then goes into an infinite event loop initialized on the title screen.
Main::
; Load the initial registers. For reasons.
ld [wInitialA], a
@ -56,6 +59,14 @@ Main::
ld [wInitialB], a
ld a, c
ld [wInitialC], a
ld a, d
ld [wInitialD], a
ld a, e
ld [wInitialE], a
ld a, h
ld [wInitialH], a
ld a, l
ld [wInitialL], a
; Let the DMG have some fun with the initial screen.
call DoDMGEffect
@ -117,7 +128,6 @@ Main::
call SwitchToTitle
; Event loop time!
EventLoop::
; Play the sound effect, if any.
call SFXPlay

View File

@ -23,7 +23,7 @@ INCLUDE "globals.asm"
SECTION "Memory Functions", ROM0
; Copies data from de to hl, bc bytes. Doesn't check for vram access.
; Copies data from de to hl, bc bytes
UnsafeMemCopy::
ld a, [de]
ld [hl+], a
@ -35,7 +35,7 @@ UnsafeMemCopy::
ret
; Copies data from de to hl, bc bytes. Checks for vram access.
; Copies data from de to hl, bc bytes
SafeMemCopy::
wait_vram
ld a, [de]
@ -47,8 +47,7 @@ SafeMemCopy::
jr nz, SafeMemCopy
ret
; Sets memory from hl to hl+bc to d. Doesn't check for vram access.
; Sets memory from hl to hl+bc to d
UnsafeMemSet::
ld [hl], d
inc hl
@ -58,8 +57,6 @@ UnsafeMemSet::
jr nz, UnsafeMemSet
ret
; Sets memory from hl to hl+bc to d. Checks for vram access.
SafeMemSet::
wait_vram
ld [hl], d

View File

@ -38,7 +38,6 @@ wTGM3WorstDroughtIdx: ds 1
section "RNG Functions", ROM0
; Snapshots the initial seed for a game, then initializes the history and piece queue.
RNGInit::
; Do some bit fuckery on the seed using the gameboy's free-running timers.
ldh a, [rDIV]
@ -113,7 +112,8 @@ RNGInit::
; Generate the next 2 to fill up the queue.
call GetNextPiece
jp GetNextPiece
call GetNextPiece
ret
; Shift the generated piece into the history and save it.
@ -354,27 +354,21 @@ GetNextTGM3Piece:
ld [hl], a
ret
; Gets the next piece depending on RNG mode.
GetNextPiece::
ld hl, .nextpiecejumps
ld a, [wRNGModeState]
ld b, 0
ld c, a
add a, c
add a, c
ld c, a
add hl, bc
jp hl
.nextpiecejumps
jp GetNextTGM1Piece
jp GetNextTGM2Piece
jp GetNextTGM3Piece
jp GetNextHellPiece
jp GetNextNesPiece
cp a, RNG_MODE_HELL
jp z, GetNextHellPiece
cp a, RNG_MODE_TGM1
jp z, GetNextTGM1Piece
cp a, RNG_MODE_TGM2
jp z, GetNextTGM2Piece
cp a, RNG_MODE_TGM3
jp z, GetNextTGM3Piece
cp a, RNG_MODE_NES
jp z, GetNextNesPiece
; Tries generating bytes until it gets one in [0; 35)
Next35Piece:
: call NextByte
and a, $3F
@ -383,7 +377,6 @@ Next35Piece:
ret
; Tries generating bytes until it gets one in [0; 7)
Next7Piece:
: call NextByte
and a, $07
@ -392,7 +385,6 @@ Next7Piece:
ret
; Cyrcles the RNG returning a random byte in a.
NextByte:
; Load seed
ld hl, hRNGSeed+3

View File

@ -30,7 +30,6 @@ hScoreIncrementHead:: ds 1
SECTION "Score Functions", ROM0
; Wipes the score.
ScoreInit::
xor a, a
ldh [hScore], a
@ -50,7 +49,6 @@ ScoreInit::
ldh [hScoreIncrementBCD+5], a
ret
; Increases the current score by the amount in wScoreIncrement.
IncreaseScore::
; Wipe the old BCD score.
@ -188,7 +186,8 @@ IncreaseScore::
xor a, a
ldh [hScore], a
ld a, SFX_RANKUP
jp SFXEnqueue
call SFXEnqueue
ret
ENDC

View File

@ -70,9 +70,8 @@ hNoisePlayhead:: ds 2
SECTION "SFX Functions", ROM0
; Audio on, volume on, and enable all channels.
; Zeroes out all playheads and the queue.
SFXInit::
; Audio on, volume on, and enable all channels.
ld a, $80
ldh [rNR52], a
ld a, $FF
@ -93,8 +92,8 @@ SFXInit::
ret
; Pop the head of the queue into A, the tail of the queue will be set to $FF.
SFXPopQueue:
; Pop the head of the queue into A, the tail of the queue will be set to $FF.
ldh a, [hPlayQueue]
ld b, a
ldh a, [hPlayQueue+1]
@ -109,8 +108,8 @@ SFXPopQueue:
ret
; Push A onto the tail of the queue, the head of the queue will be pushed off.
SFXPushQueue:
; Push A onto the tail of the queue, the head of the queue will be pushed off.
ld b, a
ldh a, [hPlayQueue+1]
ldh [hPlayQueue], a
@ -123,18 +122,18 @@ SFXPushQueue:
ret
; Process the queue, if there's more to play, it will do so.
SFXProcessQueue:
; Clear the playhead.
xor a, a
ldh [hPlayhead], a
ldh [hPlayhead+1], a
; Music will just repeat.
ldh a, [hPlayQueue]
cp a, MUSIC_MENU
jr nz, :+
jr SFXEnqueue
call SFXEnqueue
ret
; Try 4 times to pop a sound effect off the queue.
: call SFXPopQueue
@ -151,10 +150,10 @@ SFXProcessQueue:
ret z
; If we got a valid sound effect, then play it.
jr SFXEnqueue
call SFXEnqueue
ret
; Noise effects use their own playhead that can play at the same time as the normal queue.
SFXTriggerNoise::
cp a, SFX_LINE_CLEAR
jr nz, :+
@ -192,7 +191,8 @@ SFXEnqueue::
or a, l
jr z, :+
ld a, b
jr SFXPushQueue
call SFXPushQueue
ret
; Menu music
: ld a, b
@ -203,7 +203,9 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sMusicMenu)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
; Piece jingles.
: ld a, b
@ -213,7 +215,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceI)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_I | SFX_IRS
@ -222,7 +225,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSI)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_S
@ -231,7 +235,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceS)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_S | SFX_IRS
@ -240,7 +245,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSS)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_Z
@ -249,7 +255,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceZ)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_Z | SFX_IRS
@ -258,7 +265,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSZ)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_J
@ -267,7 +275,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceJ)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_J | SFX_IRS
@ -276,7 +285,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSJ)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_L
@ -285,7 +295,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceL)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_L | SFX_IRS
@ -294,7 +305,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSL)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_O
@ -303,7 +315,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceO)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_O | SFX_IRS
@ -312,7 +325,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRSO)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_T
@ -321,7 +335,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceT)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: ld a, b
cp a, PIECE_T | SFX_IRS
@ -330,7 +345,9 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXPieceIRST)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
; IRS
: cp a, SFX_IHS
@ -339,7 +356,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXIHS)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
: cp a, SFX_IHS | SFX_IRS
jr nz, :+
@ -347,7 +365,9 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXIHSIRS)
ldh [hPlayhead+1], a
jp SFXPlay
call SFXPlay
ret
; Leveling
: cp a, SFX_LEVELLOCK
@ -356,7 +376,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXLevelLock)
ldh [hPlayhead+1], a
jr SFXPlay
call SFXPlay
ret
: cp a, SFX_LEVELUP
jr nz, :+
@ -364,7 +385,9 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXLevelUp)
ldh [hPlayhead+1], a
jr SFXPlay
call SFXPlay
ret
; Other
: cp a, SFX_RANKUP
@ -373,7 +396,8 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXRankUp)
ldh [hPlayhead+1], a
jr SFXPlay
call SFXPlay
ret
: cp a, SFX_READYGO
ret nz
@ -381,9 +405,10 @@ SFXEnqueue::
ldh [hPlayhead], a
ld a, HIGH(sSFXReadyGo)
ldh [hPlayhead+1], a
jr SFXPlay
call SFXPlay
ret
; Kill the non-noise sound and clear the queue.
SFXKill::
; Kill all sound without pops.
ld a, %00111111
@ -391,10 +416,12 @@ SFXKill::
ldh [rNR21], a
ld a, $FF
ldh [rNR31], a
;ldh [rNR41], a
ld a, %01000000
ldh [rNR14], a
ldh [rNR24], a
ldh [rNR34], a
;ldh [rNR44], a
; Clear the queue.
ld a, $FF
@ -408,8 +435,6 @@ SFXKill::
ret
; Play routine for the noise channel.
; Must be called every frame.
SFXPlayNoise::
; Get the noise playhead.
ldh a, [hNoisePlayhead]
@ -459,11 +484,11 @@ SFXPlayNoise::
ldh [hNoisePlayhead], a
ld a, h
ldh [hNoisePlayhead+1], a
jp RSTRestoreBank
rst RSTRestoreBank
ret
; Play routine for the regular sfx channels.
; Must be called every frame.
; This play routine must be called every frame.
SFXPlay::
; Bank to correct bank.
ldh a, [hPlayQueue]
@ -485,7 +510,8 @@ SFXPlay::
; Nothing to do if it's a null ptr.
or a, l
jr nz, .getRegister
jp RSTRestoreBank
rst RSTRestoreBank
ret
; Otherwise, get the register to write to.
.getRegister
@ -496,7 +522,8 @@ SFXPlay::
cp a, $FE
jr nz, :+
rst RSTRestoreBank
jp SFXProcessQueue
call SFXProcessQueue
ret
; If it's $FF, then we're done for this frame.
: cp a, $FF
@ -519,7 +546,8 @@ SFXPlay::
ldh [hPlayhead], a
ld a, h
ldh [hPlayhead+1], a
jp RSTRestoreBank
rst RSTRestoreBank
ret
ENDC

View File

@ -90,15 +90,14 @@ OAMDMAEnd::
SECTION "OAM Functions", ROM0
; Copies the OAM handler to HRAM.
CopyOAMHandler::
ld de, OAMDMA
ld hl, hOAMDMA
ld bc, OAMDMAEnd - OAMDMA
jp UnsafeMemCopy
call UnsafeMemCopy
ret
; Clears OAM and shadow OAM.
ClearOAM::
ld hl, _OAMRAM
ld bc, $9F
@ -107,12 +106,12 @@ ClearOAM::
ld hl, wShadowOAM
ld bc, $9F
ld d, 0
jp UnsafeMemSet
call SafeMemSet
ret
SECTION "Domain Specific Functions", ROM0
; Puts the mode tells into sprites and displays them.
ApplyTells::
ld a, TELLS_BASE_Y
ld [wSPRModeRNG], a
@ -156,8 +155,7 @@ ApplyTells::
ret
; Draws the next pieces as a sprite.
; Index of next piece in A.
; Index of next piece in A.
ApplyNext::
; Correct color
ld [wSPRNext1+3], a
@ -221,6 +219,7 @@ ApplyNext::
add a, NEXT_BASE_Y
ld [wSPRNext4+0], a
; Queue
ld a, QUEUE_BASE_Y
ld [wSPRQueue1A], a
@ -255,10 +254,17 @@ ApplyNext::
ld [wSPRQueue2B+2], a
ret
; Draws the held piece.
; Index of held piece in A.
; Index of hold piece in A.
ApplyHold::
cp 255
jr nz, .doApplyHold
ld hl, wSPRHold1
ld bc, 16
ld d, 0
call UnsafeMemSet
ret
.doApplyHold
; Correct color
ld [wSPRHold1+3], a
ld [wSPRHold2+3], a
@ -276,6 +282,7 @@ ApplyHold::
ld a, b
jr z, .show
.hide
ld b, a
ld a, TILE_BLANK
@ -343,9 +350,8 @@ ApplyHold::
ret
; Generic function to draw a BCD number (6 digits) as 6 sprites.
; Address of first sprite in hl.
; Address of first digit in de.
; Address of first sprite in hl.
; Address of first digit in de.
ApplyNumbers::
inc hl
inc hl
@ -384,10 +390,11 @@ ApplyNumbers::
ld a, [de]
add a, TILE_0
ld [hl], a
add hl, bc
inc de
ret
; Positions all number sprites for gameplay.
SetNumberSpritePositions::
ld a, SCORE_BASE_X
ld hl, wSPRScore1

View File

@ -34,9 +34,8 @@ rSelectedStartLevel:: ds 2
SECTION "SRAM Functions", ROM0
; Check if our SRAM is initialized and of the correct version.
; Restores it if so, otherwise initializes it.
RestoreSRAM::
; Check if our SRAM is initialized and of the correct version.
ld a, [rCheck]
cp a, LOW(__UTC_YEAR__)
jr nz, InitializeSRAM
@ -76,7 +75,6 @@ RestoreSRAM::
ldh [hStartSpeed+1], a
ret
; Initializes SRAM with default values.
InitializeSRAM:
; Set the magic id.
ld a, LOW(__UTC_YEAR__)
@ -127,5 +125,4 @@ InitializeSRAM:
ld [rSelectedStartLevel+1], a
ret
ENDC

View File

@ -48,7 +48,6 @@ 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.
SwitchToGameplay::
; Turn the screen off if it's on.
ldh a, [rLCDC]
@ -114,7 +113,6 @@ SwitchToGameplay::
ret
; Main gameplay event loop.
GamePlayEventLoopHandler::
; What mode are we in?
ld hl, .modejumps
@ -136,7 +134,6 @@ GamePlayEventLoopHandler::
jp preGameOverMode
jp pauseMode
; Draw "READY" and wait a bit.
leadyMode:
ldh a, [hModeCounter]
@ -362,7 +359,6 @@ delayMode:
: jp drawStaticInfo
preGameOverMode:
; Spawn the failed piece.
call ForceSpawnPiece
@ -582,7 +578,6 @@ drawStaticInfo:
jp EventLoopPostHandler
; Do the hold action.
DoHold:
; Mark hold as spent.
ld a, $FF

View File

@ -27,7 +27,6 @@ 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.
SwitchToTitle::
; Turn the screen off if it's on.
ldh a, [rLCDC]
@ -137,7 +136,6 @@ SwitchToTitle::
ret
; Handles title screen input.
TitleEventLoopHandler::
call GBCTitleProcess
@ -211,8 +209,6 @@ TitleEventLoopHandler::
.done
jp EventLoopPostHandler
; Decrements the currently selected option.
DecrementOption:
.opt0
ld a, [wSelected]
@ -311,8 +307,6 @@ DecrementOption:
jr DecrementLevel
jp EventLoopPostHandler
; Decrements start level.
DecrementLevel:
; Decrement
ldh a, [hStartSpeed]
@ -330,7 +324,6 @@ DecrementLevel:
jp CheckLevelRange
; Increments the selected option.
IncrementOption:
.opt0
ld a, [wSelected]
@ -429,8 +422,6 @@ IncrementOption:
jr IncrementLevel
jp EventLoopPostHandler
; Increments start level.
IncrementLevel:
; Increment
ldh a, [hStartSpeed]
@ -447,11 +438,11 @@ IncrementLevel:
ld [rSelectedStartLevel+1], a
jp CheckLevelRange
; Wipes the start level upon selecting a new speed curve.
InitSpeedCurve:
ld a, [wSpeedCurveState]
call GetStart
.set
ld a, l
ldh [hStartSpeed], a
ld [rSelectedStartLevel], a
@ -461,7 +452,7 @@ InitSpeedCurve:
ret
; Gets the end of a speed curve.
GetEnd:
ld a, [wSpeedCurveState]
cp a, SCURVE_DMGT
@ -487,8 +478,6 @@ GetEnd:
: ld bc, sCHILSpeedCurveEnd
ret
; Gets the beginning of a speed curve.
GetStart:
ld a, [wSpeedCurveState]
cp a, SCURVE_DMGT
@ -514,8 +503,6 @@ GetStart:
: ld hl, sCHILSpeedCurve
ret
; Make sure we don't overflow the level range.
CheckLevelRange:
; At end?
call GetEnd
@ -560,7 +547,6 @@ CheckLevelRange:
jp EventLoopPostHandler
; Handles the display of the menu.
TitleVBlankHandler::
call ToATTR

View File

@ -27,63 +27,22 @@ hFrameCtr:: ds 1
hEvenFrame:: ds 1
SECTION "Time Variables", WRAM0
wMinutes:: ds 1
wSeconds:: ds 1
wFrames:: ds 1
SECTION "Time Functions", ROM0
; Zeroes all timers and gets the free-running timer ticking.
TimeInit::
xor a, a
ldh [rTMA], a
ldh [hEvenFrame], a
ldh [hFrameCtr], a
ld [wMinutes], a
ld [wSeconds], a
ld [wFrames], a
ld a, TACF_262KHZ | TACF_START
ldh [rTAC], a
ret
; Resets the minute-second timer.
ResetTime::
xor a, a
ld [wMinutes], a
ld [wSeconds], a
ld [wFrames], a
ret
; Increments the global timer. Also saves whether we're on an even frame.
HandleTimers::
ldh a, [hFrameCtr]
inc a
ldh [hFrameCtr], a
and 1
ldh [hEvenFrame], a
ld a, [wFrames]
inc a
ld [wFrames], a
cp a, 60
ret nz
xor a, a
ld [wFrames], a
ld a, [wSeconds]
inc a
ld [wSeconds], a
cp a, 60
ret nz
xor a, a
ld [wSeconds], a
ld a, [wMinutes]
inc a
ld [wMinutes], a
ret