; Compiled only with /DCASINO_ACTION_TEST. Uses the actual game renderer and handlers. .data actionBmpHeader db 42h,4Dh dd 1228854 dw 0,0 dd 54,40,640,-480 dw 1,32 dd 0,1228800,0,0,0,0 actionReportPath db "build\actions\test-report.txt",0 actionReportText db "PASS: fullscreen/startup/audio/dice/2000 roulette rounds; 9021 exact poker rankings, 500 poker hands, 500 blackjack hands; entrance/profiles/merchant; ",13,10 db "hall/basement/bar; multi-bet roulette; billiards impulses/rails/jaws/pockets/fixed timestep/8-ball outcomes; render invariants",13,10 db "Eight-ball: consecutive human pots, real AI scheduling, guide on/off, independent manual calls, group credit on either player's shots and fouls",13,10 db "Buckshot: 250 complete rounds, trigger timing, items/turns/payouts/death/recovery; 30 native scene snapshots",13,10 db "World: complete camera/car route; staff/front bar access; cabaret collision; six pocket throats; 100 varied-force breaks; 3 distinct drinks",13,10 db "Cards: exit/cancel from every active phase, frozen hand, mouse/keyboard, no refunds/double payouts; street lamp/window lightmap",13,10 db "Durak: 500 native complete games, 5184 beat pairs, transfers/takes/refill/trump, 36-card conservation, paging, exit in every phase",13,10 db "777: 8000 stop combinations, 500 complete spins at four rates, monotonic reels, payouts, safe queued exit, native framebuffer snapshots",13,10 db "Coin: 500 paid flips at four rates, safe exit in all phases, 1701 continuous poses, payouts, controls, missing art, 10 native frames",13,10 db "Coin detail: owned window, monitor bounds, restoration, F11, no quit/focus stealing; five private-buffer captures",13,10 actionReportSize equ ($-actionReportText) actionDiceTimes dd 0,200,500,800,1200,1600 actionDice0 db "build\actions\dice-0.bmp",0 actionDice1 db "build\actions\dice-200.bmp",0 actionDice2 db "build\actions\dice-500.bmp",0 actionDice3 db "build\actions\dice-800.bmp",0 actionDice4 db "build\actions\dice-1200.bmp",0 actionDice5 db "build\actions\dice-1600.bmp",0 actionDicePaths dd OFFSET actionDice0,OFFSET actionDice1,OFFSET actionDice2 dd OFFSET actionDice3,OFFSET actionDice4,OFFSET actionDice5 actionRRTimes dd 0,900,1600,700,500,30,200,0,900,2400 actionRRStates dd RR_LOAD,RR_LOAD,RR_LOAD,RR_SPIN,RR_RAISE,RR_FIRE,RR_GLITCH,RR_GMAN,RR_GMAN,RR_GMAN actionRR0 db "build\actions\rr-load-0.bmp",0 actionRR1 db "build\actions\rr-load-900.bmp",0 actionRR2 db "build\actions\rr-load-1600.bmp",0 actionRR3 db "build\actions\rr-spin.bmp",0 actionRR4 db "build\actions\rr-raise.bmp",0 actionRR5 db "build\actions\rr-fire.bmp",0 actionRR6 db "build\actions\rr-glitch.bmp",0 actionRR7 db "build\actions\rr-gman-0.bmp",0 actionRR8 db "build\actions\rr-gman-900.bmp",0 actionRR9 db "build\actions\rr-gman-2400.bmp",0 actionLoadingHand db "build\actions\rr-loading-hand.bmp",0 actionRRPaths dd OFFSET actionRR0,OFFSET actionRR1,OFFSET actionRR2,OFFSET actionRR3,OFFSET actionRR4 dd OFFSET actionRR5,OFFSET actionRR6,OFFSET actionRR7,OFFSET actionRR8,OFFSET actionRR9 actionStartupTimes dd 0,240,700,1300,2500,6500 actionStartup0 db "build\actions\intro-0.bmp",0 actionStartup1 db "build\actions\intro-240.bmp",0 actionStartup2 db "build\actions\intro-700.bmp",0 actionStartup3 db "build\actions\intro-1300.bmp",0 actionStartup4 db "build\actions\intro-2500.bmp",0 actionStartup5 db "build\actions\intro-6500.bmp",0 actionStartupFallback db "build\actions\intro-fallback.bmp",0 actionStartupPaths dd OFFSET actionStartup0,OFFSET actionStartup1,OFFSET actionStartup2 dd OFFSET actionStartup3,OFFSET actionStartup4,OFFSET actionStartup5 actionStudio0 db "build\actions\studio-0.bmp",0 actionStudio1 db "build\actions\studio-240.bmp",0 actionStudio2 db "build\actions\studio-700.bmp",0 actionStudio3 db "build\actions\studio-1300.bmp",0 actionStudio4 db "build\actions\studio-2500.bmp",0 actionStudio5 db "build\actions\studio-6500.bmp",0 actionStudioPaths dd OFFSET actionStudio0,OFFSET actionStudio1,OFFSET actionStudio2 dd OFFSET actionStudio3,OFFSET actionStudio4,OFFSET actionStudio5 .code WriteActionSnapshot3D PROC uses ebx path:DWORD local count:DWORD invoke CreateFileA, path, 40000000h, 0, 0, 2, 80h, 0 cmp eax, -1 je snapshot_failed mov ebx, eax invoke WriteFile, ebx, OFFSET actionBmpHeader, 54, ADDR count, 0 test eax, eax jz snapshot_close_failed invoke WriteFile, ebx, OFFSET screenBuffer, 1228800, ADDR count, 0 test eax, eax jz snapshot_close_failed cmp count, 1228800 jne snapshot_close_failed invoke CloseHandle, ebx mov eax, 1 ret snapshot_close_failed: invoke CloseHandle, ebx snapshot_failed: xor eax, eax ret WriteActionSnapshot3D ENDP include tools\tests\card_tables_test.inc include tools\tests\arrival_test.inc include tools\tests\hall_test.inc include tools\tests\buckshot_test.inc include tools\tests\unavailable_test.inc include tools\tests\card_exit_test.inc include tools\tests\city_lighting_test.inc include tools\tests\durak_test.inc include tools\tests\slots_test.inc include tools\tests\clover_test.inc include tools\tests\pyramid_test.inc include tools\tests\coin_detail_test.inc include tools\tests\coin_test.inc include tools\tests\dice_scene_test.inc include tools\tests\scratch_test.inc include tools\tests\russian_party_test.inc RunCasinoActionsTest3D PROC uses ebx esi edi local savedSeed:DWORD,iterations:DWORD,chamberMask:DWORD,value1:DWORD,value2:DWORD,count:DWORD local testExecutable[260]:BYTE invoke GetModuleFileNameA, 0, ADDR testExecutable, 260 cmp eax, 20 jb @F lea edx, testExecutable sub eax, 20 add eax, edx invoke lstrcmpiA, eax, OFFSET bsPreviewName3D test eax, eax jnz @F call RunBuckshotPreview3D ret @@: ; The actual creation path must be fullscreen before it ever becomes visible. call Create3DWindow test eax, eax jz action_fail_14 cmp fullscreen3D, 1 jne action_fail_14 invoke GetWindowLongA, h3DWnd, -16 test eax, 10000000h jnz action_fail_14 invoke GetWindowRect, h3DWnd, OFFSET clientRect3D lea esi, clientRect3D lea edi, monitor3D[4] mov ecx, 4 repe cmpsd jne action_fail_14 call ToggleFullscreen3D cmp fullscreen3D, 0 jne action_fail_14 invoke GetWindowRect, h3DWnd, OFFSET clientRect3D lea esi, clientRect3D lea edi, savedRect3D mov ecx, 4 repe cmpsd jne action_fail_14 call ToggleFullscreen3D cmp fullscreen3D, 1 jne action_fail_14 call RunScratchPointerTest3D test eax,eax jz action_fail_14 call RunCoinDetailWindowTest3D test eax,eax jz @F ret @@: invoke ReleaseDC, h3DWnd, h3DDC mov h3DDC, 0 invoke DestroyWindow, h3DWnd mov h3DWnd, 0 ; Dirty state cannot bypass the studio screen or turn an Enter into a shot. mov rngSeed3D, 12345678h mov savedSeed, 12345678h mov engineMode, MODE_RUSSIAN mov paused3D, 1 mov interactTargetId, INTERACT_RUSSIAN_ROULETTE mov keys3D[45h], 1 call BeginStartup3D cmp engineMode, MODE_INTRO jne action_fail_15 cmp paused3D, 0 jne action_fail_15 cmp interactTargetId, 0 jne action_fail_15 cmp keys3D[45h], 0 jne action_fail_15 cmp startupPixels3D, 0 je action_fail_15 cmp startupSequence3D, 0 je action_fail_15 cmp startupSequenceHeader3D[12], 100 jne action_fail_15 cmp startupSequenceHeader3D[16], 36 jne action_fail_15 mov startupElapsed3D, 1619 call ResolveStartupFrame3D cmp eax, 35 jne action_fail_15 mov startupElapsed3D, 1620 call ResolveStartupFrame3D cmp eax, 36 jne action_fail_15 mov startupElapsed3D, 4499 call ResolveStartupFrame3D cmp eax, 99 jne action_fail_15 mov startupElapsed3D, 4500 call ResolveStartupFrame3D cmp eax, 36 jne action_fail_15 xor esi, esi action_startup_snapshots: mov eax, actionStartupTimes[esi*4] mov startupElapsed3D, eax call RenderStartup3D mov eax, savedSeed cmp eax, rngSeed3D jne action_fail_15 invoke WriteActionSnapshot3D, actionStartupPaths[esi*4] test eax, eax jz action_fail_15 inc esi cmp esi, 6 jb action_startup_snapshots mov deltaTime3D, 16 mov pressedKeys3D[71h], 1 call HandleStartupInput3D cmp startupVariant3D, 1 jne action_fail_15 xor esi, esi action_studio_snapshots: mov eax, actionStartupTimes[esi*4] mov startupElapsed3D, eax call RenderStartup3D invoke WriteActionSnapshot3D, actionStudioPaths[esi*4] test eax, eax jz action_fail_15 inc esi cmp esi, 6 jb action_studio_snapshots mov deltaTime3D, 16 mov pressedKeys3D[0Dh], 1 mov keys3D[57h], 1 mov pressedKeys3D[45h], 1 call HandleStartupInput3D cmp engineMode, MODE_ARRIVAL jne action_fail_15 cmp keys3D[57h], 0 jne action_fail_15 cmp pressedKeys3D[45h], 0 jne action_fail_15 cmp startupPixels3D, 0 jne action_fail_15 cmp startupSequence3D, 0 jne action_fail_15 ; Missing intro art remains a playable branded screen, not a crash/dialog loop. mov startupPath3D, '_' mov startupSequencePath3D, '_' call BeginStartup3D mov startupPath3D, 'a' mov startupSequencePath3D, 'a' cmp startupPixels3D, 0 jne action_fail_15 mov startupElapsed3D, 2000 call RenderStartup3D invoke WriteActionSnapshot3D, OFFSET actionStartupFallback test eax, eax jz action_fail_15 mov pressedKeys3D[20h], 1 call HandleStartupInput3D cmp engineMode, MODE_ARRIVAL jne action_fail_15 cmp rngSeed3D, 12345678h jne action_fail_15 invoke PlayCasinoSound3D, OFFSET soundClick, 0, 1 cmp lastSoundPath3D, OFFSET soundClick jne action_fail_13 cmp lastSoundFlags3D, 20013h jne action_fail_13 mov bankroll, 10000 mov targetBank, 300000 invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 1 cmp lastSoundPath3D, OFFSET soundRoundWin jne action_fail_13 mov bankroll, 300000 invoke PlayCasinoSound3D, OFFSET soundVictory, 0, 1 cmp lastSoundPath3D, OFFSET soundVictory jne action_fail_13 mov bankroll, 50 invoke PlayCasinoSound3D, OFFSET soundLose, 0, 1 cmp lastSoundPath3D, OFFSET soundRoundLose jne action_fail_13 mov bankroll, 0 invoke PlayCasinoSound3D, OFFSET soundLose, 0, 1 cmp lastSoundPath3D, OFFSET soundLose jne action_fail_13 invoke PlayCasinoSound3D, OFFSET rrDrySound3D, 0, 1 cmp lastSoundPath3D, OFFSET rrDrySound3D jne action_fail_13 cmp lastSoundFlags3D, 20003h jne action_fail_13 mov bankroll, 10000 mov dice3d_bet, 50 mov dice3d_choice, 1 call InitDiceGame mov pressedKeys3D[20h], 1 call HandleDiceInput cmp lastSoundPath3D, OFFSET soundDiceRoll jne action_fail_13 cmp bankroll, 9950 jne action_fail_1 cmp dice3d_state, 1 jne action_fail_1 mov eax, rngSeed3D mov savedSeed, eax mov eax, dice3d_val1 mov value1, eax mov eax, dice3d_val2 mov value2, eax mov deltaTime3D, 16 mov esi, 100 action_dice_updates: call HandleDiceInput dec esi jnz action_dice_updates cmp dice3d_state, 2 jne action_fail_2 mov eax, savedSeed cmp eax, rngSeed3D jne action_fail_2 mov eax, value1 cmp eax, dice3d_val1 jne action_fail_2 add eax, value2 cmp eax, dice3d_sum jne action_fail_2 mov ebx, 9950 test eax, 1 jnz @F add ebx, 100 @@: cmp ebx, bankroll jne action_fail_3 mov deltaTime3D, 50 call HandleDiceInput cmp ebx, bankroll jne action_fail_3 mov dice3d_state, 1 mov dice3d_val1, 4 mov dice3d_val2, 6 xor esi, esi action_dice_snapshots: mov dice3d_sum, 10 mov dice3d_win, 100 mov eax, actionDiceTimes[esi*4] mov dice3d_timer, eax cmp eax, 1600 jne @F mov dice3d_state, 2 @@: call RenderDiceGame mov eax, savedSeed cmp eax, rngSeed3D jne action_fail_4 invoke WriteActionSnapshot3D, actionDicePaths[esi*4] test eax, eax jz action_fail_4 inc esi cmp esi, 6 jb action_dice_snapshots call RunDiceSceneTest3D test eax,eax jz action_fail_4 call RunScratchTest3D cmp eax,1 je @F ret @@: mov engineMode, MODE_RUSSIAN call InitRussianGame3D test eax, eax jz action_fail_5 mov rr3d_bullets, 3 mov rr3d_mask, 25h mov rr3d_shot, 1 xor esi, esi action_rr_snapshots: mov eax, actionRRStates[esi*4] mov rr3d_state, eax mov eax, actionRRTimes[esi*4] mov rr3d_timer, eax call RenderRussianGame3D mov eax, savedSeed cmp eax, rngSeed3D jne action_fail_6 invoke WriteActionSnapshot3D, actionRRPaths[esi*4] test eax, eax jz action_fail_6 inc esi cmp esi, 10 jb action_rr_snapshots mov rr3d_state, RR_LOAD mov rr3d_timer, 270 call RenderRussianGame3D invoke WriteActionSnapshot3D, OFFSET actionLoadingHand test eax, eax jz action_fail_6 ; Fixed empty chamber, then live dealer chamber. No cylinder reroll between turns. mov rr3d_mask, 2 mov rr3d_chamber, 0 mov rr3d_turn, 0 mov rr3d_state, RR_RAISE mov rr3d_bet, 50 mov bankroll, 9950 call AdvanceRussianScene3D cmp rr3d_shot, 0 jne action_fail_7 call AdvanceRussianScene3D cmp rr3d_state, RR_DRY jne action_fail_7 call AdvanceRussianScene3D cmp rr3d_turn, 1 jne action_fail_7 cmp rr3d_chamber, 1 jne action_fail_7 call AdvanceRussianScene3D cmp rr3d_shot, 1 jne action_fail_7 call AdvanceRussianScene3D cmp rr3d_state, RR_WIN jne action_fail_8 cmp bankroll, 10050 jne action_fail_8 call AdvanceRussianScene3D cmp bankroll, 10050 jne action_fail_8 ; Many starting chambers, bullet counts, update rates and first players. mov iterations, 2000 action_round_loop: mov bankroll, 10000 mov rr3d_state, RR_READY mov rr3d_bet, 50 mov eax, iterations xor edx, edx mov ecx, 3 div ecx inc edx mov rr3d_bullets, edx call StartRussianRound3D cmp bankroll, 9950 jne action_fail_9 mov eax, rr3d_mask mov chamberMask, eax xor ecx, ecx mov ebx, eax action_count_bits: shr ebx, 1 adc ecx, 0 test ebx, ebx jnz action_count_bits cmp ecx, rr3d_bullets jne action_fail_9 mov eax, iterations and eax, 1 imul eax, 34 add eax, 16 mov deltaTime3D, eax mov ebx, 0 action_round_tick: mov pressedKeys3D[20h], 1 call HandleRussianInput3D mov eax, chamberMask cmp eax, rr3d_mask jne action_fail_10 inc ebx cmp ebx, 1800 ja action_fail_10 cmp engineMode, MODE_WALK je action_lost cmp rr3d_state, RR_WIN jne action_round_tick cmp bankroll, 10050 jne action_fail_11 jmp action_round_done action_lost: cmp bankroll, 9950 jne action_fail_11 cmp rr3d_state, RR_READY jne action_fail_11 action_round_done: mov engineMode, MODE_RUSSIAN mov pressedKeys3D[20h], 0 dec iterations jnz action_round_loop ; A failed stake must not start a scene or create money. mov bankroll, 0 mov rr3d_state, RR_READY call StartRussianRound3D cmp rr3d_state, RR_READY jne action_fail_12 cmp bankroll, 0 jne action_fail_12 call RunRRPartyTest3D test eax,eax jz @F ret @@: call RunUnavailableTest3D test eax,eax jz @F ret @@: call RunCardTablesTest3D test eax, eax jz @F ret @@: call RunArrivalTest3D test eax, eax jz @F ret @@: call RunCardExitTest3D test eax, eax jz @F ret @@: call RunCityLightingTest3D test eax, eax jz @F ret @@: call RunDurakTest3D test eax, eax jz @F ret @@: call RunBuckshotTest3D test eax, eax jz @F ret @@: call RunSlotsTest3D test eax,eax jz @F ret @@: call RunCloverTest3D test eax,eax jz @F ret @@: call RunCoinTest3D test eax,eax jz @F ret @@: call RunHallTest3D test eax, eax jz @F ret @@: invoke CreateFileA, OFFSET actionReportPath, 40000000h, 0, 0, 2, 80h, 0 cmp eax, -1 je action_fail_12 mov ebx, eax invoke WriteFile, ebx, OFFSET actionReportText, actionReportSize, ADDR count, 0 invoke CloseHandle, ebx call FreeRussianAssets3D call FreeArrivalAssets3D invoke PlaySoundA, 0, 0, 0 xor eax, eax ret action_fail_1: mov eax, 1 ret action_fail_2: mov eax, 2 ret action_fail_3: mov eax, 3 ret action_fail_4: mov eax, 4 ret action_fail_5: mov eax, 5 ret action_fail_6: mov eax, 6 ret action_fail_7: mov eax, 7 ret action_fail_8: mov eax, 8 ret action_fail_9: mov eax, 9 ret action_fail_10: mov eax, 10 ret action_fail_11: mov eax, 11 ret action_fail_12: mov eax, 12 ret action_fail_13: mov eax, 13 ret action_fail_14: mov eax, 14 ret action_fail_15: mov eax, 15 ret RunCasinoActionsTest3D ENDP