.data scratchFXDeal3D db "build\actions\scratch-deal-" scratchFXKind3D db "0-rate-" scratchFXRate3D db "0-frame-" scratchFXFrameTens3D db "0" scratchFXFrameOnes3D db "0.bmp",0 scratchFXPay3D db "build\actions\scratch-payout-" scratchFXPayTens3D db "0" scratchFXPayOnes3D db "0.bmp",0 scratchFXSteps3D dd 10,15,30 .code RunScratchEffectsTest3D PROC uses ebx esi edi local kind:DWORD,rate:DWORD,frame:DWORD,elapsedMs:DWORD,targetMs:DWORD,cosmeticRng:DWORD mov kind,0 scratch_fx_kind: mov rate,0 scratch_fx_rate: mov scrState3D,0 mov eax,kind mov scrType3D,eax mov scrPriceIndex3D,0 mov bankroll,10000 mov rngSeed3D,47 call BuyScratch3D cmp scrDealMs3D,900 jne scratch_fx_fail cmp lastSoundPath3D,OFFSET scrPaperSound3D jne scratch_fx_fail mov eax,rngSeed3D mov cosmeticRng,eax invoke ScratchStamp3D,200,195 cmp scrCounts3D,0 jne scratch_fx_fail mov eax,kind add eax,'0' mov scratchFXKind3D,al mov eax,rate add eax,'0' mov scratchFXRate3D,al mov frame,0 mov elapsedMs,0 mov scrPointerValid3D,0 scratch_fx_deal_frame: imul eax,frame,30 mov targetMs,eax scratch_fx_deal_tick: mov eax,elapsedMs cmp eax,targetMs jae scratch_fx_deal_render mov eax,rate mov eax,scratchFXSteps3D[eax*4] mov deltaTime3D,eax add elapsedMs,eax call ScratchTickVisuals3D jmp scratch_fx_deal_tick scratch_fx_deal_render: mov eax,frame xor edx,edx mov ecx,10 div ecx add eax,'0' add edx,'0' mov scratchFXFrameTens3D,al mov scratchFXFrameOnes3D,dl call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchFXDeal3D mov eax,cosmeticRng cmp rngSeed3D,eax jne scratch_fx_fail cmp bankroll,9950 jne scratch_fx_fail inc frame cmp frame,31 jb scratch_fx_deal_frame cmp scrDealMs3D,0 jne scratch_fx_fail inc rate cmp rate,3 jb scratch_fx_rate add kind,4 cmp kind,4 jbe scratch_fx_kind ; A fixed winning ticket exercises payout without touching the save file. xor esi,esi scratch_fx_winning_fixture: lea eax,[esi+1] mov scrGrid3D[esi*4],eax mov scrCellPrizes3D[esi*4],50 inc esi cmp esi,scrCellCount3D jb scratch_fx_winning_fixture mov esi,scrPortraitWins3D mov scrGrid3D[esi*4],1 mov scrCellPrizes3D[esi*4],250 call ScratchPortraitPayout3D mov scrGross3D,eax call ScratchTestUncover3D cmp scrPayoutMs3D,1800 jne scratch_fx_fail cmp lastSoundPath3D,OFFSET scrPayoutSound3D jne scratch_fx_fail cmp bankroll,10200 jne scratch_fx_fail mov frame,0 scratch_fx_payout_frame: mov eax,frame xor edx,edx mov ecx,10 div ecx add eax,'0' add edx,'0' mov scratchFXPayTens3D,al mov scratchFXPayOnes3D,dl call RenderScratch3D invoke WriteActionSnapshot3D,OFFSET scratchFXPay3D call FinishScratch3D cmp bankroll,10200 jne scratch_fx_fail mov deltaTime3D,75 call ScratchTickVisuals3D inc frame cmp frame,25 jb scratch_fx_payout_frame mov eax,cosmeticRng cmp rngSeed3D,eax jne scratch_fx_fail ; Dust uses a private RNG and only starts audio when fresh coating is removed. mov scrState3D,0 mov scrType3D,0 call ScratchConfigure3D mov scrState3D,1 mov scrHeld3D,0 mov scrPointerX3D,200 mov scrPointerY3D,195 mov scrNewPixels3D,1 mov deltaTime3D,0 call HandleScratch3D cmp lastSoundPath3D,OFFSET scrScrapeSound3D jne scratch_fx_fail cmp scrDustIndex3D,3 jne scratch_fx_fail mov lastSoundPath3D,0 mov scrNewPixels3D,1 call HandleScratch3D cmp lastSoundPath3D,0 jne scratch_fx_fail mov deltaTime3D,16 mov edi,140 scratch_fx_dust_tick: call ScratchTickVisuals3D dec edi jnz scratch_fx_dust_tick xor esi,esi scratch_fx_dust_expired: cmp scrDustLife3D[esi*4],0 jne scratch_fx_fail inc esi cmp esi,SCR_DUST_COUNT jb scratch_fx_dust_expired mov eax,cosmeticRng cmp rngSeed3D,eax jne scratch_fx_fail mov scrState3D,0 mov eax,1 ret scratch_fx_fail: mov eax,148 ret RunScratchEffectsTest3D ENDP