# -*- coding: utf-8 -*- import sys # Builder for casino3d.inc code_chunks = [] def a(s): code_chunks.append(s) # SECTION 1: Header, APIs, Structures, Constants a(''' ; ============================================================================== ; CASINO 3D ENGINE - DOOM / RETRO RAYCASTER FOR MASM32 (CP1251) ; ALL MINI-GAMES FULLY RENDERED IN 2.5D INSIDE THE GRAPHICAL WINDOW ; ============================================================================== 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 320 SCREEN_H equ 240 HALF_W equ 160 HALF_H equ 120 SCREEN_SIZE equ (SCREEN_W * SCREEN_H) WIN_SCALE equ 4 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 .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 "CASINO 3D - RETRO DOOM ENGINE [MASM32]",0 szTexturesRelPath db "assets\\textures\\casino3d.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] Танцовщица: Дать $100 чаевых (+УДАЧА)",0 promptSlot1 db "[E] Играть в Слоты 777",0 promptSlot2 db "[E] Играть в CloverPit 5x3",0 promptBlackjack db "[E] Играть в 21 / Blackjack",0 promptPoker db "[E] Играть в Покер",0 promptRoulette db "[E] Играть в Рулетку",0 promptShop db "[E] Бармен: VIP Магазин и Напитки",0 promptATM db "[E] Банкомат: Кредит и Обмен",0 promptBackroom db "[E] Подпольный стол: Buckshot / Рулетка",0 promptDurak db "[E] Карточный стол: Дурак",0 promptHell db "[E] Портал в Адскую Башню (Floor 666)",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 * 64 * 64) dup(?) hudNumBuffer db 32 dup(?) ''') # SECTION 2: Drawing primitives & Math a(''' .code ; --- 3D Window Procedure --- Casino3DWndProc PROC hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD cmp uMsg, WM_DESTROY jne @F invoke PostQuitMessage, 0 xor eax, eax ret @@: cmp uMsg, WM_CLOSE jne @F invoke PostQuitMessage, 0 xor eax, eax ret @@: invoke DefWindowProcA, 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 --- DrawPixel PROC x:DWORD, y:DWORD, color:DWORD mov eax, x cmp eax, 0 jl @F cmp eax, SCREEN_W jge @F mov ecx, y cmp ecx, 0 jl @F cmp ecx, SCREEN_H jge @F imul ecx, SCREEN_W add ecx, eax mov edx, color mov [screenBuffer + ecx*4], edx @@: ret DrawPixel ENDP DrawBox PROC x:DWORD, y:DWORD, w:DWORD, h:DWORD, color:DWORD 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 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 x:DWORD, y:DWORD, chVal:DWORD, color:DWORD push ebx push esi push edi mov eax, chVal and eax, 0FFh shl eax, 3 lea esi, [font8x8 + eax] xor edi, edi char_row_loop: cmp edi, 8 jge char_done mov ecx, y add ecx, edi cmp ecx, 0 jl next_char_row cmp ecx, SCREEN_H jge char_done movzx ebx, BYTE PTR [esi + edi] xor edx, edx char_col_loop: cmp edx, 8 jge next_char_row mov eax, x add eax, edx cmp eax, 0 jl next_char_col cmp eax, SCREEN_W jge next_char_row test ebx, 80h jz next_char_col push ecx imul ecx, SCREEN_W add ecx, eax push edx mov edx, color mov [screenBuffer + ecx*4], edx pop edx pop ecx next_char_col: shl ebx, 1 inc edx jmp char_col_loop next_char_row: inc edi jmp char_row_loop char_done: pop edi pop esi pop ebx 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 ''') # SECTION 3: 3D Raycaster Floor, Ceiling, Walls, Sprites a(''' ; --- 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, 121 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 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, 12 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, 10 and eax, 63 mov edx, fY shr edx, 10 and edx, 63 shl edx, 6 add edx, eax mov eax, [texturesBuffer + 49152 + 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 + 81920 + 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 imul ebx, -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 mov eax, FP_1 imul eax, FP_1 cdq 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 mov eax, FP_1 imul eax, FP_1 cdq 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 * 180 / 240 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, 10 and eax, 63 mov texX, eax cmp side, 0 jne @F cmp rayDirX, 0 jle @F mov eax, 63 sub eax, texX mov texX, eax @@: cmp side, 1 jne select_tex cmp rayDirY, 0 jge select_tex mov eax, 63 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, 12 mov edx, 256 sub edx, eax cmp edx, 35 jge @F mov edx, 35 @@: 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, 64 * 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, 63 shl eax, 6 add eax, texX mov edx, texId shl edx, 12 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 ; Advance animation frame mov edx, [casinoSprites + eax].animTimer inc edx cmp edx, [casinoSprites + eax].animSpeed jl store_anim xor edx, edx mov ecx, [casinoSprites + eax].curFrame inc ecx cmp ecx, [casinoSprites + eax].frameCount jl @F xor ecx, ecx @@: mov [casinoSprites + eax].curFrame, ecx store_anim: mov [casinoSprites + eax].animTimer, edx 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 mov eax, FP_1 imul eax, FP_1 cdq 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, 12 mov edx, 256 sub edx, eax cmp edx, 40 jge @F mov edx, 40 @@: 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, 6 cdq idiv sprW cmp eax, 0 jl next_spr_stripe cmp eax, 64 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, 6 cdq idiv sprH cmp eax, 0 jl next_spr_y cmp eax, 64 jge next_spr_y mov texY, eax shl eax, 6 add eax, texX mov edx, texSlot shl edx, 12 add eax, edx mov eax, [texturesBuffer + eax*4] ; Chromakey magenta filter cmp eax, CHROMA_KEY je next_spr_y test eax, eax jz next_spr_y mov ecx, eax and ecx, 0000FF00h cmp ecx, 00002000h ja do_draw_sprite_pix mov ecx, eax and ecx, 00FF0000h cmp ecx, 00D00000h jb do_draw_sprite_pix mov ecx, eax and ecx, 000000FFh cmp ecx, 000000D0h ja 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 ''') # SECTION 4: HUD & Radar a(''' ; --- HUD & Minimap Radar --- RenderHUD PROC uses ebx esi edi ; Top Luxury Status Bar invoke DrawBox, 0, 0, SCREEN_W, 16, 001A0A0Ah invoke DrawBox, 0, 15, SCREEN_W, 1, 0000D7FFh invoke DrawString8x8, 8, 4, OFFSET statusHUDFormat, 0000D7FFh invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 90, 4, OFFSET hudNumBuffer, 0000FFFFh invoke DrawString8x8, 140, 4, OFFSET targetHUDFormat, 0000D7FFh invoke FormatNumber, targetBank, OFFSET hudNumBuffer invoke DrawString8x8, 205, 4, OFFSET hudNumBuffer, 0050FF50h invoke DrawString8x8, 250, 4, OFFSET luckHUDFormat, 00FFAA00h invoke FormatNumber, dancerLuckBuff, OFFSET hudNumBuffer invoke DrawString8x8, 305, 4, OFFSET hudNumBuffer, 0000FFFFh ; Flash notification banner cmp flashTimer, 0 jle check_prompt dec flashTimer invoke DrawBox, 10, 20, 300, 14, 00201040h invoke DrawBoxBorder, 10, 20, 300, 14, 00201040h, 0000D7FFh, 1 invoke DrawString8x8, 14, 23, OFFSET flashMessage, 00FFFFFFh check_prompt: ; Interaction prompt banner at bottom mov eax, interactPromptPtr test eax, eax jz draw_controls_hud invoke DrawBoxBorder, 20, 195, 280, 18, 00201010h, 0000FFFFh, 1 invoke DrawString8x8, 26, 200, interactPromptPtr, 0000FFFFh draw_controls_hud: invoke DrawBox, 0, 226, SCREEN_W, 14, 00101010h invoke DrawString8x8, 6, 229, OFFSET controlsHUD, 00A0A0A0h ret RenderHUD ENDP RenderMinimap PROC uses ebx esi edi local radarX:DWORD local radarY:DWORD local radarSize:DWORD mov radarX, SCREEN_W - 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 ''') # SECTION 5: In-Engine 2.5D Mini-Games a(''' ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: SLOTS 777 ; ============================================================================== HandleSlotsInput PROC invoke GetAsyncKeyState, 1Bh ; ESC -> Exit to walking test ah, 80h jz @F mov engineMode, MODE_WALK ret @@: cmp slotSpinState, 1 je slots_input_done invoke GetAsyncKeyState, 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 GetAsyncKeyState, 26h ; UP / W test ah, 80h jnz inc_bet invoke GetAsyncKeyState, 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 GetAsyncKeyState, 28h ; DOWN / S test ah, 80h jnz dec_bet invoke GetAsyncKeyState, 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 sz3DWindowTitle, 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 statusHUDFormat, 0000D7FFh invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 110, 172, OFFSET hudNumBuffer, 0000FFFFh invoke DrawString8x8, 175, 172, OFFSET targetHUDFormat, 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 promptDancer, 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 invoke GetAsyncKeyState, 1Bh ; ESC -> Exit test ah, 80h jz @F mov engineMode, MODE_WALK ret @@: cmp bjState, 0 ; Need Deal jne check_bj_player_turn invoke GetAsyncKeyState, 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 GetAsyncKeyState, 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 GetAsyncKeyState, 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 GetAsyncKeyState, 20h ; SPACE -> Next Hand test ah, 80h jz bj_input_done mov bjState, 0 ret check_bj_bet_change: invoke GetAsyncKeyState, 26h ; UP test ah, 80h jz @F cmp bjBet, 500 jge bj_input_done add bjBet, 50 ret @@: invoke GetAsyncKeyState, 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 promptBlackjack, 0000D7FFh invoke DrawString8x8, 25, 35, OFFSET statusHUDFormat, 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 invoke DrawBoxBorder, ebx, 48, 38, 52, 002020B0h, 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 targetHUDFormat, 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 promptSlot1, 00A0A0A0h ret draw_bj_controls: invoke DrawString8x8, 28, 188, OFFSET promptDancer, 00FFFFFFh invoke DrawString8x8, 28, 204, OFFSET promptSlot2, 00A0A0A0h ret RenderBlackjackGame ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: ROULETTE ; ============================================================================== HandleRouletteInput PROC invoke GetAsyncKeyState, 1Bh ; ESC test ah, 80h jz @F mov engineMode, MODE_WALK ret @@: cmp roulState, 1 je roul_input_done invoke GetAsyncKeyState, 31h ; '1' -> RED test ah, 80h jz @F mov roulBetType, 1 @@: invoke GetAsyncKeyState, 32h ; '2' -> BLACK test ah, 80h jz @F mov roulBetType, 2 @@: invoke GetAsyncKeyState, 33h ; '3' -> ZERO (0) test ah, 80h jz @F mov roulBetType, 3 @@: invoke GetAsyncKeyState, 34h ; '4' -> EVEN test ah, 80h jz @F mov roulBetType, 4 @@: invoke GetAsyncKeyState, 35h ; '5' -> ODD test ah, 80h jz check_roul_spin mov roulBetType, 5 check_roul_spin: invoke GetAsyncKeyState, 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 promptSlot1, 00FFFFFFh invoke DrawBoxBorder, 175, 60, 125, 28, 00151515h, 00FFFFFFh, 2 ; [2] BLACK invoke DrawString8x8, 190, 70, OFFSET promptSlot2, 00FFFFFFh invoke DrawBoxBorder, 175, 95, 125, 28, 00106010h, 00FFFFFFh, 2 ; [3] ZERO invoke DrawString8x8, 190, 105, OFFSET promptPoker, 00FFFFFFh invoke DrawBoxBorder, 175, 130, 60, 26, 00302020h, 00FFFFFFh, 1 ; [4] EVEN invoke DrawString8x8, 185, 139, OFFSET symBar, 00FFFFFFh invoke DrawBoxBorder, 240, 130, 60, 26, 00302020h, 00FFFFFFh, 1 ; [5] ODD invoke DrawString8x8, 250, 139, OFFSET symBell, 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 targetHUDFormat, 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 controlsHUD, 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 invoke GetAsyncKeyState, 1Bh ; ESC test ah, 80h jz @F mov engineMode, MODE_WALK ret @@: invoke GetAsyncKeyState, 31h ; '1' -> Lucky Cocktail ($150) test ah, 80h jz @F cmp bankroll, 150 jl shop_no_money sub bankroll, 150 add dancerLuckBuff, 5 invoke CopyString3D, OFFSET msgDancerTipped, OFFSET shopMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 ret @@: invoke GetAsyncKeyState, 32h ; '2' -> Gold Card ($1000) test ah, 80h jz @F cmp bankroll, 1000 jl shop_no_money sub bankroll, 1000 invoke CopyString3D, OFFSET strWin, OFFSET shopMsg invoke PlaySoundA, OFFSET soundJackpot, 0, 1 ret @@: invoke GetAsyncKeyState, 33h ; '3' -> Cigar ($250) test ah, 80h jz shop_done cmp bankroll, 250 jl shop_no_money sub bankroll, 250 add dancerLuckBuff, 2 invoke CopyString3D, OFFSET msgDancerTipped, OFFSET shopMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 ret shop_no_money: invoke CopyString3D, OFFSET msgNeedMoney, OFFSET shopMsg shop_done: 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 promptShop, 0000D7FFh invoke DrawBoxBorder, 20, 40, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 46, OFFSET promptSlot1, 0000FFFFh invoke DrawString8x8, 28, 58, OFFSET symBar, 00A0A0A0h invoke DrawBoxBorder, 20, 80, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 86, OFFSET promptSlot2, 0000FFFFh invoke DrawString8x8, 28, 98, OFFSET symBell, 00A0A0A0h invoke DrawBoxBorder, 20, 120, 280, 32, 001A1010h, 00FFFFFFh, 1 invoke DrawString8x8, 28, 126, OFFSET promptBlackjack, 0000FFFFh invoke DrawString8x8, 28, 138, OFFSET symCherry, 00A0A0A0h invoke DrawBoxBorder, 20, 165, 280, 55, 00100A0Ah, 0000D7FFh, 1 invoke DrawString8x8, 28, 172, OFFSET statusHUDFormat, 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 controlsHUD, 00A0A0A0h ret RenderShopGame ENDP ; ============================================================================== ; IN-ENGINE 2.5D MINI-GAME: ATM TERMINAL ; ============================================================================== HandleATMInput PROC invoke GetAsyncKeyState, 1Bh ; ESC test ah, 80h jz @F mov engineMode, MODE_WALK ret @@: invoke GetAsyncKeyState, 31h ; '1' -> Loan $1000 test ah, 80h jz @F add bankroll, 1000 invoke CopyString3D, OFFSET strWin, OFFSET atmMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 ret @@: invoke GetAsyncKeyState, 32h ; '2' -> Daily Bonus $250 test ah, 80h jz atm_done add bankroll, 250 invoke CopyString3D, OFFSET strWin, OFFSET atmMsg invoke PlaySoundA, OFFSET soundCoin, 0, 1 atm_done: ret HandleATMInput ENDP RenderATMGame PROC ; Retro Green CRT Screen invoke DrawBox, 0, 0, SCREEN_W, SCREEN_H, 00051505h invoke DrawBoxBorder, 10, 10, 300, 220, 000A250Ah, 0000FF00h, 2 invoke DrawString8x8, 25, 25, OFFSET promptATM, 0000FF00h invoke DrawBoxBorder, 20, 50, 280, 35, 00051805h, 0000A000h, 1 invoke DrawString8x8, 28, 58, OFFSET promptSlot1, 0050FF50h invoke DrawString8x8, 28, 70, OFFSET symBar, 0000A000h invoke DrawBoxBorder, 20, 95, 280, 35, 00051805h, 0000A000h, 1 invoke DrawString8x8, 28, 103, OFFSET promptSlot2, 0050FF50h invoke DrawString8x8, 28, 115, OFFSET symBell, 0000A000h invoke DrawBoxBorder, 20, 145, 280, 75, 00051805h, 0000FF00h, 1 invoke DrawString8x8, 28, 155, OFFSET statusHUDFormat, 0000FF00h invoke FormatNumber, bankroll, OFFSET hudNumBuffer invoke DrawString8x8, 110, 155, OFFSET hudNumBuffer, 00FFFFFFh cmp BYTE PTR [atmMsg], 0 je @F invoke DrawString8x8, 28, 175, OFFSET atmMsg, 0000FFFFh @@: invoke DrawString8x8, 28, 195, OFFSET controlsHUD, 0000A000h ret RenderATMGame ENDP ''') # SECTION 6: Player Input, Engine Init, and Main Loop a(''' ; --- Player Input & Movement Physics --- HandlePlayerInput PROC local walkSpd:DWORD local turnSpd:DWORD local moveDirX:DWORD local moveDirY:DWORD local newX:DWORD local newY:DWORD local checkTileX:DWORD local checkTileY:DWORD push ebx push esi push edi mov walkSpd, 3600 mov turnSpd, 8 invoke GetAsyncKeyState, 10h ; Shift -> Run test ah, 80h jz @F mov walkSpd, 6200 @@: invoke GetAsyncKeyState, 41h ; A / Left test ah, 80h jnz turn_left invoke GetAsyncKeyState, 25h test ah, 80h jz check_turn_right turn_left: mov eax, playerAngle sub eax, turnSpd add eax, 512 and eax, 511 mov playerAngle, eax check_turn_right: invoke GetAsyncKeyState, 44h ; D / Right test ah, 80h jnz turn_right invoke GetAsyncKeyState, 27h test ah, 80h jz check_forward turn_right: mov eax, playerAngle add eax, turnSpd and eax, 511 mov playerAngle, eax check_forward: invoke GetAsyncKeyState, 57h ; W / Up test ah, 80h jnz walk_fwd invoke GetAsyncKeyState, 26h test ah, 80h jz check_backward walk_fwd: mov eax, playerAngle and eax, 511 mov ebx, [tableCos + eax*4] imul ebx, walkSpd shrd ebx, edx, 16 mov moveDirX, ebx mov ebx, [tableSin + eax*4] imul ebx, walkSpd shrd ebx, edx, 16 mov moveDirY, ebx mov eax, playerX add eax, moveDirX mov newX, eax mov eax, playerY add eax, moveDirY mov newY, eax ; Collision X mov eax, newX sar eax, 16 mov checkTileX, eax mov eax, playerY sar eax, 16 shl eax, 5 add eax, checkTileX movzx eax, BYTE PTR [casinoMap + eax] test eax, eax jnz @F mov eax, newX mov playerX, eax @@: ; Collision Y mov eax, newY sar eax, 16 shl eax, 5 mov ebx, playerX sar ebx, 16 add eax, ebx movzx eax, BYTE PTR [casinoMap + eax] test eax, eax jnz check_interact mov eax, newY mov playerY, eax jmp check_interact check_backward: invoke GetAsyncKeyState, 53h ; S / Down test ah, 80h jnz walk_back invoke GetAsyncKeyState, 28h test ah, 80h jz check_interact walk_back: mov eax, playerAngle and eax, 511 mov ebx, [tableCos + eax*4] imul ebx, walkSpd shrd ebx, edx, 16 neg ebx mov moveDirX, ebx mov ebx, [tableSin + eax*4] imul ebx, walkSpd shrd ebx, edx, 16 neg ebx mov moveDirY, ebx mov eax, playerX add eax, moveDirX mov newX, eax mov eax, playerY add eax, moveDirY mov newY, eax mov eax, newX sar eax, 16 mov checkTileX, eax mov eax, playerY sar eax, 16 shl eax, 5 add eax, checkTileX movzx eax, BYTE PTR [casinoMap + eax] test eax, eax jnz @F mov eax, newX mov playerX, eax @@: mov eax, newY sar eax, 16 shl eax, 5 mov ebx, playerX sar ebx, 16 add eax, ebx movzx eax, BYTE PTR [casinoMap + eax] test eax, eax jnz check_interact mov eax, newY mov playerY, eax check_interact: invoke GetAsyncKeyState, 45h ; 'E' test ah, 80h jz input_done call Trigger3DInteraction invoke Sleep, 120 input_done: pop edi pop esi pop ebx ret HandlePlayerInput ENDP CheckInteractions PROC uses ebx esi edi mov interactTargetId, 0 mov interactPromptPtr, 0 xor esi, esi check_spr_prox: cmp esi, NUM_SPRITES jge prox_done mov eax, esi imul eax, SIZEOF SpriteObject mov ebx, [casinoSprites + eax].distSq cmp ebx, 45000 ; Near sprite jg next_prox_spr mov edx, [casinoSprites + eax].interactId mov interactTargetId, edx mov edx, [casinoSprites + eax].promptPtr mov interactPromptPtr, edx jmp prox_done next_prox_spr: inc esi jmp check_spr_prox prox_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 mov cheatLuckyWin, 1 invoke CopyString3D, OFFSET msgDancerTipped, 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 @F mov engineMode, MODE_ATM ret @@: 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 invoke GetConsoleWindow mov hCasinoConsole, eax ; Setup DIB Info mov bmi3D.bmiHeader.biSize, SIZEOF C3D_BITMAPINFOHEADER mov bmi3D.bmiHeader.biWidth, SCREEN_W mov bmi3D.bmiHeader.biHeight, -SCREEN_H mov bmi3D.bmiHeader.biPlanes, 1 mov bmi3D.bmiHeader.biBitCount, 32 mov bmi3D.bmiHeader.biCompression, DIB_RGB_COLORS ; Setup Window Class mov wc3D.cbSize, SIZEOF C3D_WNDCLASSEX mov wc3D.style, CS_HREDRAW or CS_VREDRAW mov wc3D.lpfnWndProc, OFFSET Casino3DWndProc mov wc3D.cbClsExtra, 0 mov wc3D.cbWndExtra, 0 mov wc3D.hInstance, 0 mov wc3D.hIcon, 0 mov wc3D.hCursor, 0 mov wc3D.hbrBackground, 0 mov wc3D.lpszMenuName, 0 mov wc3D.lpszClassName, OFFSET sz3DClassName mov wc3D.hIconSm, 0 invoke RegisterClassExA, OFFSET wc3D ; Center 1280x960 Window on Desktop invoke GetSystemMetrics, 0 mov screenCX, eax invoke GetSystemMetrics, 1 mov screenCY, eax mov eax, screenCX sub eax, WINDOW_W shr eax, 1 cmp eax, 0 jge @F xor eax, eax @@: mov posX, eax mov eax, screenCY sub eax, WINDOW_H shr eax, 1 cmp eax, 0 jge @F xor eax, eax @@: mov posY, eax invoke CreateWindowExA, 0, OFFSET sz3DClassName, OFFSET sz3DWindowTitle,\ WS_OVERLAPPEDWINDOW, posX, posY, WINDOW_W + 16, WINDOW_H + 39,\ 0, 0, 0, 0 mov h3DWnd, eax invoke GetDC, h3DWnd mov h3DDC, eax invoke ShowWindow, h3DWnd, SW_SHOW invoke UpdateWindow, h3DWnd invoke SetForegroundWindow, h3DWnd ; Load Textures invoke CreateFileA, OFFSET szTexturesRelPath, 80000000h, 1, 0, 3, 80h, 0 cmp eax, INVALID_FILE_HANDLE je init_sprites_table mov ebx, eax lea ecx, bytesRead invoke ReadFile, ebx, OFFSET texturesBuffer, (48 * 64 * 64 * 4), ecx, 0 invoke CloseHandle, ebx 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, 4 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, 4 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, 4 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, 20 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, 20 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, 20 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 pop edi pop esi pop ebx ret Init3DEngine ENDP ; --- Main Loop of the 3D Casino Engine --- StartCasino3D PROC uses ebx esi edi call Init3DEngine invoke PlaySoundA, OFFSET soundJackpot, 0, 1 engine_loop: lea eax, [msg3D] invoke PeekMessageA, eax, 0, 0, 0, PM_REMOVE test eax, eax jz dispatch_frame cmp msg3D.message, WM_QUIT je exit_3d_engine lea eax, [msg3D] invoke TranslateMessage, eax lea eax, [msg3D] invoke DispatchMessageA, eax dispatch_frame: cmp engineMode, MODE_WALK jne check_slots_mode ; MODE_WALK: 3D Raycasting Casino invoke GetAsyncKeyState, 1Bh ; ESC in walk mode -> Exit 3D test ah, 80h jnz exit_3d_engine call HandlePlayerInput call CheckInteractions 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 present_frame: invoke StretchDIBits, h3DDC, 0, 0, WINDOW_W, WINDOW_H,\ 0, 0, SCREEN_W, SCREEN_H,\ OFFSET screenBuffer, OFFSET bmi3D, DIB_RGB_COLORS, SRCCOPY invoke Sleep, 16 jmp engine_loop exit_3d_engine: cmp h3DWnd, 0 je @F invoke ShowWindow, h3DWnd, SW_HIDE @@: invoke SetForegroundWindow, hCasinoConsole ret StartCasino3D ENDP ''') # Write complete file in Windows-1251 with open('casino3d.inc', 'wb') as f: f.write(''.join(code_chunks).encode('cp1251')) print('casino3d.inc completely generated in CP1251!')