GetCapture PROTO .data scratchTestReady3D db "build\actions\scratch-ready.bmp",0 scratchTestCovered3D db "build\actions\scratch-covered.bmp",0 scratchTestPartial3D db "build\actions\scratch-partial.bmp",0 scratchTestResult3D db "build\actions\scratch-result.bmp",0 scratchTestMissing3D db "build\actions\scratch-missing.bmp",0 scratchTestStage3D dd 140 scratchTestCounts3D dd 7 dup(0) scratchTestGrid3D dd 9 dup(0) scratchTypeCapture3D db "build\actions\scratch-kind-0-covered.bmp",0 scratchTypeResult3D db "build\actions\scratch-kind-0-result.bmp",0 .code RunScratchPointerTest3D PROC uses ebx esi edi local oldMode:DWORD,oldW:DWORD,oldH:DWORD,oldLeft:DWORD,oldTop:DWORD,ok:DWORD mov eax,engineMode mov oldMode,eax mov eax,viewWidth3D mov oldW,eax mov eax,viewHeight3D mov oldH,eax mov eax,viewLeft3D mov oldLeft,eax mov eax,viewTop3D mov oldTop,eax mov ok,0 mov engineMode,MODE_SCRATCH mov scrState3D,0 mov viewWidth3D,1280 mov viewHeight3D,960 mov viewLeft3D,20 mov viewTop3D,40 ; (200,195) native -> (420,430) client, including letterbox offsets. invoke WindowEvents3D,h3DWnd,201h,1,01AE01A4h cmp scrPointerX3D,200 jne scratch_pointer_restore cmp scrPointerY3D,195 jne scratch_pointer_restore cmp scrHeld3D,1 jne scratch_pointer_restore invoke GetCapture cmp eax,h3DWnd jne scratch_pointer_restore ; Release outside the viewport still releases capture; quick click survives. invoke WindowEvents3D,h3DWnd,202h,0,0FFFFFFFFh cmp scrHeld3D,0 jne scratch_pointer_restore cmp scrClick3D,1 jne scratch_pointer_restore invoke GetCapture test eax,eax jnz scratch_pointer_restore invoke WindowEvents3D,h3DWnd,201h,1,01AE01A4h invoke WindowEvents3D,h3DWnd,8,0,0 cmp scrHeld3D,0 jne scratch_pointer_restore cmp scrLastValid3D,0 jne scratch_pointer_restore cmp scrPointerValid3D,0 jne scratch_pointer_restore invoke GetCapture test eax,eax jnz scratch_pointer_restore invoke WindowEvents3D,h3DWnd,201h,1,0FFFFFFFFh cmp scrPointerValid3D,0 jne scratch_pointer_restore cmp scrHeld3D,0 jne scratch_pointer_restore mov ok,1 scratch_pointer_restore: call ClearKeys3D mov eax,oldMode mov engineMode,eax mov eax,oldW mov viewWidth3D,eax mov eax,oldH mov viewHeight3D,eax mov eax,oldLeft mov viewLeft3D,eax mov eax,oldTop mov viewTop3D,eax mov eax,ok ret RunScratchPointerTest3D ENDP ScratchTestUncover3D PROC uses ebx esi edi local rowY:DWORD,left:DWORD,right:DWORD mov scrDealMs3D,0 xor esi,esi scratch_uncover_cell: invoke ScratchCellOrigin3D,esi mov left,eax add eax,scrCellW3D dec eax mov right,eax mov rowY,edx mov edi,edx add edi,scrCellH3D scratch_uncover_row: invoke ScratchStroke3D,left,rowY,right,rowY add rowY,6 cmp rowY,edi jb scratch_uncover_row inc esi cmp esi,scrCellCount3D jb scratch_uncover_cell ret ScratchTestUncover3D ENDP RunScratchVariantsTest3D PROC uses ebx esi edi local kind:DWORD,round:DWORD,expected:DWORD,hits:DWORD,total:DWORD,ticketSeed:DWORD mov kind,0 scratch_variant_test_kind: mov scrState3D,0 mov eax,kind mov scrType3D,eax mov round,0 scratch_variant_test_round: mov bankroll,10000 mov scrState3D,0 mov scrPriceIndex3D,0 mov eax,round add eax,47 mov rngSeed3D,eax call BuyScratch3D mov scrDealMs3D,0 cmp scrState3D,1 jne scratch_variants_fail cmp scrNewPixels3D,0 jne scratch_variants_fail xor esi,esi scratch_test_clean_dust: cmp scrDustLife3D[esi*4],0 jne scratch_variants_fail inc esi cmp esi,32 jb scratch_test_clean_dust mov eax,scrGross3D add eax,9950 mov expected,eax mov eax,rngSeed3D mov ticketSeed,eax mov eax,kind inc eax invoke ScratchSelectType3D,eax mov eax,kind cmp scrType3D,eax jne scratch_variants_fail mov hits,0 mov total,0 cmp kind,1 je scratch_test_number_rules cmp kind,2 jne scratch_variant_check_payment xor esi,esi scratch_test_row_rules: mov eax,scrGrid3D[esi*4] cmp eax,scrGrid3D[esi*4+4] jne scratch_test_row_next cmp eax,scrGrid3D[esi*4+8] jne scratch_test_row_next inc hits mov eax,scrMultipliers3D[eax*4] imul eax,scrStake3D add total,eax scratch_test_row_next: add esi,3 cmp esi,9 jb scratch_test_row_rules jmp scratch_test_rule_total scratch_test_number_rules: xor esi,esi scratch_test_number_bounds: mov eax,scrGrid3D[esi*4] dec eax cmp eax,30 jae scratch_variants_fail inc esi cmp esi,9 jb scratch_test_number_bounds mov esi,3 scratch_test_number_cell: xor edi,edi scratch_test_number_match: mov eax,scrGrid3D[edi*4] cmp eax,scrGrid3D[esi*4] jne @F inc hits mov eax,scrCellPrizes3D[esi*4] add total,eax @@: inc edi cmp edi,3 jb scratch_test_number_match inc esi cmp esi,9 jb scratch_test_number_cell scratch_test_rule_total: mov eax,total cmp eax,scrGross3D jne scratch_variants_fail cmp hits,1 ja scratch_variants_fail scratch_variant_check_payment: cmp round,0 jne scratch_variant_quit_test mov eax,kind add al,'0' mov BYTE PTR scratchTypeCapture3D[27],al mov BYTE PTR scratchTypeResult3D[27],al call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTypeCapture3D cmp kind,2 jne @F ; The corner of a circle is paper, not erasable silver. invoke ScratchCellOrigin3D,0 invoke ScratchErasePixel3D,eax,edx cmp scrCounts3D,0 jne scratch_variants_fail @@: call ScratchTestUncover3D cmp scrState3D,2 jne scratch_variants_fail mov eax,scrCellCount3D cmp scrOpened3D,eax jne scratch_variants_fail call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTypeResult3D scratch_variant_quit_test: call SettleScratchOnQuit3D call SettleScratchOnQuit3D mov eax,expected cmp bankroll,eax jne scratch_variants_fail mov eax,ticketSeed cmp rngSeed3D,eax jne scratch_variants_fail inc round cmp round,200 jb scratch_variant_test_round inc kind cmp kind,4 jb scratch_variant_test_kind mov scrState3D,0 invoke ScratchSelectType3D,0 cmp scrType3D,0 jne scratch_variants_fail mov eax,1 ret scratch_variants_fail: mov eax,145 ret RunScratchVariantsTest3D ENDP include tools/tests/scratch_portrait_test.inc include tools/tests/scratch_effects_test.inc RunScratchTest3D PROC uses ebx esi edi local oldBank:DWORD,oldRng:DWORD,paintSeed:DWORD,cleared:DWORD,expected:DWORD,round:DWORD mov eax,bankroll mov oldBank,eax mov eax,rngSeed3D mov oldRng,eax mov scratchTestStage3D,140 mov scrState3D,0 mov scrType3D,0 call BeginScratch3D cmp scrReady3D,1 jne scratch_test_fail cmp scrCounterArt3D.pixels,0 je scratch_test_fail mov scrState3D,0 mov scrPriceIndex3D,0 mov bankroll,10000 call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTestReady3D mov rngSeed3D,47 call BuyScratch3D mov scrDealMs3D,0 cmp bankroll,9950 jne scratch_test_fail cmp scrGross3D,250 jne scratch_test_fail cmp scrPrizeSymbol3D,4 jne scratch_test_fail mov eax,rngSeed3D mov paintSeed,eax call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTestCovered3D mov scratchTestStage3D,141 call BuyScratch3D cmp bankroll,9950 jne scratch_test_fail mov eax,paintSeed cmp rngSeed3D,eax jne scratch_test_fail ; Negative coordinates and panel gutters must not change any coating. invoke ScratchStamp3D,-100,-100 invoke ScratchStamp3D,258,220 cmp scrCounts3D,0 jne scratch_test_fail mov scrHeld3D,0 mov scrPointerValid3D,1 mov scrPointerX3D,200 mov scrPointerY3D,195 call HandleScratch3D cmp scrCounts3D,0 jne scratch_test_fail ; Fast drag, a release, and a second disconnected drag. mov scrHeld3D,1 call HandleScratch3D mov scrPointerX3D,490 call HandleScratch3D mov eax,scrCounts3D mov cleared,eax cmp eax,400 jb scratch_test_fail cmp scrCounts3D[4],400 jb scratch_test_fail cmp scrCounts3D[8],400 jb scratch_test_fail call ScratchCancelStroke3D mov scrPointerX3D,200 mov scrPointerY3D,295 mov scrHeld3D,1 call HandleScratch3D cmp scrCounts3D[12],0 jne scratch_test_fail mov scrPointerValid3D,0 call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTestPartial3D mov scratchTestStage3D,142 call LeaveScratch3D cmp engineMode,MODE_WALK jne scratch_test_fail call BeginScratch3D mov eax,cleared cmp scrCounts3D,eax jne scratch_test_fail mov eax,paintSeed cmp rngSeed3D,eax jne scratch_test_fail cmp bankroll,9950 jne scratch_test_fail call ScratchTestUncover3D cmp scrOpened3D,9 jne scratch_test_fail cmp scrState3D,2 jne scratch_test_fail cmp bankroll,10200 jne scratch_test_fail call FinishScratch3D call SettleScratchOnQuit3D cmp bankroll,10200 jne scratch_test_fail call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTestResult3D mov eax,paintSeed cmp rngSeed3D,eax jne scratch_test_fail mov scratchTestStage3D,143 mov round,0 scratch_test_round: mov scrState3D,0 mov bankroll,10000 mov eax,round xor edx,edx mov ecx,3 div ecx mov scrPriceIndex3D,edx call BuyScratch3D cmp scrState3D,1 jne scratch_test_fail mov eax,10000 sub eax,scrStake3D mov expected,eax cmp bankroll,eax jne scratch_test_fail lea edi,scratchTestCounts3D xor eax,eax mov ecx,7 rep stosd xor esi,esi scratch_test_grid: mov eax,scrGrid3D[esi*4] cmp eax,6 ja scratch_test_fail inc scratchTestCounts3D[eax*4] inc esi cmp esi,9 jb scratch_test_grid xor esi,esi scratch_test_triples: cmp esi,scrPrizeSymbol3D jne scratch_test_other_count cmp scratchTestCounts3D[esi*4],3 jne scratch_test_fail mov eax,scrMultipliers3D[esi*4] imul eax,scrStake3D cmp scrGross3D,eax jne scratch_test_fail jmp scratch_test_next_count scratch_test_other_count: cmp scratchTestCounts3D[esi*4],2 ja scratch_test_fail scratch_test_next_count: inc esi cmp esi,7 jb scratch_test_triples mov eax,scrGross3D add expected,eax mov eax,rngSeed3D mov paintSeed,eax call BuyScratch3D mov eax,paintSeed cmp rngSeed3D,eax jne scratch_test_fail ; Normal exit pays the pending amount once without further RNG. call SettleScratchOnQuit3D call SettleScratchOnQuit3D mov eax,expected cmp bankroll,eax jne scratch_test_fail mov eax,paintSeed cmp rngSeed3D,eax jne scratch_test_fail inc round cmp round,500 jb scratch_test_round mov scratchTestStage3D,144 mov bankroll,0 mov scrState3D,0 call BuyScratch3D cmp scrState3D,0 jne scratch_test_fail cmp scrError3D,1 jne scratch_test_fail mov scrState3D,1 mov scrOpened3D,9 mov scrGross3D,12500 mov bankroll,999999990 call FinishScratch3D cmp bankroll,1000000000 jne scratch_test_fail call RunScratchVariantsTest3D cmp eax,1 jne scratch_test_extra_fail call RunScratchPortraitTest3D cmp eax,1 jne scratch_test_extra_fail call RunScratchCatalogTest3D cmp eax,1 jne scratch_test_extra_fail call RunScratchEffectsTest3D cmp eax,1 je @F scratch_test_extra_fail: mov scratchTestStage3D,eax jmp scratch_test_fail @@: mov scrReady3D,0 call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchTestMissing3D mov scrReady3D,1 mov scrState3D,0 mov scrOpened3D,0 mov scrError3D,0 mov scrGross3D,0 mov scrPriceIndex3D,0 mov eax,oldBank mov bankroll,eax mov eax,oldRng mov rngSeed3D,eax call ClearKeys3D mov eax,1 ret scratch_test_fail: mov eax,scratchTestStage3D ret RunScratchTest3D ENDP