pokepinball/home.asm
2023-01-06 18:41:03 -06:00

3313 lines
54 KiB
NASM

SECTION "rst 00", ROM0
di
jp Entry
SECTION "rst 10", ROM0
jp DelayFrame
SECTION "rst 18", ROM0
jp JumpToFuncInTable
SECTION "rst 20", ROM0
jp _ReadHalfword
SECTION "VBlankInt", ROM0
jp VBlank
SECTION "STATInt", ROM0
jp LCDCStatus
SECTION "TimerInt", ROM0
jp Timer
SECTION "SerialInt", ROM0
jp Serial
SECTION "JoypadInt", ROM0
jp Joypad
SECTION "Entry", ROM0
Entry: ; 0x100
nop
jp Start
SECTION "Header", ROM0
; The header is generated by rgbfix.
; The space here is allocated to prevent code from being overwritten.
rept $150 - $104
db 0 ;using ds fills the area with the fill value (which may not be $00); if this is changed from $00 the ROM won't build
endr
SECTION "Main", ROM0
Start: ; 0x150
ld [hGameBoyColorFlag], a
ld sp, hGameBoyColorFlag
di
xor a
ld [rIF], a
ld a, [rLCDC] ; LCD Control
bit 7, a ; Check if LCD Display is enabled
jr nz, .LCDDisplayEnabled
set 7, a
ld [rLCDC], a
.LCDDisplayEnabled
ld bc, $0002
call SGBWait1750
.waitForVBlank
ld a, [rLY] ; LY register (LCDC Y-Coordinate)
cp 145 ; > 144 means V-Blank
jr c, .waitForVBlank
ld a, $81
ld [rLCDC], a ; Enable LCD Display
xor a
ld [rBGP], a ; Clear Palette Data
ld [rOBP0], a
ld [rOBP1], a
ld bc, $0002
call SGBWait1750
.waitForVBlank2
ld a, [rLY] ; LY register (LCDC Y-Coordinate)
cp 145 ; > 144 means V-Blank
jr c, .waitForVBlank2
xor a
ld [rLCDC], a ; Disable LCD Display
ld hl, wc000
ld bc, $2000
call ClearData ; Clear WRAM Bank 0
ld hl, vTilesOB
ld bc, $1000
call ClearData ; Clear First half of VRAM
ld a, SRAM_ENABLE
ld [MBC5SRamEnable], a ; Enable RAM
ld a, $1
ld [MBC5RomBank], a ; Load ROM Bank $1
ld a, $0
ld [MBC5RomBankOn], a ; Enable ROM Banking Mode
ld a, $0
ld [MBC5SRamBank], a ; Set bits 5 and 6 of ROM Bank Number
ld a, $1
ld [hLoadedROMBank], a
ld a, $1
ld [MBC5RomBankOn], a ; Enable RAM Banking Mode
ld a, $0
ld [MBC5SRamBank], a ; Load RAM Bank $0
ld sp, wStack ; Initialize stack pointer to the end of WRAM Bank $1
ld hl, hPushOAM
ld bc, $007e
call ClearData ; Clear High RAM (HRAM)
call WriteDMACodeToHRAM
call ClearOAMBuffer
xor a
ld [wd7fb], a
ld [wd7fc], a
ld [wd7fd], a
ld [hStatIntrRoutine], a
ld [$ffb1], a
ld [wd8e1], a
ld [wd7fe], a
ld [hSGBInit], a
ld hl, hLCDC
xor a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld a, $8f
ld [hli], a
ld a, $a6
ld [hli], a
ld a, $0
ld [wUpdateAudioEngineUsingTimerInterrupt], a
ld [wToggleAudioEngineUpdateMethod], a
ld a, Bank(PlaySong_BankF)
call SetSongBank
call Func_23b
ld a, [hGameBoyColorFlag]
and a
jr nz, .asm_222
call InitSGB
rl a
and $1
ld [hSGBFlag], a
call SendSGBBorder
ld a, [hSGBFlag]
and a
jr z, .asm_222
ld a, $1
ld [wd917], a
.asm_222
ld a, $1
ld [rIE], a ; Only enable LCD Status interrupt
ei
ld a, $ff
ld [wRNGModulus], a
call ResetRNG
xor a
ld [wBootCheck], a
ld a, BANK(Main)
ld hl, Main
call BankSwitchSimple
Func_23b: ; 0x23b
ld a, [hGameBoyColorFlag]
cp $11
jr nz, .asm_248
ld a, $1
ld [hGameBoyColorFlag], a
ld [hGameBoyColorFlagBackup], a
ret
.asm_248
xor a
ld [hGameBoyColorFlag], a
ld [hGameBoyColorFlagBackup], a
ret
SoftReset:
di
ld sp, hGameBoyColorFlag
xor a
ld [rIF], a
ld bc, $2
call SGBWait1750
ld hl, wc000
ld bc, $2000
call ClearData
ld hl, $8000
ld bc, $1000
call ClearData
ld a, SRAM_ENABLE
ld [MBC5SRamEnable], a
ld a, $1
ld [MBC5RomBank], a
ld a, $0
ld [MBC5RomBankOn], a
ld a, $0
ld [MBC5SRamBank], a
ld a, $1
ld [hLoadedROMBank], a
ld a, $1
ld [MBC5RomBankOn], a
ld a, $0
ld [MBC5SRamBank], a
ld sp, wStack
call WriteDMACodeToHRAM
call ClearOAMBuffer
xor a
ld [wd7fb], a
ld [wd7fc], a
ld [wd7fd], a
ld [hStatIntrRoutine], a
ld [$ffb1], a
ld [wd8e1], a
ld [wd7fe], a
ld hl, hLCDC
xor a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld a, $8f
ld [hli], a
ld a, $a6
ld [hli], a
ld a, $0
ld [wUpdateAudioEngineUsingTimerInterrupt], a
ld [wToggleAudioEngineUpdateMethod], a
ld a, BANK(Func_3c000)
call SetSongBank
ld a, [hSGBFlag]
and a
jr z, .asm_02d5
ld a, $1
ld [wd917], a
.asm_02d5
ld a, $1
ld [rIE], a
ei
ld a, $ff
ld [wRNGModulus], a
call ResetRNG
ld a, [hGameBoyColorFlag]
ld [hGameBoyColorFlagBackup], a
xor a
ld [wBootCheck], a
ld a, Bank(Main)
ld hl, Main
call BankSwitchSimple
; fallthrough
VBlank: ; 0x2f2
push af
push bc
push de
push hl
call hPushOAM ; OAM DMA transfer
ld a, [hLCDC]
ld [rLCDC], a
call Func_113a
ei
ld a, [rLY]
cp $90
jr c, .asm_328
ld hl, hSTAT
ld c, rSTAT - $ff00
ld a, [hli]
ld [$ff00+c], a
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
ld a, [hli]
ld [$ff00+c], a
inc c
ld a, [hli] ;hWY
ld [$ff00+c], a ;into FF4A
inc c
ld a, [hli]
ld [$ff00+c], a
.asm_328
ld a, [hLYC]
ld [hLastLYC], a
ld a, [hNextLYCSub]
ld [hLYCSub], a
ld a, [hNextFrameHBlankSCX]
ld [hHBlankSCX], a
ld a, [hNextFrameHBlankSCY]
ld [hHBlankSCY], a
call ReadJoypad
ld a, [wBootCheck]
and a
jr nz, .skipBootCheck
ld a, [hJoypadState]
cp $f
jr nz, .skipBootCheck
ld a, [hNewlyPressedButtons]
and $f
jr z, .skipBootCheck
ld hl, sp + 8
ld [hl], FadeAndSoftReset & $ff
inc hl
ld [hl], FadeAndSoftReset >> 8
ld a, $1
ld [wBootCheck], a
.skipBootCheck
ld hl, hNumFramesSinceLastVBlank
ld a, [hl]
inc [hl]
and a
jr nz, .asm_365
ld hl, hFrameCounter
inc [hl]
.asm_365
ld hl, hVBlankCount
inc [hl]
ld a, [wd8e1]
and a
call nz, Func_167b
ld a, [wUpdateAudioEngineUsingTimerInterrupt]
and a
jr nz, .skipAudioEngineUpdate
ld a, [wAudioEngineEnabled]
and a
call nz, UpdateSFX
.skipAudioEngineUpdate
ld a, [wToggleAudioEngineUpdateMethod]
and a
jr z, .skipTimerToggle
; Enable timer interrupts for audio engine updating.
xor a
ld [wToggleAudioEngineUpdateMethod], a
ld a, $1
ld [wUpdateAudioEngineUsingTimerInterrupt], a
ld a, -68
ld [rTMA], a
ld a, $0
ld [rTAC], a
ld hl, rIE
set 2, [hl]
ld a, $4
ld [rTAC], a ; Timer interrupt will fire ~60 times per second
.skipTimerToggle
ld hl, MBC5SRamBank
ld a, [wd917]
and a
jr nz, .asm_3b5
ld a, [wRumblePattern]
rrca
ld [wRumblePattern], a
and $1
jr z, .asm_3b5
set 3, [hl]
jr .asm_3b7
.asm_3b5
res 3, [hl]
.asm_3b7
ld a, [wDrawBottomMessageBox]
and a
call nz, DrawBottomMessageBox
pop hl
pop de
pop bc
pop af
reti
FadeAndSoftReset:
ld a, [rLCDC]
bit 7, a
jr z, .LCD_disabled
call FadeOut
; Fades palettes in from white screen.
call DisableLCD
.LCD_disabled
ld hl, hSTAT
res 6, [hl] ; disable LYC=LY interrupt
ld hl, rIE
res 1, [hl] ; disable STAT interrupt
xor a
ld [MBC5SRamEnable], a
ld [rSB], a
ld [rSC], a
ld [rIE], a
ld [rNR52], a
ld a, [hGameBoyColorFlagBackup]
ld [hGameBoyColorFlag], a
jp SoftReset
LCDCStatus: ; 0x3ec
push af
push bc
push de
push hl
ld a, [hStatIntrRoutine]
sla a
ld c, a
ld b, 0
ld hl, StatIntrRoutines
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
jp hl
StatIntrDone: ; 0x3ff
ld a, $1
ld [hStatIntrFired], a
pop hl
pop de
pop bc
pop af
reti
StatIntrRoutines: ; 0x408s
dw StatIntrNothing
dw StatIntrTogglePinballWindow
dw StatIntrTogglePokedexWindow
dw StatIntrToggleHighScoresWindow
dw StatIntrNothing2
dw StatIntrNothing3
dw StatIntrNothing4
dw StatIntrNothing5
Timer: ; 0x418
ei
push af
push bc
push de
push hl
ld a, [wUpdateAudioEngineUsingTimerInterrupt]
and a
jr z, .asm_42a
ld a, [wAudioEngineEnabled]
and a
call nz, UpdateSFX
.asm_42a
ld a, [wToggleAudioEngineUpdateMethod]
and a
jr z, .skipTimer
xor a
ld [wToggleAudioEngineUpdateMethod], a
ld [wUpdateAudioEngineUsingTimerInterrupt], a
; disable timer
ld a, $0
ld [rTAC], a
ld hl, rIE
res 2, [hl]
.skipTimer
pop hl
pop de
pop bc
pop af
reti
Serial: ; 0x445
push af
push bc
push de
push hl
ld hl, Data_45d
push hl
ld a, [$ffb1]
sla a
ld c, a
ld b, $0
ld hl, Data_462
add hl, bc
ld c, [hl]
inc hl
ld b, [hl]
push bc
ret
Data_45d:
db $e1, $d1, $c1, $f1, $d9
Data_462:
db $64, $16, $66, $04, $c9
Joypad: ; 0x467
reti
DelayFrame: ; 0x468
ld a, [rLCDC]
bit 7, a
ret z
ld hl, hNumFramesSinceLastVBlank
xor a
ld [hl], a
.asm_472
ld a, [hl]
and a
jr z, .asm_472
ret
JumpToFuncInTable: ; 0x477
; Jumps to a function in the pointer table immediately following
; a "rst JumpTable" call. Function must be in the same Bank as the pointer table.
; input: a = index of function in table
sla a
pop hl
push de
ld e, a
ld d, $0
add hl, de
ld e, [hl]
inc hl
ld d, [hl]
ld l, e
ld h, d
pop de
jp hl
_ReadHalfword: ; 0x486
rlca
add l
ld l, a
jr nc, .noCarry
inc h
.noCarry
ld a, [hli]
ld h, [hl]
ld l, a
ret
INCLUDE "home/audio.asm"
CallInFollowingTable: ; 0x532
; Calls a function in a table located immediately after a call to this function.
; Inputs: a = entry in the table
ld e, a
ld d, $0
sla e
rl d
sla e
rl d ; multiplied a by 4 because entries in the table are 4 bytes each
pop hl
add hl, de
ld e, [hl]
inc hl
ld d, [hl]
inc hl
ld a, [hl]
ld h, d
ld l, e
jp BankSwitch
BankSwitchSimple: ; 0x549
; Switches to Bank in register a and jumps to hl.
ld [hLoadedROMBank], a
ld [MBC5RomBank], a ; Load Bank
jp hl
BankSwitch: ; 0x54f
ld e, a
ld a, [hLoadedROMBank] ; currently-loaded Bank
cp e
jr z, .doJump
push af
ld a, e
call .loadNewBank
call .doJump
pop de
ld a, d
.loadNewBank
push hl
push de
ld hl, rIE
ld d, [hl]
ld [hl], $0
ld [MBC5RomBank], a
ld [hLoadedROMBank], a
ld [hl], d
pop de
pop hl
ret
.doJump
ld a, [hFarCallTempE]
ld e, a
ld a, [hFarCallTempA]
jp hl
DisableLCD: ; 0x576
ld a, [rLCDC]
bit 7, a
ret z
ld a, [hLCDC]
res 7, a
ld [hLCDC], a
.asm_581
ld a, [rLCDC]
bit 7, a
jr nz, .asm_581
ret
EnableLCD: ; 0x588
ld a, [hFFC4]
and a
call nz, .UpdatePals
ld a, [hLCDC]
set 7, a
ld [rLCDC], a
ld [hLCDC], a
ret
.UpdatePals
ld de, rBGPI
ld a, $80
ld [de], a
inc de
ld b, $8
.asm_5a0
ld a, [wBGP]
call .UpdateDMGPals
dec b
jr nz, .asm_5a0
ld de, rOBPI
ld a, $80
ld [de], a
inc de
ld b, $4
.asm_5b2
ld a, [wOBP0]
call .UpdateDMGPals
ld a, [wOBP1]
call .UpdateDMGPals
dec b
jr nz, .asm_5b2
ret
.UpdateDMGPals
push bc
ld b, $4
.asm_5c5
push af
push bc
and $3
sla a
ld c, a
ld b, $0
ld hl, GreyscalePalette
add hl, bc
ld a, [hli]
ld [de], a
ld a, [hli]
ld [de], a
pop bc
pop af
srl a
srl a
dec b
jr nz, .asm_5c5
pop bc
ret
GreyscalePalette:
RGB 31, 31, 31
RGB 21, 21, 21
RGB 11, 11, 11
RGB 0, 0, 0
VBlankIntDisable:
ld a, [rIE]
res 0, a
ld [rIE], a
ret
VBlankIntEnable:
ld a, [rIE]
set 0, a
ld [rIE], a
ret
WriteDMACodeToHRAM: ; 0x5f7
; Initializes registers hPushOAM - hFarCallTempA
ld c, $80
ld b, $a ; number of bytes to load
ld hl, DMARoutine
.loop
ld a, [hli]
ld [$ff00+c], a ; add register c to $ff00, and store register a into the resulting address
inc c
dec b
jr nz, .loop
ret
DMARoutine:
; This routine is initially loaded into hPushOAM - hFarCallTempA by WriteDMACodeToHRAM.
ld a, (wOAMBuffer >> 8)
ld [rDMA], a ; start DMA
ld a, $28
.waitLoop ; wait for DMA to finish
dec a
jr nz, .waitLoop
ret
WaitForLCD: ; 0x60f
; Wait for LCD controller to stop reading from both OAM and VRAM because
; CPU can't access OAM, VRAM, or palette data ($ff69, $ff6b) during this time.
ld a, [rSTAT] ; LCDC Status register
and $3
jr nz, WaitForLCD
ld a, $a
.delay40Cycles
dec a
jr nz, .delay40Cycles
ret
INCLUDE "home/copy.asm"
ClearOAMBuffer: ; 0x916
; Clears the OAM buffer by loading $f0 into all of the entries.
ld hl, wOAMBuffer ; 0xd000
ld b, 4 * 40 ; wOAMBuffer is 4 * 40 bytes long (40 OAM entries, 4 bytes each)
ld a, $f0 ; byte to write
.loop
ld [hli], a
dec b
jr nz, .loop
xor a
ld [wOAMBufferSize], a
ret
CleanOAMBuffer: ; 0x926
; Cleans up any trailing unused oam slots in the oam buffer.
ld a, [wOAMBufferSize]
cp wOAMBufferEnd % $100
jr nc, .done
ld l, a
ld h, wOAMBufferEnd / $100
cpl
add (wOAMBufferEnd + 1) % $100
ld b, a
ld a, $f0
.loop
ld [hli], a
dec b
jr nz, .loop
.done
xor a
ld [wOAMBufferSize], a
ret
AdvanceFrames: ; 0x93f
push bc
rst AdvanceFrame
pop bc
dec bc
ld a, c
or b
jr nz, AdvanceFrames
ret
SGBWait1750: ; 0x948
ld de, 1750
.asm_94b
nop
nop
nop
dec de
ld a, d
or e
jr nz, .asm_94b
dec bc
ld a, b
or c
jr nz, SGBWait1750
ret
INCLUDE "home/random.asm"
INCLUDE "home/joypad.asm"
INCLUDE "home/palettes.asm"
MultiplyAbyL_AncientEgyptian: ; 0xdd4
; Return a * l to hl
; This is a constant-time multiplication algorithm that uses binary decomposition to achieve the result.
; See https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication
push bc
ld c, l
ld b, $0
ld hl, $0000
bit 0, a
jr z, .asm_de0
add hl, bc
.asm_de0
sla c
rl b
bit 1, a
jr z, .asm_de9
add hl, bc
.asm_de9
sla c
rl b
bit 2, a
jr z, .asm_df2
add hl, bc
.asm_df2
sla c
rl b
bit 3, a
jr z, .asm_dfb
add hl, bc
.asm_dfb
sla c
rl b
bit 4, a
jr z, .asm_e04
add hl, bc
.asm_e04
sla c
rl b
bit 5, a
jr z, .asm_e0d
add hl, bc
.asm_e0d
sla c
rl b
bit 6, a
jr z, .asm_e16
add hl, bc
.asm_e16
sla c
rl b
bit 7, a
jr z, .asm_e1f
add hl, bc
.asm_e1f
pop bc
ret
ConvertHexByteToDecWord: ; 0xe21
; Convert the base-16 value in register a into a Binary Coded Decimal (base-10) word.
; Example: If a = $97, de = $0151.
ld b, a
ld hl, PowersOfTwo
ld de, $0000
.asm_e28
srl b
ld a, [hli]
jr nc, .asm_e34
add e
daa
ld e, a
ld a, [hl]
adc d
daa
ld d, a
.asm_e34
inc hl
ld a, b
and a
jr nz, .asm_e28
ret
PowersOfTwo: ; 0xe3a
dw $0001
dw $0002
dw $0004
dw $0008
dw $0016
dw $0032
dw $0064
dw $0128
Increment_Max100: ; 0xe4a
; Increments the value at [hl], but caps it at 100.
; Sets carry flag if the increment happens.
ld a, [hl]
cp 100
jr z, .maxValue
inc a
ld [hl], a
scf
ret
.maxValue
and a
ret
Modulo_C: ; 0xe55
; Calculates A modulo C
; Sets zero flag if result is zero
cp c
jr c, .done
sub c
jr Modulo_C
.done
and a
ret
ToggleAudioEngineUpdateMethod: ; 0xe5d
; The audio engine is normally updated once every V-Blank interrupt. However, during pinball gameplay,
; the LCD is disabled (no V-Blanks) when the pinball is transitioning between the Top- and Bottom-halfs of
; the Red and Blue Fields. Therefore, the audio engine wouldn't get updated for a fraction of a second, which
; would has a noticeable pause in the music. To solve this, the Timer interrupt is enabled while the V-Blank is
; disabled, and the audio engine gets updated during the Timer interrupt.
ld a, $1
ld [wToggleAudioEngineUpdateMethod], a
.wait
ld a, [wToggleAudioEngineUpdateMethod]
and a
jr nz, .wait
ret
DrawBottomMessageBox: ; 0xe69
; Draws the current scrolling bottom message box to VRAM during V-Blank.
; Note, this only applies to the 1-tile high message bar. When it displays, things like Ball Bonus summary, and
; the Save/Cancel menu, this is not used to draw the message buffer.
ld a, [rLY]
cp $90
jr nc, DrawBottomMessageBox ; ensure we're in V-Blank
.asm_e6f
ld a, [rSTAT]
and $3
jr nz, .asm_e6f
ld a, $a
.asm_e77
dec a
jr nz, .asm_e77
ld hl, wBottomMessageBuffer + $40
call Load4BottomMessageBytes
push hl
ld hl, $9c00
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c04
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c08
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c0c
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c10
call Write4BottomMessageBytes
pop hl
ld hl, wBottomMessageBuffer + $c0
call Load4BottomMessageBytes
push hl
ld hl, $9c20
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c24
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c28
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c2c
call Write4BottomMessageBytes
pop hl
call Load4BottomMessageBytes
push hl
ld hl, $9c30
call Write4BottomMessageBytes
pop hl
ret
Load4BottomMessageBytes: ; 0xeef
ld a, [hli]
ld b, a
ld a, [hli]
ld c, a
ld a, [hli]
ld d, a
ld a, [hli]
ld e, a
ret
Write4BottomMessageBytes: ; 0xef8
ld a, [rSTAT]
and $3
jr nz, Write4BottomMessageBytes
ld a, b
ld [hli], a
ld a, c
ld [hli], a
ld a, d
ld [hli], a
ld a, e
ld [hli], a
ld a, $a
.asm_f08
dec a
jr nz, .asm_f08
ret
INCLUDE "home/save.asm"
StatIntrNothing: ; 0xfbc
jp StatIntrDone
StatIntrTogglePinballWindow:
; Handles switching the tile data to the black status bar
; window anchored to the bottom of the screen during pinball
; gameplay.
ld hl, hLastLYC
ld c, [hl]
ld a, [rLY]
cp c
jp c, StatIntrDone
inc c
inc c
cp c
jp nc, StatIntrDone
ld a, [hLCDCMask]
ld c, a
ld a, [hLCDC]
xor $10 ; toggle window tile data
and c
ld c, a
ld hl, rSTAT
.waitForHBlank
ld a, [hl]
and $3
jr nz, .waitForHBlank
ld a, [rLCDC]
and $80 ; enable LCD display
or c
ld [rLCDC], a
jp StatIntrDone
StatIntrTogglePokedexWindow: ; 0xfea
ld hl, hLastLYC
ld a, [hLYCSub]
cp [hl]
jr nz, .asm_1015
ld a, [rLY]
cp [hl]
jp nz, StatIntrDone
ld a, [hLCDC]
xor $18 ; toggle window tile data and tile map
ld c, a
ld a, [hHBlankSCX]
ld b, a
ld hl, rSTAT
.waitForHBlank
ld a, [hl]
and $3
jr nz, .waitForHBlank
ld a, [rLCDC]
and $80 ; enable LCD display
or c
ld [rLCDC], a
ld a, b
ld [rSCY], a
jp StatIntrDone
.asm_1015
ld a, [rLY]
cp [hl]
jr nz, .asm_1037
ld a, [hLastLYC]
ld hl, hLYCSub
sub [hl]
add $40
ld c, a
ld a, [hLYCSub]
ld b, a
ld hl, rSTAT
.waitForHBlank_2
ld a, [hl]
and $3
jr nz, .waitForHBlank_2
ld a, c
ld [rSCY], a
ld a, b
ld [rLYC], a
jp StatIntrDone
.asm_1037
ld hl, hLYCSub
ld a, [rLY]
cp [hl]
jp nz, StatIntrDone
ld a, [hLCDC]
xor $18 ; toggle window tile data and tile map
ld c, a
ld a, [hHBlankSCX]
ld b, a
ld hl, rSTAT
.waitForHBlank_3
ld a, [hl]
and $3
jr nz, .waitForHBlank_3
ld a, [rLCDC]
and $80
or c
ld [rLCDC], a
ld a, b
ld [rSCY], a
jp StatIntrDone
StatIntrToggleHighScoresWindow:
ld hl, hLastLYC
ld a, [rLY]
cp [hl]
jr z, .asm_1069
dec a
cp [hl]
jr nz, .asm_1080
.asm_1069
ld a, [hLYCSub]
ld c, a
ld a, [hHBlankSCX]
ld b, a
ld hl, rSTAT
.waitForHBlank
ld a, [hl]
and $3
jr nz, .waitForHBlank
ld a, b
ld [rSCY], a
ld a, c
ld [rLYC], a
jp StatIntrDone
.asm_1080
ld hl, hLYCSub
ld a, [rLY]
cp [hl]
jr z, .asm_108d
dec a
cp [hl]
jp nz, StatIntrDone
.asm_108d
ld a, [hHBlankSCY]
ld b, a
ld hl, rSTAT
.waitForHBlank_2
ld a, [hl]
and $3
jr nz, .waitForHBlank_2
ld a, b
ld [rSCY], a
jp StatIntrDone
StatIntrNothing2: ; 0x109e
jp StatIntrDone
StatIntrNothing3: ; 0x10a1
jp StatIntrDone
StatIntrNothing4: ; 0x10a4
jp StatIntrDone
StatIntrNothing5: ; 0x10a7
jp StatIntrDone
QueueGraphicsToLoad: ; 0x10aa
; Queues graphics data to be loaded into VRAM at the next available time.
; See the data/queued_tiledata/ directory to view the data that is loaded by this function.
; Input: hl = pointer to async tile data header
; byte 1 = number of chunks to load
; 2*(byte 1) = list of pointers to chunks
; a = bank of async tile data
ld c, a
ld a, [hli]
ld b, a
.loop
push bc
ld a, c
ld c, [hl]
inc hl
ld b, [hl] ;pull pointer from HL, load into BC
inc hl
push af
ld a, [bc]
ld e, a
inc bc
ld a, [bc]
ld d, a ;pull de from bc
inc bc
pop af
push hl
call QueueGraphicsToLoadWithFunc
pop hl
pop bc
dec b
jr nz, .loop
ret
QueueGraphicsToLoadWithFunc: ; 0x10c5
; Queues graphics data to be loaded into VRAM with the given function at the next available time.
; See the data/queued_tiledata/ directory to view the data that is loaded by this function.
; Input: de: function that is responsible for loading the chunk of VRAM data
; hl: pointer to data
; a: bank of data
push af
ld a, [rLCDC]
bit 7, a
jr z, .skip_wait_ly
.wait_ly
ld a, [rLY]
cp $88
jr nc, .wait_ly
.skip_wait_ly
pop af
ld hl, wd7fb
ld l, [hl]
ld h, wcb00 / $100
inc bc
ld [hl], c
inc h
ld [hl], b
inc h
ld [hl], a
inc h
ld [hl], e
inc h
ld [hl], d
ld e, $ff
ld [hROMBankBuffer], a
ld a, [hLoadedROMBank]
push af
ld a, [hROMBankBuffer]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
dec bc
ld a, [bc]
ld hl, wd7fa
add [hl]
cp $30
jr c, .size_okay
ld a, [bc]
ld e, $0
.size_okay
add $4
ld [hl], a
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, wd7fb
ld l, [hl]
ld h, wca00 / $100
inc l
ld [hl], $0
dec l
ld [hl], e
ld hl, wd7fb
inc [hl]
ld a, [rLCDC]
bit 7, a
ret nz
ld a, [rIE]
push af
res 0, a
ld [rIE], a
call Func_113a
pop af
ld [rIE], a
ret
Func_1129: ; 0x1129
ld a, [wd7fb]
ld [wd7fc], a
ret
Func_1130: ; 0x1130
push hl
ld a, [wd7fb]
ld hl, wd7fc
cp [hl]
pop hl
ret
Func_113a: ; 0x113a
ld hl, wd7fc
ld a, [wd7fb]
cp [hl]
ret z
ld l, [hl]
ld h, $ca
ld [hl], $ff
.loop
ld a, [hl]
and a
jr z, .done
push hl
inc h
ld e, [hl]
inc h
ld d, [hl]
inc h
ld a, [hLoadedROMBank]
push af
ld a, [hl]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
inc h
ld a, [hl]
inc h
ld h, [hl]
ld l, a
call JumpToHL
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
pop hl
inc l
jr .loop
.done
ld a, l
ld [wd7fc], a
ld hl, wd7fb
cp [hl]
ret nz
xor a
ld [wd7fa], a
ret
JumpToHL: ; 0x117a
jp hl
LoadTileLists: ; 0x117b
; Loads a series of defined tile ids into VRAM
; input: de = pointer to data structure
; data structure: list of VRAM tile data with the following format
; [num tiles][destination pointer][list of tile ids]
ld h, d
ld l, e
.loadTileSequence
ld a, [hli]
and a
ret z
ld b, a
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a ; de = destination for tile data
.loadTileData
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .loadTileData
jr .loadTileSequence
LoadTileListsBank1: ; 0x118d
ld a, $1
ld [rVBK], a
call LoadTileLists
xor a
ld [rVBK], a
ret
Func_1198:
ld h, d
ld l, e
.asm_119a
ld a, [hli]
and a
ret z
ld b, a
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
srl b
jr nc, .asm_11a8
ld a, [hli]
ld c, a
.asm_11a8
push hl
ld h, d
ld l, e
ld a, c
.asm_11ac
ld [hli], a
inc a
dec b
jr nz, .asm_11ac
ld c, a
pop hl
jr .asm_119a
Func_11b5: ; 11b5 (0:11b5)
ld h, d
ld l, e
.asm_11b7
ld a, [hli]
and a
ret z
ld b, a
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
.asm_11c0
ld [de], a
inc de
dec b
jr nz, .asm_11c0
jr .asm_11b7
Func_11c7:
ld a, $1
ld [rVBK], a
call Func_11b5
xor a
ld [rVBK], a
ret
Func_11d2:
ld h, d
ld l, e
ld a, [hLoadedROMBank]
ld [$ff94], a
.asm_11d8
ld a, [hli]
and a
ret z
ld [$ff95], a
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hli]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
push hl
ld h, b
ld l, c
ld a, [$ff95]
ld b, a
.asm_11f1
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc e
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .asm_11f1
pop hl
ld a, [$ff94]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
jr .asm_11d8
Func_122e:
ld a, $1
ld [rVBK], a
ld h, d
ld l, e
ld a, [hLoadedROMBank]
ld [$ff94], a
.asm_1238
ld a, [hli]
and a
jr nz, .asm_1240
xor a
ld [rVBK], a
ret
.asm_1240
ld [$ff95], a
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hli]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
push hl
ld h, b
ld l, c
ld a, [$ff95]
ld b, a
.asm_1256
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .asm_1256
pop hl
ld a, [$ff94]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
jr .asm_1238
LoadPalettes:
; Loads either BG or OAM palette data
; de = pointer to palette data
; first byte is number of colors to load
; second byte determines BG or OAM palette data
; third and fourth byte are a pointer to actual color data
; fifth byte is Bank of actual color data
; $00 marks the end of the list
ld h, d
ld l, e
.loop
ld a, [hli]
and a
ret z
ld [$ff94], a
ld a, [hli]
bit 6, a
ld de, rBGPI
jr z, .asm_127a
res 6, a
ld de, rOBPI
.asm_127a
set 7, a
ld [de], a
inc de
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hLoadedROMBank]
push af
ld a, [hli]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
push hl
ld h, b
ld l, c
ld a, [$ff94]
ld b, a
.loadColor
ld a, [hli]
ld [de], a
ld a, [hli]
ld [de], a
dec b
jr nz, .loadColor
pop hl
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
jr .loop
INCLUDE "home/sgb.asm"
INCLUDE "home/serial.asm"
Func_1a21: ; 0x1a21
call Func_1a59
call Func_1a89
jr c, .asm_1a3f
.asm_1a29
call Func_1aa9
call Func_1b3d
jr c, .asm_1a3f
ld a, [wd86c]
and a
jr z, .asm_1a29
call Func_1b60
jr c, .asm_1a3f
call Func_1b88
.asm_1a3f
call Func_1ba7
ret
Func_1a43: ; 0x1a43
xor a
ld [wd86e], a
call Func_1a59
call Func_1a89
jr c, .asm_1a54
ld a, $1
ld [wd86e], a
.asm_1a54
call Func_1ba7
ret
ret ; unused instruction?
Func_1a59: ; 0x1a59
ld [wd86a], a
ld a, h
ld [wd869], a
ld a, l
ld [wd868], a
ld a, $80
ld [wd866], a
ld a, $c2
ld [wd867], a
xor a
ld [wd86b], a
ld [wd86c], a
ld [wd86d], a
call Func_16a2
ld hl, rIE
set 3, [hl]
xor a
ld [$ffb1], a
ld a, $1
ld [wd8e1], a
ret
Func_1a89: ; 0x1a89
call Func_16e2
cp $f0
jr z, .asm_1a9f
cp $ff
jp z, Func_1bb2
ld a, [wd8c8]
cp $81
jp nz, Func_1bb2
and a
ret
.asm_1a9f
ld a, [hNewlyPressedButtons]
bit 1, a
jp nz, Func_1bd3
rst AdvanceFrame
jr Func_1a89
Func_1aa9: ; 0x1aa9
ld a, [wd866]
ld l, a
ld a, [wd867]
ld h, a
ld de, wc000
ld b, $2
.asm_1ab6
ld c, $14
.asm_1ab8
ld a, [hli]
call Func_1ae2
dec c
jr nz, .asm_1ab8
ld a, l
add $c
ld l, a
jr nc, .asm_1ac6
inc h
.asm_1ac6
dec b
jr nz, .asm_1ab6
ld a, l
ld [wd866], a
ld a, h
ld [wd867], a
ld a, [wd86b]
inc a
ld [wd86b], a
cp $9
jr nz, .asm_1ae1
ld a, $1
ld [wd86c], a
.asm_1ae1
ret
Func_1ae2: ; 0x1ae2
push bc
push hl
xor $80
swap a
ld c, a
and $f
ld b, a
ld a, c
and $f0
ld c, a
ld a, [wd868]
ld l, a
ld a, [wd869]
ld h, a
add hl, bc
ld a, [hLoadedROMBank]
push af
ld a, [wd86a]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
REPT 15
ld a, [hli]
ld [de], a
inc e
ENDR
ld a, [hli]
ld [de], a
inc de
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
pop hl
pop bc
ret
Func_1b3d: ; 0x1b3d
ld a, [wd86c]
ld [wd8dd], a
ld hl, wc000
ld a, $1
call Func_1779
cp $ff
jp z, Func_1bb2
cp $f0
jr z, .asm_1b56
and a
ret
.asm_1b56
ld a, [hNewlyPressedButtons]
bit BIT_B_BUTTON, a
jp nz, Func_1bd3
rst AdvanceFrame
jr Func_1b3d
Func_1b60: ; 0x1b60
ld a, $1
ld [wd8a8], a
ld a, $13
ld [wd8a9], a
call Func_1740
cp $ff
jp z, Func_1bb2
cp $f0
jr z, .asm_1b7e
ld bc, $001e
call AdvanceFrames
and a
ret
.asm_1b7e
ld a, [hNewlyPressedButtons]
bit BIT_B_BUTTON, a
jp nz, Func_1bd3
rst AdvanceFrame
jr Func_1b60
Func_1b88: ; 0x1b88
ld a, [wd8c7]
ld b, a
cp $ff
jr z, Func_1bb2
and $f0
jr nz, Func_1bb2
bit 1, b
jr nz, .asm_1b9d
call Func_16a2
and a
ret
.asm_1b9d
ld a, [hNewlyPressedButtons]
bit BIT_B_BUTTON, a
jp nz, Func_1bd3
rst AdvanceFrame
jr Func_1b88
Func_1ba7: ; 0x1ba7
ld hl, rIE
res 3, [hl]
xor a
ld [wd8e1], a
and a
ret
Func_1bb2: ; 0x1bb2
ld hl, Data_1bcf
ld a, [wd8c7]
cp $ff
jr z, .asm_1bc6
ld b, $3
.asm_1bbe
inc hl
sla a
jr c, .asm_1bc6
dec b
jr nz, .asm_1bbe
.asm_1bc6
ld a, [hl]
ld [wd86d], a
call Func_16a2
scf
ret
Data_1bcf:
; $ff, >$7f, >$3f, else
db $02, $01, $04, $03
Func_1bd3: ; 0x1bd3
lb de, $00, $01
call PlaySoundEffect
ld a, $5
ld [wd86d], a
call Func_16a2
scf
ret
INCLUDE "home/ir.asm"
Unused_Func_1ed9:
; unused
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, $2
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, $4f06
jr asm_1f3b
Unused_Func_1ef2:
; unused
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, $2
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, $4f06
jr asm_1f3b
LoadOAMData2: ; 0x1f0b
; This function loads OAM data, but it adds b and c to the x and y values
; input: a = OAM data id (see OAMDataPointers2)
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, Bank(OAMDataPointers2)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, OAMDataPointers2
jr asm_1f3b
LoadOAMData: ; 0x1f24
; This function loads OAM data, but it adds b and c to the x and y values
; input: a = OAM data id (see OAMDataPointers)
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d ; multiply de by 2
ld a, [hLoadedROMBank]
push af
ld a, Bank(OAMDataPointers)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, OAMDataPointers
asm_1f3b: ; 0x1f3b
add hl, de ; hl points to oam pointer in OAMDataPointers
ld a, [hli]
ld e, a
ld a, [hl]
ld d, a ; de points to OAM data
ld a, [wOAMBufferSize]
ld l, a
ld h, (wOAMBuffer >> 8)
.loadOAMDataLoop
ld a, [de]
cp $80 ; OAM data list terminator
jr z, .doneReadingOAMData
add c
ld [hli], a
inc de
ld a, [de]
add b
ld [hli], a
inc de
ld a, [de]
ld [hli], a
inc de
ld a, [de]
ld [hli], a
inc de
jr .loadOAMDataLoop
.doneReadingOAMData
ld a, l
ld [wOAMBufferSize], a
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
pop hl
pop de
pop bc
ret
Unused_Func_1f68:
; unused
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, $2
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, $4f06
jr asm_1fca
Unused_Func_1f81:
; unused
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, $2
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, $4f06
jr asm_1fca
Func_1f9a:
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, BANK(OAMDataPointers2)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, OAMDataPointers2
jr asm_1fca
Func_1fb3:
push bc
push de
push hl
ld e, a
ld d, $0
sla e
rl d
ld a, [hLoadedROMBank]
push af
ld a, BANK(OAMDataPointers)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, OAMDataPointers
asm_1fca:
add hl, de
ld a, [hli]
ld e, a
ld a, [hl]
ld d, a
ld a, [wOAMBufferSize]
ld l, a
ld h, $d0
.asm_1fd5
ld a, [de]
cp $80
jr z, .asm_1fee
add c
ld [hli], a
inc de
ld a, [de]
add b
ld [hli], a
inc de
ld a, [de]
push hl
ld hl, sp+$7
add [hl]
pop hl
ld [hli], a
inc de
ld a, [de]
ld [hli], a
inc de
jr .asm_1fd5
.asm_1fee
ld a, l
ld [wOAMBufferSize], a
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
pop hl
pop de
pop bc
ret
Main: ; 0x1ffc
; This is the main game loop.
ld a, $b
ld [wd806], a
ld a, $4
ld [wd807], a
callba Func_3c000
ld a, $1
ld [wAudioEngineEnabled], a
ld a, $37 ; space character for player high scores name
ld [wPlayerName], a
ld [wPlayerName + 1], a
ld [wPlayerName + 2], a
ld a, SCREEN_ERASE_ALL_DATA
ld [wCurrentScreen], a
.master_loop
call TickRumbleDuration
call DoScreenLogic
call CleanOAMBuffer
call ClearPersistentJoypadStates
rst AdvanceFrame
jr .master_loop
TickRumbleDuration: ; 0x2034
; Decrements the Gameboy rumble duration.
; Turns off rumble when it gets to 0.
ld a, [wRumbleDuration]
and a
jr z, .rumbleOff
dec a
ld [wRumbleDuration], a
ret
.rumbleOff
ld [wRumblePattern], a
ret
DoScreenLogic: ; 0x2043
ld a, [wCurrentScreen]
call CallInFollowingTable
CallTable_2049: ; 0x2049
padded_dab HandleSelectGameboyTargetMenu ; SCREEN_SELECT_GAMEBOY_TARGET
padded_dab HandleEraseAllDataMenu ; SCREEN_ERASE_ALL_DATA
padded_dab HandleCopyrightScreen ; SCREEN_COPYRIGHT
padded_dab HandleTitlescreen ; SCREEN_TITLESCREEN
padded_dab HandlePinballGame ; SCREEN_PINBALL_GAME
padded_dab HandlePokedexScreen ; SCREEN_POKEDEX
padded_dab HandleOptionsScreen ; SCREEN_OPTIONS
padded_dab HandleHighScoresScreen ; SCREEN_HIGH_SCORES
padded_dab HandleFieldSelectScreen ; SCREEN_FIELD_SELECT
LoadDexVWFCharacter: ; 0x206d
; Loads a single variable-width-font character used in various parts of the Pokedex screen.
ld a, [hLoadedROMBank]
push af
ld a, Bank(LoadDexVWFCharacter_)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
call LoadDexVWFCharacter_
jr c, .asm_2084
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
and a
ret
.asm_2084
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
scf
ret
Func_208c: ; 0x208c
ld a, [hLoadedROMBank]
push af
ld a, Bank(Func_8ee0)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
call Func_8ee0
jr c, .asm_20a3
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
and a
ret
.asm_20a3
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
scf
ret
MultiplyBbyCUnsigned: ; 0x20ab
; u16 bc = (u8)b * (u8)c
push af
xor a
ld [hSignedMathSignBuffer], a
jr MultiplyBbyCSigned.asm_20c6
MultiplyBbyCSigned:
; s16 bc = (s8)b * (s8)c
push af
ld a, b
xor c
ld [hSignedMathSignBuffer], a
bit 7, b
jr z, .asm_20be
ld a, b
cpl
inc a
ld b, a
.asm_20be
bit 7, c
jr z, .asm_20c6
ld a, c
cpl
inc a
ld c, a
.asm_20c6
; b*c == (b**2 + c**2 - (b - c)**2) / 2
push de
push hl
ld a, b
cp c
jr nc, .c_le_b
ld b, c
ld c, a
.c_le_b
; hl = b**2 + c**2
ld h, SquaresLow / $100
ld l, c
ld e, [hl]
inc h ; SquaresHigh / $100
ld d, [hl]
ld l, b
ld a, [hl]
dec h
ld l, [hl]
ld h, a
add hl, de
push af
; hl -= (b - c) ** 2
ld d, SquaresLow / $100
ld a, b
sub c
ld e, a
ld a, [de]
ld c, a
inc d ; SquaresHigh / $100
ld a, [de]
ld b, a
ld a, l
sub c
ld l, a
ld a, h
sbc b
ld h, a
jr nc, .no_carry
pop af
ccf
jr .check_sign
.no_carry
pop af
.check_sign
; hl /= 2
rr h
rr l
ld b, h
ld c, l
ld a, [hSignedMathSignBuffer]
rlca
jr nc, .done
ld a, c
cpl
add $1
ld c, a
ld a, b
cpl
adc $0
ld b, a
.done
pop hl
pop de
pop af
ret
MultiplyVectorComponentByAngleFactor: ; 0x210b
; Input: bc = velocity
; e = multiplier
; d = $0 if multiplier is treated as positive, $ff if multiplier is treated as negative
; Output: bc = bc * e / 256
push af
push hl
ld a, b
xor d
ld [hSignedMathSignBuffer2], a
bit 7, b
jr z, .positive
; negate bc
ld a, c
cpl
add 1
ld c, a
ld a, b
cpl
adc 0
ld b, a
.positive
push bc
; first, multiply the lo byte of the vector
ld b, e
call MultiplyBbyCUnsigned
ld l, c
ld h, b
; round to nearest hi byte
ld bc, $0080
add hl, bc
ld l, h
ld h, $0
pop bc
; then, multiply the hi byte of the vector
ld c, e
call MultiplyBbyCUnsigned
add hl, bc
ld a, [hSignedMathSignBuffer2]
rlca
jr nc, .positive2
; negate hl
ld a, l
cpl
add 1
ld l, a
ld a, h
cpl
adc 0
ld h, a
.positive2
ld c, l
ld b, h
pop hl
pop af
ret
Cosine: ; 0x2147
; Input: a = angle
; Output: e = cos(a)
; d = 0 if cos(a) is positive, $ff if cos(a) is negative
add $40
; fall through
Sine: ; 0x2149
; Input: a = angle
; Output: e = sin(a)
; d = 0 if sin(a) is positive, $ff if sin(a) is negative
push hl
ld [hSignedMathSignBuffer], a
and $7f ; ensure angle is between 0 and 180 degrees
cp $40
jr c, .firstQuadrant
; convert angle so it's between 0 and 90 degrees
cpl
add $80+1
.firstQuadrant
ld hl, SineTable
ld e, a
ld d, $0
add hl, de
ld e, [hl]
pop hl
ld d, $0
ld a, [hSignedMathSignBuffer]
sla a
ret nc
ld d, $ff
ret
ApplyGravityToBall: ; 0x2168
; Adds a constant to the pinball's y velocity.
ld a, [wEnableBallGravityAndTilt]
and a
ret z
ld de, $000b ; gravity added to y velocity every frame
ld hl, wBallYVelocity
ld a, [hli]
ld h, [hl]
ld l, a
add hl, de
ld a, l
ld [wBallYVelocity], a
ld a, h
ld [wBallYVelocity + 1], a
ret
LimitBallVelocity: ; 0x2180
; Ensures that the ball's x and y velocity are kept under a threshold.
; The ball can travel at a greater max speed when moving diagonally, since it
; limits the x and y components independently.
ld hl, wBallXVelocity + 1
call _LimitBallVelocity
ld hl, wBallYVelocity + 1
; fall through
_LimitBallVelocity: ; 0x2189
ld a, [hl]
bit 7, a ; is it negative velocity? (left or up)
jr nz, .negativeVelocity
cp 8
ret c
ld a, 7 ; max positive velocity
ld [hl], a
ret
.negativeVelocity
cp -7
ret nc
ld a, -7 ; max negative velocity
ld [hl], a
ret
MoveBallPosition: ; 0x219c
; Updates the ball's position according to its velocity
ld a, [wBallXPos]
ld [wPreviousBallXPos], a
ld a, [wBallXPos + 1]
ld [wPreviousBallXPos + 1], a
ld a, [wBallYPos]
ld [wPreviousBallYPos], a
ld a, [wBallYPos + 1]
ld [wPreviousBallYPos + 1], a
ld de, wBallXVelocity + 1
ld hl, wBallXPos
call AddVelocityToPosition
ld de, wBallYVelocity + 1
ld hl, wBallYPos
; fall through
AddVelocityToPosition: ; 0x21c3
ld a, [de]
bit 7, a
jr nz, .negativeVelocity
cp 5
jr c, .readLoByte
ld bc, $04ff
jr .updateBallPos
.negativeVelocity
cp -4
jr nc, .readLoByte
ld bc, -$04ff
jr .updateBallPos
.readLoByte
ld b, a
dec de
ld a, [de]
ld c, a
.updateBallPos
ld a, [hl]
add c
ld [hli], a
ld a, [hl]
adc b
ld [hl], a
ret
NegateAngleAndRotateVector: ; 0x21e5
cpl
inc a
; fall through
RotateVector: ; 0x21e7
; Rotates a vector by an angle using the standard rotation matrix calculation. Note, that
; the matrix is inverted vertically to account for negative y values mean "up" in this world.
; Input: bc = vector x component
; de = vector y component
; a = rotation angle
; Returns: bc = resulting x component = xComponent * cos(angle) + yComponent * sin(angle)
; de = resulting y component = yComponent * cos(angle) - xComponent * sin(angle)
push hl
push bc
push de
ld [hRotationAngleBuffer], a
call Cosine
ld a, e
ld [hCosineResultBuffer], a
ld a, d
ld [hCosineResultBuffer + 1], a
; xComponent * cos(angle)
call MultiplyVectorComponentByAngleFactor
ld l, c
ld h, b
pop bc
push bc
ld a, [hRotationAngleBuffer]
call Sine
ld a, e
ld [hSineResultBuffer], a
ld a, d
ld [hSineResultBuffer + 1], a
; yComponent * sin(angle)
call MultiplyVectorComponentByAngleFactor
add hl, bc ; hl = xComponent * cos(angle) + yComponent * sin(angle)
pop de
pop bc
push hl
push de
ld a, [hSineResultBuffer]
ld e, a
ld a, [hSineResultBuffer + 1]
cpl
ld d, a
; xComponent * -sin(angle)
call MultiplyVectorComponentByAngleFactor
ld l, c
ld h, b
pop bc
ld a, [hCosineResultBuffer]
ld e, a
ld a, [hCosineResultBuffer + 1]
ld d, a
; yComponent * cos(angle)
call MultiplyVectorComponentByAngleFactor
add hl, bc ; hl = yComponent * cos(angle) - xComponent * sin(angle)
ld d, h
ld e, l
pop bc
pop hl
ret
ApplyCollisionForces: ; 0x222b
; Applies the collision force to the ball's velocity and spin.
; When this function is called, the ball's velocity has already been rotated
; by the collision's normal angle, so that the velocity components are in a
; standardized coordinate system, where the normal is pointing directly upward
; at the colliding ball. If the ball is traveling away from the normal, then this
; function is a no-op.
; Input: bc = ball x velocity in rotated coordinate system
; de = ball y velocity in rotated coordinate system
; Output: bc = updated ball x velocity in rotated coordinate system
; de = updated ball y velocity in rotated coordinate system
push hl
ld hl, wNoCollisionApplied
ld [hl], $ff
; Early exit if the ball is traveling away from the collision normal.
bit 7, d
jr nz, .exit
ld [hl], $0
ld a, d
cp 3
jr c, .applyforces
; The ball collided hard because its y velocity is a
; large value. Shake the rumble pack, and play a little
; sound effect to enhance the collision.
ld a, $ff
ld [wRumblePattern], a
ld a, 1
ld [wRumbleDuration], a
ld a, [wFlipperCollision]
and a
jr nz, .applyforces
push de
ld de, $0008
call PlaySFXIfNoneActive
pop de
.applyforces
; First, apply some dampening of the vertical
; velocity component, so that walls absorb some
; of the ball's speed. Colliding with certain objects
; dampen the speed less that normal, like the flippers
; and Poliwag button.
; Divide y velocity by 4.
srl d
rr e
srl d
rr e
ld h, d
ld l, e ; hl = yVelocity / 4
srl d
rr e ; de = yVelocity / 8
ld a, [wCollisionForceAmplification]
and a
jr z, .updateYVelocity
.amplify
add hl, de
dec a
jr nz, .amplify
.updateYVelocity
; Negate the dampened dampened y velocity so that the ball
; bounces off.
ld d, h
ld e, l
ld a, e
cpl
add 1
ld e, a
ld a, d
cpl
adc 0
ld d, a
ld a, [wBallSpin]
; Divide ball spin by 2, signed, and extend to 2 bytes (hl)
sra a
ld l, a
ld h, $0
bit 7, l
jr z, .updateXVelocity
ld h, $ff
.updateXVelocity
; hl = ballSpin / 2
; bc = x velocity component in rotated coordinate system
; Add the spin to the x velocity component.
add hl, bc
ld b, h
ld c, l
push bc
; Recalculate ball spin.
; new ball spin = (xVelocity * 4) >> 8
sla c
rl b
sla c
rl b
ld a, b
ld [wBallSpin], a
pop bc
.exit
pop hl
ret
LoadBallVelocity: ; 0x2299
; Loads velocity of the ball into bc and de
; bc = x velocity
; de = y velocity
push hl
ld hl, wBallXVelocity
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
ld a, [hli]
ld e, a
ld a, [hl]
ld d, a
pop hl
ret
SetBallVelocity: ; 0x22a7
; Sets the x and y velocities of the ball.
; bc = x velocity
; de = y velocity
push hl
ld hl, wBallXVelocity
ld a, c
ld [hli], a
ld a, b
ld [hli], a
ld a, e
ld [hli], a
ld a, d
ld [hl], a
pop hl
ret
CheckStageCollision: ; 0x22b5
ld a, [wBallXPos + 1]
sub 4
push af
and $7
ld [wSubTileBallXPos], a ; sub-tile position
pop af
and $f8
ld c, a ; c = tile x pos
ld a, [wBallYPos + 1]
sub 4
push af
and $7
ld [wSubTileBallYPos], a
pop af
and $f8
ld b, a ; b = tile y pos
ld l, b ; bc contains tile coords of ball position
; Calculate the tile offset for the ball's position, as if the
; board was composed of a 1D array starting from the top-left
; going left-to-right.
ld h, $0
sla l
rl h
sla l
rl h ; b was multiplied by 4 ((y tile) * 32)
srl c
srl c
srl c ; c was divided by 8 (x tile)
ld b, $0
add hl, bc
ld a, l
ld [wBallPositionTileOffset], a
ld a, h
ld [wBallPositionTileOffset + 1], a
ld a, [wStageCollisionMapPointer]
ld c, a
ld a, [wStageCollisionMapPointer + 1]
ld b, a
add hl, bc ; hl = address of ball tile's collision attribute
ld a, [hLoadedROMBank]
push af
ld a, [wStageCollisionMapBank]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld bc, 32 - 1 ; stage's number of tiles wide - 1
ld a, [hli]
ld [wUpperLeftCollisionAttribute], a
ld a, [hl]
ld [wUpperRightCollisionAttribute], a
add hl, bc
ld a, [hli]
ld [wLowerLeftCollisionAttribute], a
ld a, [hl]
ld [wLowerRightCollisionAttribute], a
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld a, [hLoadedROMBank]
push af
ld a, [wStageCollisionMasksBank]
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld a, [wSubTileBallXPos]
sla a
ld c, a
ld b, 0
ld hl, CollisionTests
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
ld a, [wSubTileBallYPos]
ld c, a
ld b, 16 ; length of wCollisionPointTests
.testCollisionPointLoop
push bc
ld a, [de]
inc de
add c ; add the sub tile y pos
push af
srl a
srl a
srl a
ld c, a
ld b, $0
ld hl, wUpperLeftCollisionAttribute
add hl, bc
ld a, [hl]
call TryLoadSpecialCollisionMask
jr nc, .staticMask
; Load the special mask pointer.
; hl = pointer to array of collision masks.
pop af
and $7
ld c, a
ld b, $0
add hl, bc
jr .testCollisionPoint
.staticMask
ld c, a
ld b, $0 ; bc = static collision mask id
; Multiply bc by 8. Each collision mask is an
; 8x8-tile of 1-bit-per-pixel data. Therefore,
; each collision mask tile is 8 bytes.
sla c
rl b
sla c
rl b
sla c
rl b
ld hl, wStageCollisionMasksPointer
ld a, [hli]
ld h, [hl]
ld l, a
add hl, bc ; hl = pointer to collision mask tile
pop af
and $7 ; a = y subtile offset
ld c, a
ld b, $0
add hl, bc
.testCollisionPoint
; hl = pointer to the collision mask row for the y position
ld a, [de]
inc de
and [hl]
push af
ld a, [de]
inc de
ld c, a
ld hl, wCollisionPointTests
add hl, bc
pop af
ld [hl], a
pop bc
dec b
jr nz, .testCollisionPointLoop
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld hl, wCollisionPointTests
ld de, wd7d9
ld b, 4
.copyLoop
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
dec b
jr nz, .copyLoop
ld hl, wCollisionPointTests
ld de, $0000
ld b, 0
ld a, [hl]
and a
jr z, .findNextCollisionPoint
.findNextCollisionPoint2
; This loop is nearly identical to .findNextCollisionPoint
; It exists to handle the improbable (impossible?) event that
; the ball could be completely inside a collision wall.
ld a, [hli]
inc b
and a
jr z, .findNextCollisionPoint
ld a, b
cp 16 + 1
jr nc, .determinedCollisionStatus
jr .findNextCollisionPoint2
.findNextCollisionPoint
ld a, [hli]
inc b
and a
jr nz, .handleCollisionPoint
ld a, b
cp 16 + 1
jr nc, .determinedCollisionStatus
jr .findNextCollisionPoint
.handleCollisionPoint
push de
ld d, $1
ld c, b
dec c
.findNextFailedCollisionPoint
ld a, [hli]
inc b
inc d
and a
jr nz, .findNextFailedCollisionPoint
dec d
ld a, b
dec a
dec a
and $f
swap c
or c
ld c, a ; c = (index of first collision point << 8) | (index of last consecutive collision point)
ld a, d ; d = number of consecutive successful collision points
cp e
pop de
jr c, .updatedMaxConsecutivePoints
ld e, a ; e = max number of consecutive successful collision points
ld d, c ; d = (index of first collision point << 8) | (index of last consecutive collision point)
.updatedMaxConsecutivePoints
ld a, b
cp 16
jr c, .findNextCollisionPoint
.determinedCollisionStatus
; e = maximum number of consecutive successful collision points
; d = the start and last index of that consecutive string of collision points (wCollisionPointTests)
; the hi nybble is the start index, lo nybble is the end index
ld a, e
ld [wIsBallColliding], a
and a
ret z
ld a, [hLoadedROMBank]
push af
ld a, Bank(CollisionForceAngles)
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
push de
; Based on the start and end collision point indices, look
; up the corresponding normal angle for them.
ld e, d
ld d, 0
ld hl, CollisionForceAngles
add hl, de
ld a, [hl]
ld [wCollisionNormalAngle], a
; Again, based on the start and end collision point indices, apply
; position offsets to position the ball safely outside of the wall
; it collided with.
sla e
rl d
ld hl, CollisionYDeltas
add hl, de
ld a, [wBallYPos]
add [hl]
ld [wBallYPos], a
inc hl
ld a, [wBallYPos + 1]
adc [hl]
ld [wBallYPos + 1], a
ld hl, CollisionXDeltas
add hl, de
ld a, [wBallXPos]
add [hl]
ld [wBallXPos], a
inc hl
ld a, [wBallXPos + 1]
adc [hl]
ld [wBallXPos + 1], a
pop de
pop af
ld [hLoadedROMBank], a
ld [MBC5RomBank], a
ld a, d
swap a
and $f
ld e, a
ld a, d
and $f
sub e
jr nc, .loadTestPointOffsets
add 16
.loadTestPointOffsets
; e = start index of consecutive collision points
; a = length of consecutive collision points
; The rest of the code here determines which of
; the collision mask tiles was the one that triggered
; the collision. It can be multiple tiles, so it uses
; first collision test point that was colliding. Then,
; that tile's collision attribute is saved in wCurCollisionAttribute.
add e
add e
inc a
and $1e
ld c, a
ld b, 0
ld hl, BallCollisionTestPointOffsets
add hl, bc
ld a, [wSubTileBallXPos]
add 4
add [hl]
bit 3, a
ld c, b
jr z, .checkY
ld c, 2
.checkY
ld a, [wSubTileBallYPos]
add 4
inc hl
add [hl]
bit 3, a
jr z, .saveCollisionAttribute
inc c
.saveCollisionAttribute
ld hl, wUpperLeftCollisionAttribute
add hl, bc
ld a, [hl]
ld [wCurCollisionAttribute], a
ld hl, BallPositionPointerOffsetDeltas
add hl, bc
ld a, [wBallPositionTileOffset]
add [hl]
ld [wCurCollisionTileOffset], a
ld a, [wBallPositionTileOffset + 1]
adc 0
ld [wCurCollisionTileOffset + 1], a
ret
TryLoadSpecialCollisionMask: ; 0x248a
; If it's a special collision mask attribute, load the
; pointer to its mask and set the carry flag.
; If it's a regular static collision mask attribute, simply
; reset the carry flag and don't return anything.
push af
ld a, [wCurrentStage]
bit 0, a
jr nz, .bottomStage
pop af
and a
ret
.bottomStage
pop af
cp $d0
ccf
ret nc
cp $e0
jr nc, .notAnimatedMonCollision
sub $d0
sla a
sla a
sla a
ld l, a
ld h, (wMonAnimatedCollisionMask >> 8)
scf
ret
.notAnimatedMonCollision
push de
sub $e0
ld b, a
ld a, [wCurrentStage]
cp FIRST_BONUS_STAGE
jr nc, .bonusStage
bit 4, b
ld hl, BottomLeftCollisionMasks
ld a, [wLeftFlipperState + 1]
jr z, .checkFlipperPosition
res 4, b
ld hl, BottomRightCollisionMasks
ld a, [wRightFlipperState + 1]
.checkFlipperPosition
ld de, $0080
cp 7
jr c, .loadMaskPointer
add hl, de
cp 14
jr c, .loadMaskPointer
add hl, de
.loadMaskPointer
ld e, b
sla e
sla e
sla e
add hl, de
pop de
scf
ret
.bonusStage
bit 4, b
ld hl, BottomLeftBonusStageCollisionMasks
ld a, [wLeftFlipperState + 1]
jr z, .checkFlipperPosition2
res 4, b
ld hl, BottomRightBonusStageCollisionMasks
ld a, [wRightFlipperState + 1]
.checkFlipperPosition2
ld de, $0080
cp 7
jr c, .loadMaskPointer2
add hl, de
cp 14
jr c, .loadMaskPointer2
add hl, de
.loadMaskPointer2
ld e, b
sla e
sla e
sla e
add hl, de
pop de
scf
ret
BallPositionPointerOffsetDeltas:
db $00, $20
db $01, $21
BallCollisionTestPointOffsets:
db 4, 0
db 4, 1
db 3, 3
db 1, 4
db 0, 4
db -1, 4
db -3, 3
db -4, 1
db -4, 0
db -4, -1
db -3, -3
db -1, -4
db 0, -4
db 1, -4
db 3, -3
db 4, -1
; These tables facilitate testing the 16 collision points around the ball's origin.
; Each table corresponds to an x sub-tile offset for a base point 4 pixels up and left of
; the ball's origin.
;
; First byte: y sub-tile offset, if its greater than 8, it bleeds over to the next tile in the 2x2 tile region
; Second byte: bitmask to test against the 1bpp collision mask's row
; Third byte: index of wCollisionPointTests to save the result in
CollisionTests: ; 0x252e
dw CollisionTest_X0
dw CollisionTest_X1
dw CollisionTest_X2
dw CollisionTest_X3
dw CollisionTest_X4
dw CollisionTest_X5
dw CollisionTest_X6
dw CollisionTest_X7
CollisionTest_X0: ; 0x253e
db $00, $10, $0B
db $00, $08, $0C
db $00, $04, $0D
db $01, $40, $0A
db $01, $01, $0E
db $03, $80, $09
db $13, $80, $0F
db $04, $80, $08
db $14, $80, $00
db $05, $80, $07
db $15, $80, $01
db $07, $40, $06
db $07, $01, $02
db $08, $10, $05
db $08, $08, $04
db $08, $04, $03
CollisionTest_X1: ; 0x256e
db $00, $08, $0B
db $00, $04, $0C
db $00, $02, $0D
db $01, $20, $0A
db $11, $80, $0E
db $03, $40, $09
db $13, $40, $0F
db $04, $40, $08
db $14, $40, $00
db $05, $40, $07
db $15, $40, $01
db $07, $20, $06
db $17, $80, $02
db $08, $08, $05
db $08, $04, $04
db $08, $02, $03
CollisionTest_X2: ; 0x259e
db $00, $04, $0B
db $00, $02, $0C
db $00, $01, $0D
db $01, $10, $0A
db $11, $40, $0E
db $03, $20, $09
db $13, $20, $0F
db $04, $20, $08
db $14, $20, $00
db $05, $20, $07
db $15, $20, $01
db $07, $10, $06
db $17, $40, $02
db $08, $04, $05
db $08, $02, $04
db $08, $01, $03
CollisionTest_X3: ; 0x25ce
db $00, $02, $0B
db $00, $01, $0C
db $10, $80, $0D
db $01, $08, $0A
db $11, $20, $0E
db $03, $10, $09
db $13, $10, $0F
db $04, $10, $08
db $14, $10, $00
db $05, $10, $07
db $15, $10, $01
db $07, $08, $06
db $17, $20, $02
db $08, $02, $05
db $08, $01, $04
db $18, $80, $03
CollisionTest_X4: ; 0x25fe
db $00, $01, $0B
db $10, $80, $0C
db $10, $40, $0D
db $01, $04, $0A
db $11, $10, $0E
db $03, $08, $09
db $13, $08, $0F
db $04, $08, $08
db $14, $08, $00
db $05, $08, $07
db $15, $08, $01
db $07, $04, $06
db $17, $10, $02
db $08, $01, $05
db $18, $80, $04
db $18, $40, $03
CollisionTest_X5: ; 0x262e
db $10, $80, $0B
db $10, $40, $0C
db $10, $20, $0D
db $01, $02, $0A
db $11, $08, $0E
db $03, $04, $09
db $13, $04, $0F
db $04, $04, $08
db $14, $04, $00
db $05, $04, $07
db $15, $04, $01
db $07, $02, $06
db $17, $08, $02
db $18, $80, $05
db $18, $40, $04
db $18, $20, $03
CollisionTest_X6: ; 0x265e
db $10, $40, $0B
db $10, $20, $0C
db $10, $10, $0D
db $01, $01, $0A
db $11, $04, $0E
db $03, $02, $09
db $13, $02, $0F
db $04, $02, $08
db $14, $02, $00
db $05, $02, $07
db $15, $02, $01
db $07, $01, $06
db $17, $04, $02
db $18, $40, $05
db $18, $20, $04
db $18, $10, $03
CollisionTest_X7: ; 0x268e
db $10, $20, $0B
db $10, $10, $0C
db $10, $08, $0D
db $11, $80, $0A
db $11, $02, $0E
db $03, $01, $09
db $13, $01, $0F
db $04, $01, $08
db $14, $01, $00
db $05, $01, $07
db $15, $01, $01
db $17, $80, $06
db $17, $02, $02
db $18, $20, $05
db $18, $10, $04
db $18, $08, $03
INCLUDE "data/sine_table.asm"
INCLUDE "engine/pinball_game/object_collision/object_collision.asm"
LoadFlippersPalette: ; 0x2862
; Loads the flippers' color palette.
; When the flippers are active, they are white/blue. When disabled at the end of a Bonus Stage, they turn Red.
ld a, [wFlippersDisabled]
and a
jr nz, .flippersDisabled
ld a, [hGameBoyColorFlag]
and a
jr z, .done
ld a, Bank(ActiveFlippersPalette)
ld hl, ActiveFlippersPalette
ld de, $0052
ld bc, $0004
call FarCopyPalettes
.done
ret
.flippersDisabled
ld a, [hGameBoyColorFlag]
and a
jr z, .done2
ld a, Bank(DisabledFlippersPalette)
ld hl, DisabledFlippersPalette
ld de, $0052
ld bc, $0004
call FarCopyPalettes
.done2
ret
ActiveFlippersPalette:
; The white/blue color when the flippers are active.
RGB 31, 31, 31
RGB 21, 21, 27
DisabledFlippersPalette:
; The reddish colors when the flippers are disabled at the end of a Bonus Stage.
RGB 27, 10, 10
RGB 20, 04, 04
CatchBarTiles:
; The tile ids for the blue CATCH! bar under the wild pokemon
db $80, $AE, $AF, $B0, $B1, $B2, $B3, $80
CatchBarTilesEnd:
INCLUDE "home/animation.asm"
INCLUDE "home/text.asm"
INCLUDE "home/bcd.asm"
INCLUDE "home/tilt.asm"
SECTION "bank0.2", ROM0
BottomLeftCollisionMasks:
INCBIN "data/collision/masks/bottom_left_masks.masks"
BottomRightCollisionMasks:
INCBIN "data/collision/masks/bottom_right_masks.masks"
BottomLeftBonusStageCollisionMasks:
INCBIN "data/collision/masks/bottom_left_bonus_stage_masks.masks"
BottomRightBonusStageCollisionMasks:
INCBIN "data/collision/masks/bottom_right_bonus_stage_masks.masks"
; These two squares data arrays must be aligned to $100 bytes and appear contiguously.
SquaresLow:
FOR X, 256
db (X * X) % $100
ENDR
SquaresHigh:
FOR X, 256
db (X * X) / $100
ENDR