; ============================================================================== ; CASINO 2.5D - MASM32 SOFTWARE RAYCASTER (CP1251) ; Graphical migration; this is not id Software's Doom engine. ; ============================================================================== includelib gdi32.lib includelib winmm.lib CreateWindowExA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD RegisterClassExA PROTO :DWORD DefWindowProcA PROTO :DWORD,:DWORD,:DWORD,:DWORD ShowWindow PROTO :DWORD,:DWORD UpdateWindow PROTO :DWORD GetDC PROTO :DWORD ReleaseDC PROTO :DWORD,:DWORD StretchDIBits PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD PeekMessageA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD TranslateMessage PROTO :DWORD DispatchMessageA PROTO :DWORD PostQuitMessage PROTO :DWORD DestroyWindow PROTO :DWORD SetWindowTextA PROTO :DWORD,:DWORD SetForegroundWindow PROTO :DWORD GetConsoleWindow PROTO GetSystemMetrics PROTO :DWORD CreateFileA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD ReadFile PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD CloseHandle PROTO :DWORD GetAsyncKeyState PROTO :DWORD PlaySoundA PROTO :DWORD,:DWORD,:DWORD GetModuleFileNameA PROTO :DWORD,:DWORD,:DWORD Sleep PROTO :DWORD C3D_POINT STRUCT x dd ? y dd ? C3D_POINT ENDS C3D_MSG STRUCT hwnd dd ? message dd ? wParam dd ? lParam dd ? time dd ? pt C3D_POINT <> C3D_MSG ENDS C3D_WNDCLASSEX STRUCT cbSize dd ? style dd ? lpfnWndProc dd ? cbClsExtra dd ? cbWndExtra dd ? hInstance dd ? hIcon dd ? hCursor dd ? hbrBackground dd ? lpszMenuName dd ? lpszClassName dd ? hIconSm dd ? C3D_WNDCLASSEX ENDS C3D_BITMAPINFOHEADER STRUCT biSize dd ? biWidth dd ? biHeight dd ? biPlanes dw ? biBitCount dw ? biCompression dd ? biSizeImage dd ? biXPelsPerMeter dd ? biYPelsPerMeter dd ? biClrUsed dd ? biClrImportant dd ? C3D_BITMAPINFOHEADER ENDS C3D_BITMAPINFO STRUCT bmiHeader C3D_BITMAPINFOHEADER <> bmiColors dd ? C3D_BITMAPINFO ENDS SpriteObject STRUCT posX dd ? posY dd ? baseTexId dd ? frameCount dd ? curFrame dd ? animTimer dd ? animSpeed dd ? interactId dd ? promptPtr dd ? distSq dd ? SpriteObject ENDS SCREEN_W equ 640 SCREEN_H equ 480 HALF_W equ 320 HALF_H equ 240 SCREEN_SIZE equ (SCREEN_W * SCREEN_H) WIN_SCALE equ 1 WINDOW_W equ (SCREEN_W * WIN_SCALE) WINDOW_H equ (SCREEN_H * WIN_SCALE) FP_1 equ 65536 FP_HALF equ 32768 CHROMA_KEY equ 00FF00FFh MODE_WALK equ 0 MODE_SLOTS equ 1 MODE_BLACKJACK equ 2 MODE_ROULETTE equ 3 MODE_SHOP equ 4 MODE_ATM equ 5 WS_OVERLAPPEDWINDOW equ 00CF0000h SW_SHOW equ 5 SW_HIDE equ 0 PM_REMOVE equ 1 WM_DESTROY equ 0002h WM_CLOSE equ 0010h WM_QUIT equ 0012h CS_HREDRAW equ 2 CS_VREDRAW equ 1 DIB_RGB_COLORS equ 0 SRCCOPY equ 00CC0020h INVALID_FILE_HANDLE equ -1 include casino3d_data.inc include font8x8.inc include src_graphics\platform_data.inc .data ALIGN 4 h3DInst dd 0 h3DWnd dd 0 h3DDC dd 0 hCasinoConsole dd 0 bmi3D C3D_BITMAPINFO <> msg3D C3D_MSG <> wc3D C3D_WNDCLASSEX <> sz3DClassName db "Casino3DRetroClass",0 sz3DWindowTitle db "Assembler Casino - 2.5D",0 szTexturesRelPath db "assets\textures\casino3d-hd.bin",0 szTexturesFullPath db 260 dup(0) soundCoin db "assets\audio\Çâîí ïàäàþùåé ìîíåòû.wav",0 soundCards db "assets\audio\playing_cards_deck_flick_through_001_20485.wav",0 soundRoulette db "assets\audio\roulette-wheel-throw-2.wav",0 soundJackpot db "assets\audio\Äæåêïîò.wav",0 soundClick db "assets\audio\b05e1ac8be34248.wav",0 playerX dd (16 * FP_1 + FP_HALF) playerY dd (16 * FP_1 + FP_HALF) playerAngle dd 384 playerDirX dd 0 playerDirY dd -FP_1 playerPlaneX dd (FP_1 * 66 / 100) playerPlaneY dd 0 engineMode dd 0 interactTargetId dd 0 interactPromptPtr dd 0 dancerLuckBuff dd 0 flashTimer dd 0 flashMessage db 128 dup(0) promptDancer db "[E] CABARET - TIP $100",0 promptSlot1 db "[E] SLOTS 777",0 promptSlot2 db "[E] SLOTS 777",0 promptBlackjack db "[E] BLACKJACK / 21",0 promptPoker db "POKER - UNDER CONSTRUCTION",0 promptRoulette db "[E] ROULETTE",0 promptShop db "[E] BOUTIQUE",0 promptATM db "[E] CASHIER",0 promptBackroom db "BACKROOM - UNDER CONSTRUCTION",0 promptDurak db "DURAK - UNDER CONSTRUCTION",0 promptHell db "TOWER - UNDER CONSTRUCTION",0 msgDancerTipped db "Âû áðîñèëè $100 òàíöîâùèöå! ÓÄÀ×À ÀÊÒÈÂÈÐÎÂÀÍÀ!",0 msgNeedMoney db "Íåäîñòàòî÷íî äåíåã â êîøåëüêå!",0 statusHUDFormat db "ÁÀÍÊÐÎËË: $",0 targetHUDFormat db " ÖÅËÜ: $",0 luckHUDFormat db " ÓÄÀ×À: +",0 controlsHUD db "WASD/Ñòðåëêè: Õîäüáà | E: Äåéñòâèå | ESC: Ìåíþ",0 NUM_SPRITES equ 13 ALIGN 4 casinoSprites SpriteObject NUM_SPRITES dup(<>) sortedSprites dd NUM_SPRITES dup(0) rowDistTable dd 120 dup(0) rngSeed3D dd 12345678h slotBet dd 50 slotReel1 dd 0 slotReel2 dd 1 slotReel3 dd 2 slotSpinState dd 0 slotSpinTimer dd 0 slotWinAmount dd 0 slotWinMsg db 64 dup(0) bjState dd 0 bjBet dd 100 bjPlayerCards dd 10 dup(0) bjPlayerCardCount dd 0 bjPlayerScore dd 0 bjDealerCards dd 10 dup(0) bjDealerCardCount dd 0 bjDealerScore dd 0 bjDealerHideHole dd 1 bjOutcomeMsg db 64 dup(0) roulState dd 0 roulBetType dd 1 roulBetAmount dd 100 roulWheelAngle dd 0 roulBallAngle dd 0 roulSpinTimer dd 0 roulWinningNum dd 0 roulPayout dd 0 roulOutcomeMsg db 64 dup(0) shopMsg db 128 dup(0) atmMsg db 128 dup(0) strWin db "ÏÎÁÅÄÀ! +$",0 strLose db "ÏÐÎÈÃÐÛØ",0 strJackpot db "ÄÆÅÊÏÎÒ! +$",0 strPush db "ÍÈ×Üß (PUSH)",0 strDealerBust db "ÄÈËÅÐ ÏÅÐÅÁÐÀË! ÏÎÁÅÄÀ! +$",0 strPlayerBust db "ÏÅÐÅÁÎÐ (>21)! ÏÐÎÈÃÐÛØ",0 sym7 db " 777 ",0 symBar db " BAR ",0 symBell db " BELL",0 symCherry db "CHERRY",0 symClover db "CLOVER",0 symGem db " GEM ",0 symCrown db "CROWN",0 cardRankStr db "A ",0,"2 ",0,"3 ",0,"4 ",0,"5 ",0,"6 ",0,"7 ",0,"8 ",0,"9 ",0,"10",0,"J ",0,"Q ",0,"K ",0 .data? ALIGN 4 screenBuffer dd SCREEN_SIZE dup(?) ALIGN 4 zBuffer dd SCREEN_W dup(?) ALIGN 4 texturesBuffer dd (48 * 128 * 128) dup(?) hudNumBuffer db 32 dup(?) .code ; --- 3D Window Procedure --- Casino3DWndProc PROC hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD invoke WindowEvents3D, hwnd, uMsg, wParam, lParam ret Casino3DWndProc ENDP ; --- Random Generator --- RandomRange3D PROC maxVal:DWORD mov eax, rngSeed3D imul eax, 1103515245 add eax, 12345 mov rngSeed3D, eax shr eax, 16 and eax, 7FFFh xor edx, edx div maxVal mov eax, edx ret RandomRange3D ENDP ; --- Copy String --- CopyString3D PROC src:DWORD, dst:DWORD push esi push edi mov esi, src mov edi, dst @@: mov al, [esi] mov [edi], al test al, al jz @F inc esi inc edi jmp @B @@: pop edi pop esi ret CopyString3D ENDP ; --- Format Number to Decimal String --- FormatNumber PROC num:DWORD, buf:DWORD push ebx push esi push edi mov eax, num mov edi, buf test eax, eax jns fn_pos mov BYTE PTR [edi], '-' inc edi neg eax fn_pos: mov ebx, 10 push 0 fn_div: xor edx, edx div ebx add dl, '0' push edx test eax, eax jnz fn_div fn_pop: pop eax test al, al jz fn_done mov [edi], al inc edi jmp fn_pop fn_done: mov BYTE PTR [edi], 0 pop edi pop esi pop ebx ret FormatNumber ENDP ; --- Fast 2D Drawing Primitives --- DrawBox PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD DrawPixel PROC x:DWORD, y:DWORD, color:DWORD invoke DrawBox, x, y, 1, 1, color ret DrawPixel ENDP DrawBox PROC x:DWORD, y:DWORD, w:DWORD, h:DWORD, color:DWORD shl x, 1 shl y, 1 shl w, 1 shl h, 1 push ebx push esi push edi mov edi, y box_row_loop: mov eax, y add eax, h cmp edi, eax jge box_done cmp edi, 0 jl next_box_row cmp edi, SCREEN_H jge box_done mov esi, x box_col_loop: mov eax, x add eax, w cmp esi, eax jge next_box_row cmp esi, 0 jl next_box_col cmp esi, SCREEN_W jge next_box_row mov ecx, edi imul ecx, SCREEN_W add ecx, esi mov edx, color mov [screenBuffer + ecx*4], edx next_box_col: inc esi jmp box_col_loop next_box_row: inc edi jmp box_row_loop box_done: pop edi pop esi pop ebx ret DrawBox ENDP DrawBoxBorder PROC uses ebx x:DWORD, y:DWORD, w:DWORD, h:DWORD, fillColor:DWORD, borderColor:DWORD, bWidth:DWORD invoke DrawBox, x, y, w, h, borderColor mov eax, x add eax, bWidth mov edx, y add edx, bWidth mov ecx, w sub ecx, bWidth sub ecx, bWidth mov ebx, h sub ebx, bWidth sub ebx, bWidth invoke DrawBox, eax, edx, ecx, ebx, fillColor ret DrawBoxBorder ENDP DrawCircle PROC cxVal:DWORD, cyVal:DWORD, radius:DWORD, color:DWORD push ebx push esi push edi mov eax, radius neg eax mov edi, eax circ_y: cmp edi, radius jg circ_done mov eax, radius neg eax mov esi, eax circ_x: cmp esi, radius jg next_circ_y mov eax, esi imul eax, eax mov ebx, edi imul ebx, ebx add eax, ebx mov edx, radius imul edx, edx cmp eax, edx jg next_circ_x mov eax, cxVal add eax, esi mov ecx, cyVal add ecx, edi invoke DrawPixel, eax, ecx, color next_circ_x: inc esi jmp circ_x next_circ_y: inc edi jmp circ_y circ_done: pop edi pop esi pop ebx ret DrawCircle ENDP DrawChar8x8 PROC uses ebx esi edi x:DWORD, y:DWORD, chVal:DWORD, color:DWORD local column:DWORD mov eax, chVal and eax, 255 lea esi, [font8x8 + eax*8] xor edi, edi glyph_row: movzx ebx, BYTE PTR [esi+edi] mov column, 0 glyph_col: test ebx, 80h jz glyph_next mov eax, x add eax, column mov edx, y add edx, edi invoke DrawPixel, eax, edx, color glyph_next: shl ebx, 1 inc column cmp column, 8 jl glyph_col inc edi cmp edi, 8 jl glyph_row ret DrawChar8x8 ENDP DrawString8x8 PROC x:DWORD, y:DWORD, strPtr:DWORD, color:DWORD push ebx push esi mov esi, strPtr mov ebx, x str_loop: movzx eax, BYTE PTR [esi] test al, al jz str_done invoke DrawChar8x8, ebx, y, eax, color add ebx, 8 inc esi jmp str_loop str_done: pop esi pop ebx ret DrawString8x8 ENDP ; --- True 3D Perspective Floor & Ceiling Rendering --- RenderCeilingAndFloor PROC uses ebx esi edi local floorRow:DWORD local pDist:DWORD local fStepX:DWORD local fStepY:DWORD local fX:DWORD local fY:DWORD local shade:DWORD local cShade:DWORD ; Horizon line: row 120 mov edi, HALF_H floor_scanlines: cmp edi, SCREEN_H jge floor_done mov floorRow, edi ; Distance = (HALF_H * FP_1) / (y - HALF_H) mov eax, edi sub eax, HALF_H inc eax mov ecx, eax mov eax, HALF_H * FP_1 cdq idiv ecx mov pDist, eax ; Distance shading (closer is brighter, far horizon is dark) mov edx, pDist shr edx, 13 mov eax, 255 sub eax, edx cmp eax, 35 jge @F mov eax, 35 @@: mov shade, eax mov edx, eax sub edx, 25 cmp edx, 20 jge @F mov edx, 20 @@: mov cShade, edx ; Step along scanline: (2 * playerPlane) * pDist / SCREEN_W mov eax, playerPlaneX shl eax, 1 imul pDist shrd eax, edx, 16 cdq mov ecx, SCREEN_W idiv ecx mov fStepX, eax mov eax, playerPlaneY shl eax, 1 imul pDist shrd eax, edx, 16 cdq mov ecx, SCREEN_W idiv ecx mov fStepY, eax ; Starting floor coordinates at x=0: ; player + pDist * (playerDir - playerPlane) mov eax, playerDirX sub eax, playerPlaneX imul pDist shrd eax, edx, 16 add eax, playerX mov fX, eax mov eax, playerDirY sub eax, playerPlaneY imul pDist shrd eax, edx, 16 add eax, playerY mov fY, eax ; Fill scanline for floor (y) and ceiling (SCREEN_H - 1 - y) xor esi, esi col_floor_loop: cmp esi, SCREEN_W jge next_floor_row ; Carpet Texture (Slot 3: 3 * 4096 * 4 = 49152 bytes) mov eax, fX shr eax, 9 and eax, 127 mov edx, fY shr edx, 9 and edx, 127 shl edx, 7 add edx, eax mov eax, [texturesBuffer + (3 * 128 * 128 * 4) + edx*4] ; Shade Floor RGB mov ebx, shade movzx ecx, al imul ecx, ebx shr ecx, 8 push ecx movzx ecx, ah imul ecx, ebx shr ecx, 8 shl ecx, 8 shr eax, 16 movzx eax, al imul eax, ebx shr eax, 8 shl eax, 16 or eax, ecx pop ecx or eax, ecx ; Store to Floor pixel mov ecx, floorRow imul ecx, SCREEN_W add ecx, esi mov [screenBuffer + ecx*4], eax ; Ceiling Spotlight Texture (Slot 5: 5 * 4096 * 4 = 81920 bytes) mov eax, [texturesBuffer + (5 * 128 * 128 * 4) + edx*4] mov ebx, cShade movzx ecx, al imul ecx, ebx shr ecx, 8 push ecx movzx ecx, ah imul ecx, ebx shr ecx, 8 shl ecx, 8 shr eax, 16 movzx eax, al imul eax, ebx shr eax, 8 shl eax, 16 or eax, ecx pop ecx or eax, ecx ; Store to Ceiling pixel: (SCREEN_H - 1 - floorRow) mov ecx, SCREEN_H - 1 sub ecx, floorRow imul ecx, SCREEN_W add ecx, esi mov [screenBuffer + ecx*4], eax mov eax, fStepX add fX, eax mov eax, fStepY add fY, eax inc esi jmp col_floor_loop next_floor_row: inc edi jmp floor_scanlines floor_done: ret RenderCeilingAndFloor ENDP ; --- DDA Raycasting Walls --- RenderWalls PROC local col:DWORD local camX:DWORD local rayDirX:DWORD local rayDirY:DWORD local mapX:DWORD local mapY:DWORD local deltaDistX:DWORD local deltaDistY:DWORD local stepX:DWORD local stepY:DWORD local sideDistX:DWORD local sideDistY:DWORD local side:DWORD local perpWallDist:DWORD local lineH:DWORD local drawStart:DWORD local drawEnd:DWORD local wallHit:DWORD local texX:DWORD local texId:DWORD local shade:DWORD push ebx push esi push edi mov eax, playerAngle and eax, 511 mov ebx, [tableCos + eax*4] mov playerDirX, ebx mov ebx, [tableSin + eax*4] mov playerDirY, ebx mov eax, ebx imul eax, -66 cdq mov ecx, 100 idiv ecx mov playerPlaneX, eax mov eax, playerDirX imul eax, 66 cdq idiv ecx mov playerPlaneY, eax mov col, 0 col_loop: cmp col, SCREEN_W jge walls_done mov eax, col shl eax, 1 sub eax, SCREEN_W imul eax, FP_1 cdq mov ecx, SCREEN_W idiv ecx mov camX, eax mov eax, playerPlaneX imul camX shrd eax, edx, 16 add eax, playerDirX mov rayDirX, eax mov eax, playerPlaneY imul camX shrd eax, edx, 16 add eax, playerDirY mov rayDirY, eax mov eax, playerX sar eax, 16 mov mapX, eax mov eax, playerY sar eax, 16 mov mapY, eax mov eax, rayDirX test eax, eax jnz calc_delta_x mov deltaDistX, 7FFFFFFFh jmp calc_delta_y calc_delta_x: test eax, eax jns @F neg eax @@: mov ebx, eax ; 2^32 needs the full EDX:EAX dividend, not a truncated multiply. xor eax, eax mov edx, 1 idiv ebx mov deltaDistX, eax calc_delta_y: mov eax, rayDirY test eax, eax jnz calc_delta_y_ok mov deltaDistY, 7FFFFFFFh jmp check_step calc_delta_y_ok: test eax, eax jns @F neg eax @@: mov ebx, eax ; 2^32 needs the full EDX:EAX dividend, not a truncated multiply. xor eax, eax mov edx, 1 idiv ebx mov deltaDistY, eax check_step: cmp rayDirX, 0 jge step_x_pos mov stepX, -1 mov eax, playerX mov edx, mapX shl edx, 16 sub eax, edx imul deltaDistX shrd eax, edx, 16 mov sideDistX, eax jmp check_step_y step_x_pos: mov stepX, 1 mov eax, mapX inc eax shl eax, 16 sub eax, playerX imul deltaDistX shrd eax, edx, 16 mov sideDistX, eax check_step_y: cmp rayDirY, 0 jge step_y_pos mov stepY, -1 mov eax, playerY mov edx, mapY shl edx, 16 sub eax, edx imul deltaDistY shrd eax, edx, 16 mov sideDistY, eax jmp dda_start step_y_pos: mov stepY, 1 mov eax, mapY inc eax shl eax, 16 sub eax, playerY imul deltaDistY shrd eax, edx, 16 mov sideDistY, eax dda_start: xor ecx, ecx dda_step_loop: inc ecx cmp ecx, 64 jge hit_wall mov eax, sideDistX cmp eax, sideDistY jge step_in_y mov eax, deltaDistX add sideDistX, eax mov eax, stepX add mapX, eax mov side, 0 jmp check_tile step_in_y: mov eax, deltaDistY add sideDistY, eax mov eax, stepY add mapY, eax mov side, 1 check_tile: cmp mapX, 0 jl hit_wall cmp mapX, MAP_WIDTH jge hit_wall cmp mapY, 0 jl hit_wall cmp mapY, MAP_HEIGHT jge hit_wall mov eax, mapY shl eax, 5 add eax, mapX movzx eax, BYTE PTR [casinoMap + eax] test eax, eax jnz hit_wall jmp dda_step_loop hit_wall: cmp side, 0 jne perp_y mov eax, sideDistX sub eax, deltaDistX mov perpWallDist, eax jmp perp_done perp_y: mov eax, sideDistY sub eax, deltaDistY mov perpWallDist, eax perp_done: cmp perpWallDist, 2048 jge @F mov perpWallDist, 2048 @@: mov eax, col mov edx, perpWallDist mov [zBuffer + eax*4], edx ; High casino ceiling: lineH = (SCREEN_H * FP_1 * 180 / 240) / perpWallDist mov eax, SCREEN_H imul eax, FP_1 cdq idiv perpWallDist mov lineH, eax mov eax, lineH shr eax, 1 mov ecx, HALF_H sub ecx, eax mov drawStart, ecx mov eax, lineH shr eax, 1 mov ecx, HALF_H add ecx, eax mov drawEnd, ecx cmp side, 0 jne hit_side_y mov eax, perpWallDist imul rayDirY shrd eax, edx, 16 add eax, playerY mov wallHit, eax jmp calc_tex_x hit_side_y: mov eax, perpWallDist imul rayDirX shrd eax, edx, 16 add eax, playerX mov wallHit, eax calc_tex_x: ; MASK WITH 0FFFFh to prevent texture scrambling! mov eax, wallHit and eax, 0FFFFh shr eax, 9 and eax, 127 mov texX, eax cmp side, 0 jne @F cmp rayDirX, 0 jle @F mov eax, 127 sub eax, texX mov texX, eax @@: cmp side, 1 jne select_tex cmp rayDirY, 0 jge select_tex mov eax, 127 sub eax, texX mov texX, eax select_tex: mov eax, mapY shl eax, 5 add eax, mapX movzx eax, BYTE PTR [casinoMap + eax] mov texId, eax cmp texId, 0 jne @F mov texId, 1 @@: mov eax, perpWallDist shr eax, 13 mov edx, 256 sub edx, eax cmp edx, 75 jge @F mov edx, 75 @@: cmp side, 1 jne @F imul edx, 3 shr edx, 2 @@: mov shade, edx cmp drawStart, 0 jge @F mov drawStart, 0 @@: cmp drawEnd, SCREEN_H jl @F mov drawEnd, SCREEN_H - 1 @@: mov eax, 128 * FP_1 cdq idiv lineH mov esi, eax ; stepY mov eax, lineH shr eax, 1 add eax, drawStart sub eax, HALF_H imul eax, esi mov edi, eax ; texPos mov ecx, drawStart draw_stripe_loop: cmp ecx, drawEnd jg next_col mov eax, edi shr eax, 16 and eax, 127 shl eax, 7 add eax, texX mov edx, texId shl edx, 14 add eax, edx mov eax, [texturesBuffer + eax*4] ; Shade wall pixel mov ebx, shade movzx edx, al imul edx, ebx shr edx, 8 push edx movzx edx, ah imul edx, ebx shr edx, 8 shl edx, 8 shr eax, 16 movzx eax, al imul eax, ebx shr eax, 8 shl eax, 16 or eax, edx pop edx or eax, edx mov edx, ecx imul edx, SCREEN_W add edx, col mov [screenBuffer + edx*4], eax add edi, esi inc ecx jmp draw_stripe_loop next_col: inc col jmp col_loop walls_done: pop edi pop esi pop ebx ret RenderWalls ENDP ; --- Render 3D Billboard Sprites --- RenderSprites PROC local sprIdx:DWORD local relX:DWORD local relY:DWORD local invDet:DWORD local transX:DWORD local transY:DWORD local sprScreenX:DWORD local sprH:DWORD local sprW:DWORD local drawStartY:DWORD local drawEndY:DWORD local drawStartX:DWORD local drawEndX:DWORD local stripe:DWORD local texX:DWORD local texY:DWORD local shade:DWORD local texSlot:DWORD push ebx push esi push edi xor esi, esi calc_dist_loop: cmp esi, NUM_SPRITES jge sort_sprites mov eax, esi imul eax, SIZEOF SpriteObject mov edx, [casinoSprites + eax].posX sub edx, playerX sar edx, 8 imul edx, edx mov ebx, edx mov edx, [casinoSprites + eax].posY sub edx, playerY sar edx, 8 imul edx, edx add ebx, edx mov [casinoSprites + eax].distSq, ebx mov [sortedSprites + esi*4], esi inc esi jmp calc_dist_loop sort_sprites: xor esi, esi sort_outer: cmp esi, NUM_SPRITES - 1 jge render_sorted_sprites mov edi, esi inc edi sort_inner: cmp edi, NUM_SPRITES jge next_sort_outer mov eax, [sortedSprites + esi*4] imul eax, SIZEOF SpriteObject mov eax, [casinoSprites + eax].distSq mov ebx, [sortedSprites + edi*4] imul ebx, SIZEOF SpriteObject mov ebx, [casinoSprites + ebx].distSq cmp eax, ebx jge @F mov ecx, [sortedSprites + esi*4] mov edx, [sortedSprites + edi*4] mov [sortedSprites + esi*4], edx mov [sortedSprites + edi*4], ecx @@: inc edi jmp sort_inner next_sort_outer: inc esi jmp sort_outer render_sorted_sprites: xor esi, esi draw_spr_loop: cmp esi, NUM_SPRITES jge sprites_rendered mov eax, [sortedSprites + esi*4] mov sprIdx, eax imul eax, SIZEOF SpriteObject ; Sample animation by elapsed time. Pausing freezes the clock. push eax mov ecx, [casinoSprites + eax].animSpeed imul ecx, 40 mov eax, animationClock3D xor edx, edx div ecx pop ebx xor edx, edx div [casinoSprites + ebx].frameCount mov [casinoSprites + ebx].curFrame, edx mov eax, ebx cmp [casinoSprites + eax].distSq, 16 jle next_spr mov edx, [casinoSprites + eax].posX sub edx, playerX mov relX, edx mov edx, [casinoSprites + eax].posY sub edx, playerY mov relY, edx mov eax, playerPlaneX imul playerDirY shrd eax, edx, 16 mov ebx, eax mov eax, playerDirX imul playerPlaneY shrd eax, edx, 16 sub ebx, eax test ebx, ebx jz next_spr ; 2^32 needs the full EDX:EAX dividend, not a truncated multiply. xor eax, eax mov edx, 1 idiv ebx mov invDet, eax mov eax, playerDirY imul relX shrd eax, edx, 16 mov ebx, eax mov eax, playerDirX imul relY shrd eax, edx, 16 sub ebx, eax mov eax, ebx imul invDet shrd eax, edx, 16 mov transX, eax mov eax, playerPlaneY neg eax imul relX shrd eax, edx, 16 mov ebx, eax mov eax, playerPlaneX imul relY shrd eax, edx, 16 add ebx, eax mov eax, ebx imul invDet shrd eax, edx, 16 mov transY, eax cmp transY, 4096 jle next_spr mov eax, transX imul eax, HALF_W cdq idiv transY add eax, HALF_W mov sprScreenX, eax mov eax, SCREEN_H imul eax, FP_1 cdq idiv transY test eax, eax jns @F neg eax @@: cmp eax, SCREEN_H * 2 jle @F mov eax, SCREEN_H * 2 @@: mov sprH, eax mov sprW, eax mov eax, HALF_H mov ebx, sprH shr ebx, 1 sub eax, ebx mov drawStartY, eax add eax, sprH mov drawEndY, eax mov eax, sprScreenX mov ebx, sprW shr ebx, 1 sub eax, ebx mov drawStartX, eax add eax, sprW mov drawEndX, eax cmp drawStartY, 0 jge @F mov drawStartY, 0 @@: cmp drawEndY, SCREEN_H jl @F mov drawEndY, SCREEN_H - 1 @@: mov eax, transY shr eax, 13 mov edx, 256 sub edx, eax cmp edx, 110 jge @F mov edx, 110 @@: mov shade, edx mov eax, sprIdx imul eax, SIZEOF SpriteObject mov edx, [casinoSprites + eax].baseTexId add edx, [casinoSprites + eax].curFrame mov texSlot, edx mov eax, drawStartX mov stripe, eax spr_stripe_loop: mov eax, stripe cmp eax, drawEndX jge next_spr cmp eax, 0 jl next_spr_stripe cmp eax, SCREEN_W jge next_spr mov edx, transY cmp edx, [zBuffer + eax*4] jge next_spr_stripe mov eax, stripe sub eax, sprScreenX mov ebx, sprW shr ebx, 1 add eax, ebx shl eax, 7 cdq idiv sprW cmp eax, 0 jl next_spr_stripe cmp eax, 128 jge next_spr_stripe mov texX, eax mov edi, drawStartY spr_pix_y_loop: cmp edi, drawEndY jg next_spr_stripe mov eax, edi sub eax, HALF_H mov ebx, sprH shr ebx, 1 add eax, ebx shl eax, 7 cdq idiv sprH cmp eax, 0 jl next_spr_y cmp eax, 128 jge next_spr_y mov texY, eax shl eax, 7 add eax, texX mov edx, texSlot shl edx, 14 add eax, edx mov eax, [texturesBuffer + eax*4] ; Chromakey magenta filter cmp eax, CHROMA_KEY je next_spr_y do_draw_sprite_pix: mov ebx, shade movzx edx, al imul edx, ebx shr edx, 8 push edx movzx edx, ah imul edx, ebx shr edx, 8 shl edx, 8 shr eax, 16 movzx eax, al imul eax, ebx shr eax, 8 shl eax, 16 or eax, edx pop edx or eax, edx mov ecx, edi imul ecx, SCREEN_W add ecx, stripe mov [screenBuffer + ecx*4], eax next_spr_y: inc edi jmp spr_pix_y_loop next_spr_stripe: inc stripe jmp spr_stripe_loop next_spr: inc esi jmp draw_spr_loop sprites_rendered: pop edi pop esi pop ebx ret RenderSprites ENDP ; --- HUD & Minimap Radar --- RenderHUD PROC uses ebx esi edi invoke DrawBox, 0, 0, 320, 16, 0014191Dh invoke DrawString8x8, 8, 4, OFFSET textBank3D, 00D8BC6Ah invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 64, 4, OFFSET hudNumBuffer, 00FFFFFFh invoke DrawString8x8, 176, 4, OFFSET textWindowKeys3D, 00A8B6BBh invoke DrawBox, 0, 226, 320, 14, 0014191Dh invoke DrawString8x8, 12, 230, OFFSET textWalkKeys3D, 00A8B6BBh invoke DrawBox, 159, 118, 2, 5, 00E7DFC8h invoke DrawBox, 157, 120, 6, 1, 00E7DFC8h cmp interactPromptPtr, 0 je @F invoke DrawBoxBorder, 4, 199, 312, 18, 0014191Dh, 00D8BC6Ah, 1 invoke DrawString8x8, 10, 204, interactPromptPtr, 00F5E2B0h @@: cmp flashTimer, 0 je hud_finished dec flashTimer invoke DrawBox, 4, 22, 312, 16, 0014191Dh invoke DrawString8x8, 10, 26, OFFSET flashMessage, 00FFFFFFh hud_finished: ret RenderHUD ENDP RenderMinimap PROC uses ebx esi edi local radarX:DWORD local radarY:DWORD local radarSize:DWORD mov radarX, 320 - 48 mov radarY, 20 mov radarSize, 44 invoke DrawBoxBorder, radarX, radarY, radarSize, radarSize, 00101510h, 0000D7FFh, 1 ; Draw Sprites on radar xor esi, esi radar_spr_loop: cmp esi, NUM_SPRITES jge draw_player_radar mov eax, esi imul eax, SIZEOF SpriteObject mov eax, [casinoSprites + eax].posX sar eax, 16 imul eax, radarSize shr eax, 5 add eax, radarX mov ebx, eax mov eax, esi imul eax, SIZEOF SpriteObject mov eax, [casinoSprites + eax].posY sar eax, 16 imul eax, radarSize shr eax, 5 add eax, radarY invoke DrawPixel, ebx, eax, 00FFAA00h inc esi jmp radar_spr_loop draw_player_radar: mov eax, playerX sar eax, 16 imul eax, radarSize shr eax, 5 add eax, radarX mov ebx, eax mov eax, playerY sar eax, 16 imul eax, radarSize shr eax, 5 add eax, radarY invoke DrawCircle, ebx, eax, 2, 000000FFh ret RenderMinimap ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: SLOTS 777 ; ============================================================================== HandleSlotsInput PROC cmp slotSpinState, 1 je slots_input_done invoke Pressed3D, 20h ; SPACE -> Spin test ah, 80h jz check_bet_adjust mov eax, bankroll cmp eax, slotBet jl @F sub eax, slotBet mov bankroll, eax mov slotSpinState, 1 mov slotSpinTimer, 0 mov slotWinAmount, 0 invoke PlaySoundA, OFFSET soundClick, 0, 1 jmp slots_input_done @@: invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage mov flashTimer, 60 check_bet_adjust: invoke Pressed3D, 26h ; UP / W test ah, 80h jnz inc_bet invoke Pressed3D, 57h test ah, 80h jz check_bet_down inc_bet: cmp slotBet, 500 jge slots_input_done cmp slotBet, 100 jge @F cmp slotBet, 50 jge set_100 mov slotBet, 50 jmp slots_input_done set_100: mov slotBet, 100 jmp slots_input_done @@: mov slotBet, 500 jmp slots_input_done check_bet_down: invoke Pressed3D, 28h ; DOWN / S test ah, 80h jnz dec_bet invoke Pressed3D, 53h test ah, 80h jz slots_input_done dec_bet: cmp slotBet, 50 jle set_10 cmp slotBet, 100 jle set_50 mov slotBet, 100 jmp slots_input_done set_50: mov slotBet, 50 jmp slots_input_done set_10: mov slotBet, 10 slots_input_done: ret HandleSlotsInput ENDP RenderSlotsGame PROC uses ebx esi edi ; Cabinet Background (Dark Cherry Wood & Gold) invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00150A10h invoke DrawBoxBorder, 10, 10, 300, 220, 00251015h, 0000D7FFh, 3 ; Illuminated Top Marquee invoke DrawBoxBorder, 25, 20, 270, 32, 000A0505h, 0000FFFFh, 2 invoke DrawString8x8, 55, 32, OFFSET textSlots3D, 0000D7FFh ; Spinning Animation Logic cmp slotSpinState, 1 jne draw_reels inc slotSpinTimer cmp slotSpinTimer, 22 jge @F invoke RandomRange3D, 7 mov slotReel1, eax @@: cmp slotSpinTimer, 36 jge @F invoke RandomRange3D, 7 mov slotReel2, eax @@: cmp slotSpinTimer, 50 jge @F invoke RandomRange3D, 7 mov slotReel3, eax @@: cmp slotSpinTimer, 50 jl draw_reels ; Spin finished! Check outcome! mov slotSpinState, 0 mov eax, slotReel1 cmp eax, slotReel2 jne check_pairs cmp eax, slotReel3 jne check_pairs ; 3 Matching! cmp eax, 0 ; 777! jne @F mov eax, slotBet imul eax, 25 mov slotWinAmount, eax add bankroll, eax invoke PlaySoundA, OFFSET soundJackpot, 0, 1 jmp draw_reels @@: cmp eax, 6 ; CROWN! jne @F mov eax, slotBet imul eax, 50 mov slotWinAmount, eax add bankroll, eax invoke PlaySoundA, OFFSET soundJackpot, 0, 1 jmp draw_reels @@: mov eax, slotBet imul eax, 10 mov slotWinAmount, eax add bankroll, eax invoke PlaySoundA, OFFSET soundCoin, 0, 1 jmp draw_reels check_pairs: mov eax, slotReel1 cmp eax, slotReel2 je pair_win mov eax, slotReel2 cmp eax, slotReel3 je pair_win mov eax, slotReel1 cmp eax, slotReel3 je pair_win jmp draw_reels pair_win: mov eax, slotBet imul eax, 2 mov slotWinAmount, eax add bankroll, eax invoke PlaySoundA, OFFSET soundCoin, 0, 1 draw_reels: ; Reels Window invoke DrawBoxBorder, 30, 62, 260, 95, 000F0F12h, 0000A5FFh, 2 ; Reel 1 (45..105) invoke DrawBoxBorder, 45, 68, 65, 82, 00F0F0F5h, 00505050h, 2 mov eax, slotReel1 call DrawReelSymbolAt1 ; Reel 2 (128..188) invoke DrawBoxBorder, 128, 68, 65, 82, 00F0F0F5h, 00505050h, 2 mov eax, slotReel2 call DrawReelSymbolAt2 ; Reel 3 (210..270) invoke DrawBoxBorder, 210, 68, 65, 82, 00F0F0F5h, 00505050h, 2 mov eax, slotReel3 call DrawReelSymbolAt3 ; Bottom Control Panel invoke DrawBoxBorder, 20, 165, 280, 58, 00151515h, 0000D7FFh, 1 invoke DrawString8x8, 28, 172, OFFSET textBank3D, 0000D7FFh invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 0000FFFFh invoke DrawString8x8, 175, 172, OFFSET textBet3D, 0000D7FFh invoke FormatNumber, slotBet, OFFSET hudNumBuffer invoke DrawString8x8, 240, 172, OFFSET hudNumBuffer, 0050FF50h cmp slotWinAmount, 0 jle draw_slot_ctrls invoke DrawString8x8, 28, 187, OFFSET strWin, 0000FFFFh invoke FormatNumber, slotWinAmount, OFFSET hudNumBuffer invoke DrawString8x8, 110, 187, OFFSET hudNumBuffer, 0000FFFFh draw_slot_ctrls: invoke DrawString8x8, 28, 204, OFFSET textSlotsKeys3D, 00A0A0A0h ret RenderSlotsGame ENDP DrawReelSymbolAt1 PROC cmp eax, 0 jne @F invoke DrawString8x8, 52, 105, OFFSET sym7, 000000FFh ret @@: cmp eax, 1 jne @F invoke DrawString8x8, 52, 105, OFFSET symBar, 00FFAA00h ret @@: cmp eax, 2 jne @F invoke DrawString8x8, 52, 105, OFFSET symBell, 0000D7FFh ret @@: cmp eax, 3 jne @F invoke DrawString8x8, 48, 105, OFFSET symCherry, 000000D0h ret @@: cmp eax, 4 jne @F invoke DrawString8x8, 48, 105, OFFSET symClover, 0000A000h ret @@: cmp eax, 5 jne @F invoke DrawString8x8, 52, 105, OFFSET symGem, 00FFFF00h ret @@: invoke DrawString8x8, 52, 105, OFFSET symCrown, 0000D7FFh ret DrawReelSymbolAt1 ENDP DrawReelSymbolAt2 PROC cmp eax, 0 jne @F invoke DrawString8x8, 135, 105, OFFSET sym7, 000000FFh ret @@: cmp eax, 1 jne @F invoke DrawString8x8, 135, 105, OFFSET symBar, 00FFAA00h ret @@: cmp eax, 2 jne @F invoke DrawString8x8, 135, 105, OFFSET symBell, 0000D7FFh ret @@: cmp eax, 3 jne @F invoke DrawString8x8, 131, 105, OFFSET symCherry, 000000D0h ret @@: cmp eax, 4 jne @F invoke DrawString8x8, 131, 105, OFFSET symClover, 0000A000h ret @@: cmp eax, 5 jne @F invoke DrawString8x8, 135, 105, OFFSET symGem, 00FFFF00h ret @@: invoke DrawString8x8, 135, 105, OFFSET symCrown, 0000D7FFh ret DrawReelSymbolAt2 ENDP DrawReelSymbolAt3 PROC cmp eax, 0 jne @F invoke DrawString8x8, 218, 105, OFFSET sym7, 000000FFh ret @@: cmp eax, 1 jne @F invoke DrawString8x8, 218, 105, OFFSET symBar, 00FFAA00h ret @@: cmp eax, 2 jne @F invoke DrawString8x8, 218, 105, OFFSET symBell, 0000D7FFh ret @@: cmp eax, 3 jne @F invoke DrawString8x8, 214, 105, OFFSET symCherry, 000000D0h ret @@: cmp eax, 4 jne @F invoke DrawString8x8, 214, 105, OFFSET symClover, 0000A000h ret @@: cmp eax, 5 jne @F invoke DrawString8x8, 218, 105, OFFSET symGem, 00FFFF00h ret @@: invoke DrawString8x8, 218, 105, OFFSET symCrown, 0000D7FFh ret DrawReelSymbolAt3 ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: BLACKJACK (21) ; ============================================================================== HandleBlackjackInput PROC uses ebx cmp bjState, 0 ; Need Deal jne check_bj_player_turn invoke Pressed3D, 20h ; SPACE -> Deal test ah, 80h jz check_bj_bet_change mov eax, bankroll cmp eax, bjBet jl bj_need_cash sub eax, bjBet mov bankroll, eax ; Deal 2 cards to player, 2 cards to dealer mov bjPlayerCardCount, 0 mov bjDealerCardCount, 0 mov bjDealerHideHole, 1 ; Player Card 1 invoke RandomRange3D, 13 inc eax mov ebx, bjPlayerCardCount mov [bjPlayerCards + ebx*4], eax inc bjPlayerCardCount ; Dealer Card 1 invoke RandomRange3D, 13 inc eax mov ebx, bjDealerCardCount mov [bjDealerCards + ebx*4], eax inc bjDealerCardCount ; Player Card 2 invoke RandomRange3D, 13 inc eax mov ebx, bjPlayerCardCount mov [bjPlayerCards + ebx*4], eax inc bjPlayerCardCount ; Dealer Card 2 (Hole card) invoke RandomRange3D, 13 inc eax mov ebx, bjDealerCardCount mov [bjDealerCards + ebx*4], eax inc bjDealerCardCount invoke PlaySoundA, OFFSET soundCards, 0, 1 ; Calc Player Score call CalcPlayerBJScore cmp bjPlayerScore, 21 jne set_bj_turn ; Instant Blackjack! mov bjDealerHideHole, 0 mov eax, bjBet imul eax, 5 shr eax, 1 add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET bjOutcomeMsg invoke PlaySoundA, OFFSET soundJackpot, 0, 1 mov bjState, 2 ret set_bj_turn: mov bjState, 1 mov BYTE PTR [bjOutcomeMsg], 0 ret bj_need_cash: invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage mov flashTimer, 60 ret check_bj_player_turn: cmp bjState, 1 jne check_bj_round_over invoke Pressed3D, 48h ; 'H' -> Hit test ah, 80h jz check_bj_stand invoke RandomRange3D, 13 inc eax mov ebx, bjPlayerCardCount cmp ebx, 8 jge @F mov [bjPlayerCards + ebx*4], eax inc bjPlayerCardCount @@: invoke PlaySoundA, OFFSET soundCards, 0, 1 call CalcPlayerBJScore cmp bjPlayerScore, 21 jle bj_input_done ; Bust! invoke CopyString3D, OFFSET strPlayerBust, OFFSET bjOutcomeMsg mov bjDealerHideHole, 0 mov bjState, 2 ret check_bj_stand: invoke Pressed3D, 53h ; 'S' -> Stand test ah, 80h jz bj_input_done ; Dealer Turn mov bjDealerHideHole, 0 dealer_loop: call CalcDealerBJScore cmp bjDealerScore, 17 jge dealer_finished invoke RandomRange3D, 13 inc eax mov ebx, bjDealerCardCount cmp ebx, 8 jge dealer_finished mov [bjDealerCards + ebx*4], eax inc bjDealerCardCount jmp dealer_loop dealer_finished: cmp bjDealerScore, 21 jle compare_scores ; Dealer Bust! mov eax, bjBet shl eax, 1 add bankroll, eax invoke CopyString3D, OFFSET strDealerBust, OFFSET bjOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 mov bjState, 2 ret compare_scores: mov eax, bjPlayerScore cmp eax, bjDealerScore jle check_dealer_won ; Player Won! mov eax, bjBet shl eax, 1 add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET bjOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 mov bjState, 2 ret check_dealer_won: cmp eax, bjDealerScore jl dealer_wins ; Push (Tie) mov eax, bjBet add bankroll, eax invoke CopyString3D, OFFSET strPush, OFFSET bjOutcomeMsg mov bjState, 2 ret dealer_wins: invoke CopyString3D, OFFSET strLose, OFFSET bjOutcomeMsg mov bjState, 2 ret check_bj_round_over: invoke Pressed3D, 20h ; SPACE -> Next Hand test ah, 80h jz bj_input_done mov bjState, 0 ret check_bj_bet_change: invoke Pressed3D, 26h ; UP test ah, 80h jz @F cmp bjBet, 500 jge bj_input_done add bjBet, 50 ret @@: invoke Pressed3D, 28h ; DOWN test ah, 80h jz bj_input_done cmp bjBet, 50 jle bj_input_done sub bjBet, 50 bj_input_done: ret HandleBlackjackInput ENDP CalcPlayerBJScore PROC uses ebx esi xor eax, eax xor ebx, ebx xor esi, esi calc_p_loop: cmp esi, bjPlayerCardCount jge calc_p_done mov edx, [bjPlayerCards + esi*4] cmp edx, 10 jle @F mov edx, 10 @@: cmp edx, 1 jne add_p_val inc ebx ; count Aces add eax, 11 jmp next_p_card add_p_val: add eax, edx next_p_card: inc esi jmp calc_p_loop calc_p_done: ; Soft Ace reduction reduce_p_ace: cmp eax, 21 jle store_p_score test ebx, ebx jz store_p_score sub eax, 10 dec ebx jmp reduce_p_ace store_p_score: mov bjPlayerScore, eax ret CalcPlayerBJScore ENDP CalcDealerBJScore PROC uses ebx esi xor eax, eax xor ebx, ebx xor esi, esi calc_d_loop: cmp esi, bjDealerCardCount jge calc_d_done mov edx, [bjDealerCards + esi*4] cmp edx, 10 jle @F mov edx, 10 @@: cmp edx, 1 jne add_d_val inc ebx add eax, 11 jmp next_d_card add_d_val: add eax, edx next_d_card: inc esi jmp calc_d_loop calc_d_done: reduce_d_ace: cmp eax, 21 jle store_d_score test ebx, ebx jz store_d_score sub eax, 10 dec ebx jmp reduce_d_ace store_d_score: mov bjDealerScore, eax ret CalcDealerBJScore ENDP RenderBlackjackGame PROC uses ebx esi edi ; Emerald Felt Table Background invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 000A3015h invoke DrawBoxBorder, 10, 10, 300, 220, 000D4018h, 0000D7FFh, 3 ; Dealer Area Top invoke DrawString8x8, 25, 20, OFFSET textBJ3D, 0000D7FFh invoke DrawString8x8, 25, 35, OFFSET textDealer3D, 00FFFFFFh invoke FormatNumber, bjDealerScore, OFFSET hudNumBuffer invoke DrawString8x8, 120, 35, OFFSET hudNumBuffer, 0000FFFFh ; Dealer Cards xor esi, esi draw_dealer_cards: cmp esi, bjDealerCardCount jge draw_player_bj_area mov eax, esi imul eax, 45 add eax, 25 mov ebx, eax cmp esi, 1 jne draw_dealer_face cmp bjDealerHideHole, 1 jne draw_dealer_face ; Face Down Card mov eax, selectedBack3D mov eax, cardBackColors3D[eax*4] invoke DrawBoxBorder, ebx, 48, 38, 52, eax, 00FFFFFFh, 2 jmp next_dealer_card_draw draw_dealer_face: invoke DrawBoxBorder, ebx, 48, 38, 52, 00F0F0F5h, 00000000h, 2 mov eax, [bjDealerCards + esi*4] dec eax imul eax, 3 lea edx, [cardRankStr + eax] mov eax, ebx add eax, 8 invoke DrawString8x8, eax, 68, edx, 00000000h next_dealer_card_draw: inc esi jmp draw_dealer_cards draw_player_bj_area: ; Player Area Bottom invoke DrawString8x8, 25, 110, OFFSET textPlayer3D, 00FFFFFFh invoke FormatNumber, bjPlayerScore, OFFSET hudNumBuffer invoke DrawString8x8, 120, 110, OFFSET hudNumBuffer, 0050FF50h ; Player Cards xor esi, esi draw_player_cards: cmp esi, bjPlayerCardCount jge draw_bj_footer mov eax, esi imul eax, 45 add eax, 25 mov ebx, eax invoke DrawBoxBorder, ebx, 124, 38, 52, 00F0F0F5h, 00000000h, 2 mov eax, [bjPlayerCards + esi*4] dec eax imul eax, 3 lea edx, [cardRankStr + eax] mov eax, ebx add eax, 8 invoke DrawString8x8, eax, 144, edx, 00000000h inc esi jmp draw_player_cards draw_bj_footer: ; Footer Status & Controls invoke DrawBoxBorder, 20, 182, 280, 42, 00102010h, 0000D7FFh, 1 cmp BYTE PTR [bjOutcomeMsg], 0 je draw_bj_controls invoke DrawString8x8, 28, 188, OFFSET bjOutcomeMsg, 0000FFFFh invoke DrawString8x8, 28, 204, OFFSET textNext3D, 00A0A0A0h ret draw_bj_controls: invoke DrawString8x8, 28, 188, OFFSET textBJKeys3D, 00FFFFFFh invoke DrawString8x8, 28, 204, OFFSET textDeal3D, 00A0A0A0h ret RenderBlackjackGame ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: ROULETTE ; ============================================================================== HandleRouletteInput PROC uses ebx cmp roulState, 1 je roul_input_done invoke Pressed3D, 31h ; '1' -> RED test ah, 80h jz @F mov roulBetType, 1 @@: invoke Pressed3D, 32h ; '2' -> BLACK test ah, 80h jz @F mov roulBetType, 2 @@: invoke Pressed3D, 33h ; '3' -> ZERO (0) test ah, 80h jz @F mov roulBetType, 3 @@: invoke Pressed3D, 34h ; '4' -> EVEN test ah, 80h jz @F mov roulBetType, 4 @@: invoke Pressed3D, 35h ; '5' -> ODD test ah, 80h jz check_roul_spin mov roulBetType, 5 check_roul_spin: invoke Pressed3D, 20h ; SPACE -> Spin test ah, 80h jz roul_input_done mov eax, bankroll cmp eax, roulBetAmount jl roul_no_cash sub eax, roulBetAmount mov bankroll, eax mov roulState, 1 mov roulSpinTimer, 50 mov roulPayout, 0 invoke PlaySoundA, OFFSET soundRoulette, 0, 1 ret roul_no_cash: invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage mov flashTimer, 60 roul_input_done: ret HandleRouletteInput ENDP RenderRouletteGame PROC uses ebx esi edi ; Table felt background invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00151525h invoke DrawBoxBorder, 10, 10, 300, 220, 00201525h, 0000D7FFh, 3 ; 2.5D Rotating Wheel on Left invoke DrawCircle, 85, 110, 65, 00102550h invoke DrawCircle, 85, 110, 60, 0000D7FFh invoke DrawCircle, 85, 110, 52, 00101010h invoke DrawCircle, 85, 110, 22, 0000D7FFh ; Center brass turret ; Spinning Wheel / Ball Logic cmp roulState, 1 jne draw_roul_ball dec roulSpinTimer add roulWheelAngle, 8 sub roulBallAngle, 14 cmp roulSpinTimer, 0 jg draw_roul_ball ; Wheel stopped! Determine result! mov roulState, 2 invoke RandomRange3D, 37 mov roulWinningNum, eax ; Check bet cmp roulBetType, 1 ; RED jne check_ro_black call IsNumberRed test eax, eax jz ro_lost mov eax, roulBetAmount shl eax, 1 mov roulPayout, eax add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET roulOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 jmp draw_roul_ball check_ro_black: cmp roulBetType, 2 ; BLACK jne check_ro_zero cmp roulWinningNum, 0 je ro_lost call IsNumberRed test eax, eax jnz ro_lost mov eax, roulBetAmount shl eax, 1 mov roulPayout, eax add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET roulOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 jmp draw_roul_ball check_ro_zero: cmp roulBetType, 3 ; ZERO jne check_ro_even cmp roulWinningNum, 0 jne ro_lost mov eax, roulBetAmount imul eax, 36 mov roulPayout, eax add bankroll, eax invoke CopyString3D, OFFSET strJackpot, OFFSET roulOutcomeMsg invoke PlaySoundA, OFFSET soundJackpot, 0, 1 jmp draw_roul_ball check_ro_even: cmp roulBetType, 4 ; EVEN jne check_ro_odd mov eax, roulWinningNum test eax, eax jz ro_lost test al, 1 jnz ro_lost mov eax, roulBetAmount shl eax, 1 mov roulPayout, eax add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET roulOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 jmp draw_roul_ball check_ro_odd: mov eax, roulWinningNum test eax, eax jz ro_lost test al, 1 jz ro_lost mov eax, roulBetAmount shl eax, 1 mov roulPayout, eax add bankroll, eax invoke CopyString3D, OFFSET strWin, OFFSET roulOutcomeMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 jmp draw_roul_ball ro_lost: invoke CopyString3D, OFFSET strLose, OFFSET roulOutcomeMsg draw_roul_ball: ; Draw White Ball on Rim mov eax, roulBallAngle and eax, 511 mov ebx, [tableCos + eax*4] imul ebx, 42 sar ebx, 16 add ebx, 85 mov eax, roulBallAngle and eax, 511 mov edx, [tableSin + eax*4] imul edx, 42 sar edx, 16 add edx, 110 invoke DrawCircle, ebx, edx, 3, 00FFFFFFh ; Right Betting Board invoke DrawBoxBorder, 175, 25, 125, 28, 001010C0h, 00FFFFFFh, 2 ; [1] RED invoke DrawString8x8, 190, 35, OFFSET textRed3D, 00FFFFFFh invoke DrawBoxBorder, 175, 60, 125, 28, 00151515h, 00FFFFFFh, 2 ; [2] BLACK invoke DrawString8x8, 190, 70, OFFSET textBlack3D, 00FFFFFFh invoke DrawBoxBorder, 175, 95, 125, 28, 00106010h, 00FFFFFFh, 2 ; [3] ZERO invoke DrawString8x8, 190, 105, OFFSET textZero3D, 00FFFFFFh invoke DrawBoxBorder, 175, 130, 60, 26, 00302020h, 00FFFFFFh, 1 ; [4] EVEN invoke DrawString8x8, 185, 139, OFFSET textEven3D, 00FFFFFFh invoke DrawBoxBorder, 240, 130, 60, 26, 00302020h, 00FFFFFFh, 1 ; [5] ODD invoke DrawString8x8, 250, 139, OFFSET textOdd3D, 00FFFFFFh ; Highlight Active Bet cmp roulBetType, 1 jne @F invoke DrawBoxBorder, 173, 23, 129, 32, 0, 0000FFFFh, 2 @@: cmp roulBetType, 2 jne @F invoke DrawBoxBorder, 173, 58, 129, 32, 0, 0000FFFFh, 2 @@: cmp roulBetType, 3 jne @F invoke DrawBoxBorder, 173, 93, 129, 32, 0, 0000FFFFh, 2 @@: cmp roulBetType, 4 jne @F invoke DrawBoxBorder, 173, 128, 64, 30, 0, 0000FFFFh, 2 @@: cmp roulBetType, 5 jne draw_ro_footer invoke DrawBoxBorder, 238, 128, 64, 30, 0, 0000FFFFh, 2 draw_ro_footer: invoke DrawBoxBorder, 20, 180, 280, 42, 00101015h, 0000D7FFh, 1 cmp roulState, 2 jne @F invoke DrawString8x8, 28, 186, OFFSET textResult3D, 0000D7FFh invoke FormatNumber, roulWinningNum, OFFSET hudNumBuffer invoke DrawString8x8, 85, 186, OFFSET hudNumBuffer, 0000FFFFh invoke DrawString8x8, 130, 186, OFFSET roulOutcomeMsg, 0050FF50h @@: invoke DrawString8x8, 28, 202, OFFSET textSpin3D, 00A0A0A0h ret RenderRouletteGame ENDP IsNumberRed PROC mov eax, roulWinningNum cmp eax, 1 je red_yes cmp eax, 3 je red_yes cmp eax, 5 je red_yes cmp eax, 7 je red_yes cmp eax, 9 je red_yes cmp eax, 12 je red_yes cmp eax, 14 je red_yes cmp eax, 16 je red_yes cmp eax, 18 je red_yes cmp eax, 19 je red_yes cmp eax, 21 je red_yes cmp eax, 23 je red_yes cmp eax, 25 je red_yes cmp eax, 27 je red_yes cmp eax, 30 je red_yes cmp eax, 32 je red_yes cmp eax, 34 je red_yes cmp eax, 36 je red_yes xor eax, eax ret red_yes: mov eax, 1 ret IsNumberRed ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: BAR & SHOP ; ============================================================================== HandleShopInput PROC uses ebx esi xor esi, esi shop_choice: inc esi lea eax, [esi+30h] invoke Pressed3D, eax test eax, eax jnz shop_chosen cmp esi, 3 jb shop_choice ret shop_chosen: bt ownedBacks3D, esi jc shop_equip mov ebx, 1500 cmp esi, 1 jne @F mov ebx, 1000 @@: cmp bankroll, ebx jb shop_no_money sub bankroll, ebx bts ownedBacks3D, esi shop_equip: mov selectedBack3D, esi invoke CopyString3D, OFFSET textBought3D, OFFSET shopMsg call SaveProgress3D ret shop_no_money: invoke CopyString3D, OFFSET textNoCash3D, OFFSET shopMsg ret HandleShopInput ENDP RenderShopGame PROC invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00150A0Ah invoke DrawBoxBorder, 10, 10, 300, 220, 00251515h, 0000D7FFh, 3 invoke DrawString8x8, 25, 20, OFFSET textShop3D, 0000D7FFh invoke DrawBoxBorder, 20, 40, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 46, OFFSET textItem1_3D, 0000FFFFh invoke DrawString8x8, 28, 58, OFFSET textShopHint3D, 00A0A0A0h invoke DrawBoxBorder, 20, 80, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 86, OFFSET textItem2_3D, 0000FFFFh invoke DrawString8x8, 28, 98, OFFSET textShopHint3D, 00A0A0A0h invoke DrawBoxBorder, 20, 120, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 126, OFFSET textItem3_3D, 0000FFFFh invoke DrawString8x8, 28, 138, OFFSET textShopHint3D, 00A0A0A0h invoke DrawBoxBorder, 20, 165, 280, 55, 00100A0Ah, 0000D7FFh, 1 invoke DrawString8x8, 28, 172, OFFSET textBank3D, 0000D7FFh invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 0000FFFFh cmp BYTE PTR [shopMsg], 0 je @F invoke DrawString8x8, 28, 188, OFFSET shopMsg, 0050FF50h @@: invoke DrawString8x8, 28, 204, OFFSET textBack3D, 00A0A0A0h ret RenderShopGame ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: ATM TERMINAL ; ============================================================================== HandleATMInput PROC ret HandleATMInput ENDP RenderATMGame PROC invoke DrawBox, 0, 0, 320, 240, 00172120h invoke DrawString8x8, 24, 30, OFFSET textATM3D, 00D8BC6Ah invoke DrawString8x8, 24, 70, OFFSET textBank3D, 00FFFFFFh invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 96, 70, OFFSET hudNumBuffer, 0089DAB2h invoke DrawString8x8, 24, 115, OFFSET textATMNote3D, 00B7C8C1h invoke DrawString8x8, 24, 140, OFFSET textATMNote2_3D, 00B7C8C1h invoke DrawString8x8, 24, 208, OFFSET textBack3D, 00D8BC6Ah ret RenderATMGame ENDP ; --- Player Input & Movement Physics --- HandlePlayerInput PROC uses ebx esi edi local speed:DWORD local nextX:DWORD local nextY:DWORD mov eax, deltaTime3D imul eax, 200 mov speed, eax cmp keys3D[10h], 0 je @F shl speed, 1 @@: mov eax, deltaTime3D shr eax, 2 inc eax cmp keys3D[41h], 0 jne input_turn_left cmp keys3D[25h], 0 je input_right input_turn_left: sub playerAngle, eax input_right: cmp keys3D[44h], 0 jne input_turn_right cmp keys3D[27h], 0 je input_forward input_turn_right: add playerAngle, eax input_forward: and playerAngle, 511 call UpdateCamera3D xor edi, edi cmp keys3D[57h], 0 jne input_go_forward cmp keys3D[26h], 0 je input_back input_go_forward: inc edi input_back: cmp keys3D[53h], 0 jne input_go_back cmp keys3D[28h], 0 je input_move input_go_back: dec edi input_move: test edi, edi jz input_action imul edi, speed mov eax, playerDirX imul edi shrd eax, edx, 16 add eax, playerX mov nextX, eax mov eax, playerDirY imul edi shrd eax, edx, 16 add eax, playerY mov nextY, eax invoke CanWalk3D, nextX, playerY test eax, eax jz @F mov eax, nextX mov playerX, eax @@: invoke CanWalk3D, playerX, nextY test eax, eax jz input_action mov eax, nextY mov playerY, eax input_action: invoke Pressed3D, 45h test eax, eax jz @F call Trigger3DInteraction @@: ret HandlePlayerInput ENDP CheckInteractions PROC uses ebx esi edi local nearest:DWORD mov nearest, 262144 mov interactTargetId, 0 mov interactPromptPtr, 0 xor esi, esi interaction_scan: cmp esi, NUM_SPRITES jge interaction_done imul edi, esi, SIZEOF SpriteObject cmp [casinoSprites+edi].interactId, 0 je interaction_next mov eax, [casinoSprites+edi].posX sub eax, playerX sar eax, 8 mov ebx, eax imul eax, eax mov ecx, eax mov eax, [casinoSprites+edi].posY sub eax, playerY sar eax, 8 mov edx, eax imul eax, eax add ecx, eax cmp ecx, nearest jae interaction_next ; Only target objects in front of the camera. mov eax, playerDirX sar eax, 8 imul eax, ebx mov ebx, playerDirY sar ebx, 8 imul ebx, edx add eax, ebx cmp eax, 18000 jl interaction_next mov nearest, ecx mov eax, [casinoSprites+edi].interactId mov interactTargetId, eax mov eax, [casinoSprites+edi].promptPtr mov interactPromptPtr, eax interaction_next: inc esi jmp interaction_scan interaction_done: ret CheckInteractions ENDP Trigger3DInteraction PROC mov eax, interactTargetId test eax, eax jz @F cmp eax, 8 ; DANCER jne check_target_slots cmp bankroll, 100 jl dancer_no_cash sub bankroll, 100 inc dancerLuckBuff ; Tips are cosmetic and must not silently change game odds. invoke CopyString3D, OFFSET textTips3D, OFFSET flashMessage mov flashTimer, 100 invoke PlaySoundA, OFFSET soundJackpot, 0, 1 ret dancer_no_cash: invoke CopyString3D, OFFSET msgNeedMoney, OFFSET flashMessage mov flashTimer, 60 ret check_target_slots: cmp eax, 3 ; SLOTS jne check_target_bj mov engineMode, MODE_SLOTS invoke PlaySoundA, OFFSET soundClick, 0, 1 ret check_target_bj: cmp eax, 1 ; BLACKJACK jne check_target_roulette mov engineMode, MODE_BLACKJACK mov bjState, 0 ret check_target_roulette: cmp eax, 4 ; ROULETTE jne check_target_shop mov engineMode, MODE_ROULETTE mov roulState, 0 ret check_target_shop: cmp eax, 6 ; SHOP jne check_target_atm mov engineMode, MODE_SHOP ret check_target_atm: cmp eax, 7 ; ATM jne target_unported mov engineMode, MODE_ATM ret target_unported: invoke CopyString3D, OFFSET textUnavailable3D, OFFSET flashMessage mov flashTimer, 150 @@: ret Trigger3DInteraction ENDP ; --- Engine Initialization --- Init3DEngine PROC local screenCX:DWORD local screenCY:DWORD local posX:DWORD local posY:DWORD local bytesRead:DWORD push ebx push esi push edi call Create3DWindow test eax, eax jz init_failed call LoadTextures3D test eax, eax jz init_failed init_sprites_table: ; Sprite 0: VIP Dancer 1 (Stage Left) mov casinoSprites[0*SIZEOF SpriteObject].posX, (13 * FP_1 + FP_HALF) mov casinoSprites[0*SIZEOF SpriteObject].posY, (4 * FP_1) mov casinoSprites[0*SIZEOF SpriteObject].baseTexId, 10 mov casinoSprites[0*SIZEOF SpriteObject].frameCount, 12 mov casinoSprites[0*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[0*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[0*SIZEOF SpriteObject].animSpeed, 5 mov casinoSprites[0*SIZEOF SpriteObject].interactId, 8 mov casinoSprites[0*SIZEOF SpriteObject].promptPtr, OFFSET promptDancer ; Sprite 1: VIP Dancer 2 (Center Stage Star) mov casinoSprites[1*SIZEOF SpriteObject].posX, (16 * FP_1 + FP_HALF) mov casinoSprites[1*SIZEOF SpriteObject].posY, (3 * FP_1 + FP_HALF) mov casinoSprites[1*SIZEOF SpriteObject].baseTexId, 10 mov casinoSprites[1*SIZEOF SpriteObject].frameCount, 12 mov casinoSprites[1*SIZEOF SpriteObject].curFrame, 2 mov casinoSprites[1*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[1*SIZEOF SpriteObject].animSpeed, 5 mov casinoSprites[1*SIZEOF SpriteObject].interactId, 8 mov casinoSprites[1*SIZEOF SpriteObject].promptPtr, OFFSET promptDancer ; Sprite 2: VIP Dancer 3 (Stage Right) mov casinoSprites[2*SIZEOF SpriteObject].posX, (19 * FP_1 + FP_HALF) mov casinoSprites[2*SIZEOF SpriteObject].posY, (4 * FP_1) mov casinoSprites[2*SIZEOF SpriteObject].baseTexId, 10 mov casinoSprites[2*SIZEOF SpriteObject].frameCount, 12 mov casinoSprites[2*SIZEOF SpriteObject].curFrame, 1 mov casinoSprites[2*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[2*SIZEOF SpriteObject].animSpeed, 5 mov casinoSprites[2*SIZEOF SpriteObject].interactId, 8 mov casinoSprites[2*SIZEOF SpriteObject].promptPtr, OFFSET promptDancer ; Sprite 3: Blackjack Table with Dealer (Front Center Left) mov casinoSprites[3*SIZEOF SpriteObject].posX, (12 * FP_1 + FP_HALF) mov casinoSprites[3*SIZEOF SpriteObject].posY, (10 * FP_1) mov casinoSprites[3*SIZEOF SpriteObject].baseTexId, 30 mov casinoSprites[3*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[3*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[3*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[3*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[3*SIZEOF SpriteObject].interactId, 1 mov casinoSprites[3*SIZEOF SpriteObject].promptPtr, OFFSET promptBlackjack ; Sprite 4: Roulette Table (Front Center) mov casinoSprites[4*SIZEOF SpriteObject].posX, (16 * FP_1 + FP_HALF) mov casinoSprites[4*SIZEOF SpriteObject].posY, (10 * FP_1) mov casinoSprites[4*SIZEOF SpriteObject].baseTexId, 31 mov casinoSprites[4*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[4*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[4*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[4*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[4*SIZEOF SpriteObject].interactId, 4 mov casinoSprites[4*SIZEOF SpriteObject].promptPtr, OFFSET promptRoulette ; Sprite 5: Poker Table (Front Center Right) mov casinoSprites[5*SIZEOF SpriteObject].posX, (21 * FP_1) mov casinoSprites[5*SIZEOF SpriteObject].posY, (10 * FP_1) mov casinoSprites[5*SIZEOF SpriteObject].baseTexId, 30 mov casinoSprites[5*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[5*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[5*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[5*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[5*SIZEOF SpriteObject].interactId, 1 mov casinoSprites[5*SIZEOF SpriteObject].promptPtr, OFFSET promptPoker ; Sprite 6: Slot Machine 1 (West Arcade) mov casinoSprites[6*SIZEOF SpriteObject].posX, (6 * FP_1) mov casinoSprites[6*SIZEOF SpriteObject].posY, (8 * FP_1) mov casinoSprites[6*SIZEOF SpriteObject].baseTexId, 24 mov casinoSprites[6*SIZEOF SpriteObject].frameCount, 3 mov casinoSprites[6*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[6*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[6*SIZEOF SpriteObject].animSpeed, 8 mov casinoSprites[6*SIZEOF SpriteObject].interactId, 3 mov casinoSprites[6*SIZEOF SpriteObject].promptPtr, OFFSET promptSlot1 ; Sprite 7: Slot Machine 2 (CloverPit) mov casinoSprites[7*SIZEOF SpriteObject].posX, (6 * FP_1) mov casinoSprites[7*SIZEOF SpriteObject].posY, (11 * FP_1) mov casinoSprites[7*SIZEOF SpriteObject].baseTexId, 24 mov casinoSprites[7*SIZEOF SpriteObject].frameCount, 3 mov casinoSprites[7*SIZEOF SpriteObject].curFrame, 1 mov casinoSprites[7*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[7*SIZEOF SpriteObject].animSpeed, 8 mov casinoSprites[7*SIZEOF SpriteObject].interactId, 3 mov casinoSprites[7*SIZEOF SpriteObject].promptPtr, OFFSET promptSlot2 ; Sprite 8: Slot Machine 3 mov casinoSprites[8*SIZEOF SpriteObject].posX, (6 * FP_1) mov casinoSprites[8*SIZEOF SpriteObject].posY, (14 * FP_1) mov casinoSprites[8*SIZEOF SpriteObject].baseTexId, 24 mov casinoSprites[8*SIZEOF SpriteObject].frameCount, 3 mov casinoSprites[8*SIZEOF SpriteObject].curFrame, 2 mov casinoSprites[8*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[8*SIZEOF SpriteObject].animSpeed, 8 mov casinoSprites[8*SIZEOF SpriteObject].interactId, 3 mov casinoSprites[8*SIZEOF SpriteObject].promptPtr, OFFSET promptSlot1 ; Sprite 9: Bartender / Bar Counter (East Wing) mov casinoSprites[9*SIZEOF SpriteObject].posX, (26 * FP_1) mov casinoSprites[9*SIZEOF SpriteObject].posY, (12 * FP_1) mov casinoSprites[9*SIZEOF SpriteObject].baseTexId, 32 mov casinoSprites[9*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[9*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[9*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[9*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[9*SIZEOF SpriteObject].interactId, 6 mov casinoSprites[9*SIZEOF SpriteObject].promptPtr, OFFSET promptShop ; Sprite 10: ATM Bank Terminal (East Wing) mov casinoSprites[10*SIZEOF SpriteObject].posX, (26 * FP_1) mov casinoSprites[10*SIZEOF SpriteObject].posY, (16 * FP_1) mov casinoSprites[10*SIZEOF SpriteObject].baseTexId, 33 mov casinoSprites[10*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[10*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[10*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[10*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[10*SIZEOF SpriteObject].interactId, 7 mov casinoSprites[10*SIZEOF SpriteObject].promptPtr, OFFSET promptATM ; Sprite 11: Underground Table (South Wing) mov casinoSprites[11*SIZEOF SpriteObject].posX, (16 * FP_1 + FP_HALF) mov casinoSprites[11*SIZEOF SpriteObject].posY, (24 * FP_1) mov casinoSprites[11*SIZEOF SpriteObject].baseTexId, 34 mov casinoSprites[11*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[11*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[11*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[11*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[11*SIZEOF SpriteObject].interactId, 5 mov casinoSprites[11*SIZEOF SpriteObject].promptPtr, OFFSET promptBackroom ; Sprite 12: Secret Demon Portal (South Wing) mov casinoSprites[12*SIZEOF SpriteObject].posX, (16 * FP_1 + FP_HALF) mov casinoSprites[12*SIZEOF SpriteObject].posY, (29 * FP_1) mov casinoSprites[12*SIZEOF SpriteObject].baseTexId, 4 mov casinoSprites[12*SIZEOF SpriteObject].frameCount, 1 mov casinoSprites[12*SIZEOF SpriteObject].curFrame, 0 mov casinoSprites[12*SIZEOF SpriteObject].animTimer, 0 mov casinoSprites[12*SIZEOF SpriteObject].animSpeed, 1 mov casinoSprites[12*SIZEOF SpriteObject].interactId, 9 mov casinoSprites[12*SIZEOF SpriteObject].promptPtr, OFFSET promptHell mov eax, 1 jmp init_return init_failed: xor eax, eax init_return: pop edi pop esi pop ebx ret Init3DEngine ENDP ; --- Main Loop of the 3D Casino Engine --- StartCasino3D PROC uses ebx esi edi call Init3DEngine test eax, eax jz engine_shutdown invoke GetTickCount mov rngSeed3D, eax mov previousTick3D, eax engine_loop: invoke PeekMessageA, OFFSET msg3D, 0, 0, 0, PM_REMOVE test eax, eax jz dispatch_frame cmp msg3D.message, WM_QUIT je engine_shutdown invoke TranslateMessage, OFFSET msg3D invoke DispatchMessageA, OFFSET msg3D jmp engine_loop dispatch_frame: invoke GetTickCount mov frameStart3D, eax sub eax, previousTick3D cmp eax, 50 jbe @F mov eax, 50 @@: mov deltaTime3D, eax mov eax, frameStart3D mov previousTick3D, eax invoke GetForegroundWindow cmp eax, h3DWnd jne engine_idle invoke IsIconic, h3DWnd test eax, eax jnz engine_idle invoke Pressed3D, 7Ah test eax, eax jz @F call ToggleFullscreen3D @@: invoke Pressed3D, 1Bh test eax, eax jz engine_tick cmp engineMode, MODE_WALK jne leave_table xor paused3D, 1 jmp engine_tick leave_table: ; An already paid round cannot be skipped or settled twice. cmp slotSpinState, 1 je engine_tick cmp roulState, 1 je engine_tick mov engineMode, MODE_WALK engine_tick: cmp paused3D, 0 jne draw_pause mov eax, deltaTime3D add animationClock3D, eax cmp engineMode, MODE_WALK jne check_slots_mode call UpdateCamera3D call CheckInteractions call HandlePlayerInput call UpdateCamera3D call RenderCeilingAndFloor call RenderWalls call RenderSprites call RenderHUD call RenderMinimap jmp present_frame check_slots_mode: cmp engineMode, MODE_SLOTS jne check_bj_mode call HandleSlotsInput call RenderSlotsGame jmp present_frame check_bj_mode: cmp engineMode, MODE_BLACKJACK jne check_roul_mode call HandleBlackjackInput call RenderBlackjackGame jmp present_frame check_roul_mode: cmp engineMode, MODE_ROULETTE jne check_shop_mode call HandleRouletteInput call RenderRouletteGame jmp present_frame check_shop_mode: cmp engineMode, MODE_SHOP jne check_atm_mode call HandleShopInput call RenderShopGame jmp present_frame check_atm_mode: call HandleATMInput call RenderATMGame jmp present_frame draw_pause: invoke DrawBoxBorder, 65, 75, 190, 85, 00151C21h, 00D8BC6Ah, 2 invoke DrawString8x8, 86, 88, OFFSET textPause3D, 00FFFFFFh invoke DrawString8x8, 78, 111, OFFSET textResume3D, 00D8BC6Ah invoke DrawString8x8, 78, 131, OFFSET textQuit3D, 00BBBBBBh invoke Pressed3D, 51h test eax, eax jnz engine_shutdown present_frame: call Present3D lea edi, pressedKeys3D xor eax, eax mov ecx, 64 rep stosd invoke GetTickCount sub eax, frameStart3D cmp eax, 16 jae engine_loop mov ecx, 16 sub ecx, eax invoke Sleep, ecx jmp engine_loop engine_idle: invoke Sleep, 50 jmp engine_loop engine_shutdown: call SaveProgress3D cmp h3DDC, 0 je @F invoke ReleaseDC, h3DWnd, h3DDC mov h3DDC, 0 @@: cmp h3DWnd, 0 je @F invoke DestroyWindow, h3DWnd mov h3DWnd, 0 @@: ret StartCasino3D ENDP include src_graphics\platform_code.inc