; Source-space masks keep the supplied ticket art intact across both views. ScratchPortraitField3D PROC cell:DWORD mov eax,scrType3D sub eax,4 imul eax,24 add eax,cell shl eax,4 add eax,OFFSET scrPortraitFields3D ret ScratchPortraitField3D ENDP ScratchPortraitMapBase3D PROC mov eax,scrType3D sub eax,4 imul eax,540*720*4 add eax,scrPortraitMap3D.pixels ret ScratchPortraitMapBase3D ENDP ScratchPortraitView3D PROC mov scrViewX3D,194 mov scrViewY3D,46 mov scrViewW3D,252 mov scrViewH3D,336 cmp scrZoom3D,0 je @F mov scrViewX3D,68 mov scrViewY3D,-230 mov scrViewW3D,504 mov scrViewH3D,672 cmp scrDealMs3D,0 je @F mov eax,350 sub eax,scrDealMs3D jns portrait_view_ease xor eax,eax portrait_view_ease: invoke ScratchEase3D,eax,350 imul ecx,eax,252 sar ecx,8 add ecx,252 mov scrViewW3D,ecx imul ecx,eax,336 sar ecx,8 add ecx,336 mov scrViewH3D,ecx imul ecx,eax,126 sar ecx,8 neg ecx add ecx,194 mov scrViewX3D,ecx imul ecx,eax,276 sar ecx,8 neg ecx add ecx,46 mov scrViewY3D,ecx @@: ret ScratchPortraitView3D ENDP ScratchToggleZoom3D PROC cmp scrDealMs3D,0 jne @F cmp scrType3D,4 jb @F xor scrZoom3D,1 call ScratchCancelStroke3D @@: ret ScratchToggleZoom3D ENDP ScratchConfigurePortrait3D PROC uses ebx esi edi local rowY:DWORD,pointX:DWORD,fieldPtr:DWORD,mapBase:DWORD,maskBase:DWORD mov eax,scrType3D sub eax,4 mov ecx,scrPortraitWinning3D[eax*4] mov scrPortraitWins3D,ecx add ecx,scrPortraitPlayers3D[eax*4] mov scrCellCount3D,ecx lea edi,scrPortraitMask3D xor eax,eax mov ecx,24*SCR_PORTRAIT_STRIDE rep stosb lea edi,scrPortraitAreas3D mov ecx,24 rep stosd cmp scrPortraitMap3D.pixels,0 je portrait_config_done call ScratchPortraitMapBase3D mov mapBase,eax xor esi,esi portrait_config_field: invoke ScratchPortraitField3D,esi mov fieldPtr,eax imul eax,esi,SCR_PORTRAIT_STRIDE add eax,OFFSET scrPortraitMask3D mov maskBase,eax mov rowY,0 portrait_config_row: mov pointX,0 portrait_config_pixel: mov ebx,fieldPtr mov eax,rowY add eax,[ebx+4] imul eax,540 add eax,[ebx] add eax,pointX mov edx,mapBase movzx eax,BYTE PTR [edx+eax*4] dec eax cmp eax,esi jne portrait_config_next mov eax,rowY imul eax,[ebx+8] add eax,pointX mov edi,maskBase mov BYTE PTR [edi+eax],255 inc scrPortraitAreas3D[esi*4] portrait_config_next: inc pointX mov eax,pointX cmp eax,[ebx+8] jb portrait_config_pixel inc rowY mov eax,rowY cmp eax,[ebx+12] jb portrait_config_row inc esi cmp esi,scrCellCount3D jb portrait_config_field portrait_config_done: ret ScratchConfigurePortrait3D ENDP ScratchPortraitBounds3D PROC uses ebx esi cell:DWORD local left:DWORD,top:DWORD call ScratchPortraitView3D invoke ScratchPortraitField3D,cell mov esi,eax mov eax,[esi] imul eax,scrViewW3D xor edx,edx mov ebx,540 div ebx add eax,scrViewX3D mov left,eax mov eax,[esi] add eax,[esi+8] imul eax,scrViewW3D xor edx,edx div ebx add eax,scrViewX3D sub eax,left inc eax mov scrCellW3D,eax mov eax,[esi+4] imul eax,scrViewH3D xor edx,edx mov ebx,720 div ebx add eax,scrViewY3D mov top,eax mov eax,[esi+4] add eax,[esi+12] imul eax,scrViewH3D xor edx,edx div ebx add eax,scrViewY3D sub eax,top inc eax mov scrCellH3D,eax mov eax,left mov edx,top ret ScratchPortraitBounds3D ENDP ScratchPortraitHit3D PROC uses ebx px:DWORD,py:DWORD cmp scrPortraitMap3D.pixels,0 je portrait_hit_no cmp py,40 jb portrait_hit_no cmp py,388 jae portrait_hit_no call ScratchPortraitView3D mov eax,px sub eax,scrViewX3D cmp eax,scrViewW3D jae portrait_hit_no imul eax,540 xor edx,edx div scrViewW3D mov scrHitX3D,eax mov eax,py sub eax,scrViewY3D cmp eax,scrViewH3D jae portrait_hit_no imul eax,720 xor edx,edx div scrViewH3D mov scrHitY3D,eax imul ebx,eax,540 add ebx,scrHitX3D call ScratchPortraitMapBase3D movzx eax,BYTE PTR [eax+ebx*4] dec eax cmp eax,scrCellCount3D jb portrait_hit_done portrait_hit_no: mov eax,-1 portrait_hit_done: ret ScratchPortraitHit3D ENDP ScratchErasePortrait3D PROC uses ebx esi edi px:DWORD,py:DWORD local rowY:DWORD,startX:DWORD,endX:DWORD,endY:DWORD invoke ScratchPortraitHit3D,px,py cmp eax,-1 je portrait_erase_done mov esi,eax cmp scrRevealed3D[esi*4],0 jne portrait_erase_done invoke ScratchPortraitField3D,esi mov ebx,eax imul edi,esi,SCR_PORTRAIT_STRIDE add edi,OFFSET scrPortraitMask3D ; A screen pixel covers multiple source pixels in the full-ticket view. mov eax,scrHitX3D sub eax,[ebx] mov startX,eax mov eax,540 add eax,scrViewW3D dec eax xor edx,edx div scrViewW3D add eax,startX cmp eax,[ebx+8] jbe @F mov eax,[ebx+8] @@: mov endX,eax mov eax,scrHitY3D sub eax,[ebx+4] mov rowY,eax mov eax,720 add eax,scrViewH3D dec eax xor edx,edx div scrViewH3D add eax,rowY cmp eax,[ebx+12] jbe @F mov eax,[ebx+12] @@: mov endY,eax portrait_erase_row: mov eax,rowY imul eax,[ebx+8] add eax,startX mov ecx,startX portrait_erase_point: cmp BYTE PTR [edi+eax],0 je portrait_erase_next mov BYTE PTR [edi+eax],0 inc scrCounts3D[esi*4] inc scrNewPixels3D portrait_erase_next: inc eax inc ecx cmp ecx,endX jb portrait_erase_point inc rowY mov eax,rowY cmp eax,endY jb portrait_erase_row mov eax,scrCounts3D[esi*4] imul eax,100 imul edx,scrPortraitAreas3D[esi*4],72 cmp eax,edx jb portrait_erase_done mov scrRevealed3D[esi*4],1 mov eax,scrPortraitAreas3D[esi*4] mov scrCounts3D[esi*4],eax xor eax,eax mov ecx,SCR_PORTRAIT_STRIDE rep stosb inc scrOpened3D call FinishScratch3D portrait_erase_done: ret ScratchErasePortrait3D ENDP ScratchBuildPortrait3D PROC uses ebx esi edi local first:DWORD,chosen:DWORD xor esi,esi portrait_pool: lea eax,[esi+1] mov scrBag3D[esi*4],eax inc esi cmp esi,60 jb portrait_pool mov esi,59 portrait_shuffle: lea eax,[esi+1] invoke RandomRange3D,eax mov ebx,scrBag3D[esi*4] mov edx,scrBag3D[eax*4] mov scrBag3D[esi*4],edx mov scrBag3D[eax*4],ebx dec esi jnz portrait_shuffle xor esi,esi portrait_fill: mov eax,scrBag3D[esi*4] mov scrGrid3D[esi*4],eax invoke RandomRange3D,7 mov eax,scrMultipliers3D[eax*4] imul eax,scrStake3D mov scrCellPrizes3D[esi*4],eax inc esi cmp esi,scrCellCount3D jb portrait_fill mov scrPortraitOutcome3D,0 invoke RandomRange3D,1000 push eax call BackroomsLuck3D pop edx cmp eax,-1 je br_portrait_original imul eax,920 jmp br_portrait_fixed br_portrait_original: mov eax,edx br_portrait_fixed: cmp eax,600 jb portrait_build_payout mov ebx,eax mov eax,scrCellCount3D sub eax,scrPortraitWins3D invoke RandomRange3D,eax add eax,scrPortraitWins3D mov esi,eax cmp ebx,900 jb portrait_number_win cmp ebx,980 jb portrait_double_win cmp scrType3D,4 je portrait_ten_win cmp ebx,995 jae portrait_all_win mov scrPortraitOutcome3D,4 mov scrCellPrizes3D[esi*4],0 mov eax,scrStake3D mov scrCellPrizes3D[esi*4],eax mov eax,scrGrid3D mov scrGrid3D[esi*4],eax inc esi cmp esi,scrCellCount3D jb @F mov esi,scrPortraitWins3D @@: mov eax,scrGrid3D[4] mov scrGrid3D[esi*4],eax mov eax,scrStake3D mov scrCellPrizes3D[esi*4],eax jmp portrait_build_payout portrait_number_win: mov scrPortraitOutcome3D,1 invoke RandomRange3D,scrPortraitWins3D mov eax,scrGrid3D[eax*4] mov scrGrid3D[esi*4],eax invoke RandomRange3D,1000 mov ebx,700 mov edi,990 cmp scrType3D,4 je @F mov ebx,650 mov edi,980 @@: mov ecx,1 cmp eax,ebx jb portrait_number_amount mov ecx,2 add ebx,200 cmp eax,ebx jb portrait_number_amount mov ecx,5 cmp eax,edi jb portrait_number_amount mov ecx,25 portrait_number_amount: imul ecx,scrStake3D mov scrCellPrizes3D[esi*4],ecx jmp portrait_build_payout portrait_double_win: mov scrPortraitOutcome3D,2 mov scrGrid3D[esi*4],61 mov eax,scrStake3D mov scrCellPrizes3D[esi*4],eax jmp portrait_build_payout portrait_ten_win: mov scrPortraitOutcome3D,3 mov scrGrid3D[esi*4],62 mov eax,scrStake3D mov scrCellPrizes3D[esi*4],eax jmp portrait_build_payout portrait_all_win: mov scrPortraitOutcome3D,5 mov scrGrid3D[esi*4],62 mov esi,scrPortraitWins3D mov eax,scrStake3D xor edx,edx mov ecx,5 div ecx portrait_all_amount: mov scrCellPrizes3D[esi*4],eax inc esi cmp esi,scrCellCount3D jb portrait_all_amount portrait_build_payout: call ScratchPortraitPayout3D mov scrGross3D,eax ret ScratchBuildPortrait3D ENDP ; All-prizes overrides the individual awards, rather than paying them twice. ScratchPortraitPayout3D PROC uses ebx esi edi local total:DWORD,allPrizes:DWORD mov total,0 mov allPrizes,0 mov esi,scrPortraitWins3D portrait_award: mov scrAwards3D[esi*4],0 mov eax,scrGrid3D[esi*4] cmp eax,61 je portrait_award_double cmp eax,62 je portrait_award_special xor edi,edi portrait_award_match: cmp eax,scrGrid3D[edi*4] je portrait_award_normal inc edi cmp edi,scrPortraitWins3D jb portrait_award_match jmp portrait_award_next portrait_award_normal: mov eax,scrCellPrizes3D[esi*4] jmp portrait_award_store portrait_award_double: imul eax,scrCellPrizes3D[esi*4],2 jmp portrait_award_store portrait_award_special: cmp scrType3D,4 je portrait_award_ten mov allPrizes,1 jmp portrait_award_next portrait_award_ten: imul eax,scrCellPrizes3D[esi*4],10 portrait_award_store: mov scrAwards3D[esi*4],eax add total,eax portrait_award_next: inc esi cmp esi,scrCellCount3D jb portrait_award cmp allPrizes,0 je portrait_award_done mov total,0 mov esi,scrPortraitWins3D portrait_award_all: mov eax,scrCellPrizes3D[esi*4] mov scrAwards3D[esi*4],eax add total,eax inc esi cmp esi,scrCellCount3D jb portrait_award_all portrait_award_done: mov eax,total ret ScratchPortraitPayout3D ENDP ScratchPortraitLayers3D PROC uses ebx esi edi coating:DWORD local cell:DWORD,fieldPtr:DWORD,mapBase:DWORD,left:DWORD,top:DWORD,right:DWORD,bottom:DWORD local screenX:DWORD,screenY:DWORD,sourceRow:DWORD,sourceY:DWORD,sourceX:DWORD,maskRow:DWORD call ScratchPortraitMapBase3D mov mapBase,eax mov cell,0 portrait_layer_cell: invoke ScratchPortraitBounds3D,cell mov left,eax add eax,scrCellW3D mov right,eax mov top,edx add edx,scrCellH3D mov bottom,edx invoke ScratchPortraitField3D,cell mov fieldPtr,eax mov eax,top mov screenY,eax portrait_layer_row: cmp screenY,40 jb portrait_layer_next_row cmp screenY,388 jae portrait_layer_next_row mov eax,screenY sub eax,scrViewY3D imul eax,720 xor edx,edx div scrViewH3D mov sourceY,eax imul eax,540 mov sourceRow,eax mov ebx,fieldPtr mov eax,sourceY sub eax,[ebx+4] cmp eax,[ebx+12] jae portrait_layer_next_row imul eax,[ebx+8] imul edx,cell,SCR_PORTRAIT_STRIDE add eax,edx mov maskRow,eax mov eax,left mov screenX,eax portrait_layer_pixel: cmp screenX,640 jae portrait_layer_next_pixel mov eax,screenX sub eax,scrViewX3D imul eax,540 xor edx,edx div scrViewW3D mov sourceX,eax add eax,sourceRow mov edi,mapBase movzx eax,BYTE PTR [edi+eax*4] dec eax cmp eax,cell jne portrait_layer_next_pixel mov ebx,fieldPtr mov eax,sourceX sub eax,[ebx] add eax,maskRow cmp coating,0 je portrait_layer_paper ; Coating is indexed in source pixels so zoom cannot restore old scratches. cmp scrPortraitMask3D[eax],0 je portrait_layer_next_pixel mov eax,sourceY xor edx,edx mov ecx,42 div ecx imul esi,edx,104 mov eax,sourceX xor edx,edx mov ecx,104 div ecx add esi,edx mov edi,scrFoilArt3D.pixels mov eax,[edi+esi*4] jmp portrait_layer_write portrait_layer_paper: mov eax,00F3EBD7h cmp scrState3D,2 jne portrait_layer_write mov edx,cell cmp edx,scrPortraitWins3D jb portrait_layer_write cmp scrAwards3D[edx*4],0 je portrait_layer_write mov eax,00D5EFDCh portrait_layer_write: imul edx,screenY,640 add edx,screenX mov screenBuffer[edx*4],eax portrait_layer_next_pixel: inc screenX mov eax,screenX cmp eax,right jb portrait_layer_pixel portrait_layer_next_row: inc screenY mov eax,screenY cmp eax,bottom jb portrait_layer_row inc cell mov eax,cell cmp eax,scrCellCount3D jb portrait_layer_cell ret ScratchPortraitLayers3D ENDP ScratchPortraitText3D PROC uses ebx esi edi cell:DWORD local left:DWORD,top:DWORD,ink:DWORD,textPtr:DWORD invoke ScratchPortraitBounds3D,cell mov left,eax mov top,edx mov esi,cell mov ink,00303B32h cmp esi,scrPortraitWins3D jb @F cmp scrAwards3D[esi*4],0 je @F mov ink,00056837h @@: mov eax,scrGrid3D[esi*4] cmp eax,61 je portrait_text_double cmp eax,62 je portrait_text_special invoke FormatNumber,eax,OFFSET hudNumBuffer mov textPtr,OFFSET hudNumBuffer jmp portrait_text_number portrait_text_double: mov textPtr,OFFSET scrDouble3D jmp portrait_text_number portrait_text_special: mov textPtr,OFFSET scrTen3D cmp scrType3D,4 je portrait_text_number mov textPtr,OFFSET scratchAll3D portrait_text_number: mov edi,textPtr xor ecx,ecx portrait_text_length: cmp BYTE PTR [edi+ecx],0 je @F inc ecx jmp portrait_text_length @@: shl ecx,3 mov eax,scrCellW3D sub eax,ecx sar eax,1 add eax,left mov ebx,eax mov eax,scrCellH3D shr eax,1 add eax,top sub eax,4 cmp esi,scrPortraitWins3D jb @F cmp scrZoom3D,0 je @F sub eax,7 @@: invoke DrawBuckshotText3D,ebx,eax,textPtr,ink cmp esi,scrPortraitWins3D jb portrait_text_done cmp scrZoom3D,0 je portrait_text_done invoke FormatNumber,scrCellPrizes3D[esi*4],OFFSET hudNumBuffer lea edi,hudNumBuffer xor ecx,ecx portrait_prize_length: cmp BYTE PTR [edi+ecx],0 je @F inc ecx jmp portrait_prize_length @@: shl ecx,3 mov eax,scrCellW3D sub eax,ecx sar eax,1 add eax,left mov ebx,eax mov eax,scrCellH3D shr eax,1 add eax,top add eax,4 invoke DrawBuckshotText3D,ebx,eax,OFFSET hudNumBuffer,ink portrait_text_done: ret ScratchPortraitText3D ENDP ScratchPortraitInfo3D PROC uses ebx esi edi invoke DrawBox,4,44,88,35,0014191Dh invoke DrawBuckshotText3D,16,100,OFFSET scratchMatch3D,00E5D29Eh mov eax,OFFSET scratchNeonDouble3D mov ebx,OFFSET scratchNeonTen3D cmp scrType3D,4 je portrait_info_rules mov eax,OFFSET scratchRubyDouble3D mov ebx,OFFSET scratchRubyAll3D cmp scrType3D,5 je portrait_info_rules mov eax,OFFSET scratchSeaDouble3D mov ebx,OFFSET scratchSeaAll3D portrait_info_rules: invoke DrawBuckshotText3D,16,120,eax,00E5D29Eh invoke DrawBuckshotText3D,16,140,ebx,00E5D29Eh cmp scrPointerValid3D,1 jne portrait_info_done invoke ScratchPortraitHit3D,scrPointerX3D,scrPointerY3D cmp eax,-1 je portrait_info_done mov esi,eax cmp scrRevealed3D[esi*4],1 jne portrait_info_done invoke DrawBox,4,88,88,50,0014191Dh invoke DrawBuckshotText3D,16,190,OFFSET scratchField3D,00ADB9BCh lea eax,[esi+1] invoke FormatNumber,eax,OFFSET hudNumBuffer invoke DrawString8x8,8,102,OFFSET hudNumBuffer,00FFFFFFh cmp esi,scrPortraitWins3D jb portrait_info_done invoke DrawBuckshotText3D,16,240,OFFSET scratchPayout3D,00ADB9BCh invoke FormatNumber,scrAwards3D[esi*4],OFFSET hudNumBuffer invoke DrawString8x8,8,128,OFFSET hudNumBuffer,0090D5ADh portrait_info_done: ret ScratchPortraitInfo3D ENDP RenderScratchPortrait3D PROC uses esi call ScratchPortraitView3D mov eax,scrType3D sub eax,4 invoke DrawAnimSprite3D,OFFSET scrPortraitArt3D,eax,scrViewX3D,scrViewY3D,scrViewW3D,scrViewH3D invoke ScratchPortraitLayers3D,0 cmp scrState3D,0 je portrait_render_foil xor esi,esi portrait_render_text: invoke ScratchPortraitText3D,esi inc esi cmp esi,scrCellCount3D jb portrait_render_text portrait_render_foil: invoke ScratchPortraitLayers3D,1 ret RenderScratchPortrait3D ENDP