.data dkTestSeen dd 52 dup(0) dkTestTotal dd 0 dkTestReady db "build\actions\durak-ready.bmp",0 dkTestDeal db "build\actions\durak-deal.bmp",0 dkTestAttack db "build\actions\durak-attack.bmp",0 dkTestDefense db "build\actions\durak-defense.bmp",0 dkTestFlight db "build\actions\durak-flight.bmp",0 dkTestTaking db "build\actions\durak-taking.bmp",0 dkTestResult db "build\actions\durak-result.bmp",0 dkTestLong db "build\actions\durak-long-hand.bmp",0 dkTestExit db "build\actions\durak-exit.bmp",0 dkTestStages dd 0 dkTestTakingFrames dd 0 .code DurakTestMark3D PROC uses ebx card:DWORD mov ebx, card cmp ebx, 52 jae dk_mark_bad invoke DurakCardRank, ebx cmp eax, 4 jb dk_mark_bad cmp dkTestSeen[ebx*4], 0 jne dk_mark_bad inc dkTestSeen[ebx*4] inc dkTestTotal mov eax, 1 ret dk_mark_bad: xor eax, eax ret DurakTestMark3D ENDP DurakTestHand3D PROC uses ebx esi ptrHand:DWORD,nCards:DWORD xor esi, esi mov ebx, ptrHand dk_test_hand_loop: cmp esi, nCards jae dk_test_hand_ok invoke DurakTestMark3D, DWORD PTR [ebx+esi*4] test eax, eax jz dk_test_hand_done inc esi jmp dk_test_hand_loop dk_test_hand_ok: mov eax, 1 dk_test_hand_done: ret DurakTestHand3D ENDP DurakTestConservation3D PROC uses ebx esi edi lea edi, dkTestSeen xor eax, eax mov ecx, 52 rep stosd mov dkTestTotal, 0 cmp durakPlayerCnt, 36 ja dk_conserve_bad cmp durakAICnt, 36 ja dk_conserve_bad cmp dkDiscardCount3D, 36 ja dk_conserve_bad cmp durakTableCnt, 6 ja dk_conserve_bad cmp dkCursor3D, 36 ja dk_conserve_bad mov eax, 36 sub eax, dkCursor3D cmp eax, durakDeckLeft jne dk_conserve_bad invoke DurakTestHand3D, OFFSET durakPlayerHand, durakPlayerCnt test eax, eax jz dk_conserve_bad invoke DurakTestHand3D, OFFSET durakAIHand, durakAICnt test eax, eax jz dk_conserve_bad invoke DurakTestHand3D, OFFSET dkDiscard3D, dkDiscardCount3D test eax, eax jz dk_conserve_bad mov eax, dkCursor3D lea ebx, dkDeck3D[eax*4] invoke DurakTestHand3D, ebx, durakDeckLeft test eax, eax jz dk_conserve_bad xor esi, esi dk_conserve_table: cmp esi, durakTableCnt jae dk_conserve_pending invoke DurakTestMark3D, durakAttackCards[esi*4] test eax, eax jz dk_conserve_bad mov eax, durakDefenseCards[esi*4] cmp eax, 0FFFFFFFFh je @F invoke DurakTestMark3D, eax test eax, eax jz dk_conserve_bad @@: inc esi jmp dk_conserve_table dk_conserve_pending: cmp dkPendingCard3D, 0FFFFFFFFh je @F invoke DurakTestMark3D, dkPendingCard3D test eax, eax jz dk_conserve_bad @@: cmp dkTestTotal, 36 jne dk_conserve_bad mov eax, 1 ret dk_conserve_bad: xor eax, eax ret DurakTestConservation3D ENDP RunDurakTest3D PROC uses ebx esi edi local rounds:DWORD,ticks:DWORD,expected:DWORD,oldTimer:DWORD local attackSuit:DWORD,attackRank:DWORD,defSuit:DWORD,defRank:DWORD mov interactTargetId, INTERACT_DURAK mov engineMode, MODE_WALK call Trigger3DInteraction cmp engineMode, MODE_DURAK jne dk_test_301 cmp dkState3D, DK_IDLE jne dk_test_301 mov bankroll, 10000 call RenderNativeDurak3D invoke WriteActionSnapshot3D, OFFSET dkTestReady test eax, eax jz dk_test_301 ; Face-up fills cannot index back colors with a clobbered DrawBox EAX. xor esi, esi dk_test_face_fill: invoke DrawNativeCard3D, 100, 100, esi, 0, 34 cmp screenBuffer[(244*SCREEN_W+212)*4], 00EEEDE2h jne dk_test_307 inc esi cmp esi, 52 jb dk_test_face_fill ; Independent 36x36 beat matrix for all four trump suits. mov durakTrumpSuit, 0 dk_test_trump: xor esi, esi dk_test_attack_matrix: invoke DurakCardRank, esi cmp eax, 4 jb dk_test_next_attack mov attackRank, eax invoke DurakCardSuit, esi mov attackSuit, eax xor edi, edi dk_test_def_matrix: invoke DurakCardRank, edi cmp eax, 4 jb dk_test_next_def mov defRank, eax invoke DurakCardSuit, edi mov defSuit, eax mov expected, 0 cmp eax, attackSuit jne dk_test_matrix_trump mov eax, defRank cmp eax, attackRank jbe dk_test_matrix_call jmp dk_test_matrix_yes dk_test_matrix_trump: cmp eax, durakTrumpSuit jne dk_test_matrix_call mov eax, attackSuit cmp eax, durakTrumpSuit je dk_test_matrix_call dk_test_matrix_yes: mov expected, 1 dk_test_matrix_call: invoke CanDurakBeat, esi, edi cmp eax, expected jne dk_test_302 dk_test_next_def: inc edi cmp edi, 52 jb dk_test_def_matrix dk_test_next_attack: inc esi cmp esi, 52 jb dk_test_attack_matrix inc durakTrumpSuit cmp durakTrumpSuit, 4 jb dk_test_trump ; Transfer must precede any defense and fit the new defender's hand. mov durakTrumpSuit, 3 mov dkVariant3D, 1 mov dkState3D, DK_TURN mov dkActor3D, 0 mov dkAttacker3D, 1 mov dkTaking3D, 0 mov dkLimit3D, 3 mov durakTableCnt, 1 mov durakAttackCards[0], 5 mov durakDefenseCards[0], 0FFFFFFFFh mov durakPlayerCnt, 2 mov durakPlayerHand[0], 18 mov durakPlayerHand[4], 6 mov durakAICnt, 3 invoke DurakCanPlay3D, 0, 0, DK_TRANSFER cmp eax, 1 jne dk_test_303 mov durakAICnt, 1 invoke DurakCanPlay3D, 0, 0, DK_TRANSFER test eax, eax jnz dk_test_303 mov durakAICnt, 3 mov durakDefenseCards[0], 6 invoke DurakCanPlay3D, 0, 0, DK_TRANSFER test eax, eax jnz dk_test_303 mov durakDefenseCards[0], 0FFFFFFFFh invoke DurakCanPlay3D, 0, 1, DK_DEFEND cmp eax, 1 jne dk_test_303 mov dkVariant3D, 0 invoke DurakCanPlay3D, 0, 0, DK_TRANSFER test eax, eax jnz dk_test_303 ; Neither the opponent's identities nor the unrevealed talon influence AI. call ClearDurakTable mov dkAttacker3D, 1 mov dkActor3D, 1 mov dkLimit3D, 6 mov durakAICnt, 2 mov durakAIHand[0], 5 mov durakAIHand[4], 43 mov durakPlayerCnt, 6 mov durakPlayerHand[0], 12 mov dkDeck3D[35*4], 51 invoke DurakFindMove3D, 1, DK_ATTACK cmp eax, 0 jne dk_test_303 mov durakPlayerHand[0], 0FFFFFFFFh mov dkDeck3D[35*4], 0FFFFFFFFh invoke DurakFindMove3D, 1, DK_ATTACK cmp eax, 0 jne dk_test_303 ; Full real handlers, both variants, visible and pending card conservation. mov rounds, 500 mov dkTestStages, 0 mov dkTestTakingFrames, 0 dk_test_round: mov engineMode, MODE_DURAK mov cardExitActive3D, 0 mov bankroll, 10000 mov dkState3D, DK_IDLE mov dkBet3D, 100 mov eax, rounds and eax, 1 mov dkVariant3D, eax mov eax, rounds imul eax, 7919 mov rngSeed3D, eax call StartNativeDurak3D cmp dkState3D, DK_DEAL jne dk_test_304 cmp bankroll, 9900 jne dk_test_304 mov eax, dkDeck3D[35*4] cmp eax, durakTrumpCard jne dk_test_304 call DurakTestConservation3D test eax, eax jz dk_test_305 cmp rounds, 500 jne @F mov dkTimer3D, 1850 call RenderNativeDurak3D invoke WriteActionSnapshot3D, OFFSET dkTestDeal test eax, eax jz dk_test_304 @@: mov ticks, 0 mov deltaTime3D, 1000 dk_test_tick: call ClearKeys3D cmp dkState3D, DK_TURN jne dk_test_advance cmp dkActor3D, 0 jne dk_test_advance cmp dkAttacker3D, 0 je dk_test_player_attack invoke DurakFindMove3D, 0, DK_TRANSFER cmp eax, 0FFFFFFFFh je @F mov dkSelection3D, eax mov pressedKeys3D[54h], 1 jmp dk_test_advance @@: invoke DurakFindMove3D, 0, DK_DEFEND cmp eax, 0FFFFFFFFh je dk_test_player_take mov dkSelection3D, eax mov pressedKeys3D[0Dh], 1 jmp dk_test_advance dk_test_player_take: mov pressedKeys3D[42h], 1 jmp dk_test_advance dk_test_player_attack: invoke DurakFindMove3D, 0, DK_ATTACK cmp eax, 0FFFFFFFFh je dk_test_player_finish mov dkSelection3D, eax mov pressedKeys3D[0Dh], 1 jmp dk_test_advance dk_test_player_finish: mov pressedKeys3D[44h], 1 dk_test_advance: call HandleNativeDurak3D call DurakTestConservation3D test eax, eax jz dk_test_305 inc ticks cmp ticks, 12000 ja dk_test_306 cmp dkState3D, DK_RESULT je dk_test_round_end ; Snapshot real phases, rendering must not alter RNG, cards or bank. mov esi, 1 mov edi, OFFSET dkTestAttack cmp dkState3D, DK_TURN jne dk_test_flight_snap cmp dkActor3D, 0 jne dk_test_tick cmp dkTaking3D, 0 jne dk_test_taking_snap cmp dkAttacker3D, 0 je dk_test_snapshot mov esi, 2 mov edi, OFFSET dkTestDefense jmp dk_test_snapshot dk_test_taking_snap: mov esi, 8 mov edi, OFFSET dkTestTaking jmp dk_test_snapshot dk_test_flight_snap: cmp dkState3D, DK_FLIGHT jne dk_test_tick mov esi, 4 mov edi, OFFSET dkTestFlight mov dkTimer3D, 180 dk_test_snapshot: test dkTestStages, esi jnz dk_test_tick or dkTestStages, esi mov ebx, rngSeed3D call RenderNativeDurak3D cmp ebx, rngSeed3D jne dk_test_307 call DurakTestConservation3D test eax, eax jz dk_test_307 invoke WriteActionSnapshot3D, edi test eax, eax jz dk_test_307 jmp dk_test_tick dk_test_round_end: mov eax, 9900 cmp dkOutcome3D, 1 je @F add eax, 100 cmp dkOutcome3D, 2 je @F add eax, 100 @@: cmp bankroll, eax jne dk_test_308 mov expected, eax invoke NativeDurakSettle3D, dkOutcome3D mov eax, expected cmp bankroll, eax jne dk_test_308 cmp rounds, 500 jne @F call RenderNativeDurak3D invoke WriteActionSnapshot3D, OFFSET dkTestResult test eax, eax jz dk_test_307 @@: dec rounds jnz dk_test_round cmp dkTestStages, 15 jne dk_test_307 ; Fixed bout limit does not shrink as a defender spends cards. mov dkState3D, DK_TURN mov dkActor3D, 0 mov dkAttacker3D, 0 mov dkTaking3D, 0 mov dkLimit3D, 3 mov durakPlayerCnt, 1 mov durakPlayerHand[0], 18 mov durakAICnt, 1 mov durakTableCnt, 2 mov durakAttackCards[0], 5 mov durakDefenseCards[0], 6 mov durakAttackCards[4], 19 mov durakDefenseCards[4], 20 invoke DurakCanPlay3D, 0, 0, DK_ATTACK cmp eax, 1 jne dk_test_309 mov durakTableCnt, 3 invoke DurakCanPlay3D, 0, 0, DK_ATTACK test eax, eax jnz dk_test_309 ; Refill original attacker first, exposed trump last, next attacker skips taker. mov dkState3D, DK_SWEEP mov dkOriginal3D, 0 mov dkAttacker3D, 0 mov dkTaking3D, 1 mov dkBouts3D, 1 mov durakTableCnt, 1 mov durakAttackCards[0], 5 mov durakDefenseCards[0], 0FFFFFFFFh mov durakPlayerCnt, 5 mov durakAICnt, 3 mov dkCursor3D, 34 mov durakDeckLeft, 2 mov dkDeck3D[34*4], 12 mov dkDeck3D[35*4], 51 call DurakResolveBout3D cmp durakPlayerHand[5*4], 12 jne dk_test_310 cmp durakAIHand[4*4], 51 jne dk_test_310 cmp durakDeckLeft, 0 jne dk_test_310 cmp dkAttacker3D, 0 jne dk_test_310 ; Every card remains selectable even with all 36 cards in one hand. mov durakPlayerCnt, 36 xor esi, esi xor edi, edi dk_test_long_cards: invoke DurakCardRank, esi cmp eax, 4 jb @F mov durakPlayerHand[edi*4], esi inc edi @@: inc esi cmp esi, 52 jb dk_test_long_cards call ClearDurakTable mov dkState3D, DK_TURN mov dkActor3D, 0 mov dkAttacker3D, 0 mov dkSelection3D, 0 mov dkTaking3D, 0 mov dkLimit3D, 6 mov durakAICnt, 0 mov durakDeckLeft, 0 xor esi, esi dk_test_selection: mov eax, dkSelection3D cmp eax, esi jne dk_test_311 invoke DurakMoveSelection3D, 1 inc esi cmp esi, 36 jb dk_test_selection cmp dkSelection3D, 0 jne dk_test_311 invoke DurakMoveSelection3D, -1 cmp dkSelection3D, 35 jne dk_test_311 cmp dkPage3D, 32 jne dk_test_311 call RenderNativeDurak3D invoke WriteActionSnapshot3D, OFFSET dkTestLong test eax, eax jz dk_test_311 mov mouseX3D, 21 mov mouseY3D, 180 mov mouseClick3D, 1 call HandleNativeDurak3D cmp dkSelection3D, 32 jne dk_test_311 mov mouseX3D, 5 mov mouseY3D, 186 mov mouseClick3D, 1 call HandleNativeDurak3D cmp dkSelection3D, 24 jne dk_test_311 ; Exit confirmation freezes every active animation/turn phase. mov esi, DK_DEAL dk_test_exit_phase: mov engineMode, MODE_DURAK mov dkState3D, esi mov dkTimer3D, 90 mov bankroll, 9900 mov dkStake3D, 100 call ClearKeys3D call CardTableEscape3D cmp eax, 1 jne dk_test_312 cmp cardExitActive3D, 1 jne dk_test_312 mov deltaTime3D, 1000 call HandleNativeDurak3D cmp dkTimer3D, 90 jne dk_test_312 cmp dkState3D, esi jne dk_test_312 cmp esi, DK_DEAL jne @F call RenderNativeDurak3D invoke WriteActionSnapshot3D, OFFSET dkTestExit test eax, eax jz dk_test_312 @@: mov pressedKeys3D[4Eh], 1 call HandleNativeDurak3D cmp cardExitActive3D, 0 jne dk_test_312 cmp engineMode, MODE_DURAK jne dk_test_312 cmp dkTimer3D, 90 jne dk_test_312 call RequestCardExit3D mov pressedKeys3D[59h], 1 call HandleNativeDurak3D cmp engineMode, MODE_WALK jne dk_test_312 cmp bankroll, 9900 jne dk_test_312 cmp dkState3D, DK_RESULT jne dk_test_312 inc esi cmp esi, DK_RESULT jb dk_test_exit_phase mov engineMode, MODE_DURAK mov dkState3D, DK_IDLE call CardTableEscape3D cmp engineMode, MODE_WALK jne dk_test_312 xor eax, eax ret dk_test_301: mov eax, 301 ret dk_test_302: mov eax, 302 ret dk_test_303: mov eax, 303 ret dk_test_304: mov eax, 304 ret dk_test_305: mov eax, 305 ret dk_test_306: mov eax, 306 ret dk_test_307: mov eax, 307 ret dk_test_308: mov eax, 308 ret dk_test_309: mov eax, 309 ret dk_test_310: mov eax, 310 ret dk_test_311: mov eax, 311 ret dk_test_312: mov eax, 312 ret RunDurakTest3D ENDP