Pieces are spawning, basic movement is working.

This commit is contained in:
Randy Thiemann 2023-10-20 08:17:40 +02:00
parent 07dd076301
commit 0f2e811130
4 changed files with 610 additions and 61 deletions

View File

@ -10,6 +10,16 @@ wField:: ds (10*24)
wShadowField:: ds (14*26)
SECTION "Field High Variables", HRAM
hToppedOut:: ds 1
hPieceDataBase:: ds 2
hPieceDataOffset:: ds 1
hCurrentLockDelayRemaining:: ds 1
hTicksUntilG:: ds 1
hWantX:: ds 1
hWantRotation:: ds 1
SECTION "Field Functions", ROM0
FieldInit::
ld hl, wField
@ -30,7 +40,8 @@ FieldClear::
call UnsafeMemSet
ret
ToShadowField::
ToShadowField:
ld hl, wField
ld de, wShadowField+2
ld c, 24
@ -51,7 +62,7 @@ ToShadowField::
ret
FromShadowField::
FromShadowField:
ld hl, wField
ld de, wShadowField+2
ld c, 24
@ -121,4 +132,554 @@ BlitField::
jp EventLoop
SetPieceData:
ldh a, [hCurrentPiece]
ld hl, sPieceRotationStates
ld de, 16
: cp a, 0
jr z, :+
add hl, de
dec a
jr :-
: ld a, l
ldh [hPieceDataBase], a
ld a, h
ldh [hPieceDataBase+1], a
ret
SetPieceDataOffset:
ldh a, [hCurrentPieceRotationState]
rlc a
rlc a
ldh [hPieceDataOffset], a
ret
; Converts piece Y in B and a piece X in A to a pointer to the shadow field in HL.
XYToSFieldPtr:
ld hl, wShadowField
ld de, 14
inc a
inc b
: dec b
jr z, :+
add hl, de
jr :-
: dec a
ret z
inc hl
jr :-
ret
; Converts piece Y in B and a piece X in A to a pointer to the field in HL.
XYToFieldPtr:
ld hl, wField-2
ld de, 10
inc a
inc b
: dec b
jr z, :+
add hl, de
jr :-
: dec a
ret z
inc hl
jr :-
ret
GetPieceData:
ldh a, [hPieceDataBase]
ld l, a
ldh a, [hPieceDataBase+1]
ld h, a
ldh a, [hPieceDataOffset]
ld c, a
xor a, a
ld b, a
add hl, bc
ret
; Checks if the piece can fit at the current position.
; HL should point to the piece's rotation state data.
; DE should be pointing to the right place in the SHADOW field.
CanPieceFit:
xor a, a
ld b, a
; Row 1
bit 3, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 2, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 1, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 0, [hl]
jr z, .r1end
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
.r1end
REPT 11
inc de
ENDR
; Row 2
inc hl
bit 3, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 2, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 1, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 0, [hl]
jr z, .r2end
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
.r2end
REPT 11
inc de
ENDR
; Row 3
inc hl
bit 3, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 2, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 1, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 0, [hl]
jr z, .r3end
ld a, [de]
cp a, TILE_FIELD_EMPTY
ret nz
.r3end
REPT 11
inc de
ENDR
; Row 4
inc hl
bit 3, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 2, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 1, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
: inc de
inc b
bit 0, [hl]
jr z, :+
ld a, [de]
cp a, TILE_FIELD_EMPTY
ld a, b
ret nz
; If we got here, the piece can fit.
: ld a, $FF
ret
TrySpawnPiece::
ldh a, [hCurrentFramesPerGravityTick]
ldh [hTicksUntilG], a
; Copy the field to the shadow field.
call ToShadowField
; Assume we're not topped out.
xor a, a
ldh [hToppedOut], a
; Point the piece data to the correct piece.
call SetPieceData
call SetPieceDataOffset
; Get the piece's spawn position.
ldh a, [hCurrentPieceY]
ld b, a
ldh a, [hCurrentPieceX]
call XYToSFieldPtr
; Check if the piece can spawn.
ld d, h
ld e, l
call GetPieceData
jp CanPieceFit
; A will be $FF if the piece can fit.
; We jump instead of return to save a few cycles.
; Draws the piece onto the field.
; B is the tile.
; DE should point to the piece's rotation state data.
; HL should be pointing to the right place in the NORMAL field.
DrawPiece:
ld a, [de]
inc de
bit 3, a
jr z, :+
ld [hl], b
: inc hl
bit 2, a
jr z, :+
ld [hl], b
: inc hl
bit 1, a
jr z, :+
ld [hl], b
: inc hl
bit 0, a
jr z, .r1end2
ld [hl], b
.r1end2
REPT 7
inc hl
ENDR
ld a, [de]
inc de
bit 3, a
jr z, :+
ld [hl], b
: inc hl
bit 2, a
jr z, :+
ld [hl], b
: inc hl
bit 1, a
jr z, :+
ld [hl], b
: inc hl
bit 0, a
jr z, .r2end2
ld [hl], b
.r2end2
REPT 7
inc hl
ENDR
ld a, [de]
inc de
bit 3, a
jr z, :+
ld [hl], b
: inc hl
bit 2, a
jr z, :+
ld [hl], b
: inc hl
bit 1, a
jr z, :+
ld [hl], b
: inc hl
bit 0, a
jr z, .r3end2
ld [hl], b
.r3end2
REPT 7
inc hl
ENDR
ld a, [de]
inc de
bit 3, a
jr z, :+
ld [hl], b
: inc hl
bit 2, a
jr z, :+
ld [hl], b
: inc hl
bit 1, a
jr z, :+
ld [hl], b
: inc hl
bit 0, a
ret z
ld [hl], b
ret
FieldProcess::
; Wipe out the piece.
ldh a, [hCurrentPieceY]
ld b, a
ldh a, [hCurrentPieceX]
call XYToFieldPtr
ld d, h
ld e, l
call GetPieceData
ld b, TILE_FIELD_EMPTY
push hl
push de
pop hl
pop de
call DrawPiece
; Gravity?
ldh a, [hTicksUntilG]
dec a
ldh [hTicksUntilG], a
jr nz, .nograv
ldh a, [hCurrentFramesPerGravityTick]
ldh [hTicksUntilG], a
; Move the piece down, but first check if there's still sufficient "down" to go.
ldh a, [hCurrentGravityPerTick]
ld b, a
: ldh a, [hCurrentPieceY]
add a, b
cp a, 22
jr c, :+
dec b
jr z, .nograv
jr :-
: push bc
ldh a, [hCurrentPieceY]
add a, b
ld b, a
ldh a, [hCurrentPieceX]
call XYToSFieldPtr
ld d, h
ld e, l
call GetPieceData
call CanPieceFit
cp a, $FF
jr z, .dolower
pop bc
dec b
jr z, .nograv
jr :-
.dolower
pop bc
ldh a, [hCurrentPieceY]
add a, b
ldh [hCurrentPieceY], a
.nograv
ldh a, [hCurrentPieceX]
ldh [hWantX], a
ldh a, [hCurrentPieceRotationState]
ldh [hWantRotation], a
; Want left?
.wantleft
ldh a, [hLeftState]
cp a, 1
jr z, :+
ld b, a
ldh a, [hCurrentDAS]
ld c, a
ld a, b
cp a, c
jr c, .wantright
: ldh a, [hWantX]
dec a
ldh [hWantX], a
; Want right?
.wantright
ldh a, [hRightState]
cp a, 1
jr z, :+
ld b, a
ldh a, [hCurrentDAS]
ld c, a
ld a, b
cp a, c
jr c, .wantrotccw
: ldh a, [hWantX]
inc a
ldh [hWantX], a
; Want rotate CCW?
.wantrotccw
ldh a, [hAState]
cp a, 1
jr nz, .wantrotcw
ldh a, [hWantRotation]
inc a
and a, $03
ldh [hWantRotation], a
; Want rotate CW?
.wantrotcw
ldh a, [hBState]
cp a, 1
jr nz, .moverotrequested
ldh a, [hWantRotation]
dec a
and a, $03
ldh [hWantRotation], a
; Do we need to try to move/rotate the piece?
.moverotrequested
ldh a, [hWantRotation]
ld b, a
ldh a, [hCurrentPieceRotationState]
cp a, b
jr nz, .trymoverot ; Move and rotate.
ldh a, [hWantX]
ld b, a
ldh a, [hCurrentPieceX]
cp a, b
jr z, .postmove ; Neither move nor rotate.
; Move only.
ldh a, [hCurrentPieceY]
ld b, a
ldh a, [hWantX]
call XYToSFieldPtr
ld d, h
ld e, l
call GetPieceData
call CanPieceFit
cp a, $FF
jr nz, .postmove
ldh a, [hWantX]
ldh [hCurrentPieceX], a
jr .postmove
.trymoverot
ldh a, [hCurrentPieceY]
ld b, a
ldh a, [hWantX]
call XYToSFieldPtr
ld d, h
ld e, l
ldh a, [hPieceDataBase]
ld l, a
ldh a, [hPieceDataBase+1]
ld h, a
ldh a, [hWantRotation]
rlc a
rlc a
push bc
ld c, a
xor a, a
ld b, a
add hl, bc
pop bc
call CanPieceFit
cp a, $FF
jr nz, .postmove
ldh a, [hWantX]
ldh [hCurrentPieceX], a
ldh a, [hWantRotation]
ldh [hCurrentPieceRotationState], a
call SetPieceDataOffset
.postmove
; Draw the piece.
.draw
ldh a, [hCurrentPieceY]
ld b, a
ldh a, [hCurrentPieceX]
call XYToFieldPtr
ld d, h
ld e, l
call GetPieceData
ldh a, [hCurrentPiece]
ld b, TILE_PIECE_0
add a, b
ld b, a
push hl
push de
pop hl
pop de
call DrawPiece
ret
ENDC

View File

@ -10,6 +10,9 @@ DEF MODE_GO EQU 1
DEF MODE_POSTGO EQU 2
DEF MODE_FETCH_PIECE EQU 3
DEF MODE_SPAWN_PIECE EQU 4
DEF MODE_PIECE_IN_MOTION EQU 5
DEF MODE_DELAY EQU 6
DEF MODE_GAME_OVER EQU 7
SECTION "Gameplay Variables", WRAM0
@ -17,10 +20,10 @@ wMode: ds 1
wModeCounter: ds 1
SECTION "Critical Gameplay Variables", HRAM
hCurrentPiece: ds 1
hCurrentPieceX: ds 1
hCurrentPieceY: ds 1
hCurrentPieceRotationState: ds 1
hCurrentPiece:: ds 1
hCurrentPieceX:: ds 1
hCurrentPieceY:: ds 1
hCurrentPieceRotationState:: ds 1
hHeldPiece: ds 1
hHoldSpent: ds 1
hSkipJingle: ds 1
@ -101,6 +104,12 @@ GamePlayEventLoopHandler::
jr z, fetchPieceMode
cp MODE_SPAWN_PIECE
jp z, spawnPieceMode
cp MODE_PIECE_IN_MOTION
jp z, pieceInMotionMode
cp MODE_DELAY
jp z, delayMode
cp MODE_GAME_OVER
jp z, gameOverMode
; Draw "READY" and wait a bit.
@ -204,53 +213,28 @@ fetchPieceMode:
; Spawn the piece.
spawnPieceMode:
; TODO: At this point all the info needed to spawn the piece is known.
; We spawn the piece and then check if this causes a top out, and transition to the game over state if so.
; This then immediately transitions into regular gameplay.
call ToShadowField
call FromShadowField
ld a, [hEvenFrame]
cp a, 0
jr nz, :+
ld e, 1
call LevelUp
ld a, $10
ld hl, wScoreIncrement+1
ld [hl], a
call IncreaseScore
: ld a, [hUpState]
cp a, 1
jr nz, :+
ld a, MODE_FETCH_PIECE
call TrySpawnPiece
cp a, $FF
jr z, :+
ld a, MODE_GAME_OVER
ld [wMode], a
jr drawStaticInfo
: ld a, [hLeftState]
cp a, 1
jr z, :++
cp a, 12
jr nc, :+
ld a, [hRightState]
cp a, 1
jr z, :++
cp a, 12
jr nc, :+
jr drawStaticInfo
: ldh a, [hFrameCtr]
and %00000111
cp 4
jr nz, drawStaticInfo
: ld a, SFX_MOVE
call SFXEnqueue
jr drawStaticInfo
: ld a, MODE_PIECE_IN_MOTION
ld [wMode], a
; This mode lasts for as long as the piece is in motion.
; Field will let us know when it has locked in place.
pieceInMotionMode:
call FieldProcess
jr drawStaticInfo
delayMode:
; TODO.
gameOverMode:
; TODO.

View File

@ -1,5 +1,5 @@
#Emulicious settings file
#Wed Oct 18 13:09:20 CEST 2023
#Fri Oct 20 08:16:53 CEST 2023
WindowEventViewerWindowHeight=1416
WindowEventViewerWindowDivider=876
WindowMemoryTracerWindowY=631
@ -72,7 +72,7 @@ InterruptBreakpointEnabled=false
OutlineWidth=425
DebuggerEventFiltersGameBoy=
GameBoyErrorBreakpointSuspend9=true
WindowMemoryEditorOpen=false
WindowMemoryEditorOpen=true
GameBoyErrorBreakpointSuspend8=true
GameBoyErrorBreakpointSuspend7=true
WindowPaletteViewerY=619
@ -98,8 +98,8 @@ Gamepad1Key31=-1
Gamepad1Key30=-1
BankSwapAtPCBreakpointEnabled=false
DebuggerMemorySelectedTab=HRAM
WindowVideoViewerOpen=true
WindowMemoryEditorTabVisibleRect=0,0,583,128
WindowVideoViewerOpen=false
WindowMemoryEditorTabVisibleRect=0,496,583,384
Gamepad1Key29=-1
Gamepad1Key28=-1
Gamepad1Key27=-1
@ -126,9 +126,9 @@ Key1=75
Key0=74
Gamepad1Key19=-1
Gamepad1Key18=-1
WindowEventViewerWindowY=24
WindowEventViewerWindowY=99
Gamepad1Key17=-1
WindowEventViewerWindowX=0
WindowEventViewerWindowX=570
Gamepad1Key16=-1
Gamepad1Key15=-1
Gamepad1Key14=-1
@ -136,7 +136,7 @@ Gamepad1Key13=-1
Gamepad1Key12=-1
Gamepad1Key11=-1
Gamepad1Key10=-1
WindowMemoryEditorSelectedAddress=0
WindowMemoryEditorSelectedAddress=503
WindowMemoryEditorWidth=665
GameBoyErrorBreakpointCondition9=
GameBoyErrorBreakpointCondition8=
@ -155,7 +155,7 @@ Gamepad0Key35=-1
Gamepad0Key34=-1
Gamepad0Key33=-1
Gamepad0Key32=-1
WindowMemoryEditorSelectedTab=HRAM
WindowMemoryEditorSelectedTab=RAM
Gamepad0Key31=-1
Gamepad0Key30=-1
SMSGamepadAThreshold=50
@ -178,8 +178,8 @@ Gamepad0Key20=-1
DebuggerSouthPanelSelectedTab=1
WindowEmuliciousWidth=816
WindowVideoViewerWidth=980
WindowMemoryEditorY=557
WindowMemoryEditorX=837
WindowMemoryEditorY=732
WindowMemoryEditorX=2558
Gamepad0Key19=-1
Gamepad0Key18=-1
Gamepad0Key17=-1
@ -199,8 +199,8 @@ GameBoyErrorBreakpointMessage32=
InterruptBreakpointCondition=
Recent0=C\:\\workspace\\dmgtris\\bin\\out.gb
GameBoyErrorBreakpointMessage20=
WindowEmuliciousY=474
WindowEmuliciousX=1512
WindowEmuliciousY=422
WindowEmuliciousX=89
GameBoyErrorBreakpointEnabled9=false
GameBoyErrorBreakpointEnabled8=false
GameBoyErrorBreakpointEnabled7=false
@ -243,7 +243,7 @@ Gamepad1Key0=-1
RomDir=C\:\\workspace\\dmgtris\\bin
GameBoyErrorBreakpointCondition20=
WindowVideoViewerHeight=1027
WindowEventViewerWindowOpen=false
WindowEventViewerWindowOpen=true
WindowSpriteViewerY=512
WindowSpriteViewerX=320
CodeFontSize=13
@ -264,8 +264,8 @@ Gamepad0Key3=-1
Gamepad0Key2=-1
Gamepad0Key1=-1
Gamepad0Key0=-1
WindowDebuggerY=103
WindowDebuggerX=166
WindowDebuggerY=201
WindowDebuggerX=727
InterruptBreakpointSuspend=true
SMSGamepadAKeyboard=false
GameBoyErrorBreakpointSuspend32=true

View File

@ -4,3 +4,7 @@ hPlayhead 4 Hexadecimal
wScoreIncrementBCD 6 Hexadecimal
wScoreIncrement 2 Hexadecimal
wScore 6 Hexadecimal
hPieceDataBase 2 Hexadecimal
hPieceDataOffset 1 Hexadecimal
hCurrentPiece 1 Hexadecimal
hCurrentPieceY 1 Hexadecimal