KAZIK/tools/tests/card_tables_test.inc
Artvasil09 3ad5bf4c9d Develop assembly-only casino scenes and native games
Add native Durak, poker, blackjack, roulette, Buckshot and billiards scenes with animation assets and regression tests. Improve arrival, city, hall, profiles, shops, audio and exit handling; remove the portable C game core and refresh shipping executables.
2026-10-08 22:39:19 +03:00

575 lines
14 KiB
PHP

; Headless verification executes the production MASM handlers and framebuffer renderer.
wsprintfA PROTO C :DWORD,:DWORD,:VARARG
.data
tableVectorPath db "build\tables\poker-vectors.bin",0
tableVectorCount dd 0
tableDuplicate dd 0,0,2,3,4
tableAces dd 12,25,38,9
tablePKDeal db "build\actions\poker-deal.bmp",0
tablePKFlop db "build\actions\poker-flop.bmp",0
tablePKTurn db "build\actions\poker-turn.bmp",0
tablePKReveal db "build\actions\poker-reveal.bmp",0
tablePKResult db "build\actions\poker-result.bmp",0
tableBJDeal db "build\actions\blackjack-deal.bmp",0
tableBJHit db "build\actions\blackjack-hit.bmp",0
tableBJResult db "build\actions\blackjack-result.bmp",0
tableHandSnapshotFormat db "build\actions\poker-hand-%02u.bmp",0
tableHandSnapshotName db 128 dup(0)
.code
RunCardTablesTest3D PROC uses ebx esi edi
local countRead:DWORD,vectors:DWORD,heap:DWORD,rounds:DWORD,ticks:DWORD,seenLo:DWORD,seenHi:DWORD
local savedBank:DWORD,savedSeed:DWORD,savedState:DWORD,savedPot:DWORD,savedStack:DWORD,savedPaid:DWORD
call LoadArrivalAssets3D
cmp handsPack3D.frames, 8
jne table_fail_20
call LoadCardTableAssets3D
test eax, eax
jz table_fail_20
cmp cardTablePixels3D, 0
je table_fail_20
mov interactTargetId, INTERACT_POKER
call Trigger3DInteraction
cmp engineMode, MODE_POKER
jne table_fail_20
mov interactTargetId, INTERACT_BLACKJACK
call Trigger3DInteraction
cmp engineMode, MODE_BLACKJACK
jne table_fail_20
invoke CreateFileA, OFFSET tableVectorPath, 80000000h, 1, 0, 3, 80h, 0
cmp eax, -1
je table_fail_20
mov ebx, eax
invoke ReadFile, ebx, OFFSET tableVectorCount, 4, ADDR countRead, 0
cmp countRead, 4
jne table_fail_20
cmp tableVectorCount, 9021
jne table_fail_20
invoke GetProcessHeap
mov heap, eax
invoke HeapAlloc, eax, 0, 9021 * 36
mov vectors, eax
test eax, eax
jz table_fail_20
invoke ReadFile, ebx, vectors, 9021 * 36, ADDR countRead, 0
invoke CloseHandle, ebx
cmp countRead, 9021 * 36
jne table_fail_20
mov esi, vectors
mov edi, tableVectorCount
table_vectors:
lea eax, [esi+4]
invoke EvaluateNativePoker3D, eax, DWORD PTR [esi]
cmp eax, [esi+32]
jne table_fail_21
add esi, 36
dec edi
jnz table_vectors
invoke HeapFree, heap, 0, vectors
invoke EvaluateNativePoker3D, OFFSET tableDuplicate, 5
cmp eax, 7463
jne table_fail_21
invoke NativeBJScore3D, OFFSET tableAces, 4
cmp eax, 13
jne table_fail_22
; Blinds and the big blind's option; postflop action starts off-button.
mov engineMode, MODE_POKER
mov pkButton3D, 1
mov pkBlind3D, 50
mov bankroll, 1000
mov pkState3D, PK_IDLE
call StartNativePoker3D
cmp pkPot3D, 75
jne table_fail_23
cmp pkTurn3D, 0
jne table_fail_23
cmp pkPaid3D, 25
jne table_fail_23
mov eax, pkDeck3D
cmp pkHole3D[8], eax
jne table_fail_23
invoke PokerRaise3D, 0, 10
cmp pkError3D, 2
jne table_fail_23
cmp pkPot3D, 75
jne table_fail_23
cmp bankroll, 975
jne table_fail_23
invoke PokerCall3D, 0
cmp pkState3D, PK_AI
jne table_fail_23
invoke PokerCall3D, 1
cmp pkState3D, PK_BOARD
jne table_fail_23
cmp pkBoardCount3D, 3
jne table_fail_23
cmp pkTurn3D, 1
jne table_fail_23
cmp pkCursor3D, 8
jne table_fail_23
; A shared royal flush must split, including the correct odd chip.
mov pkBoard3D[0], 8
mov pkBoard3D[4], 9
mov pkBoard3D[8], 10
mov pkBoard3D[12], 11
mov pkBoard3D[16], 12
mov pkBoardCount3D, 5
mov pkHole3D[0], 0
mov pkHole3D[4], 1
mov pkHole3D[8], 13
mov pkHole3D[12], 14
mov pkButton3D, 0
mov pkPot3D, 151
mov bankroll, 1000
mov pkStack3D, 1000
mov pkState3D, PK_REVEAL
call PokerShowdown3D
cmp pkOutcome3D, 2
jne table_fail_24
cmp bankroll, 1075
jne table_fail_24
cmp pkStack3D, 1076
jne table_fail_24
call PokerShowdown3D
cmp bankroll, 1075
jne table_fail_24
call RenderNativePoker3D
invoke WriteActionSnapshot3D, OFFSET tablePKResult
; Unmatched short all-in money goes back to its owner.
mov pkPaid3D, 100
mov pkPaid3D[4], 400
mov pkCurrent3D, 400
mov pkPot3D, 500
mov pkStack3D, 600
mov bankroll, 50
mov pkState3D, PK_PLAYER
mov pkStreet3D, 0
mov pkCursor3D, 4
mov pkBoardCount3D, 0
invoke PokerCall3D, 0
cmp pkPot3D, 300
jne table_fail_24
cmp pkStack3D, 850
jne table_fail_24
; Effective-stack all-in must run out the whole board without user input.
mov bankroll, 1000
mov pkState3D, PK_IDLE
mov pkButton3D, 1
call StartNativePoker3D
invoke PokerRaise3D, 0, bankroll
cmp bankroll, 0
jne table_fail_24
invoke PokerCall3D, 1
mov ticks, 0
mov deltaTime3D, 50
table_all_in_tick:
call HandleNativePoker3D
cmp pkState3D, PK_RESULT
je table_all_in_settled
inc ticks
cmp ticks, 200
jae table_fail_30
jmp table_all_in_tick
table_all_in_settled:
cmp pkBoardCount3D, 5
jne table_fail_24
mov eax, bankroll
add eax, pkStack3D
cmp eax, 2000
jne table_fail_24
; Insufficient funds cannot start a hand. A one-blind bankroll still completes.
mov pkState3D, PK_IDLE
mov bankroll, 49
call StartNativePoker3D
cmp pkState3D, PK_IDLE
jne table_fail_24
cmp bankroll, 49
jne table_fail_24
mov pkButton3D, 0
mov bankroll, 50
call StartNativePoker3D
cmp pkTurn3D, 1
jne table_fail_24
invoke PokerCall3D, 1
mov ticks, 0
table_low_bank_tick:
call HandleNativePoker3D
cmp pkState3D, PK_RESULT
je table_low_bank_settled
inc ticks
cmp ticks, 200
jae table_fail_30
jmp table_low_bank_tick
table_low_bank_settled:
mov eax, bankroll
add eax, pkStack3D
cmp eax, 100
jne table_fail_24
; State, bank and RNG cannot change when the same frame is drawn repeatedly.
mov bankroll, 10000
mov pkState3D, PK_IDLE
call StartNativePoker3D
mov pkState3D, PK_DEAL
mov pkTimer3D, 310
mov eax, bankroll
mov savedBank, eax
mov eax, rngSeed3D
mov savedSeed, eax
mov eax, pkPot3D
mov savedPot, eax
mov edi, 30
table_render_repeat:
call RenderNativePoker3D
dec edi
jnz table_render_repeat
mov eax, savedBank
cmp bankroll, eax
jne table_fail_25
mov eax, savedSeed
cmp rngSeed3D, eax
jne table_fail_25
mov eax, savedPot
cmp pkPot3D, eax
jne table_fail_25
cmp pkState3D, PK_DEAL
jne table_fail_25
invoke WriteActionSnapshot3D, OFFSET tablePKDeal
xor edi, edi
table_hand_sequence:
mov eax, edi
imul eax, 60
mov pkTimer3D, eax
call RenderNativePoker3D
invoke wsprintfA, OFFSET tableHandSnapshotName, OFFSET tableHandSnapshotFormat, edi
invoke WriteActionSnapshot3D, OFFSET tableHandSnapshotName
inc edi
cmp edi, 24
jb table_hand_sequence
mov pkState3D, PK_BOARD
mov pkStreet3D, 1
mov pkBoard3D[0], 8
mov pkBoard3D[4], 24
mov pkBoard3D[8], 35
mov pkOldBoardCount3D, 0
mov pkBoardCount3D, 3
mov pkTimer3D, 400
call RenderNativePoker3D
invoke WriteActionSnapshot3D, OFFSET tablePKFlop
mov pkState3D, PK_PLAYER
mov pkChipTimer3D, 320
call RenderNativePoker3D
invoke WriteActionSnapshot3D, OFFSET tablePKTurn
mov pkState3D, PK_REVEAL
mov pkTimer3D, 90
call RenderNativePoker3D
invoke WriteActionSnapshot3D, OFFSET tablePKReveal
; Client pixels convert to logical coordinates even with pillarboxing.
mov viewWidth3D, 800
mov viewHeight3D, 600
mov viewLeft3D, 100
mov viewTop3D, 0
invoke WindowEvents3D, 0, 201h, 0, 023F01A9h ; (425,575) -> (130,230)
cmp mouseClick3D, 1
jne table_fail_26
cmp mouseX3D, 130
jne table_fail_26
cmp mouseY3D, 230
jne table_fail_26
mov mouseClick3D, 0
invoke WindowEvents3D, 0, 201h, 0, 023F0032h ; click in the black left bar
cmp mouseClick3D, 0
jne table_fail_26
; Mouse and keyboard share the command path; animated states ignore clicks.
call ClearKeys3D
mov mouseClick3D, 1
mov mouseX3D, 100
mov mouseY3D, 230
mov pkState3D, PK_PLAYER
invoke CardTableMouse3D, MODE_POKER
cmp pressedKeys3D[52h], 1
jne table_fail_26
call ClearKeys3D
mov mouseClick3D, 1
mov pkState3D, PK_AI
invoke CardTableMouse3D, MODE_POKER
cmp pressedKeys3D[52h], 0
jne table_fail_26
mov engineMode, MODE_WALK
mov dice3d_state, 1
call TableBusy3D
test eax, eax
jnz table_fail_26
mov engineMode, MODE_POKER
call TableBusy3D
cmp eax, 1
jne table_fail_26
; The AI's decision cannot depend on the unseen player cards or undealt cards.
mov pkHole3D[8], 12
mov pkHole3D[12], 25
mov pkBoardCount3D, 0
mov pkStreet3D, 0
mov pkState3D, PK_AI
mov pkPaid3D, 200
mov pkPaid3D[4], 50
mov pkCurrent3D, 200
mov pkPot3D, 250
mov bankroll, 9800
mov pkStack3D, 9950
mov pkMinRaise3D, 150
mov pkRaisedCount3D, 0
mov pkCanRaise3D, 1
mov rngSeed3D, 77123
call PokerAIDecide3D
mov eax, bankroll
mov savedBank, eax
mov eax, pkStack3D
mov savedStack, eax
mov eax, pkPot3D
mov savedPot, eax
mov eax, pkState3D
mov savedState, eax
mov eax, pkPaid3D[4]
mov savedPaid, eax
mov pkHole3D, 2
mov pkHole3D[4], 3
mov pkDeck3D[180], 51
mov pkState3D, PK_AI
mov pkPaid3D, 200
mov pkPaid3D[4], 50
mov pkCurrent3D, 200
mov pkPot3D, 250
mov bankroll, 9800
mov pkStack3D, 9950
mov pkMinRaise3D, 150
mov pkRaisedCount3D, 0
mov pkCanRaise3D, 1
mov rngSeed3D, 77123
call PokerAIDecide3D
mov eax, savedBank
cmp bankroll, eax
jne table_fail_27
mov eax, savedStack
cmp pkStack3D, eax
jne table_fail_27
mov eax, savedPot
cmp pkPot3D, eax
jne table_fail_27
mov eax, savedState
cmp pkState3D, eax
jne table_fail_27
mov eax, savedPaid
cmp pkPaid3D[4], eax
jne table_fail_27
mov rounds, 500
mov deltaTime3D, 50
table_poker_round:
mov eax, rounds
imul eax, 137
mov rngSeed3D, eax
mov bankroll, 10000
mov pkState3D, PK_IDLE
call StartNativePoker3D
mov seenLo, 0
mov seenHi, 0
xor esi, esi
table_check_deck:
mov eax, pkDeck3D[esi*4]
cmp eax, 52
jae table_fail_28
cmp eax, 32
jb @F
sub eax, 32
bts seenHi, eax
jc table_fail_28
jmp table_next_deck
@@:
bts seenLo, eax
jc table_fail_28
table_next_deck:
inc esi
cmp esi, 52
jb table_check_deck
mov ticks, 0
table_poker_tick:
cmp pkState3D, PK_RESULT
je table_poker_settled
mov eax, bankroll
add eax, pkStack3D
add eax, pkPot3D
cmp eax, 20000
jne table_fail_29
cmp pkState3D, PK_PLAYER
jne table_poker_handle
mov eax, ticks
and eax, 7
cmp eax, 1
je table_poker_raise
cmp eax, 3
jne table_poker_call
invoke PokerFold3D, 0
jmp table_poker_handle
table_poker_raise:
invoke PokerRaise3D, 0, pkMinRaise3D
jmp table_poker_handle
table_poker_call:
invoke PokerCall3D, 0
table_poker_handle:
call ClearKeys3D
call HandleNativePoker3D
inc ticks
cmp ticks, 3000
jae table_fail_30
jmp table_poker_tick
table_poker_settled:
mov eax, bankroll
add eax, pkStack3D
cmp eax, 20000
jne table_fail_29
dec rounds
jnz table_poker_round
; Natural, push and loss settle once, including the stake already deducted.
mov engineMode, MODE_BLACKJACK
mov cbStake3D, 100
mov cbBet3D, 100
mov bankroll, 99
mov cbState3D, CB_IDLE
call StartNativeBlackjack3D
cmp cbState3D, CB_IDLE
jne table_fail_31
cmp bankroll, 99
jne table_fail_31
mov bankroll, 900
mov cbState3D, CB_PLAYER
invoke NativeBJSettle3D, 3
cmp bankroll, 1150
jne table_fail_31
invoke NativeBJSettle3D, 3
cmp bankroll, 1150
jne table_fail_31
mov cbState3D, CB_PLAYER
mov bankroll, 900
invoke NativeBJSettle3D, 2
cmp bankroll, 1000
jne table_fail_31
mov rounds, 500
mov cbBet3D, 100
table_bj_round:
mov eax, rounds
imul eax, 161
mov rngSeed3D, eax
mov bankroll, 10000
mov cbState3D, CB_IDLE
call StartNativeBlackjack3D
mov ticks, 0
table_bj_tick:
cmp cbState3D, CB_RESULT
je table_bj_settled
cmp cbState3D, CB_PLAYER
jne table_bj_handle
mov pressedKeys3D[53h], 1
cmp cbPlayerScore3D, 16
jae @F
mov pressedKeys3D[53h], 0
mov pressedKeys3D[48h], 1
@@:
cmp cbPlayerCount3D, 2
jne table_bj_handle
test rounds, 1
jz table_bj_handle
mov pressedKeys3D[44h], 1
table_bj_handle:
call HandleNativeBlackjack3D
call ClearKeys3D
inc ticks
cmp ticks, 3000
jae table_fail_32
jmp table_bj_tick
table_bj_settled:
mov eax, 10000
sub eax, cbStake3D
cmp cbOutcome3D, 1
je table_bj_expected
add eax, cbStake3D
cmp cbOutcome3D, 2
je table_bj_expected
add eax, cbStake3D
cmp cbOutcome3D, 3
jne table_bj_expected
mov edx, cbStake3D
shr edx, 1
add eax, edx
table_bj_expected:
cmp eax, bankroll
jne table_fail_33
cmp cbCursor3D, 26
ja table_fail_33
dec rounds
jnz table_bj_round
call RenderNativeBlackjack3D
invoke WriteActionSnapshot3D, OFFSET tableBJResult
mov cbState3D, CB_IDLE
mov bankroll, 10000
call StartNativeBlackjack3D
mov cbTimer3D, 600
call RenderNativeBlackjack3D
invoke WriteActionSnapshot3D, OFFSET tableBJDeal
mov cbState3D, CB_PLAYER
call NativeBJHit3D
mov cbTimer3D, 90
mov eax, rngSeed3D
mov savedSeed, eax
mov eax, bankroll
mov savedBank, eax
call RenderNativeBlackjack3D
invoke WriteActionSnapshot3D, OFFSET tableBJHit
mov eax, savedSeed
cmp rngSeed3D, eax
jne table_fail_25
mov eax, savedBank
cmp bankroll, eax
jne table_fail_25
call FreeCardTableAssets3D
xor eax, eax
ret
table_fail_20:
mov eax, 20
ret
table_fail_21:
mov eax, 21
ret
table_fail_22:
mov eax, 22
ret
table_fail_23:
mov eax, 23
ret
table_fail_24:
mov eax, 24
ret
table_fail_25:
mov eax, 25
ret
table_fail_26:
mov eax, 26
ret
table_fail_27:
mov eax, 27
ret
table_fail_28:
mov eax, 28
ret
table_fail_29:
mov eax, 29
ret
table_fail_30:
mov eax, 30
ret
table_fail_31:
mov eax, 31
ret
table_fail_32:
mov eax, 32
ret
table_fail_33:
mov eax, 33
ret
RunCardTablesTest3D ENDP