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.
575 lines
14 KiB
PHP
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
|