KAZIK/tools/generators/build_all_3d.py

3233 lines
73 KiB
Python

# -*- 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
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
with open(REPO_ROOT / 'casino3d.inc', 'wb') as f:
f.write(''.join(code_chunks).encode('cp1251'))
print('casino3d.inc completely generated in CP1251!')