; Native state-machine regression. Tests never write the real player's profile. .data bjPartySeenLo dd 0 bjPartySeenHi dd 0 bjPartySeenCount dd 0 bjPartyShot1 db "build\actions\blackjack-party-1.bmp",0 bjPartyShot2 db "build\actions\blackjack-party-2.bmp",0 bjPartyShot3 db "build\actions\blackjack-party-3.bmp",0 bjPartyShots dd OFFSET bjPartyShot1,OFFSET bjPartyShot2,OFFSET bjPartyShot3 bjPartyFlightShot db "build\actions\blackjack-party-flight.bmp",0 bjPartyResultShot db "build\actions\blackjack-party-result.bmp",0 bjPartyExitShot db "build\actions\blackjack-party-exit.bmp",0 .code CheckBJPartyHand3D PROC uses ebx esi hand:DWORD,count:DWORD mov esi,hand cmp count,2 jb bj_party_hand_bad cmp count,12 ja bj_party_hand_bad xor ebx,ebx bj_party_hand_card: mov eax,[esi+ebx*4] cmp eax,52 jae bj_party_hand_bad cmp eax,32 jb bj_party_hand_low sub eax,32 bts bjPartySeenHi,eax jc bj_party_hand_bad jmp bj_party_hand_next bj_party_hand_low: bts bjPartySeenLo,eax jc bj_party_hand_bad bj_party_hand_next: inc bjPartySeenCount inc ebx cmp ebx,count jb bj_party_hand_card xor eax,eax ret bj_party_hand_bad: mov eax,8104 ret CheckBJPartyHand3D ENDP RunBJPartyTest3D PROC uses ebx esi edi local rounds:DWORD,ticks:DWORD,savedBank:DWORD,savedSeed:DWORD,savedCursor:DWORD,fixtureSeed:DWORD mov engineMode,MODE_BLACKJACK mov cbBet3D,100 mov cbBotCount3D,0 call InitNativeBlackjack3D cmp cbPartyArt3D.pixels,0 je bj_party_fail_art cmp cbPartyRoom3D.pixels,0 je bj_party_fail_art ; Real mouse selection; changing seats resets the displayed hand, not money. mov bankroll,10000 mov mouseClick3D,1 mov mouseX3D,270 mov mouseY3D,40 call BJPartyInput3D cmp cbBotCount3D,2 jne bj_party_fail_input cmp mouseClick3D,0 jne bj_party_fail_input cmp bankroll,10000 jne bj_party_fail_input call StartNativeBlackjack3D invoke SetBJPartyCount3D,3 cmp cbBotCount3D,2 jne bj_party_fail_input cmp cbCursor3D,8 jne bj_party_fail_deck cmp bankroll,9900 jne bj_party_fail_wallet ; A bot decision may see its own total and the dealer's upcard, nothing else. mov cbBots3D.score,16 mov cbBots3D.count,2 mov cbDealer3D,4 invoke BJBotDecision3D,0 mov savedCursor,eax mov cbDealer3D[4],12 mov cbPlayer3D,51 mov cbDeck3D[120],33 invoke BJBotDecision3D,0 cmp eax,savedCursor jne bj_party_fail_hidden mov cbBots3D[SIZEOF BJBot3D].score,18 mov cbBots3D[SIZEOF BJBot3D].count,2 invoke BJBotDecision3D,1 cmp eax,1 jne bj_party_fail_hidden mov cbBots3D[SIZEOF BJBot3D*2].score,13 mov cbBots3D[SIZEOF BJBot3D*2].count,2 invoke BJBotDecision3D,2 test eax,eax jnz bj_party_fail_hidden ; Natural beats a drawn 21, but a dealer natural beats a drawn guest 21. mov cbBotCount3D,3 mov cbBotsSettled3D,0 mov cbDealerScore3D,21 mov cbDealerCount3D,2 mov cbBots3D.score,21 mov cbBots3D.count,2 mov cbBots3D[SIZEOF BJBot3D].score,21 mov cbBots3D[SIZEOF BJBot3D].count,3 mov cbBots3D[SIZEOF BJBot3D*2].score,22 call ResolveBJParty3D cmp cbBots3D.outcome,2 jne bj_party_fail_wallet cmp cbBots3D[SIZEOF BJBot3D].outcome,1 jne bj_party_fail_wallet cmp cbBots3D[SIZEOF BJBot3D*2].outcome,1 jne bj_party_fail_wallet mov cbDealerCount3D,3 mov cbBotsSettled3D,0 call ResolveBJParty3D cmp cbBots3D.outcome,3 jne bj_party_fail_wallet ; Run 200 full rounds with each party size, alternating hits and doubles. mov edi,1 bj_party_test_size: mov cbBotCount3D,edi mov rounds,200 bj_party_test_round: mov eax,rounds imul eax,2137 add eax,edi mov rngSeed3D,eax mov bankroll,10000 mov cbState3D,CB_IDLE mov engineMode,MODE_BLACKJACK call StartNativeBlackjack3D mov eax,edi add eax,2 shl eax,1 cmp cbCursor3D,eax jne bj_party_fail_deck mov ticks,0 mov deltaTime3D,50 bj_party_test_tick: cmp cbState3D,CB_RESULT je bj_party_test_result cmp cbState3D,CB_PLAYER jne bj_party_test_handle mov pressedKeys3D[53h],1 cmp cbPlayerScore3D,16 jae @F mov pressedKeys3D[53h],0 mov pressedKeys3D[48h],1 @@: cmp cbPlayerCount3D,2 jne bj_party_test_handle test rounds,1 jz bj_party_test_handle mov pressedKeys3D[44h],1 bj_party_test_handle: call HandleNativeBlackjack3D call ClearKeys3D cmp cbBotCount3D,edi jne bj_party_fail_input cmp cbCursor3D,52 ja bj_party_fail_deck inc ticks cmp ticks,2000 jae bj_party_fail_stuck jmp bj_party_test_tick bj_party_test_result: mov eax,10000 sub eax,cbStake3D cmp cbOutcome3D,1 je bj_party_expected add eax,cbStake3D cmp cbOutcome3D,2 je bj_party_expected add eax,cbStake3D cmp cbOutcome3D,3 jne bj_party_expected mov edx,cbStake3D shr edx,1 add eax,edx bj_party_expected: cmp bankroll,eax jne bj_party_fail_wallet mov savedBank,eax invoke NativeBJSettle3D,cbOutcome3D mov eax,savedBank cmp bankroll,eax jne bj_party_fail_wallet mov bjPartySeenLo,0 mov bjPartySeenHi,0 mov bjPartySeenCount,0 invoke CheckBJPartyHand3D,OFFSET cbPlayer3D,cbPlayerCount3D test eax,eax jnz bj_party_test_done invoke CheckBJPartyHand3D,OFFSET cbDealer3D,cbDealerCount3D test eax,eax jnz bj_party_test_done xor ebx,ebx bj_party_check_guests: mov esi,ebx imul esi,SIZEOF BJBot3D add esi,OFFSET cbBots3D cmp [esi].BJBot3D.state,BJ_BOT_DONE jne bj_party_fail_stuck cmp [esi].BJBot3D.outcome,3 ja bj_party_fail_wallet invoke CheckBJPartyHand3D,esi,[esi].BJBot3D.count test eax,eax jnz bj_party_test_done inc ebx cmp ebx,edi jb bj_party_check_guests mov eax,bjPartySeenCount cmp cbCursor3D,eax jne bj_party_fail_deck xor ebx,ebx bj_party_check_prefix: mov eax,cbDeck3D[ebx*4] cmp eax,32 jb @F sub eax,32 bt bjPartySeenHi,eax jnc bj_party_fail_deck jmp bj_party_prefix_next @@: bt bjPartySeenLo,eax jnc bj_party_fail_deck bj_party_prefix_next: inc ebx cmp ebx,cbCursor3D jb bj_party_check_prefix dec rounds jnz bj_party_test_round cmp edi,3 jne @F call RenderNativeBlackjack3D invoke WriteActionSnapshot3D,OFFSET bjPartyResultShot @@: ; Actual framebuffer for each seat count, then repeat without state changes. mov cbState3D,CB_IDLE mov bankroll,10000 call StartNativeBlackjack3D mov cbState3D,CB_PLAYER mov eax,cbInitialFlights3D imul eax,TABLE_FLIGHT_MS mov cbTimer3D,eax mov eax,rngSeed3D mov savedSeed,eax mov eax,cbCursor3D mov savedCursor,eax mov eax,bankroll mov savedBank,eax call RenderNativeBlackjack3D mov eax,edi dec eax invoke WriteActionSnapshot3D,bjPartyShots[eax*4] mov ebx,8 bj_party_render_repeat: call RenderNativeBlackjack3D dec ebx jnz bj_party_render_repeat mov eax,savedSeed cmp rngSeed3D,eax jne bj_party_fail_render mov eax,savedCursor cmp cbCursor3D,eax jne bj_party_fail_render mov eax,savedBank cmp bankroll,eax jne bj_party_fail_render inc edi cmp edi,4 jb bj_party_test_size ; Player bust does not prematurely end or hide the other guests' turns. invoke FinishBJPlayer3D,1 cmp cbState3D,CB_BOTS jne bj_party_fail_stuck ; Choose a genuine deal that needs a guest card for the animation capture. mov fixtureSeed,1001 bj_party_find_flight: mov eax,fixtureSeed mov rngSeed3D,eax mov cbState3D,CB_IDLE mov bankroll,10000 call StartNativeBlackjack3D cmp cbPlayerScore3D,21 je bj_party_next_fixture cmp cbDealerScore3D,21 je bj_party_next_fixture cmp cbBots3D.score,17 jb bj_party_flight_found bj_party_next_fixture: inc fixtureSeed cmp fixtureSeed,1101 jae bj_party_fail_stuck jmp bj_party_find_flight bj_party_flight_found: invoke FinishBJPlayer3D,-1 mov deltaTime3D,50 mov cbBotTimer3D,BJ_PARTY_MS call UpdateBJParty3D cmp cbBots3D.state,BJ_BOT_FLIGHT jne bj_party_fail_stuck mov cbBotTimer3D,180 call RenderNativeBlackjack3D invoke WriteActionSnapshot3D,OFFSET bjPartyFlightShot ; Confirmation pauses bot timers; leaving counts once as player's loss. call RequestCardExit3D cmp cardExitActive3D,1 jne bj_party_fail_input mov savedCursor,180 call HandleNativeBlackjack3D cmp cbBotTimer3D,180 jne bj_party_fail_input call RenderNativeBlackjack3D invoke WriteActionSnapshot3D,OFFSET bjPartyExitShot mov eax,bankroll mov savedBank,eax mov pressedKeys3D[59h],1 call HandleNativeBlackjack3D cmp engineMode,MODE_WALK jne bj_party_fail_input mov eax,savedBank cmp bankroll,eax jne bj_party_fail_wallet mov engineMode,MODE_BLACKJACK ; A result table can return to solo by keyboard, without another settlement. mov pressedKeys3D[30h],1 call BJPartyInput3D cmp cbBotCount3D,0 jne bj_party_fail_input cmp cbState3D,CB_IDLE jne bj_party_fail_input cmp cbPlayerCount3D,0 jne bj_party_fail_input mov eax,savedBank cmp bankroll,eax jne bj_party_fail_wallet xor eax,eax ret bj_party_fail_art: mov eax,8101 ret bj_party_fail_input: mov eax,8102 ret bj_party_fail_wallet: mov eax,8103 ret bj_party_fail_deck: mov eax,8104 ret bj_party_fail_hidden: mov eax,8105 ret bj_party_fail_stuck: mov eax,8106 ret bj_party_fail_render: mov eax,8107 bj_party_test_done: ret RunBJPartyTest3D ENDP