KAZIK/tools/tests/scratch_test.inc
Игорь Федосеев ca62db53e9 feat: implement native billiards, scratch tickets, first-person dice, and city wake scene
- Billiards: add native Russian Pyramid & American Eight-Ball pool with physics prediction, controls, and regression tests
- Scratch Tickets: add dedicated counter, mat presentation, elliptical coin scraping, 4 ticket types, and payout effects
- First-Person Dice: add native dice scene, hand anchor frames, throwing animation, and table perspective
- City Wake & Weather: add arrival cutscene, alley geometry, weather/rain effects, and lighter/rocker animation
- World Dressing: add hall paintings, furniture packs, hall lighting, and scene regression tests
- Build & Tooling: update build.bat for modern MSVC toolchain, update launcher hash, and refresh shipping binaries
2026-10-16 12:37:40 +03:00

481 lines
12 KiB
PHP

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