Start on actual gameplay

This commit is contained in:
Randy Thiemann 2023-10-16 07:47:11 +02:00
parent 7bc9588c02
commit c33caf39e4
22 changed files with 372 additions and 176 deletions

View File

@ -2,7 +2,48 @@ IF !DEF(CONSTANTS_ASM)
DEF CONSTANTS_ASM EQU 1
CHARMAP " ", 1
CHARMAP "A", 74
CHARMAP "B", 75
CHARMAP "C", 76
CHARMAP "D", 77
CHARMAP "E", 78
CHARMAP "F", 79
CHARMAP "G", 80
CHARMAP "H", 81
CHARMAP "I", 82
CHARMAP "J", 83
CHARMAP "K", 84
CHARMAP "L", 85
CHARMAP "M", 86
CHARMAP "N", 87
CHARMAP "O", 88
CHARMAP "P", 89
CHARMAP "Q", 90
CHARMAP "R", 91
CHARMAP "S", 92
CHARMAP "T", 93
CHARMAP "U", 94
CHARMAP "V", 95
CHARMAP "W", 96
CHARMAP "X", 97
CHARMAP "Y", 98
CHARMAP "Z", 99
CHARMAP "0", 100
CHARMAP "1", 101
CHARMAP "2", 102
CHARMAP "3", 103
CHARMAP "4", 104
CHARMAP "5", 105
CHARMAP "6", 106
CHARMAP "7", 107
CHARMAP "8", 108
CHARMAP "9", 109
SECTION "Static Data", ROM0
sLeady:: db " READY "
sGo:: db " GO "
sPieceXOffsets:: ; How to draw each piece. X-offsets of the sprites.
db 0, 8, 16, 24 ; I
db 0, 8, 8, 16 ; Z
@ -299,40 +340,4 @@ sPieceRotationStates:: ; How each piece is rotated.
db %0000
DEF PALETTE_REGULAR EQU %11100100
DEF PALETTE_INVERTED EQU %00011011
DEF PALETTE_MONO_0 EQU %11111111
DEF PALETTE_MONO_1 EQU %10101010
DEF PALETTE_MONO_2 EQU %01010101
DEF PALETTE_MONO_3 EQU %00000000
DEF PALETTE_DARKER_0 EQU %11100100
DEF PALETTE_DARKER_1 EQU %11111001
DEF PALETTE_DARKER_2 EQU %11111110
DEF PALETTE_DARKER_3 EQU %11111111
DEF PALETTE_LIGHTER_0 EQU %11100100
DEF PALETTE_LIGHTER_1 EQU %10010000
DEF PALETTE_LIGHTER_2 EQU %01000000
DEF PALETTE_LIGHTER_3 EQU %00000000
DEF FIELD_TOP_LEFT EQU $9800+(1*32)+1
DEF TILE_FIELD_EMPTY EQU 7
DEF TILE_PIECE_0 EQU 10
DEF TILE_0 EQU 100
DEF NEXT_BASE_X EQU 120
DEF NEXT_BASE_Y EQU 40
DEF HOLD_BASE_X EQU 120
DEF HOLD_BASE_Y EQU 80
DEF DIGIT_BASE_X EQU 112
DEF SCORE_BASE_Y EQU 115
DEF CLEVEL_BASE_Y EQU 136
DEF NLEVEL_BASE_Y EQU 148
DEF SCURVE_N_ENTRIES EQU 32
DEF SCURVE_ENTRY_SIZE EQU 8
DEF PIECE_I EQU 0
DEF PIECE_Z EQU 1
DEF PIECE_S EQU 2
DEF PIECE_J EQU 3
DEF PIECE_L EQU 4
DEF PIECE_O EQU 5
DEF PIECE_T EQU 6
ENDC

View File

@ -2,12 +2,23 @@ IF !DEF(FIELD_ASM)
DEF FIELD_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Field Variables", WRAM0
wField:: ds (10*21)
SECTION "Field Functions", ROM0
FieldInit::
ld hl, wField
ld bc, 10*21
ld d, 1
call UnsafeMemSet
ret
FieldClear::
ld hl, wField
ld bc, 10*21
ld d, TILE_FIELD_EMPTY
@ -17,7 +28,7 @@ FieldInit::
BlitField::
; The first 14 rows can be blitted without checking for vram access.
ld de, wField + (1*10)
ld de, wField + 10
DEF row = 0
REPT 14
ld hl, FIELD_TOP_LEFT+(32*row)
@ -49,6 +60,8 @@ BlitField::
ENDR
DEF row += 1
ENDR
; This has to finish just before the first LCDC interrupt of the frame or stuff will break in weird ways.
ret

View File

@ -1,4 +1,11 @@
IF !DEF(HEADER_ASM)
DEF HEADER_ASM EQU 1
SECTION "Cartridge Header", ROM0[$100]
nop
jp Main
ds $150 - @, 0
ENDC

View File

@ -2,13 +2,8 @@ IF !DEF(GLOBALS_ASM)
DEF GLOBALS_ASM EQU 1
INCLUDE "vendor/hardware.inc"
INCLUDE "vendor/structs.asm"
INCLUDE "constants.asm"
SECTION "Important Game Variables", HRAM
hCtr:: ds 1
INCLUDE "hardware.inc"
INCLUDE "structs.asm"
; Waits for VRAM to be safe to access. (Includes hblank.)
@ -72,4 +67,43 @@ MACRO lb
ENDM
DEF PALETTE_REGULAR EQU %11100100
DEF PALETTE_INVERTED EQU %00011011
DEF PALETTE_MONO_0 EQU %11111111
DEF PALETTE_MONO_1 EQU %10101010
DEF PALETTE_MONO_2 EQU %01010101
DEF PALETTE_MONO_3 EQU %00000000
DEF PALETTE_DARKER_0 EQU %11100100
DEF PALETTE_DARKER_1 EQU %11111001
DEF PALETTE_DARKER_2 EQU %11111110
DEF PALETTE_DARKER_3 EQU %11111111
DEF PALETTE_LIGHTER_0 EQU %11100100
DEF PALETTE_LIGHTER_1 EQU %10010000
DEF PALETTE_LIGHTER_2 EQU %01000000
DEF PALETTE_LIGHTER_3 EQU %00000000
DEF FIELD_TOP_LEFT EQU $9800+1
DEF TILE_FIELD_EMPTY EQU 7
DEF TILE_PIECE_0 EQU 10
DEF TILE_0 EQU 100
DEF NEXT_BASE_X EQU 120
DEF NEXT_BASE_Y EQU 40
DEF HOLD_BASE_X EQU 120
DEF HOLD_BASE_Y EQU 80
DEF SCORE_BASE_X EQU 112
DEF SCORE_BASE_Y EQU 115
DEF LEVEL_BASE_X EQU 120
DEF CLEVEL_BASE_Y EQU 136
DEF NLEVEL_BASE_Y EQU 148
DEF SCURVE_N_ENTRIES EQU 32
DEF SCURVE_ENTRY_SIZE EQU 8
DEF PIECE_I EQU 0
DEF PIECE_Z EQU 1
DEF PIECE_S EQU 2
DEF PIECE_J EQU 3
DEF PIECE_L EQU 4
DEF PIECE_O EQU 5
DEF PIECE_T EQU 6
DEF PIECE_NONE EQU 255
ENDC

View File

@ -2,6 +2,9 @@ IF !DEF(INPUT_ASM)
DEF INPUT_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Input Variables", HRAM
hUpState:: ds 1
hDownState:: ds 1

View File

@ -2,6 +2,9 @@ IF !DEF(INTERRUPTS_ASM)
DEF INTERRUPTS_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Interrupt Variables", HRAM
hLCDCCtr:: ds 1

View File

@ -2,9 +2,12 @@ IF !DEF(LEVEL_ASM)
DEF LEVEL_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Level Variables", WRAM0
wCLevel:: ds 6
wNLevel:: ds 6
wCLevel:: ds 4
wNLevel:: ds 6 ; The extra 2 bytes will be clobbered by the sprite drawing functions.
SECTION "Level Functions", ROM0
@ -14,15 +17,11 @@ LevelInit::
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl], a
ld hl, wNLevel
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl+], a
ld [hl], a
ret

View File

@ -1,16 +1,17 @@
IF !DEF(MAIN_ASM)
DEF MAIN_ASM EQU 1
INCLUDE "globals.asm"
INCLUDE "memory.asm"
INCLUDE "interrupts.asm"
INCLUDE "sprites.asm"
INCLUDE "rng.asm"
INCLUDE "input.asm"
INCLUDE "time.asm"
INCLUDE "score.asm"
INCLUDE "level.asm"
INCLUDE "field.asm"
INCLUDE "res/tiles.inc"
INCLUDE "res/gameplay_map.inc"
SECTION "Globals", WRAM0
wStateEventHandler:: ds 2
wStateVBlankHandler:: ds 2
SECTION "Code Entry Point", ROM0
Main::
; Turn off LCD during initialization.
@ -39,16 +40,9 @@ Main::
or LCDCF_BLK01
ldh [rLCDC], a
; The tilemap is just for testing for now.
ld de, GameplayTilemap
ld hl, $9800
ld bc, GameplayTilemapEnd - GameplayTilemap
call UnsafeMemCopy
; Clear OAM.
call ClearOAM
call CopyOAMHandler
call SetNumberSpritePositions
; Set up the palettes.
ld a, PALETTE_REGULAR
@ -68,57 +62,37 @@ Main::
; Set up the interrupt handlers.
call InitializeLCDCInterrupt
; And turn the LCD back on before we start.
ldh a, [rLCDC]
or LCDCF_ON | LCDCF_BGON | LCDCF_OBJON
ldh [rLCDC], a
; Make sure the first game loop starts just like all the future ones.
wait_vblank
wait_vblank_end
; TEMP: Set up the game.
call StartNewGame
; Switch to gameplay state.
call SwitchToGameplay
GameLoop::
EventLoop::
; Wrangle inputs and timers at the start of every frame.
call GetInput
call HandleTimers
; Handle gameplay here
; TODO
; Call the current state's event handler.
ld a, [wStateEventHandler]
ld l, a
ld a, [wStateEventHandler + 1]
ld h, a
jp hl
EventLoopPostHandler::
ldh a, [hCtr]
inc a
and a, $1F
ldh [hCtr], a
jr nz, :+
call GetNextPiece
: ld a, [wNextPiece]
call ApplyNext
ld a, [wNextPiece]
call ApplyHold
ld hl, wSPRScore1
ld de, wScore
call ApplyNumbers
ld hl, wSPRCLevel1
ld de, wCLevel
call ApplyNumbers
ld hl, wSPRNLevel1
ld de, wNLevel
call ApplyNumbers
GameLoopEnd:
; Wait for vblank and update OAM.
wait_vblank
call hOAMDMA
call BlitField
jr GameLoop
; Call the current state's vblank handler.
ld a, [wStateVBlankHandler]
ld l, a
ld a, [wStateVBlankHandler + 1]
ld h, a
jp hl
EventLoopPostVBlankHandler::
; Jump back to the start of the event loop.
jr EventLoop
@ -136,3 +110,6 @@ InitializeVariables:
call LevelInit
call FieldInit
ret
ENDC

View File

@ -2,6 +2,9 @@ IF !DEF(MEMORY_ASM)
DEF MEMORY_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Memory Functions", ROM0
; Copies data from de to hl, bc bytes
UnsafeMemCopy::

View File

@ -1,6 +1,13 @@
IF !DEF(BUILD_DATE_ASM)
DEF BUILD_DATE_ASM EQU 1
SECTION "Build date", ROM0
db "Built "
BuildDate::
db __ISO_8601_UTC__
db 0
ENDC

View File

@ -1,3 +1,7 @@
IF !DEF(GAMEPLAY_MAP_INC)
DEF GAMEPLAY_MAP_INC EQU 1
SECTION "Gameplay Tilemap", ROM0
GameplayTilemap::
DB $02,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$03,$44,$42,$42,$42,$42,$42,$42,$43, 0,0,0,0,0,0,0,0,0,0,0,0
@ -22,3 +26,6 @@ GameplayTilemap::
DB $02,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$03,$49,$01,$01,$01,$01,$01,$01,$49, 0,0,0,0,0,0,0,0,0,0,0,0
DB $05,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$06,$46,$42,$42,$42,$42,$42,$42,$45, 0,0,0,0,0,0,0,0,0,0,0,0
GameplayTilemapEnd::
ENDC

View File

@ -1,3 +1,6 @@
IF !DEF(TILES_INC)
DEF TILES_INC EQU 1
SECTION "Tile data", ROM0
Tiles::
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
@ -257,3 +260,6 @@ Tiles::
DB $00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00
TilesEnd::
ENDC

View File

@ -2,6 +2,9 @@ IF !DEF(SCORE_ASM)
DEF SCORE_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Score Variables", WRAM0
wScore:: ds 6

View File

@ -2,6 +2,9 @@ IF !DEF(SPRITES_ASM)
DEF SPRITES_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Shadow OAM", WRAM0, ALIGN[8]
UNION
wShadowOAM:: ds 160
@ -24,15 +27,11 @@ wSPRCLevel1:: ds 4
wSPRCLevel2:: ds 4
wSPRCLevel3:: ds 4
wSPRCLevel4:: ds 4
wSPRCLevel5:: ds 4
wSPRCLevel6:: ds 4
wSPRNLevel1:: ds 4
wSPRNLevel2:: ds 4
wSPRNLevel3:: ds 4
wSPRNLevel4:: ds 4
wSPRNLevel5:: ds 4
wSPRNLevel6:: ds 4
wSPRUnused:: ds (14 * 4)
wSPRUnused:: ds (16 * 4)
ENDU
@ -244,7 +243,7 @@ ApplyNumbers::
SetNumberSpritePositions::
ld a, DIGIT_BASE_X
ld a, SCORE_BASE_X
ld hl, wSPRScore1
ld [hl], SCORE_BASE_Y
inc hl
@ -314,7 +313,7 @@ SetNumberSpritePositions::
ld a, OAMF_PAL1
ld [hl], a
ld a, DIGIT_BASE_X
ld a, LEVEL_BASE_X
ld hl, wSPRCLevel1
ld [hl], CLEVEL_BASE_Y
inc hl
@ -357,34 +356,10 @@ SetNumberSpritePositions::
ld [hl], a
inc hl
inc hl
ld b, a
ld a, OAMF_PAL1
ld [hl], a
ld a, b
add a, 8
ld hl, wSPRCLevel5
ld [hl], CLEVEL_BASE_Y
inc hl
ld [hl], a
inc hl
inc hl
ld b, a
ld a, OAMF_PAL1
ld [hl], a
ld a, b
add a, 8
ld hl, wSPRCLevel6
ld [hl], CLEVEL_BASE_Y
inc hl
ld [hl], a
inc hl
inc hl
ld a, OAMF_PAL1
ld [hl], a
ld a, DIGIT_BASE_X
ld a, LEVEL_BASE_X
ld hl, wSPRNLevel1
ld [hl], NLEVEL_BASE_Y
inc hl
@ -427,30 +402,6 @@ SetNumberSpritePositions::
ld [hl], a
inc hl
inc hl
ld b, a
ld a, OAMF_PAL1
ld [hl], a
ld a, b
add a, 8
ld hl, wSPRNLevel5
ld [hl], NLEVEL_BASE_Y
inc hl
ld [hl], a
inc hl
inc hl
ld b, a
ld a, OAMF_PAL1
ld [hl], a
ld a, b
add a, 8
ld hl, wSPRNLevel6
ld [hl], NLEVEL_BASE_Y
inc hl
ld [hl], a
inc hl
inc hl
ld a, OAMF_PAL1
ld [hl], a
ret

175
src/state_gameplay.asm Normal file
View File

@ -0,0 +1,175 @@
IF !DEF(STATE_GAMEPLAY_ASM)
DEF STATE_GAMEPLAY_ASM EQU 1
INCLUDE "globals.asm"
DEF MODE_LEADY EQU 0
DEF MODE_GO EQU 1
DEF MODE_POSTGO EQU 2
DEF MODE_FETCH_PIECE EQU 3
DEF MODE_SPAWN_PIECE EQU 4
SECTION "Gameplay Variables", WRAM0
wMode: ds 1
wModeCounter: ds 1
wCurrentPiece: ds 1
wHeldPiece: ds 1
SECTION "Gameplay Functions", ROM0
SwitchToGameplay::
; Turn the screen off if it's on.
ldh a, [rLCDC]
and LCDCF_ON
jr z, :+ ; Screen is already off.
wait_vram
xor a, a
ldh [rLCDC], a
; Load the gameplay tilemap.
: ld de, GameplayTilemap
ld hl, $9800
ld bc, GameplayTilemapEnd - GameplayTilemap
call UnsafeMemCopy
; Clear OAM.
call ClearOAM
call SetNumberSpritePositions
; Initialize the RNG.
call StartNewGame
; Initialize the score and level.
call ScoreInit
call LevelInit
call FieldInit
; We don't start with a held piece.
ld a, PIECE_NONE
ld [wHeldPiece], a
; Leady mode.
ld a, MODE_LEADY
ld [wMode], a
ld a, 150
ld [wModeCounter], a
; Install the event loop handlers.
ld hl, GamePlayEventLoopHandler
ld a, l
ld [wStateEventHandler], a
ld a, h
ld [wStateEventHandler + 1], a
ld hl, GamePlayEventLoopVBlankHandler
ld a, l
ld [wStateVBlankHandler], a
ld a, h
ld [wStateVBlankHandler + 1], a
; And turn the LCD back on before we start.
ldh a, [rLCDC]
or LCDCF_ON | LCDCF_BGON | LCDCF_OBJON
ldh [rLCDC], a
; Make sure the first game loop starts just like all the future ones.
wait_vblank
wait_vblank_end
ret
GamePlayEventLoopHandler::
; What mode are we in?
ld a, [wMode]
cp MODE_LEADY
jr z, leadyMode
cp MODE_GO
jr z, goMode
cp MODE_POSTGO
jr z, postGoMode
cp MODE_FETCH_PIECE
jr z, fetchPieceMode
cp MODE_SPAWN_PIECE
jr z, spawnPieceMode
; Draw "READY" and wait a bit.
leadyMode:
ld a, [wModeCounter]
dec a
jr nz, :+
ld a, MODE_GO
ld [wMode], a
ld a, 150
: ld [wModeCounter], a
ld de, sLeady
ld hl, wField+(10*10)
ld bc, 10
call UnsafeMemCopy
jp drawStaticInfo
; Draw "GO" and wait a bit.
goMode:
ld a, [wModeCounter]
dec a
jr nz, :+
ld a, MODE_POSTGO
ld [wMode], a
xor a, a
: ld [wModeCounter], a
ld de, sGo
ld hl, wField+(10*10)
ld bc, 10
call UnsafeMemCopy
jp drawStaticInfo
; Clear the field, ready for gameplay.
postGoMode:
ld a, MODE_FETCH_PIECE
ld [wMode], a
call FieldClear
jp drawStaticInfo
; Fetch the next piece.
fetchPieceMode:
ld a, [wNextPiece]
ld [wCurrentPiece], a
call GetNextPiece
ld a, MODE_SPAWN_PIECE
ld [wMode], a
jp drawStaticInfo
; Spawn the piece.
spawnPieceMode:
; todo
; Always draw the score, level, next piece, and held piece.
drawStaticInfo:
: ld a, [wNextPiece]
call ApplyNext
ld a, [wHeldPiece]
call ApplyHold
ld hl, wSPRScore1
ld de, wScore
call ApplyNumbers
ld hl, wSPRCLevel1
ld de, wCLevel
call ApplyNumbers
ld hl, wSPRNLevel1
ld de, wNLevel
call ApplyNumbers
jp EventLoopPostHandler
GamePlayEventLoopVBlankHandler::
call BlitField
jp EventLoopPostVBlankHandler
ENDC

View File

@ -2,6 +2,9 @@ IF !DEF(TIME_ASM)
DEF TIME_ASM EQU 1
INCLUDE "globals.asm"
SECTION "Time Variables", HRAM
hEvenFrame:: ds 1

View File

@ -1,5 +1,5 @@
#Emulicious settings file
#Mon Oct 16 05:45:08 CEST 2023
#Mon Oct 16 07:46:46 CEST 2023
WindowEventViewerWindowHeight=861
WindowEventViewerWindowDivider=309
WindowMemoryTracerWindowY=631
@ -99,7 +99,7 @@ Gamepad1Key30=-1
BankSwapAtPCBreakpointEnabled=false
DebuggerMemorySelectedTab=HRAM
WindowVideoViewerOpen=false
WindowMemoryEditorTabVisibleRect=0,0,583,128
WindowMemoryEditorTabVisibleRect=0,160,583,384
Gamepad1Key29=-1
Gamepad1Key28=-1
Gamepad1Key27=-1
@ -125,9 +125,9 @@ Key1=75
Key0=74
Gamepad1Key19=-1
Gamepad1Key18=-1
WindowEventViewerWindowY=673
WindowEventViewerWindowY=293
Gamepad1Key17=-1
WindowEventViewerWindowX=1846
WindowEventViewerWindowX=1480
Gamepad1Key16=-1
Gamepad1Key15=-1
Gamepad1Key14=-1
@ -135,7 +135,7 @@ Gamepad1Key13=-1
Gamepad1Key12=-1
Gamepad1Key11=-1
Gamepad1Key10=-1
WindowMemoryEditorSelectedAddress=116
WindowMemoryEditorSelectedAddress=160
WindowMemoryEditorWidth=665
GameBoyErrorBreakpointCondition9=
GameBoyErrorBreakpointCondition8=
@ -154,7 +154,7 @@ Gamepad0Key35=-1
Gamepad0Key34=-1
Gamepad0Key33=-1
Gamepad0Key32=-1
WindowMemoryEditorSelectedTab=HRAM
WindowMemoryEditorSelectedTab=RAM
Gamepad0Key31=-1
Gamepad0Key30=-1
SMSGamepadAThreshold=50
@ -177,8 +177,8 @@ Gamepad0Key20=-1
DebuggerSouthPanelSelectedTab=0
WindowEmuliciousWidth=816
WindowVideoViewerWidth=980
WindowMemoryEditorY=612
WindowMemoryEditorX=1589
WindowMemoryEditorY=827
WindowMemoryEditorX=2697
Gamepad0Key19=-1
Gamepad0Key18=-1
Gamepad0Key17=-1
@ -198,8 +198,8 @@ GameBoyErrorBreakpointMessage32=
InterruptBreakpointCondition=
Recent0=C\:\\workspace\\dmgtris\\bin\\out.gb
GameBoyErrorBreakpointMessage20=
WindowEmuliciousY=489
WindowEmuliciousX=666
WindowEmuliciousY=192
WindowEmuliciousX=661
GameBoyErrorBreakpointEnabled9=false
GameBoyErrorBreakpointEnabled8=false
GameBoyErrorBreakpointEnabled7=false
@ -242,7 +242,7 @@ Gamepad1Key0=-1
RomDir=C\:\\workspace\\dmgtris\\bin
GameBoyErrorBreakpointCondition20=
WindowVideoViewerHeight=1027
WindowEventViewerWindowOpen=true
WindowEventViewerWindowOpen=false
WindowSpriteViewerY=512
WindowSpriteViewerX=320
CodeFontSize=13