Overworld HUD implementation (#15)

This commit is contained in:
xCrystal
2023-08-29 18:33:20 +02:00
parent b275d642cd
commit f386a63cf8
21 changed files with 214 additions and 98 deletions

View File

@@ -55,3 +55,8 @@ DEF SPRITE_GFX_LIST_CAPACITY EQU 32 ; see wUsedSprites
const ANIM_MON_HOF const ANIM_MON_HOF
const ANIM_MON_EGG1 const ANIM_MON_EGG1
const ANIM_MON_EGG2 const ANIM_MON_EGG2
; LoadHUD indexes (see engine/gfx/hud.asm)
const_def 1
const HUD_OVERWORLD ; 1
DEF NUM_HUD_TYPES EQU const_value - 1

View File

@@ -132,15 +132,15 @@ DEF rLCDC_ENABLE EQU 7 ; 0=Off, 1=On
DEF LCDC_DEFAULT EQU (1 << rLCDC_ENABLE) | (1 << rLCDC_WINDOW_TILEMAP) | (1 << rLCDC_WINDOW_ENABLE) | (1 << rLCDC_SPRITES_ENABLE) | (1 << rLCDC_BG_PRIORITY) DEF LCDC_DEFAULT EQU (1 << rLCDC_ENABLE) | (1 << rLCDC_WINDOW_TILEMAP) | (1 << rLCDC_WINDOW_ENABLE) | (1 << rLCDC_SPRITES_ENABLE) | (1 << rLCDC_BG_PRIORITY)
DEF rSTAT EQU $ff41 ; LCDC Status (R/W) DEF rSTAT EQU $ff41 ; LCDC Status (R/W)
DEF rSTAT_STATUS_FLAGS EQU %00000011 ; LCD controller status (Read Only) DEF rSTAT_STATUS_FLAGS EQU %00000011 ; LCD controller status (Read Only)
DEF rSTAT_HBLANK_MASK EQU %00000000 ; In H-Blank (Read Only) DEF rSTAT_HBLANK_MASK EQU %00000000 ; In Mode 0: H-Blank (Read Only)
DEF rSTAT_VBLANK_MASK EQU %00000001 ; In V-Blank (Read Only) DEF rSTAT_VBLANK_MASK EQU %00000001 ; In Mode 1: V-Blank (Read Only)
DEF rSTAT_OAM_MASK EQU %00000010 ; OAM is used by system (Read Only) DEF rSTAT_OAM_MASK EQU %00000010 ; In Mode 2: OAM is used by system (Read Only)
DEF rSTAT_LCD_MASK EQU %00000011 ; Both OAM and VRAM used by system (Read Only) DEF rSTAT_LCD_MASK EQU %00000011 ; In Mode 3: Both OAM and VRAM used by system (Read Only)
DEF rSTAT_BUSY EQU 1 ; When set, VRAM access is unsafe (Read Only) DEF rSTAT_BUSY EQU 1 ; When set, VRAM access is unsafe (Read Only)
DEF rSTAT_LYC EQU 2 ; LYC=LY (0=Different, 1=Equal) (Read Only) DEF rSTAT_LYC EQU 2 ; LYC=LY (0=Different, 1=Equal) (Read Only)
DEF rSTAT_INT_HBLANK EQU 3 ; Mode 00: H-Blank (Selectable) DEF rSTAT_INT_HBLANK EQU 3 ; Mode 0: H-Blank (Selectable)
DEF rSTAT_INT_VBLANK EQU 4 ; Mode 01: V-Blank (Selectable) DEF rSTAT_INT_VBLANK EQU 4 ; Mode 1: V-Blank (Selectable)
DEF rSTAT_INT_OAM EQU 5 ; Mode 02: OAM (Selectable) DEF rSTAT_INT_OAM EQU 5 ; Mode 2: OAM (Selectable)
DEF rSTAT_INT_LYC EQU 6 ; LYC=LY Coincidence (Selectable) DEF rSTAT_INT_LYC EQU 6 ; LYC=LY Coincidence (Selectable)
DEF rSCY EQU $ff42 ; Scroll Y (R/W) DEF rSCY EQU $ff42 ; Scroll Y (R/W)
DEF rSCX EQU $ff43 ; Scroll X (R/W) DEF rSCX EQU $ff43 ; Scroll X (R/W)

View File

@@ -41,12 +41,12 @@ HDMATransferTilemapAndAttrmap_OverworldEffect::
call PadTilemapForHDMATransfer call PadTilemapForHDMATransfer
call DelayFrame call DelayFrame
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .go jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUD] >= 0) ; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd .wait_lcd
; ldh a, [hWindowHUD] ; ldh a, [hWindowHUDLY]
ld b, a ld b, a
ldh a, [rLY] ldh a, [rLY]
sub b sub b
@@ -86,12 +86,12 @@ _HDMATransferTilemapAndAttrmap_OpenAndCloseMenu::
call PadTilemapForHDMATransfer call PadTilemapForHDMATransfer
call DelayFrame call DelayFrame
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .go jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUD] >= 0) ; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd .wait_lcd
; ldh a, [hWindowHUD] ; ldh a, [hWindowHUDLY]
ld b, a ld b, a
ldh a, [rLY] ldh a, [rLY]
sub b sub b
@@ -276,12 +276,12 @@ _continue_HDMATransfer:
cp d cp d
jr nc, .ly_loop jr nc, .ly_loop
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .go jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUD] >= 0) ; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd .wait_lcd
; ldh a, [hWindowHUD] ; ldh a, [hWindowHUDLY]
ld b, a ld b, a
ldh a, [rLY] ldh a, [rLY]
sub b sub b

29
engine/gfx/hud.asm Executable file
View File

@@ -0,0 +1,29 @@
_LoadHUD::
jumptable .Jumptable, wWhichHUD
.Jumptable:
; entries correspond to HUD_* constants (see constants/gfx_constants.asm)
table_width 2, _LoadHUD.Jumptable
dw .None
dw _LoadOverworldHUDTilemapAndAttrmap
assert_table_length NUM_HUD_TYPES + 1
.None:
ret
_LoadOverworldHUDTilemapAndAttrmap:
call _LoadOverworldHUDAttrmap
; fallthrough
_LoadOverworldHUDTilemap:
; overworld HUD reads SCREEN_WIDTH tiles from wOverworldHUDTiles
ld hl, wOverworldHUDTiles
decoord 0, 0, wTilemap
ld bc, wOverworldHUDTilesEnd - wOverworldHUDTiles ; SCREEN_WIDTH
jp CopyBytes
_LoadOverworldHUDAttrmap:
hlcoord 0, 0, wAttrmap
ld bc, SCREEN_WIDTH
ld a, PAL_BG_TEXT | PRIORITY
jp ByteFill

View File

@@ -126,7 +126,9 @@ EnterMap:
ld [wPoisonStepCount], a ld [wPoisonStepCount], a
.dontresetpoison .dontresetpoison
call EnableOverworldWindowHUD call ConstructOverworldHUDTilemap
call TransferOverworldHUDToBGMap
call EnableOverworldHUD
xor a ; end map entry xor a ; end map entry
ldh [hMapEntryMethod], a ldh [hMapEntryMethod], a

View File

@@ -25,17 +25,20 @@ ReanchorBGMap_NoOAMUpdate::
xor a xor a
ldh [hLCDCPointer], a ldh [hLCDCPointer], a
ldh [hBGMapMode], a ldh [hBGMapMode], a
; prepare vBGMap1/vBGMap3 to be displayed while vBGMap0/vBGMap2 is reanchored.
; draw screen at wTilemap and wAttrmap and then transfer it.
ld a, $90 ld a, $90
ldh [hWY], a ldh [hWY], a
call LoadScreenTilemapAndAttrmapPals call LoadScreenTilemapAndAttrmapPals
call LoadWindowHUD
ld a, HIGH(vBGMap1) ld a, HIGH(vBGMap1)
call .LoadBGMapAddrIntoHRAM call .LoadBGMapAddrIntoHRAM
call HDMATransferTilemapAndAttrmap_OpenAndCloseMenu call HDMATransferTilemapAndAttrmap_OpenAndCloseMenu
farcall ApplyPals farcall ApplyPals
ld a, TRUE ld a, TRUE
ldh [hCGBPalUpdate], a ldh [hCGBPalUpdate], a
; display window while BG map is reanchored. ; display window using vBGMap1/vBGMap3 while vBGMap0/vBGMap2 is reanchored.
; disable LCD interrupt to prevent cropping the window due to hWindowHUD ; disable LCD interrupt to prevent cropping the window if window HUD is active
; (caller must re-enable when window is hidden again). ; (caller must re-enable when window is hidden again).
xor a xor a
ldh [rSTAT], a ldh [rSTAT], a

View File

@@ -33,4 +33,5 @@ _LoadScreenTilemap::
.carry .carry
dec b dec b
jr nz, .loop jr nz, .loop
ret ret

View File

@@ -1165,7 +1165,7 @@ Script_loadtrainer:
ret ret
Script_startbattle: Script_startbattle:
call DisableWindowHUD call DisableOverworldHUD
call BufferScreen call BufferScreen
predef StartBattle predef StartBattle
ld a, [wBattleResult] ld a, [wBattleResult]

View File

@@ -1,5 +1,4 @@
HandleNewMap: HandleNewMap:
call ClearUnusedMapBuffer
call ResetMapBufferEventFlags call ResetMapBufferEventFlags
call ResetFlashIfOutOfCave call ResetFlashIfOutOfCave
call GetCurrentMapSceneID call GetCurrentMapSceneID

View File

@@ -547,7 +547,7 @@ Phone_StartRinging:
call PlaySFX call PlaySFX
call Phone_CallerTextbox call Phone_CallerTextbox
call UpdateSprites call UpdateSprites
farcall PhoneRing_CopyTilemapAtOnce call PhoneRing_CopyTilemapAtOnce
ret ret
HangUp_Wait20Frames: HangUp_Wait20Frames:
@@ -556,7 +556,7 @@ HangUp_Wait20Frames:
Phone_Wait20Frames: Phone_Wait20Frames:
ld c, 20 ld c, 20
call DelayFrames call DelayFrames
farcall PhoneRing_CopyTilemapAtOnce call PhoneRing_CopyTilemapAtOnce
ret ret
PhoneRing_CopyTilemapAtOnce: PhoneRing_CopyTilemapAtOnce:

View File

@@ -29,6 +29,7 @@ INCLUDE "home/map.asm"
INCLUDE "home/farcall.asm" INCLUDE "home/farcall.asm"
INCLUDE "home/predef.asm" INCLUDE "home/predef.asm"
INCLUDE "home/window.asm" INCLUDE "home/window.asm"
INCLUDE "home/hud.asm"
INCLUDE "home/flag.asm" INCLUDE "home/flag.asm"
INCLUDE "home/sprite_updates.asm" INCLUDE "home/sprite_updates.asm"
INCLUDE "home/string.asm" INCLUDE "home/string.asm"

122
home/hud.asm Executable file
View File

@@ -0,0 +1,122 @@
OVERWORLD_HUD_HEIGHT EQU 8
EnableOverworldHUD::
ld a, HUD_OVERWORLD
ld [wWhichHUD], a
ld a, OVERWORLD_HUD_HEIGHT - 1
; fallthrough
EnableWindowHUD:
ldh [hWindowHUDLY], a
; configure LCD interrupt
ldh [rLYC], a
; make window hidden this frame to prevent graphical glitches
ld a, $90
ldh [hWY], a
; configure LCD interrupt
ld a, 1 << rSTAT_INT_LYC ; LYC=LC
ldh [rSTAT], a
ret
DisableOverworldHUD::
xor a
ld [wWhichHUD], a
; fallthrough
DisableWindowHUD::
xor a
ldh [hWindowHUDLY], a
; configure LCD interrupt
xor a
ldh [rLYC], a
ld a, 1 << rSTAT_INT_HBLANK ; hblank (default)
ldh [rSTAT], a
; leave window in default state (hidden with WY=$90)
; rLCDC[rLCDC_WINDOW_ENABLE] will be set during next vblank
ld a, $90
ldh [hWY], a
ret
LoadWindowHUD::
; like LoadHUD, but for HUDs that require a Window overlay
ldh a, [hWindowHUDLY]
and a
ret z
; fallthrough
LoadHUD::
; load the HUD at wWhichHUD to the top of wTilemap and wAttrmap
ld a, [wWhichHUD]
and a
ret z
farcall _LoadHUD
ret
ConstructOverworldHUDTilemap::
; draw the overworld HUD's tilemap into wOverworldHUDTiles
ld hl, .Tilemap
ld de, wOverworldHUDTiles
ld bc, .TilemapEnd - .Tilemap ; SCREEN_WIDTH
call CopyBytes
ret
.Tilemap:
db "▶- ▶- ▶ ▶ "
.TilemapEnd:
assert .TilemapEnd - .Tilemap == wOverworldHUDTilesEnd - wOverworldHUDTiles
TransferOverworldHUDToBGMap::
; transfer overworld HUD to vBGMap1/vBGMap3 during v/hblank(s)
; tilemap is read from wOverworldHUDTiles, attrmap is all PAL_BG_TEXT | PRIORITY
ldh a, [rVBK]
push af
; Tilemap
ld a, BANK(vBGMap1)
ldh [rVBK], a
ld de, vBGMap1
ld hl, wOverworldHUDTiles
ld b, 1 << rSTAT_BUSY ; not in v/hblank
ld c, LOW(rSTAT)
rept SCREEN_WIDTH / 2
; if not in v/hblank, wait until in v/hblank
.loop\@
ldh a, [c]
and b
jr nz, .loop\@
; copy
; we have at least a margin of 16 cycles of Mode2 left
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
endr
; Attrmap
ld a, BANK(vBGMap3)
ldh [rVBK], a
ld hl, vBGMap3
rept SCREEN_WIDTH / 5
; if not in v/hblank, wait until in v/hblank
.loop\@
ldh a, [c]
and b
jr nz, .loop\@
; fill
; we have at least a margin of 16 cycles of Mode2 left
ld a, PAL_BG_TEXT | PRIORITY
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hli], a
endr
pop af
ld [rVBK], a
ret

View File

@@ -4,7 +4,7 @@ LCD::
push af push af
; hLCDCPointer is used in battle transition, battle anims, and movies (crystal intro, credits, etc.) ; hLCDCPointer is used in battle transition, battle anims, and movies (crystal intro, credits, etc.)
; uses rSTAT_INT_HBLANK and doesn't overlap with hWindowHUD. ; uses rSTAT_INT_HBLANK and doesn't overlap with hWindowHUDLY.
ldh a, [hLCDCPointer] ldh a, [hLCDCPointer]
and a and a
jr z, .next jr z, .next
@@ -23,8 +23,8 @@ LCD::
pop bc pop bc
.next .next
; hWindowHUD uses rSTAT_INT_LYC ; hWindowHUDLY uses rSTAT_INT_LYC
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .done jr z, .done

View File

@@ -1,12 +1,5 @@
; Functions dealing with rendering and interacting with maps. ; Functions dealing with rendering and interacting with maps.
ClearUnusedMapBuffer::
ld hl, wUnusedMapBuffer
ld bc, wUnusedMapBufferEnd - wUnusedMapBuffer
ld a, 0
call ByteFill
ret
CheckScenes:: CheckScenes::
; Checks wCurMapSceneScriptPointer. If it's empty, returns -1 in a. Otherwise, returns the active scene ID in a. ; Checks wCurMapSceneScriptPointer. If it's empty, returns -1 in a. Otherwise, returns the active scene ID in a.
push hl push hl
@@ -146,7 +139,6 @@ LoadMetatiles::
ld e, l ld e, l
ld d, h ld d, h
; Set hl to the address of the current metatile data ([wTilesetBlocksAddress] + (a) tiles). ; Set hl to the address of the current metatile data ([wTilesetBlocksAddress] + (a) tiles).
; BUG: LoadMetatiles wraps around past 128 blocks (see docs/bugs_and_glitches.md)
ld l, a ld l, a
ld h, 0 ld h, 0
add hl, hl add hl, hl

View File

@@ -49,20 +49,15 @@ CopyTilemapAtOnce::
xor a xor a
ldh [hMapAnims], a ldh [hMapAnims], a
; .wait
; ldh a, [rLY]
; cp $80 - 1
; jr c, .wait
call DelayFrame call DelayFrame
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .go jr z, .go
; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUD] >= 0) ; wait until LCD interrupt has ocurred this frame ([rLY] - [hWindowHUDLY] >= 0)
.wait_lcd .wait_lcd
; ldh a, [hWindowHUD] ; ldh a, [hWindowHUDLY]
ld b, a ld b, a
ldh a, [rLY] ldh a, [rLY]
sub b sub b
@@ -78,11 +73,6 @@ CopyTilemapAtOnce::
ldh [rVBK], a ldh [rVBK], a
hlcoord 0, 0 hlcoord 0, 0
call .CopyBGMapViaStack call .CopyBGMapViaStack
; .wait2
; ldh a, [rLY]
; cp $80 - 1
; jr c, .wait2
ei ei
pop af pop af

View File

@@ -65,12 +65,12 @@ VBlank0::
ldh a, [hROMBank] ldh a, [hROMBank]
ldh [hROMBankBackup], a ldh [hROMBankBackup], a
; enable window back in case LCD interrupt disabled it mid-frame due to hWindowHUD ; enable window back in case LCD interrupt disabled it mid-frame due to hWindowHUDLY
ldh a, [rLCDC] ldh a, [rLCDC]
set rLCDC_WINDOW_ENABLE, a set rLCDC_WINDOW_ENABLE, a
ldh [rLCDC], a ldh [rLCDC], a
ld a, [hWindowHUD] ld a, [hWindowHUDLY]
and a and a
jr z, .next jr z, .next
@@ -117,8 +117,8 @@ VBlank0::
xor a xor a
ld [wVBlankOccurred], a ld [wVBlankOccurred], a
; if hWindowHUD is active, enable interrupts so the LCD interrupt can trigger ; if hWindowHUDLY is active, enable interrupts so the LCD interrupt can trigger
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
jr z, .next2 jr z, .next2
@@ -163,17 +163,17 @@ VBlank0::
ldh a, [hROMBankBackup] ldh a, [hROMBankBackup]
rst Bankswitch rst Bankswitch
; if hWindowHUD is not active, we're done ; if hWindowHUDLY is not active, we're done
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
ret z ret z
; interrupts must be enabled in the cycle that rLY becomes [hWindowHUD] to prevent flickering ; interrupts must be enabled in the cycle that rLY becomes [hWindowHUDLY] to prevent flickering
; wait until [hWindowHUD] - [rLY] is NOT between 0 and 2 before disabling interrupts ; wait until [hWindowHUDLY] - [rLY] is NOT between 0 and 2 before disabling interrupts
.wait_loop .wait_loop
ldh a, [rLY] ldh a, [rLY]
ld b, a ld b, a
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
sub b sub b
cp 2 + 1 cp 2 + 1
jr c, .wait_loop jr c, .wait_loop

View File

@@ -110,7 +110,7 @@ SafeUpdateSprites::
HideWindow_EnableLCDInt:: HideWindow_EnableLCDInt::
ld a, $90 ld a, $90
ldh [hWY], a ldh [hWY], a
ldh a, [hWindowHUD] ldh a, [hWindowHUDLY]
and a and a
ld a, 1 << rSTAT_INT_HBLANK ld a, 1 << rSTAT_INT_HBLANK
jr z, .ok jr z, .ok
@@ -118,35 +118,3 @@ HideWindow_EnableLCDInt::
.ok .ok
ldh [rSTAT], a ldh [rSTAT], a
ret ret
OVERWORLD_HUD_HEIGHT EQU 8
EnableOverworldWindowHUD::
ld a, OVERWORLD_HUD_HEIGHT - 1
; fallthrough
EnableWindowHUD:
ldh [hWindowHUD], a
; configure LCD interrupt
ldh [rLYC], a
; make window hidden this frame to prevent graphical glitches
ld a, $90
ldh [hWY], a
; configure LCD interrupt
ld a, 1 << rSTAT_INT_LYC ; LYC=LC
ldh [rSTAT], a
ret
DisableWindowHUD::
xor a
ldh [hWindowHUD], a
; configure LCD interrupt
xor a
ldh [rLYC], a
ld a, 1 << rSTAT_INT_HBLANK ; hblank (default)
ldh [rSTAT], a
; leave window in default state (hidden with WY=$90)
; rLCDC[rLCDC_WINDOW_ENABLE] will be set during next vblank
ld a, $90
ldh [hWY], a
ret

View File

@@ -249,7 +249,7 @@ WRAM0
"Sprites" "Sprites"
"Tilemap" "Tilemap"
"Miscellaneous" "Miscellaneous"
"Unused Map Buffer" "Overworld HUD"
align 8 align 8
"Overworld Map" "Overworld Map"
align 4 align 4

View File

@@ -189,6 +189,7 @@ INCLUDE "engine/menus/empty_sram.asm"
INCLUDE "engine/events/checksave.asm" INCLUDE "engine/events/checksave.asm"
INCLUDE "data/maps/scenes.asm" INCLUDE "data/maps/scenes.asm"
INCLUDE "engine/overworld/load_screen_tilemap.asm" INCLUDE "engine/overworld/load_screen_tilemap.asm"
INCLUDE "engine/gfx/hud.asm"
SECTION "bank13_2", ROMX SECTION "bank13_2", ROMX

View File

@@ -148,7 +148,7 @@ if DEF(_DEBUG)
hDebugRoomMenuPage:: db hDebugRoomMenuPage:: db
endc endc
hWindowHUD:: hWindowHUDLY::
; Window HUD is enabled when non-0. ; Window HUD is enabled when non-0.
; Its value indicates the last scanline that the window spans from the top. ; Its value indicates the last scanline that the window spans from the top.
db db

Some files were not shown because too many files have changed in this diff Show More