diff options
| author | Rangi <35663410+Rangi42@users.noreply.github.com> | 2020-12-17 15:56:19 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-17 15:56:19 -0500 |
| commit | b1ae1098d06d9865c767471e539fa65f77101aaa (patch) | |
| tree | 4b6d8fc9c449169705e224508a8d5e238fda18ab /engine/games | |
| parent | 9352a537c39471410314be76cf866e058a9349bf (diff) | |
| parent | 37e60a9457643720dae714f8d2df0cf5ad31d919 (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.asm | 1447 |
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" |
