summaryrefslogtreecommitdiff
path: root/engine/games
diff options
context:
space:
mode:
authorRangi <35663410+Rangi42@users.noreply.github.com>2020-12-17 15:56:19 -0500
committerGitHub <noreply@github.com>2020-12-17 15:56:19 -0500
commitb1ae1098d06d9865c767471e539fa65f77101aaa (patch)
tree4b6d8fc9c449169705e224508a8d5e238fda18ab /engine/games
parent9352a537c39471410314be76cf866e058a9349bf (diff)
parent37e60a9457643720dae714f8d2df0cf5ad31d919 (diff)
Merge pull request #84 from ZoomTen/pikachu-minigame
Disassemble opening cutscene, Game Freak intro, and Pikachu minigame
Diffstat (limited to 'engine/games')
-rw-r--r--engine/games/pikachu_minigame.asm1447
1 files changed, 1447 insertions, 0 deletions
diff --git a/engine/games/pikachu_minigame.asm b/engine/games/pikachu_minigame.asm
new file mode 100644
index 0000000..de930da
--- /dev/null
+++ b/engine/games/pikachu_minigame.asm
@@ -0,0 +1,1447 @@
+INCLUDE "constants.asm"
+
+; MinigamePikachuDoMovement.Jumptable constants
+ const_def
+ const MINIGAME_PIKACHU_INIT ; 00
+ const MINIGAME_PIKACHU_CONTROL ; 01
+ const MINIGAME_PIKACHU_JUMPING ; 02
+ const MINIGAME_PIKACHU_FALLING ; 03
+
+; PikachuMiniGame_PerformGameFunction.Jumptable constants
+ const_def
+ const PIKACHU_MINIGAME_SETUP ; 00
+ const PIKACHU_MINIGAME_NOTE_SPAWNER ; 01
+ const PIKACHU_MINIGAME_SET_NEXT_SCENE_TIMER ; 02
+ const PIKACHU_MINIGAME_WAIT_AND_GOTO_NEXT ; 03
+ const PIKACHU_MINIGAME_SHOW_JIGGLYPUFF ; 04
+ const PIKACHU_MINIGAME_FADE_OUT ; 05
+
+SECTION "engine/games/pikachu_minigame.asm@Pikachu Minigame", ROMX
+
+PikachuMiniGame::
+ ld a, HIGH(vBGMap1)
+ ldh [hBGMapAddress + 1], a
+ call .Init
+ call DelayFrame
+.loop
+ call PikachuMiniGame_RunFrame
+ jr nc, .loop
+
+; exit
+ ld a, HIGH(vBGMap0)
+ ldh [hBGMapAddress + 1], a
+ ld de, MUSIC_NONE
+ call PlayMusic
+ ret
+
+.Init:
+ call DisableLCD
+ ld b, SGB_BETA_PIKACHU_MINIGAME
+ call GetSGBLayout
+ callab InitEffectObject
+ call PikachuMiniGame_ClearBothTilemaps
+
+ ld hl, IntroForestGFX
+ ld de, vChars2
+ ld bc, $80 tiles
+ ld a, BANK(IntroForestGFX)
+ call FarCopyData
+
+ ld hl, IntroJigglypuffPikachuGFX
+ ld de, vChars0
+ ld bc, $90 tiles
+ ld a, BANK(IntroJigglypuffPikachuGFX)
+ call FarCopyData
+
+; Metatiles
+ ld a, LOW(PikachuMiniGame_Meta)
+ ld [wPikachuMinigameTilesPointer], a
+ ld a, HIGH(PikachuMiniGame_Meta)
+ ld [wPikachuMinigameTilesPointer + 1], a
+
+; BG map destination
+ ld hl, vBGMap0
+ ld a, l
+ ld [wPikachuMinigameBGMapPointer], a
+ ld a, h
+ ld [wPikachuMinigameBGMapPointer + 1], a
+
+; Block map
+ ld de, PikachuMiniGame_Blockmap
+ ld a, e
+ ld [wPikachuMinigameTilemapPointer], a
+ ld a, d
+ ld [wPikachuMinigameTilemapPointer + 1], a
+ call PikachuMiniGame_DrawBackground
+
+ ld hl, wSpriteAnimDict
+ ld a, SPRITE_ANIM_INDEX_GS_INTRO_OMANYTE
+ ld [hli], a
+ ld a, SPRITE_ANIM_DICT_DEFAULT
+ ld [hli], a
+ call PikachuMiniGame_LoadFont
+
+ xor a
+ ldh [hSCY], a
+ ld [wGlobalAnimYOffset], a
+ ldh [hSCX], a
+ ld [wGlobalAnimXOffset], a
+ ld [wPikachuMinigameJumptableIndex], a
+ ld [wPikachuMinigameScrollSpeed], a
+ ld [wPikachuMinigameScore], a
+ ld [wPikachuMinigameScore + 1], a
+ ld [wPikachuMinigameNoteCounter], a
+ ld [wPikachuMinigameNoteCounter + 1], a
+ ld [wPikachuMinigameTimeFrames], a
+ ld [wPikachuMinigameTimeSeconds], a
+ ld [wc613], a
+ ld [wc614], a
+ ld [wPikachuMinigameNoteTimer], a
+ ld [wPikachuMinigameSpawnTypeIndex], a
+ ld [wPikachuMinigameSpawnDataIndex], a
+ ld [wPikachuMinigameRedrawTimer], a
+ ld [wPikachuMinigameColumnFlags], a
+ ld [wPikachuMinigameSavedColumnPointer], a
+ ld [wPikachuMinigameSavedColumnPointer + 1], a
+ ld [wPikachuMinigameRepeatColumnCounter], a
+ ld [wPikachuMinigameRepeatColumnCounter2], a
+
+ ld a, LOW(PikachuMiniGame_Columns)
+ ld [wPikachuMinigameColumnPointer], a
+ ld a, HIGH(PikachuMiniGame_Columns)
+ ld [wPikachuMinigameColumnPointer + 1], a
+
+; Set status bar position
+ ld a, $7c
+ ldh [hWY], a
+
+ ld a, $e3
+ ldh [rLCDC], a
+
+ ld a, [wSGB]
+ and a
+ jr nz, .not_sgb
+
+ ld a, %10010100
+ ldh [rBGP], a
+ ld a, %11100100
+ ldh [rOBP0], a
+ jr .load_pikachu
+
+.not_sgb
+; Normal palette if on GB / GBC
+ ld a, %11100100
+ ldh [rBGP], a
+ ldh [rOBP0], a
+
+.load_pikachu
+ depixel 14, 11
+ ld a, SPRITE_ANIM_INDEX_MINIGAME_PIKACHU
+ call InitSpriteAnimStruct
+
+; Save pointer to the newly initialized Pikachu object
+ ld a, c
+ ld [wPikachuMinigamePikachuObjectPointer], a
+ ld a, b
+ ld [wPikachuMinigamePikachuObjectPointer + 1], a
+
+; load Pikachu's tail object
+ depixel 14, 11
+ ld a, SPRITE_ANIM_INDEX_MINIGAME_PIKACHU_TAIL
+ call InitSpriteAnimStruct
+
+ ld a, c
+ ld [wPikachuMinigamePikachuTailObjectPointer], a
+ ld a, b
+ ld [wPikachuMinigamePikachuTailObjectPointer + 1], a
+ ret
+
+PikachuMiniGame_ClearBothTilemaps:
+ ld hl, vBGMap1
+ ld bc, SCREEN_WIDTH * BG_MAP_HEIGHT
+.clear_bgmap
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .clear_bgmap
+
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+.clear_tilemap
+ ld [hl], 0
+ inc hl
+ dec bc
+ ld a, b
+ or c
+ jr nz, .clear_tilemap
+
+ ld a, 7
+ ldh [hWX], a
+ ret
+
+PikachuMiniGame_LoadFont:
+ ld hl, FontGFX
+ ld de, vFont tile $10
+ ld bc, 112 * LEN_1BPP_TILE
+ ld a, BANK(FontGFX)
+ call FarCopyDataDouble
+
+ ld hl, FontGFX tile $39
+ ld de, vChars2 tile $32
+ ld bc, 16 * LEN_1BPP_TILE
+ ld a, BANK(FontGFX)
+ call FarCopyDataDouble
+ ret
+
+PikachuMiniGame_BlinkText:
+; Blink the window text according to the current X scroll position.
+; 00 - 7f = hide text
+; 80 - ff = show text
+
+ ldh a, [hSCX]
+ ld d, a
+ and $7f
+ ret nz
+ bit 7, d
+ jr nz, .DisplayText
+
+; clear dakutens
+ xor a
+ hlcoord 5, 0
+ ld [hl], a
+ hlcoord 13, 0
+ ld [hl], a
+
+; clear text
+ hlcoord 1, 1
+ ld c, 15
+.text_clear
+ ld [hli], a
+ dec c
+ jr nz, .text_clear
+ ret
+
+.DisplayText:
+ decoord 1, 1
+ ld hl, .text
+
+.render_text
+ ld a, [hli]
+ and a
+ jr z, .render_dakutens
+
+; Tiles are shifted so add $10 to each character
+ add $10
+ ld [de], a
+ inc de
+ jr .render_text
+
+.render_dakutens
+; Render dakuten marks separately
+ ld a, "゙" + $10
+
+ hlcoord 5, 0
+ ld [hl], a
+
+ hlcoord 13, 0
+ ld [hl], a
+
+ ret
+
+.text
+ db "スタートホタン▶タイトルかめん"
+ db 0 ; terminator
+
+PikachuMiniGame_Copy128Tiles: ; unreferenced?
+ ld bc, $80 tiles
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+PikachuMiniGame_DrawBackground:
+ ld b, BG_MAP_HEIGHT / 2
+
+.outer_loop
+ push hl
+ ld c, BG_MAP_WIDTH / 2
+
+.inner_loop
+ call PikachuMiniGame_Draw2x2Tile
+ dec c
+ jr nz, .inner_loop
+ pop hl
+ push bc
+ ld bc, BG_MAP_HEIGHT * 2
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .outer_loop
+ ret
+
+PikachuMiniGame_Draw2x2Tile:
+ push bc
+ push de
+ push hl
+
+ push hl
+
+ push hl
+ ld a, [de]
+ ld l, a
+ ld h, 0
+ ld a, [wPikachuMinigameTilesPointer]
+ ld e, a
+ ld a, [wPikachuMinigameTilesPointer + 1]
+ ld d, a
+ add hl, hl
+ add hl, hl
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ pop hl
+
+ ld bc, BG_MAP_WIDTH
+ add hl, bc
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ pop hl
+
+ inc hl
+ inc hl
+
+ pop de
+ inc de
+
+ pop bc
+ ret
+
+
+PikachuMiniGame_RunFrame:
+; Run a single frame of the minigame
+
+ call GetJoypad
+ ld hl, hJoyState
+ ld a, [hl]
+
+; Skip minigame on pressing Start
+ and START
+ jr nz, .Done
+
+ ld a, [wPikachuMinigameJumptableIndex]
+ bit 7, a
+ jr nz, .Done
+
+ ld a, [wPikachuMinigameNoteCaught]
+ and a
+ jr z, .skip_playing_sfx
+
+ xor a
+ ld [wPikachuMinigameNoteCaught], a
+ ld de, SFX_PAY_DAY
+ call PlaySFX
+
+.skip_playing_sfx
+ call PikachuMiniGame_PerformGameFunction
+ callba EffectObjectJumpNoDelay
+
+ ld a, 1
+ ldh [hBGMapMode], a
+
+ call PikachuMiniGame_ScrollScene
+ call PikachuMiniGame_UpdateBlocks
+
+; Print minigame score, starting from the last digit
+ decoord 18, 1
+ ld hl, wPikachuMinigameScore
+ call PikachuMiniGame_PrintBCD
+
+ call PikachuMiniGame_BlinkText
+
+ call DelayFrame
+ and a
+ ret
+
+.Done:
+ callab InitEffectObject
+
+ ld hl, wVirtualOAM
+ ld c, SPRITEOAMSTRUCT_LENGTH * NUM_SPRITE_OAM_STRUCTS
+ xor a
+.clear_oam
+ ld [hli], a
+ dec c
+ jr nz, .clear_oam
+
+ call DelayFrame
+
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+
+ ld a, 144
+ ldh [hWY], a
+ scf
+ ret
+
+
+PikachuMiniGame_RunTimer:
+ ld hl, wPikachuMinigameTimeFrames
+
+; Run BCD frame counter
+ ld a, [hl]
+ add 1
+ daa
+ ld [hl], a
+ cp $60
+ ret c
+
+; Clear frame counter upon passing one second and increment the
+; seconds counter instead
+ ld [hl], 0
+ ld hl, wPikachuMinigameTimeSeconds
+ ld a, [hl]
+ add 1
+ daa
+ ld [hl], a
+ cp $60
+ ret c
+
+; When gameplay time reaches 1 minute, end the game here
+ ld a, PIKACHU_MINIGAME_SET_NEXT_SCENE_TIMER
+ ld [wPikachuMinigameJumptableIndex], a
+ ret
+
+
+PikachuMiniGame_UpdateBlocks:
+ ldh a, [hSCX]
+ ld e, a
+ and 7
+ ret nz
+
+ ld a, $48
+ add e
+ and $f8
+ ld e, a
+ srl e
+ srl e
+ srl e
+ ld d, 0
+ hlbgcoord 0, 8
+ add hl, de
+ ld de, wPikachuMinigameColumnBuffer
+ ld a, e
+ ld [wVBCopyDst], a
+ ld a, d
+ ld [wVBCopyDst + 1], a
+ ld a, l
+ ld [wVBCopySrc], a
+ ld a, h
+ ld [wVBCopySrc + 1], a
+ ld a, 1
+ ld [wVBCopySize], a
+ ret
+
+
+PikachuMiniGame_PrintBCD:
+; Print the BCD number in HL to DE, least-significant
+; digit first.
+
+ push hl
+ push de
+ push bc
+
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ ld l, e
+ ld h, d
+
+; in the thousandths range?
+ ld a, b
+ swap a
+ and $f
+ jr nz, .four_digits
+
+; in the hundredths range?
+ ld a, b
+ and $f
+ jr nz, .three_digits
+
+; in the tenths range?
+ ld a, c
+ swap a
+ and $f
+ jr nz, .two_digits
+
+; got one digit
+ ld a, c
+ call .PlaceDigit
+ jr .finished
+
+.two_digits
+ ld a, c
+ call .PlaceDigit
+ ld a, c
+ swap a
+ call .PlaceDigit
+ jr .finished
+
+.three_digits
+ ld a, c
+ call .PlaceDigit
+ ld a, c
+ swap a
+ call .PlaceDigit
+ ld a, b
+ call .PlaceDigit
+ jr .finished
+
+.four_digits
+ ld a, c
+ call .PlaceDigit
+ ld a, c
+ swap a
+ call .PlaceDigit
+ ld a, b
+ call .PlaceDigit
+ ld a, b
+ swap a
+ call .PlaceDigit
+
+.finished
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.PlaceDigit:
+ and $0f
+ add $36
+ ld [hld], a
+ ret
+
+PikachuMiniGame_PerformGameFunction:
+ jumptable .Jumptable, wPikachuMinigameJumptableIndex
+
+.Jumptable:
+ dw PikachuMiniGame_SetupScene
+ dw PikachuMiniGame_NoteSpawner
+ dw PikachuMiniGame_SetNextSceneTimer
+ dw PikachuMiniGame_WaitAndGotoNextScene
+ dw PikachuMiniGame_ShowJigglypuff
+ dw PikachuMiniGame_FadeOut
+
+PikachuMiniGame_SetupScene:
+; Set scroll speed and joypad enable here
+ ld a, 4
+ ld [wPikachuMinigameScrollSpeed], a
+
+ ld a, D_LEFT | D_RIGHT | A_BUTTON
+ ld [wPikachuMinigameControlEnable], a
+
+ ld hl, wPikachuMinigameJumptableIndex
+ inc [hl]
+ ret
+
+PikachuMiniGame_SetNextSceneTimer:
+ ld a, 64
+ ld [wPikachuMinigameSceneTimer], a
+ ld hl, wPikachuMinigameJumptableIndex
+ inc [hl]
+
+PikachuMiniGame_WaitAndGotoNextScene:
+ ld hl, wPikachuMinigameSceneTimer
+ ld a, [hl]
+ and a
+ jr z, .next_scene
+ dec [hl]
+ ret
+
+.next_scene
+ ld hl, wPikachuMinigameJumptableIndex
+ inc [hl]
+
+PikachuMiniGame_ShowJigglypuff:
+ depixel 14, 24
+ ld a, SPRITE_ANIM_INDEX_MINIGAME_JIGGLYPUFF
+ call InitSpriteAnimStruct
+
+ xor a
+ ld [wPikachuMinigameSceneTimer], a
+ ld hl, wPikachuMinigameJumptableIndex
+ inc [hl]
+
+PikachuMiniGame_FadeOut:
+ ld a, [wPikachuMinigameScrollSpeed]
+ and a
+ ret nz
+
+ ld a, [wPikachuMinigameSceneTimer]
+ srl a
+ srl a
+ srl a
+ srl a
+
+ ld e, a
+ ld d, 0
+ ld hl, .DMGPals
+ add hl, de
+
+ ld a, [hl]
+ cp -1
+ jr z, .end_minigame
+
+ ldh [rBGP], a
+
+ ld hl, .Obj_SGBPals
+ add hl, de
+
+ ld a, [wSGB]
+ and a
+ jr z, .not_sgb
+
+ ld a, [hl]
+ ldh [rBGP], a
+
+.not_sgb
+ ld a, [hl]
+ ldh [rOBP0], a
+
+; from this point, the timer increments*instead
+ ld hl, wPikachuMinigameSceneTimer
+ inc [hl]
+ ret
+
+.end_minigame
+; once everything fades out, the minigame ends here
+; leading to the title screen
+
+ ld hl, wPikachuMinigameJumptableIndex
+ set 7, [hl]
+ ret
+
+.DMGPals:
+ db $94, $94
+ db $94, $94
+ db $94, $50
+ db $40, $00
+ db -1
+
+.Obj_SGBPals:
+ db $e4, $e4
+ db $e4, $e4
+ db $e4, $90
+ db $40, $00
+ db -1
+
+PikachuMiniGame_NoteSpawner:
+; Spawn notes from the left side of the screen.
+;
+ call PikachuMiniGame_RunTimer
+ ldh a, [hSCX]
+ and $20
+ ld hl, wPikachuMinigameNoteTimer
+ cp [hl]
+ jr nz, .spawn_note
+ ret
+
+.spawn_note
+ ld a, [hl]
+ xor $20
+ ld [hl], a
+
+ call .DetermineSpawnType
+ jr c, .next_scene
+
+; Skip spawning if y = $FF
+ call .DetermineSpawnPosition
+ ret c
+
+ ldh a, [hSCX]
+ and $1f
+ ld e, a
+ ld a, 0
+ sub e
+ ld e, a
+ ld a, 3
+ ld [wSpriteAnimCount], a
+
+ ld a, SPRITE_ANIM_INDEX_MINIGAME_NOTE
+ call InitSpriteAnimStruct
+
+; add one to the note counter
+ ld hl, wPikachuMinigameNoteCounter
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, 1
+ add e
+ daa
+ ld e, a
+ ld a, d
+ adc 0
+ daa
+ ld d, a
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ret
+
+.next_scene ; can this be reached?
+ ld hl, wPikachuMinigameJumptableIndex
+ inc [hl]
+ ret
+
+.DetermineSpawnType:
+ ld a, [wPikachuMinigameSpawnTypeIndex]
+ ld l, a
+ ld h, 0
+ ld de, .SpawnTypes
+ add hl, de
+ ld a, [hl]
+ cp -1
+ jr nz, .got_type
+ xor a
+ ld [wPikachuMinigameSpawnTypeIndex], a
+.got_type
+ and a
+ ret
+
+.SpawnTypes:
+; or .SpawnPositions indices
+ db $00, $01, $02, $03, $04, $05, $06, $00, $01, $02, $03, $04, $05, $06
+ db -1
+
+.DetermineSpawnPosition:
+; a = spawn type (index of spawn data)
+
+; returns d = Y-starting position of a note
+; carry, if no note is to be spawned
+
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, .SpawnPositions
+ add hl, de
+
+ ld a, [wPikachuMinigameSpawnDataIndex]
+ and 7
+ ld e, a
+ inc a
+ cp 8
+ jr c, .determine_y_coords
+
+; next spawn type
+ push hl
+ ld hl, wPikachuMinigameSpawnTypeIndex
+ inc [hl]
+ pop hl
+
+.determine_y_coords
+ ld [wPikachuMinigameSpawnDataIndex], a
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ cp $ff
+ jr z, .skip_spawning_note
+ ld d, a
+ and a
+ ret
+
+.skip_spawning_note
+ scf
+ ret
+
+.SpawnPositions:
+ db $70, $60, $50, $48, $48, $48, $48, $38 ; 00
+ db $28, $20, $28, $ff, $ff, $ff, $48, $48 ; 01
+ db $70, $70, $ff, $58, $ff, $ff, $48, $38 ; 02
+ db $28, $20, $28, $38, $48, $ff, $ff, $ff ; 03
+ db $70, $70, $70, $70, $60, $50, $48, $38 ; 04
+ db $ff, $28, $30, $38, $48, $48, $48, $48 ; 05
+ db $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff ; 06
+
+MinigamePikachuDoMovement::
+; called from sprite animation routine
+ ld a, [wPikachuMinigamePikachuObjectPointer]
+ ld c, a
+ ld a, [wPikachuMinigamePikachuObjectPointer + 1]
+ ld b, a
+ call MinigamePikachuCheckFloorCollision
+ call .ResetScoreModifiersAndCheckNoteCollision
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld e, [hl]
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .InitPikachuMovement
+ dw .ControlPikachu
+ dw .PikachuJumping
+ dw .FallDown
+
+.InitPikachuMovement:
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], MINIGAME_PIKACHU_CONTROL
+ ld a, 2
+ ld [wPikachuMinigamePikachuNextAnim], a
+ ret
+
+.ControlPikachu:
+ ldh a, [hJoyState]
+ ld hl, wPikachuMinigameControlEnable
+ and [hl]
+ ld d, a
+
+ and A_BUTTON
+ jr nz, .do_jump
+
+; Don't animate Pikachu when the screen is still
+ ld a, [wPikachuMinigameScrollSpeed]
+ and a
+ ret nz
+
+ ld a, 1
+ ld [wPikachuMinigamePikachuNextAnim], a
+ ret
+
+.do_jump
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+ ld a, 64
+ ld [wPikachuMinigamePikachuYOffset], a
+ ld a, 3
+ ld [wPikachuMinigamePikachuNextAnim], a
+ ld a, $10
+ ld [wc606], a
+ ret
+
+.PikachuJumping:
+ ld hl, wPikachuMinigamePikachuYOffset
+ ld a, [hl]
+ cp 32
+ jr c, .fall_down_from_jump
+ dec [hl]
+ ld d, $30
+ ld e, a
+ callba BattleAnim_Sine_e
+ ld a, e
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+.fall_down_from_jump
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], MINIGAME_PIKACHU_FALLING
+ ret
+
+.FallDown:
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ret
+
+.ResetScoreModifiersAndCheckNoteCollision:
+ xor a
+ ld [wPikachuMinigameScoreModifier], a
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ add [hl]
+
+; Set the Y-collision range between Pikachu and note
+; between y-$10 and y+$10
+
+ add $10
+ ld e, a
+ sub $10 * 2
+ ld d, a
+ push bc
+
+; Check if the Pikachu object collides with any of the note
+; objects.
+
+ ld bc, wSpriteAnim1
+ ld a, NUM_SPRITE_ANIM_STRUCTS
+.check_note_object
+ push af
+ push de
+ ld hl, SPRITEANIMSTRUCT_INDEX
+ add hl, bc
+ ld a, [hl]
+ and a
+; Deinitialized object, get the next object
+ jr z, .get_next_object
+
+; Is the current object a note?
+ ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
+ add hl, bc
+ ld a, [hl]
+ cp 7
+ jr nz, .get_next_object
+
+; Check if note collides with Pikachu
+ call .IsNoteColliding
+
+.get_next_object
+ ld hl, SPRITEANIMSTRUCT_LENGTH
+ add hl, bc
+ ld c, l
+ ld b, h
+ pop de
+ pop af
+ dec a
+ jr nz, .check_note_object
+ pop bc
+ call PikachuMiniGame_AddToScore
+ ret
+
+.IsNoteColliding:
+; Is the note object within $48 - $68 (middle of the screen)?
+ ld a, $48
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ cp [hl]
+ ret nc
+
+ ld a, $68
+ cp [hl]
+ ret c
+
+; Is the note object within collision range?
+ ld a, d
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ cp [hl]
+ ret nc
+
+ ld a, e
+ cp [hl]
+ ret c
+
+; Pikachu caught a note
+ ld a, 1
+ ld [wPikachuMinigameNoteCaught], a
+
+; Delete the note object
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ inc [hl]
+
+ ld hl, wPikachuMinigameScoreModifier
+ inc [hl]
+ ret
+
+PikachuMiniGame_AddToScore:
+ ld hl, wPikachuMinigameScore
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [wPikachuMinigameScoreModifier]
+ add e
+ daa
+ ld e, a
+ ld a, d
+ adc 0
+ daa
+ ld d, a
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ret
+
+CopyPikachuObjDataToTailObj::
+; copies the object data for Pikachu to Pikachu's tail object
+; called from sprite animation routine
+
+ ld a, [wPikachuMinigamePikachuObjectPointer]
+ ld e, a
+ ld a, [wPikachuMinigamePikachuObjectPointer + 1]
+ ld d, a
+
+ ld a, [wPikachuMinigamePikachuTailObjectPointer]
+ ld c, a
+ ld a, [wPikachuMinigamePikachuTailObjectPointer + 1]
+ ld b, a
+
+ ld hl, SPRITEANIMSTRUCT_DURATIONOFFSET
+ add hl, de
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_DURATIONOFFSET
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, de
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, de
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, de
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_XCOORD
+ add hl, bc
+ ld [hl], a
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, de
+ ld a, [hl]
+
+ ld hl, SPRITEANIMSTRUCT_XOFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+MinigamePikachuCheckFloorCollision:
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ add [hl]
+ ld d, a
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld a, [hl]
+
+; Pikachu is jumping
+ cp MINIGAME_PIKACHU_JUMPING
+ jr z, .jumping
+
+; Pikachu is falling
+ cp MINIGAME_PIKACHU_FALLING
+ jr z, .falling
+
+ ld a, d
+ cp $70
+ ret z
+
+ call .CheckCollidingFloor
+ ret nz
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], MINIGAME_PIKACHU_FALLING
+ ret
+
+.jumping
+ ld a, [wPikachuMinigamePikachuYOffset]
+ cp $3e
+ ret nc
+
+ call .CheckCollidingFloor
+ ret z
+
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], MINIGAME_PIKACHU_INIT
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld [hl], 0
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ add [hl]
+ and %11111000
+ ld [hl], a
+ ret
+
+.falling
+ ld a, d
+ cp $70
+ jr z, .landed
+ call .CheckCollidingFloor
+ ret z
+
+.landed
+ ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
+ add hl, bc
+ ld [hl], MINIGAME_PIKACHU_INIT
+ ld hl, SPRITEANIMSTRUCT_YOFFSET
+ add hl, bc
+ ld a, [hl]
+ ld [hl], 0
+ ld hl, SPRITEANIMSTRUCT_YCOORD
+ add hl, bc
+ add [hl]
+ and %11111000
+ ld [hl], a
+ ret
+
+.CheckCollidingFloor:
+; Returns z if we collided with a platform.
+
+ ld a, d
+ cp 64
+ jr z, .check_tile_below
+ xor a
+ ret
+.check_tile_below
+ ld hl, wPikachuMinigameColumnBuffer
+ ld a, $16
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret
+
+
+PikachuMiniGame_ScrollScene:
+ ld hl, wPikachuMinigameScrollSpeed
+ ldh a, [hSCX]
+ sub [hl]
+ ldh [hSCX], a
+ and $10
+ ld hl, wPikachuMinigameRedrawTimer
+ cp [hl]
+ jr nz, .new_column
+ ret
+.new_column
+ ld a, [hl]
+ xor $10
+ ld [hl], a
+ xor a
+ ldh [hBGMapMode], a
+ call PikachuMiniGame_RenderColumn
+ ldh a, [hSCX]
+ and $f0
+ srl a
+ srl a
+ srl a
+ ld e, a
+ ld d, 0
+ ld hl, vBGMap0
+ add hl, de
+ ld a, l
+ ldh [hRedrawRowOrColumnDest], a
+ ld a, h
+ ldh [hRedrawRowOrColumnDest + 1], a
+ ld a, $01
+ ldh [hRedrawRowOrColumnMode], a
+ ret
+
+
+PikachuMiniGame_RenderColumn:
+ call PikachuMiniGame_GetNextColumn
+ ret nc
+
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, .ColumnSet
+ add hl, de
+ ld e, l
+ ld d, h
+ call PikachuMiniGame_UpdateColumn
+ ret
+
+.ColumnSet:
+; The "level" block set
+; top to bottom
+
+ db $05, $0d, $02, $09, $14, $14, $14, $0b ; 00
+ db $04, $0c, $02, $08, $14, $14, $14, $0b ; 01
+ db $05, $0d, $02, $09, $15, $14, $14, $0b ; 02
+ db $04, $0c, $02, $08, $15, $14, $14, $0b ; 03
+
+PikachuMiniGame_UpdateColumn:
+ push de
+ ld hl, wRedrawRowOrColumnSrcTiles
+ ld c, 8
+.update
+ ld a, [de]
+ call PikachuMiniGame_DrawTileToBuffer
+ inc de
+ dec c
+ jr nz, .update
+ pop de
+ ret
+
+PikachuMiniGame_DrawTileToBuffer:
+ push bc
+ push de
+ push hl
+ ld l, a
+ ld h, 0
+ ld a, [wPikachuMinigameTilesPointer]
+ ld e, a
+ ld a, [wPikachuMinigameTilesPointer + 1]
+ ld d, a
+ add hl, hl
+ add hl, hl
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ pop de
+ pop bc
+ ret
+
+PikachuMiniGame_GetNextColumn:
+ call .GetNextByte
+ cp $f0
+ ret c
+
+ call .GetColumnCommand
+ jr PikachuMiniGame_GetNextColumn
+
+.GetColumnCommand:
+ sub $f0
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .DummyCommand ; f0
+ dw .DummyCommand ; f1
+ dw .DummyCommand ; f2
+ dw .DummyCommand ; f3
+ dw .DummyCommand ; f4
+ dw .DummyCommand ; f5
+ dw .DummyCommand ; f6
+ dw .DummyCommand ; f7
+ dw .DummyCommand ; f8
+ dw .CommandF9 ; f9
+ dw .CommandFA ; fa
+ dw .CommandFB ; fb
+ dw .JumpCommand ; fc
+ dw .CommandFD ; fd
+ dw .CallCommand ; fe
+ dw .ReturnCommand ; ff
+
+.DummyCommand:
+ ret
+
+.ReturnCommand:
+; End level subpart
+
+ ld hl, wPikachuMinigameColumnFlags
+ res 0, [hl]
+
+ ld hl, wPikachuMinigameSavedColumnPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, wPikachuMinigameColumnPointer
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ ret
+
+.CallCommand:
+; Call a level subpart
+
+ call .GetNextByte
+ ld e, a
+ call .GetNextByte
+ ld hl, wPikachuMinigameColumnPointer
+ ld c, [hl]
+ inc hl
+ ld b, [hl]
+
+ ld hl, wPikachuMinigameSavedColumnPointer
+ ld [hl], c
+ inc hl
+ ld [hl], b
+
+ ld hl, wPikachuMinigameColumnPointer + 1
+ ld [hld], a
+ ld [hl], e
+
+ ld hl, wPikachuMinigameColumnFlags
+ set 0, [hl]
+ ret
+
+.JumpCommand:
+; Jump to another part of the level
+
+ call .GetNextByte
+ ld e, a
+ call .GetNextByte
+ ld hl, wPikachuMinigameColumnPointer + 1
+ ld [hld], a
+ ld [hl], e
+ ret
+
+.CommandFD:
+ call .GetNextByte
+ ld hl, wPikachuMinigameColumnFlags
+ bit 1, [hl]
+ jr nz, .flag_set
+ and a
+ jr z, .update_pointer
+ dec a
+ ld [wPikachuMinigameRepeatColumnCounter], a
+ set 1, [hl]
+.flag_set
+ ld hl, wPikachuMinigameRepeatColumnCounter
+ ld a, [hl]
+ and a
+ jr z, .done
+ dec [hl]
+.update_pointer
+ call .GetNextByte
+ ld e, a
+ call .GetNextByte
+ ld hl, wPikachuMinigameColumnPointer + 1
+ ld [hld], a
+ ld [hl], e
+ ret
+.done
+ ld hl, wPikachuMinigameColumnFlags
+ res 2, [hl]
+ call .ReplaceColumnPointer
+ ret
+
+.CommandF9:
+ call .GetNextByte
+ ld [wPikachuMinigameRepeatColumnCounter2], a
+ ret
+
+.CommandFA:
+ ld hl, wPikachuMinigameRepeatColumnCounter2
+ inc [hl]
+ ret
+
+.CommandFB:
+ call .GetNextByte
+ ld hl, wPikachuMinigameRepeatColumnCounter2
+ cp [hl]
+ jr z, .got_match
+ call .ReplaceColumnPointer
+ ret
+.got_match
+ call .GetNextByte
+ ld e, a
+ call .GetNextByte
+ ld hl, wPikachuMinigameColumnPointer + 1
+ ld [hld], a
+ ld [hl], e
+ ret
+
+.ReplaceColumnPointer:
+ ld hl, wPikachuMinigameColumnPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc de
+ inc de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ret
+
+.GetNextByte:
+ push hl
+ push de
+ ld hl, wPikachuMinigameColumnPointer
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [de]
+ inc de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ pop de
+ pop hl
+ ret
+
+PikachuMiniGame_Columns:
+; Essentially the "level design" of the minigame
+; See also PikachuMiniGame_RenderColumn.ColumnSet
+
+ db $00, $01
+ db $00, $01
+ db $00, $01
+ db $00, $01
+ db $02, $03
+ db $02, $03
+ db $02, $03
+ db $02, $03
+ db $FC
+ dw PikachuMiniGame_Columns
+ db $FF
+
+PikachuMiniGame_Blockmap:
+INCBIN "gfx/minigames/pikachu_blockmap.bin"
+
+PikachuMiniGame_Meta:
+INCBIN "gfx/minigames/pikachu_blockset.bin"