HandlePinballGame: ; 0xd853
	ld a, [wScreenState]
	rst JumpTable  ; calls JumpToFuncInTable
PinballGameScreenFunctions: ; 0xd857
	dw GameScreenFunction_LoadGFX
	dw GameScreenFunction_StartBall
	dw GameScreenFunction_HandleBallPhysics
	dw GameScreenFunction_HandleBallLoss
	dw GameScreenFunction_EndBall

GameScreenFunction_LoadGFX: ; 0xd861
	call SetDoubleSpeedMode
	xor a
	ld [wd908], a
	callba InitializeCurrentStage
	call FillBottomMessageBufferWithBlackTile
	ld a, $1
	ld [wAudioEngineEnabled], a
	ld [wDrawBottomMessageBox], a
	ld hl, wScreenState
	inc [hl]
	ret

GameScreenFunction_StartBall: ; 0xd87f
	ld a, $67
	ld [hLCDC], a
	ld a, $e4
	ld [wBGP], a
	ld a, $e1
	ld [wOBP0], a
	ld a, $e4
	ld [wOBP1], a
	ld a, [wSCX]
	ld [hSCX], a
	xor a
	ld [hSCY], a
	ld a, $7
	ld [hWX], a
	ld a, $83
	ld [hLYC], a
	ld [hLastLYC], a
	ld a, $ff
	ld [hLCDCMask], a
	ld hl, hSTAT
	set 6, [hl]
	ld hl, rIE
	set 1, [hl]
	ld a, $1
	ld [hStatIntrRoutine], a
	callba InitBallForStage
	callba LoadStageCollisionAttributes
	callba LoadStageData
	callba ScrollScreenToShowPinball
	call ClearOAMBuffer
	callba DrawSpritesForStage
	ld a, [wUpdateAudioEngineUsingTimerInterrupt]
	and a
	call nz, ToggleAudioEngineUpdateMethod
	ld a, $1
	ld [wDrawBottomMessageBox], a
	xor a
	ld [wLoadingSavedGame], a
	call SetAllPalettesWhite
	call EnableLCD
	call FadeIn
	ld hl, wScreenState
	inc [hl]
	ret

GameScreenFunction_HandleBallPhysics: ; 0xd909
; main loop for stage logic
	xor a
	ld [wFlipperCollision], a
	ld [wCollisionForceAmplification], a
	call ApplyGravityToBall
	call LimitBallVelocity
	xor a
	ld [wIsBallColliding], a
	call HandleTilts
	ld a, [wCurrentStage]
	bit 0, a
	callba nz, HandleFlippers  ; only perform flipper logic on the lower half of stages
	ld a, [wFlipperCollision]
	and a
	ld a, [wCollisionNormalAngle]
	push af
	call CheckStageCollision
	pop af
	jr z, .noFlipperCollision
	ld [wCollisionNormalAngle], a
.noFlipperCollision
	call CheckGameObjectCollisions
	call ResolveGameObjectCollisions
	ld hl, wKeyConfigMenu
	call IsKeyPressed
	jr z, .didntPressMenuKey
	lb de, $03, $4c
	call PlaySoundEffect
	callba HandleInGameMenu
	jp z, SaveGame
.didntPressMenuKey
	ld a, [wIsBallColliding]  ; check for collision flag
	and a
	jr z, .moveBallPosition
	call ApplyTiltForces
	call LoadBallVelocity ; bc = x velocity, de = y velocity
	; First, rotate the velocity vector into a standardized coordinate
	; system where the normal angle points upwards.
	ld a, [wCollisionNormalAngle]
	call RotateVector
	; Apply the collision forces to the ball in the rotated coordinate system.
	call ApplyCollisionForces
	ld a, [wFlipperCollision]
	and a
	jr z, .noFlipperCollision2
	; de -= *wFlipperYForce
	ld hl, wFlipperYForce
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ld a, e
	sub l
	ld e, a
	ld a, d
	sbc h
	ld d, a
	; bc += *wFlipperXForce
	ld hl, wFlipperXForce
	ld a, [hli]
	ld h, [hl]
	ld l, a
	ld a, c
	add l
	ld c, a
	ld a, b
	adc h
	ld b, a
	jr .updateBallVelocity

.noFlipperCollision2
	ld a, [wNoCollisionApplied]
	and a
	jr nz, .moveBallPosition
.updateBallVelocity
	; Rotate the velocity vector back to the regular coordinate system, and
	; set the ball's velocity to the resulting vector.
	ld a, [wCollisionNormalAngle]
	call NegateAngleAndRotateVector
	call SetBallVelocity
.moveBallPosition
	call MoveBallPosition
	callba CheckStageTransition
	callba DrawSpritesForStage
	call UpdateBottomText
	ld a, [wDisableDrawScoreboardInfo]
	and a
	jr nz, .skipDrawingScoreboard
	callba Func_85c7
	callba HideScoreIfBallLow
	callba Func_8645
	call Func_dba9
	call DrawNumPartyMonsIcon
	call DrawPikachuSaverLightningBoltIcon
.skipDrawingScoreboard
	ld a, [wTimerActive]
	and a
	callba nz, DecrementTimer
	ld a, [wMoveToNextScreenState]
	and a
	ret z
	xor a
	ld [wMoveToNextScreenState], a
	ld hl, wScreenState
	inc [hl]
	ret

INCLUDE "engine/pinball_game/save_game.asm"

GameScreenFunction_HandleBallLoss: ; 0xda36
	xor a
	ld [hJoypadState], a
	ld [hNewlyPressedButtons], a
	ld [hPressedButtons], a
	ld [wFlipperCollision], a
	ld [wCollisionForceAmplification], a
	xor a
	ld [wIsBallColliding], a
	ld [wPinballIsVisible], a
	ld [wEnableBallGravityAndTilt], a
	call HandleTilts
	ld a, [wCurrentStage]
	bit 0, a
	callba nz, HandleFlippers
	callba DrawSpritesForStage
	call UpdateBottomText
	callba Func_85c7
	ld a, [wBottomTextEnabled]
	and a
	ret nz
	ld a, [wLostBall]
	and a
	jr z, .asm_daa9
	ld a, [wExtraBallState]
	cp $2
	jr z, .asm_daa9
	call EndOfBallBonus
	ld a, [wExtraBallState]
	and a
	jr z, .asm_daa9
	ld a, $2
	ld [wExtraBallState], a
	ld [wDrawBottomMessageBox], a
	call FillBottomMessageBufferWithBlackTile
	call EnableBottomText
	ld hl, wScrollingText3
	ld de, ShootAgainText
	call LoadScrollingText
	ret

.asm_daa9
	xor a
	ld [wExtraBallState], a
	ld hl, wScreenState
	inc [hl]
	ret

GameScreenFunction_EndBall: ; 0xdab2
	xor a
	ld [wRumblePattern], a
	ld a, [wGameOver]
	and a
	jp nz, TransitionToHighScoresScreen
	ld a, [wGoingToBonusStage]
	and a
	jr nz, .goingToBonusStage
	ld a, [wReturningFromBonusStage]
	and a
	jr nz, .returningFromBonusStage
	call FadeOut
	ld a, [wUpdateAudioEngineUsingTimerInterrupt]
	and a
	call z, ToggleAudioEngineUpdateMethod
	call DisableLCD
	ld hl, hSTAT
	res 6, [hl]
	ld hl, rIE
	res 1, [hl]
	ld a, $1
	ld [wScreenState], a
	ret

.goingToBonusStage
	ld de, MUSIC_NOTHING
	call PlaySong
	ld bc, $0004
	call AdvanceFrames
	call FadeOut
	ld a, [wUpdateAudioEngineUsingTimerInterrupt]
	and a
	call nz, ToggleAudioEngineUpdateMethod
	call DisableLCD
	ld hl, hSTAT
	res 6, [hl]
	ld hl, rIE
	res 1, [hl]
	ld a, [wCurrentStage]
	ld [wCurrentStageBackup], a
	ld a, [wStageCollisionState]
	ld [wStageCollisionStateBackup], a
	ld a, [wNextStage]
	ld [wCurrentStage], a
	xor a
	ld [wReturningFromBonusStage], a
	ld [wGoingToBonusStage], a
	ld a, $0
	ld [wScreenState], a
	ret

.returningFromBonusStage
	ld de, MUSIC_NOTHING
	call PlaySong
	ld bc, $0004
	call AdvanceFrames
	call FadeOut
	ld a, [wUpdateAudioEngineUsingTimerInterrupt]
	and a
	call nz, ToggleAudioEngineUpdateMethod
	call DisableLCD
	ld hl, hSTAT
	res 6, [hl]
	ld hl, rIE
	res 1, [hl]
	ld a, [wCurrentStageBackup]
	ld [wCurrentStage], a
	ld a, [wStageCollisionStateBackup]
	ld [wStageCollisionState], a
	ld a, $1
	ld [wScreenState], a
	ret

TransitionToHighScoresScreen: ; 0xdb5d
	xor a
	ld [wGameOver], a
	ld de, MUSIC_NOTHING
	call PlaySong
	ld bc, $0004
	call AdvanceFrames
	call FadeOut
	call DisableLCD
	ld hl, hSTAT
	res 6, [hl]
	ld hl, rIE
	res 1, [hl]
	xor a
	ld [wDrawBottomMessageBox], a
	ld a, [wCurrentStage]
	ld c, a
	ld b, $0
	ld hl, HighScoresStageMapping
	add hl, bc
	ld a, [hl]
	ld [wHighScoresStage], a
	ld a, SCREEN_HIGH_SCORES
	ld [wCurrentScreen], a
	xor a
	ld [wScreenState], a
	call SetNormalSpeedMode
	ret

HighScoresStageMapping: ; 0xdb99
; Determines which stage the high scores screen will start in,
; based on the map the player ended in.
; See wHighScoresStage for more info.
	db $00  ; STAGE_RED_FIELD_TOP
	db $00  ; STAGE_RED_FIELD_BOTTOM
	db $01  ; STAGE_BLUE_FIELD_TOP
	db $01  ; STAGE_BLUE_FIELD_BOTTOM
	db $02  ; STAGE_GOLD_FIELD_TOP
	db $02  ; STAGE_GOLD_FIELD_BOTTOM
	db $03  ; STAGE_SILVER_FIELD_TOP
	db $03  ; STAGE_SILVER_FIELD_BOTTOM
	db $04  ; STAGE_RUBY_FIELD_TOP
	db $04  ; STAGE_RUBY_FIELD_BOTTOM
	db $05  ; STAGE_SAPPHIRE_FIELD_TOP
	db $05  ; STAGE_SAPPHIRE_FIELD_BOTTOM
	db $00  ; STAGE_GENGAR_BONUS
	db $00  ; STAGE_GENGAR_BONUS
	db $00  ; STAGE_MEWTWO_BONUS
	db $00  ; STAGE_MEWTWO_BONUS
	db $00  ; STAGE_MEOWTH_BONUS
	db $00  ; STAGE_MEOWTH_BONUS
	db $00  ; STAGE_DIGLETT_BONUS
	db $00  ; STAGE_DIGLETT_BONUS
	db $00  ; STAGE_SEEL_BONUS
	db $00  ; STAGE_SEEL_BONUS

Func_dba9: ; 0xdba9
	ld a, $85
	ld [wBottomMessageBuffer + $44], a
	ld a, [wCurBallLife]
	xor $3
	inc a
	add $86
	ld [wBottomMessageBuffer + $45], a
	ret
