FreeNativeSlots3D PROC invoke FreeAnimPack3D, OFFSET slotCabinetPack3D invoke FreeAnimPack3D, OFFSET slotSymbolsPack3D ret FreeNativeSlots3D ENDP InitNativeSlots3D PROC invoke LoadAnimPack3D, OFFSET slotCabinetPack3D, OFFSET slotCabinetPath3D test eax,eax jz slot_init_fail cmp slotCabinetPack3D.imageWidth,640 jne slot_init_fail cmp slotCabinetPack3D.height,480 jne slot_init_fail cmp slotCabinetPack3D.frames,1 jne slot_init_fail invoke LoadAnimPack3D, OFFSET slotSymbolsPack3D, OFFSET slotSymbolsPath3D test eax,eax jz slot_init_fail cmp slotSymbolsPack3D.imageWidth,64 jne slot_init_fail cmp slotSymbolsPack3D.height,64 jne slot_init_fail cmp slotSymbolsPack3D.frames,8 jne slot_init_fail mov slotSpinState,SLOT_READY mov slotSpinTimer,0 mov slotWinAmount,0 mov slotStake3D,0 mov slotLeaveAfter3D,0 mov slotPaytable3D,0 mov slotError3D,0 mov slotEffects3D,0 mov slotBetIndex3D,1 mov slotBet,50 mov cardExitActive3D,0 mov paused3D,0 call ClearKeys3D mov eax,1 ret slot_init_fail: call FreeNativeSlots3D xor eax,eax ret InitNativeSlots3D ENDP ; Results are sampled once at stake debit. Rendering never consumes RNG or pays. StartNativeSlots3D PROC uses ebx esi cmp slotSpinState,SLOT_SPIN je slot_start_done cmp slotPaytable3D,0 jne slot_start_done cmp slotCabinetPack3D.pixels,0 je slot_start_done cmp slotSymbolsPack3D.pixels,0 je slot_start_done mov eax,slotBet test eax,eax jz slot_start_done cmp eax,10000 ja slot_start_done cmp eax,bankroll ja slot_start_money sub bankroll,eax mov slotStake3D,eax mov slotSpinState,SLOT_SPIN mov slotSpinTimer,0 mov slotWinAmount,0 mov slotLeaveAfter3D,0 mov slotError3D,0 mov slotEffects3D,0 xor esi,esi slot_start_reel: mov eax,slotStops3D[esi*4] mov slotStartStops3D[esi*4],eax invoke RandomRange3D,20 mov slotTargets3D[esi*4],eax mov edx,slotStrip3D[eax*4] mov slotReel1[esi*4],edx sub eax,slotStartStops3D[esi*4] jns @F add eax,20 @@: add eax,slotCycles3D[esi*4] shl eax,6 mov slotTravel3D[esi*4],eax inc esi cmp esi,3 jb slot_start_reel call SaveProgress3D invoke PlayCasinoSound3D, OFFSET soundSlotSpin,0,1 ret slot_start_money: mov slotError3D,1 slot_start_done: ret StartNativeSlots3D ENDP ; Gross multipliers. A cherry pair pays 2x, any other pair returns the stake. SlotMultiplier3D PROC first:DWORD,second:DWORD,third:DWORD mov eax,first cmp eax,7 ja slot_multiplier_zero cmp second,7 ja slot_multiplier_zero cmp third,7 ja slot_multiplier_zero cmp eax,second jne slot_multiplier_other_pair cmp eax,third jne slot_multiplier_pair mov eax,slotTriple3D[eax*4] ret slot_multiplier_other_pair: cmp eax,third je slot_multiplier_pair mov eax,second cmp eax,third jne slot_multiplier_zero slot_multiplier_pair: cmp eax,1 jne @F mov eax,2 ret @@: mov eax,1 ret slot_multiplier_zero: xor eax,eax ret SlotMultiplier3D ENDP SettleNativeSlots3D PROC uses esi cmp slotSpinState,SLOT_SPIN jne slot_settle_done invoke SlotMultiplier3D,slotReel1,slotReel2,slotReel3 mul slotStake3D mov slotWinAmount,eax add bankroll,eax jc slot_settle_cap cmp bankroll,1000000000 jbe @F slot_settle_cap: mov bankroll,1000000000 @@: xor esi,esi slot_settle_stops: mov eax,slotTargets3D[esi*4] mov slotStops3D[esi*4],eax inc esi cmp esi,3 jb slot_settle_stops mov slotSpinTimer,3000 mov slotSpinState,SLOT_RESULT mov slotEffects3D,0 call SaveProgress3D cmp slotWinAmount,0 je slot_settle_loss invoke PlayCasinoSound3D,OFFSET soundRoundWin,0,1 jmp slot_settle_exit slot_settle_loss: invoke PlayCasinoSound3D,OFFSET soundRoundLose,0,1 slot_settle_exit: cmp slotLeaveAfter3D,0 je slot_settle_done call SlotEscape3D slot_settle_done: ret SettleNativeSlots3D ENDP ; Escape queues a safe exit during a paid spin; it never opens the pause menu. SlotEscape3D PROC mov paused3D,0 cmp slotPaytable3D,0 je @F mov slotPaytable3D,0 call ClearKeys3D ret @@: cmp slotSpinState,SLOT_SPIN jne slot_exit_hall mov slotLeaveAfter3D,1 call ClearKeys3D ret slot_exit_hall: mov slotLeaveAfter3D,0 mov paused3D,0 mov engineMode,MODE_WALK call ClearKeys3D invoke PlayCasinoSound3D,0,0,0 ret SlotEscape3D ENDP ; A monotonic quadratic ease-out maps elapsed milliseconds to strip pixels. SlotReelPosition3D PROC uses ebx index:DWORD mov ebx,index cmp ebx,2 ja slot_position_zero mov eax,slotStops3D[ebx*4] shl eax,6 cmp slotSpinState,SLOT_SPIN jne slot_position_done mov eax,slotSpinTimer cmp eax,slotDurations3D[ebx*4] jae slot_position_end shl eax,10 xor edx,edx div slotDurations3D[ebx*4] mov ecx,2048 sub ecx,eax imul eax,ecx mul slotTravel3D[ebx*4] shrd eax,edx,20 mov edx,slotStartStops3D[ebx*4] shl edx,6 add eax,edx ret slot_position_end: mov eax,slotStartStops3D[ebx*4] shl eax,6 add eax,slotTravel3D[ebx*4] slot_position_done: ret slot_position_zero: xor eax,eax ret SlotReelPosition3D ENDP SlotExitMouse3D PROC cmp mouseClick3D,0 je slot_exit_mouse_done mov mouseClick3D,0 cmp mouseY3D,3 jb slot_exit_mouse_done cmp mouseY3D,17 jae slot_exit_mouse_done cmp mouseX3D,252 jb slot_exit_mouse_done cmp mouseX3D,312 jae slot_exit_mouse_done call SlotEscape3D slot_exit_mouse_done: ret SlotExitMouse3D ENDP HandleNativeSlots3D PROC uses ebx cmp slotSpinState,SLOT_SPIN jne slot_handle_idle ; Process the header before settlement so the final spin tick cannot eat it. call SlotExitMouse3D mov eax,deltaTime3D cmp eax,250 jbe @F mov eax,250 @@: add slotSpinTimer,eax cmp slotSpinTimer,3000 jb slot_handle_exit_mouse call SettleNativeSlots3D ret slot_handle_idle: mov eax,deltaTime3D add slotEffects3D,eax cmp slotEffects3D,2000 jbe @F mov slotEffects3D,2000 @@: cmp slotPaytable3D,0 je slot_handle_controls invoke Pressed3D,0Dh test eax,eax jnz slot_close_paytable invoke Pressed3D,20h test eax,eax jnz slot_close_paytable invoke Pressed3D,50h test eax,eax jnz slot_close_paytable cmp mouseClick3D,0 je slot_handle_done mov mouseClick3D,0 cmp mouseY3D,202 jb slot_handle_done cmp mouseY3D,220 jae slot_handle_done cmp mouseX3D,112 jb slot_handle_done cmp mouseX3D,208 jae slot_handle_done slot_close_paytable: mov slotPaytable3D,0 ret slot_handle_controls: cmp mouseClick3D,0 je slot_handle_keys cmp mouseY3D,222 jb slot_handle_keys cmp mouseY3D,238 jae slot_handle_keys mov mouseClick3D,0 mov eax,mouseX3D cmp eax,11 jb slot_handle_keys cmp eax,29 jb slot_bet_down cmp eax,35 jb slot_handle_keys cmp eax,53 jb slot_bet_up cmp eax,120 jb slot_handle_keys cmp eax,190 jb slot_handle_start cmp eax,202 jb slot_handle_keys cmp eax,272 jae slot_handle_keys mov slotPaytable3D,1 ret slot_handle_keys: invoke Pressed3D,50h test eax,eax jz @F mov slotPaytable3D,1 ret @@: invoke Pressed3D,57h test eax,eax jnz slot_bet_up invoke Pressed3D,26h test eax,eax jnz slot_bet_up invoke Pressed3D,53h test eax,eax jnz slot_bet_down invoke Pressed3D,28h test eax,eax jnz slot_bet_down invoke Pressed3D,20h test eax,eax jnz slot_handle_start invoke Pressed3D,0Dh test eax,eax jz slot_handle_exit_mouse slot_handle_start: call StartNativeSlots3D ret slot_bet_up: cmp slotBetIndex3D,6 jae slot_handle_done inc slotBetIndex3D jmp slot_bet_changed slot_bet_down: cmp slotBetIndex3D,0 je slot_handle_done dec slotBetIndex3D slot_bet_changed: mov ecx,slotBetIndex3D mov eax,slotBetValues3D[ecx*4] mov slotBet,eax mov slotError3D,0 ret slot_handle_exit_mouse: call SlotExitMouse3D slot_handle_done: ret HandleNativeSlots3D ENDP ; Clip the 64x64 alpha-tested symbol to its own reel window, not the cabinet. DrawSlotSymbol3D PROC uses ebx esi edi symbol:DWORD,x:DWORD,y:DWORD local row:DWORD,lastRow:DWORD,source:DWORD cmp symbol,7 ja slot_symbol_done mov eax,slotSymbolsPack3D.pixels test eax,eax jz slot_symbol_done mov ecx,symbol shl ecx,14 add eax,ecx mov source,eax mov eax,y cmp eax,SLOT_TOP jge @F mov eax,SLOT_TOP @@: mov row,eax mov eax,y add eax,64 cmp eax,SLOT_BOTTOM jle @F mov eax,SLOT_BOTTOM @@: mov lastRow,eax slot_symbol_row: mov eax,row cmp eax,lastRow jge slot_symbol_done mov ecx,eax sub ecx,y shl ecx,8 mov esi,source add esi,ecx imul eax,640*4 mov ecx,x lea edi,screenBuffer[eax+ecx*4] mov ecx,64 slot_symbol_column: lodsd test eax,0FF000000h jz @F and eax,00FFFFFFh mov [edi],eax @@: add edi,4 dec ecx jnz slot_symbol_column inc row jmp slot_symbol_row slot_symbol_done: ret DrawSlotSymbol3D ENDP DrawSlotReel3D PROC uses ebx esi edi index:DWORD local offsetPx:DWORD,baseStop:DWORD,symbolY:DWORD,symbolX:DWORD invoke SlotReelPosition3D,index xor edx,edx mov ecx,64 div ecx mov offsetPx,edx xor edx,edx mov ecx,20 div ecx mov baseStop,edx mov ebx,index mov eax,slotWindows3D[ebx*4] add eax,12 mov symbolX,eax mov eax,160 sub eax,offsetPx sub eax,64 mov symbolY,eax mov esi,baseStop add esi,19 xor edi,edi slot_reel_symbol: mov eax,esi xor edx,edx mov ecx,20 div ecx mov eax,slotStrip3D[edx*4] invoke DrawSlotSymbol3D,eax,symbolX,symbolY add symbolY,64 inc esi inc edi cmp edi,4 jb slot_reel_symbol ret DrawSlotReel3D ENDP RenderNativeSlots3D PROC uses ebx esi edi ; The validated cabinet is opaque and already framebuffer-sized. mov esi,slotCabinetPack3D.pixels test esi,esi jz slot_render_done lea edi,screenBuffer mov ecx,SCREEN_SIZE rep movsd xor esi,esi slot_render_reels: invoke DrawSlotReel3D,esi inc esi cmp esi,3 jb slot_render_reels ; The payline is fixed at the center of the three physical drums. invoke DrawBox,86,94,4,3,00E9CE71h invoke DrawBox,232,94,4,3,00E9CE71h cmp slotSpinState,SLOT_RESULT jne slot_render_header cmp slotWinAmount,0 je slot_render_header mov eax,slotEffects3D xor edx,edx mov ecx,200 div ecx test eax,1 jnz slot_render_header invoke DrawBox,90,94,142,1,00E9CE71h slot_render_header: invoke DrawBox,0,0,320,19,00151D20h invoke DrawString8x8,8,6,OFFSET slotTitle3D,00E8D7ADh invoke DrawString8x8,54,6,OFFSET textBank3D,00A8DDB9h invoke FormatNumber,bankroll,OFFSET hudNumBuffer invoke DrawString8x8,103,6,OFFSET hudNumBuffer,00F4F3E8h invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1 invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h mov ebx,OFFSET slotReadyText3D cmp slotSpinState,SLOT_SPIN jne @F mov ebx,OFFSET slotRollingText3D @@: cmp slotSpinState,SLOT_RESULT jne @F mov ebx,OFFSET slotLoseText3D cmp slotWinAmount,0 je @F mov ebx,OFFSET slotWinText3D @@: cmp slotError3D,0 je @F mov ebx,OFFSET slotNoMoney3D @@: cmp slotLeaveAfter3D,0 je @F mov ebx,OFFSET slotExitText3D @@: ; Keep the message on the generated inset plate, with fixed-size numerals. invoke DrawBox,98,147,126,12,00151D20h invoke DrawString8x8,104,149,ebx,00E8D7ADh cmp slotSpinState,SLOT_RESULT jne slot_render_controls cmp slotWinAmount,0 je slot_render_controls invoke FormatNumber,slotWinAmount,OFFSET hudNumBuffer invoke DrawString8x8,164,149,OFFSET hudNumBuffer,00A8DDB9h slot_render_controls: invoke DrawBox,0,202,320,38,00151D20h invoke DrawString8x8,11,207,OFFSET slotBetText3D,00E8D7ADh invoke FormatNumber,slotBet,OFFSET hudNumBuffer invoke DrawString8x8,83,207,OFFSET hudNumBuffer,00F4F3E8h mov ebx,1 cmp slotSpinState,SLOT_SPIN jne @F xor ebx,ebx @@: mov edi,006D7470h test ebx,ebx jz @F mov edi,00EEE5CDh @@: invoke DrawBoxBorder,11,222,18,16,0025372Ch,edi,1 invoke DrawBoxBorder,35,222,18,16,0025372Ch,edi,1 invoke DrawString8x8,16,226,OFFSET tableMinusText3D,edi invoke DrawString8x8,40,226,OFFSET tablePlusText3D,edi invoke DrawTableButton3D,120,OFFSET slotSpinText3D,ebx invoke DrawTableButton3D,202,OFFSET slotPayText3D,ebx cmp slotPaytable3D,0 je slot_render_done invoke DrawBoxBorder,30,23,260,198,00151D20h,00D1B16Eh,1 invoke DrawString8x8,76,31,OFFSET slotPayTitle3D,00E8D7ADh invoke DrawString8x8,66,48,OFFSET slotTripleText3D,00A8DDB9h xor esi,esi slot_render_pay_row: mov edi,esi imul edi,14 add edi,66 mov eax,slotSymbolNames3D[esi*4] invoke DrawString8x8,62,edi,eax,00F4F3E8h invoke FormatNumber,slotTriple3D[esi*4],OFFSET hudNumBuffer invoke DrawString8x8,212,edi,OFFSET strMultiplier3D,00E8D7ADh invoke DrawString8x8,220,edi,OFFSET hudNumBuffer,00E8D7ADh inc esi cmp esi,8 jb slot_render_pay_row invoke DrawString8x8,62,181,OFFSET slotPairText3D,00A8DDB9h invoke DrawString8x8,62,192,OFFSET slotCherryPair3D,00A8DDB9h invoke DrawBoxBorder,112,204,96,15,003B6C59h,00E9D8B0h,1 invoke DrawString8x8,128,207,OFFSET slotCloseText3D,00E9D8B0h slot_render_done: ret RenderNativeSlots3D ENDP