- Billiards: add native Russian Pyramid & American Eight-Ball pool with physics prediction, controls, and regression tests - Scratch Tickets: add dedicated counter, mat presentation, elliptical coin scraping, 4 ticket types, and payout effects - First-Person Dice: add native dice scene, hand anchor frames, throwing animation, and table perspective - City Wake & Weather: add arrival cutscene, alley geometry, weather/rain effects, and lighter/rocker animation - World Dressing: add hall paintings, furniture packs, hall lighting, and scene regression tests - Build & Tooling: update build.bat for modern MSVC toolchain, update launcher hash, and refresh shipping binaries
584 lines
13 KiB
PHP
584 lines
13 KiB
PHP
; Moving cube geometry shares the existing 320x240 logical game canvas.
|
|
include src_graphics/dice_anchors.inc
|
|
.data
|
|
cubeCorners3D dd -32768,-32768,-32768, 32768,-32768,-32768
|
|
dd 32768,32768,-32768, -32768,32768,-32768
|
|
dd -32768,-32768,32768, 32768,-32768,32768
|
|
dd 32768,32768,32768, -32768,32768,32768
|
|
cubeFaces3D db 0,1,2,3, 4,7,6,5, 0,3,7,4
|
|
db 1,5,6,2, 0,4,5,1, 3,2,6,7
|
|
cubeTop3D dd 3,1,1,1,1,3
|
|
cubeRight3D dd 2,3,2,2,3,2
|
|
cubeColors3D dd 00FAF1DFh,00C9C1B0h,00D1C5AEh
|
|
dd 00DFD3BDh,00FFF9EAh,00B5AA98h
|
|
cubePips3D dd 32768,32768, 16384,16384, 49152,49152
|
|
dd 49152,16384, 16384,49152, 16384,32768, 49152,32768
|
|
cubeX3D dd 0
|
|
cubeY3D dd 0
|
|
cubeScale3D dd 36
|
|
cubeSinX3D dd 0
|
|
cubeCosX3D dd 65536
|
|
cubeSinY3D dd 0
|
|
cubeCosY3D dd 65536
|
|
cubeSinZ3D dd 0
|
|
cubeCosZ3D dd 65536
|
|
cubeVertices3D dd 16 dup(0)
|
|
cubeFaceValues3D dd 6 dup(0)
|
|
cubeQuad3D dd 8 dup(0)
|
|
cubeContactShadow3D dd 0
|
|
.code
|
|
|
|
; Fill clockwise triangles. Edges are incremented per pixel, avoiding divisions.
|
|
DrawTriangle3D PROC uses ebx esi edi x1:DWORD,y1:DWORD,x2:DWORD,y2:DWORD,x3:DWORD,y3:DWORD,tint:DWORD
|
|
local lowX:DWORD,highX:DWORD,lowY:DWORD,highY:DWORD
|
|
local dx0:DWORD,dy0:DWORD,dx1:DWORD,dy1:DWORD,dx2:DWORD,dy2:DWORD
|
|
local row0:DWORD,row1:DWORD,row2:DWORD,e0:DWORD,e1:DWORD,e2:DWORD
|
|
local py:DWORD,px:DWORD
|
|
mov eax, x2
|
|
sub eax, x1
|
|
mov dx0, eax
|
|
mov edx, y2
|
|
sub edx, y1
|
|
mov dy0, edx
|
|
mov ebx, x3
|
|
sub ebx, x1
|
|
imul ebx, edx
|
|
mov ecx, y3
|
|
sub ecx, y1
|
|
imul eax, ecx
|
|
sub eax, ebx
|
|
cmp eax, 0
|
|
jle triangle_done
|
|
mov eax, x3
|
|
sub eax, x2
|
|
mov dx1, eax
|
|
mov eax, y3
|
|
sub eax, y2
|
|
mov dy1, eax
|
|
mov eax, x1
|
|
sub eax, x3
|
|
mov dx2, eax
|
|
mov eax, y1
|
|
sub eax, y3
|
|
mov dy2, eax
|
|
mov eax, x1
|
|
mov ebx, eax
|
|
cmp eax, x2
|
|
jle @F
|
|
mov eax, x2
|
|
@@:
|
|
cmp eax, x3
|
|
jle @F
|
|
mov eax, x3
|
|
@@:
|
|
cmp eax, 0
|
|
jge @F
|
|
xor eax, eax
|
|
@@:
|
|
mov lowX, eax
|
|
cmp ebx, x2
|
|
jge @F
|
|
mov ebx, x2
|
|
@@:
|
|
cmp ebx, x3
|
|
jge @F
|
|
mov ebx, x3
|
|
@@:
|
|
cmp ebx, 319
|
|
jle @F
|
|
mov ebx, 319
|
|
@@:
|
|
mov highX, ebx
|
|
mov eax, y1
|
|
mov ebx, eax
|
|
cmp eax, y2
|
|
jle @F
|
|
mov eax, y2
|
|
@@:
|
|
cmp eax, y3
|
|
jle @F
|
|
mov eax, y3
|
|
@@:
|
|
cmp eax, 0
|
|
jge @F
|
|
xor eax, eax
|
|
@@:
|
|
mov lowY, eax
|
|
cmp ebx, y2
|
|
jge @F
|
|
mov ebx, y2
|
|
@@:
|
|
cmp ebx, y3
|
|
jge @F
|
|
mov ebx, y3
|
|
@@:
|
|
cmp ebx, 239
|
|
jle @F
|
|
mov ebx, 239
|
|
@@:
|
|
mov highY, ebx
|
|
mov eax, lowY
|
|
sub eax, y1
|
|
imul eax, dx0
|
|
mov edx, lowX
|
|
sub edx, x1
|
|
imul edx, dy0
|
|
sub eax, edx
|
|
mov row0, eax
|
|
mov eax, lowY
|
|
sub eax, y2
|
|
imul eax, dx1
|
|
mov edx, lowX
|
|
sub edx, x2
|
|
imul edx, dy1
|
|
sub eax, edx
|
|
mov row1, eax
|
|
mov eax, lowY
|
|
sub eax, y3
|
|
imul eax, dx2
|
|
mov edx, lowX
|
|
sub edx, x3
|
|
imul edx, dy2
|
|
sub eax, edx
|
|
mov row2, eax
|
|
mov eax, lowY
|
|
mov py, eax
|
|
triangle_row:
|
|
mov eax, py
|
|
cmp eax, highY
|
|
jg triangle_done
|
|
mov eax, row0
|
|
mov e0, eax
|
|
mov eax, row1
|
|
mov e1, eax
|
|
mov eax, row2
|
|
mov e2, eax
|
|
mov eax, lowX
|
|
mov px, eax
|
|
triangle_pixel:
|
|
mov eax, px
|
|
cmp eax, highX
|
|
jg triangle_next_row
|
|
mov eax, e0
|
|
or eax, e1
|
|
or eax, e2
|
|
js triangle_next_pixel
|
|
mov edi, py
|
|
imul edi, SCREEN_W * 2
|
|
mov eax, px
|
|
shl eax, 1
|
|
add edi, eax
|
|
mov eax, tint
|
|
mov screenBuffer[edi*4], eax
|
|
mov screenBuffer[edi*4+4], eax
|
|
mov screenBuffer[edi*4+SCREEN_W*4], eax
|
|
mov screenBuffer[edi*4+SCREEN_W*4+4], eax
|
|
triangle_next_pixel:
|
|
mov eax, dy0
|
|
sub e0, eax
|
|
mov eax, dy1
|
|
sub e1, eax
|
|
mov eax, dy2
|
|
sub e2, eax
|
|
inc px
|
|
jmp triangle_pixel
|
|
triangle_next_row:
|
|
mov eax, dx0
|
|
add row0, eax
|
|
mov eax, dx1
|
|
add row1, eax
|
|
mov eax, dx2
|
|
add row2, eax
|
|
inc py
|
|
jmp triangle_row
|
|
triangle_done:
|
|
ret
|
|
DrawTriangle3D ENDP
|
|
|
|
; Local 16.16 coordinates -> yaw, pitch, roll -> screen coordinates.
|
|
ProjectCubePoint3D PROC uses ebx esi edi nx:DWORD,ny:DWORD,nz:DWORD
|
|
local rx:DWORD,ry:DWORD,rz:DWORD
|
|
mov eax, nx
|
|
imul cubeCosY3D
|
|
shrd eax, edx, 16
|
|
mov ebx, eax
|
|
mov eax, nz
|
|
imul cubeSinY3D
|
|
shrd eax, edx, 16
|
|
add eax, ebx
|
|
mov rx, eax
|
|
mov eax, nz
|
|
imul cubeCosY3D
|
|
shrd eax, edx, 16
|
|
mov ebx, eax
|
|
mov eax, nx
|
|
imul cubeSinY3D
|
|
shrd eax, edx, 16
|
|
sub ebx, eax
|
|
mov rz, ebx
|
|
mov eax, ny
|
|
imul cubeCosX3D
|
|
shrd eax, edx, 16
|
|
mov ebx, eax
|
|
mov eax, rz
|
|
imul cubeSinX3D
|
|
shrd eax, edx, 16
|
|
sub ebx, eax
|
|
mov ry, ebx
|
|
mov eax, rx
|
|
imul cubeCosZ3D
|
|
shrd eax, edx, 16
|
|
mov ebx, eax
|
|
mov eax, ry
|
|
imul cubeSinZ3D
|
|
shrd eax, edx, 16
|
|
sub ebx, eax
|
|
imul ebx, cubeScale3D
|
|
sar ebx, 16
|
|
add ebx, cubeX3D
|
|
mov eax, rx
|
|
imul cubeSinZ3D
|
|
shrd eax, edx, 16
|
|
mov esi, eax
|
|
mov eax, ry
|
|
imul cubeCosZ3D
|
|
shrd eax, edx, 16
|
|
add eax, esi
|
|
imul eax, cubeScale3D
|
|
sar eax, 16
|
|
add eax, cubeY3D
|
|
mov edx, eax
|
|
mov eax, ebx
|
|
ret
|
|
ProjectCubePoint3D ENDP
|
|
|
|
DrawCubePip3D PROC uses ebx esi u:DWORD,v:DWORD,pipRadius:DWORD
|
|
mov eax, cubeQuad3D[8]
|
|
sub eax, cubeQuad3D
|
|
imul u
|
|
shrd eax, edx, 16
|
|
mov ebx, eax
|
|
mov eax, cubeQuad3D[24]
|
|
sub eax, cubeQuad3D
|
|
imul v
|
|
shrd eax, edx, 16
|
|
add ebx, eax
|
|
add ebx, cubeQuad3D
|
|
mov eax, cubeQuad3D[12]
|
|
sub eax, cubeQuad3D[4]
|
|
imul u
|
|
shrd eax, edx, 16
|
|
mov esi, eax
|
|
mov eax, cubeQuad3D[28]
|
|
sub eax, cubeQuad3D[4]
|
|
imul v
|
|
shrd eax, edx, 16
|
|
add esi, eax
|
|
add esi, cubeQuad3D[4]
|
|
invoke DrawCircle, ebx, esi, pipRadius, 00A31D25h
|
|
ret
|
|
DrawCubePip3D ENDP
|
|
|
|
DrawTumblingDie3D PROC uses ebx esi edi centerX:DWORD,centerY:DWORD,pitch:DWORD,yaw:DWORD,roll:DWORD,value:DWORD
|
|
local face:DWORD,pip:DWORD,pipRadius:DWORD,area:DWORD
|
|
mov eax, centerX
|
|
mov cubeX3D, eax
|
|
mov eax, centerY
|
|
mov cubeY3D, eax
|
|
mov eax, pitch
|
|
and eax, 511
|
|
mov edx, tableSin[eax*4]
|
|
mov cubeSinX3D, edx
|
|
mov edx, tableCos[eax*4]
|
|
mov cubeCosX3D, edx
|
|
mov eax, yaw
|
|
and eax, 511
|
|
mov edx, tableSin[eax*4]
|
|
mov cubeSinY3D, edx
|
|
mov edx, tableCos[eax*4]
|
|
mov cubeCosY3D, edx
|
|
mov eax, roll
|
|
and eax, 511
|
|
mov edx, tableSin[eax*4]
|
|
mov cubeSinZ3D, edx
|
|
mov edx, tableCos[eax*4]
|
|
mov cubeCosZ3D, edx
|
|
mov eax, value
|
|
mov cubeFaceValues3D[16], eax
|
|
mov edx, 7
|
|
sub edx, eax
|
|
mov cubeFaceValues3D[20], edx
|
|
dec eax
|
|
mov edx, cubeRight3D[eax*4]
|
|
mov cubeFaceValues3D[12], edx
|
|
mov ecx, 7
|
|
sub ecx, edx
|
|
mov cubeFaceValues3D[8], ecx
|
|
mov edx, cubeTop3D[eax*4]
|
|
mov cubeFaceValues3D, edx
|
|
mov ecx, 7
|
|
sub ecx, edx
|
|
mov cubeFaceValues3D[4], ecx
|
|
xor esi, esi
|
|
cube_project_loop:
|
|
imul edi, esi, 12
|
|
invoke ProjectCubePoint3D, cubeCorners3D[edi], cubeCorners3D[edi+4], cubeCorners3D[edi+8]
|
|
mov cubeVertices3D[esi*8], eax
|
|
mov cubeVertices3D[esi*8+4], edx
|
|
inc esi
|
|
cmp esi, 8
|
|
jb cube_project_loop
|
|
; A resting cube touches the cloth along its projected bottom face.
|
|
; Reverse the underside winding; the normal face pass culls it.
|
|
cmp cubeContactShadow3D,0
|
|
je cube_no_contact_shadow
|
|
mov eax,cubeVertices3D[28]
|
|
inc eax
|
|
mov ebx,cubeVertices3D[60]
|
|
inc ebx
|
|
mov edi,cubeVertices3D[52]
|
|
inc edi
|
|
invoke DrawTriangle3D,cubeVertices3D[24],eax,cubeVertices3D[56],ebx,cubeVertices3D[48],edi,00153122h
|
|
mov eax,cubeVertices3D[28]
|
|
inc eax
|
|
mov ebx,cubeVertices3D[52]
|
|
inc ebx
|
|
mov edi,cubeVertices3D[20]
|
|
inc edi
|
|
invoke DrawTriangle3D,cubeVertices3D[24],eax,cubeVertices3D[48],ebx,cubeVertices3D[16],edi,00153122h
|
|
cube_no_contact_shadow:
|
|
mov face, 0
|
|
cube_face_loop:
|
|
mov esi, face
|
|
xor edi, edi
|
|
cube_load_quad:
|
|
movzx eax, cubeFaces3D[esi*4+edi]
|
|
mov ebx, cubeVertices3D[eax*8]
|
|
mov cubeQuad3D[edi*8], ebx
|
|
mov ebx, cubeVertices3D[eax*8+4]
|
|
mov cubeQuad3D[edi*8+4], ebx
|
|
inc edi
|
|
cmp edi, 4
|
|
jb cube_load_quad
|
|
mov eax, cubeQuad3D[8]
|
|
sub eax, cubeQuad3D
|
|
mov edx, cubeQuad3D[28]
|
|
sub edx, cubeQuad3D[4]
|
|
imul eax, edx
|
|
mov ebx, cubeQuad3D[24]
|
|
sub ebx, cubeQuad3D
|
|
mov edx, cubeQuad3D[12]
|
|
sub edx, cubeQuad3D[4]
|
|
imul ebx, edx
|
|
sub eax, ebx
|
|
mov area, eax
|
|
cmp eax, 0
|
|
jle cube_next_face
|
|
mov ebx, cubeColors3D[esi*4]
|
|
invoke DrawTriangle3D, cubeQuad3D, cubeQuad3D[4], cubeQuad3D[8], cubeQuad3D[12], cubeQuad3D[16], cubeQuad3D[20], ebx
|
|
invoke DrawTriangle3D, cubeQuad3D, cubeQuad3D[4], cubeQuad3D[16], cubeQuad3D[20], cubeQuad3D[24], cubeQuad3D[28], ebx
|
|
cmp area, 70
|
|
jl cube_next_face
|
|
mov pipRadius, 1
|
|
cmp area, 450
|
|
jl @F
|
|
mov pipRadius, 2
|
|
@@:
|
|
mov ebx, cubeFaceValues3D[esi*4]
|
|
test ebx, 1
|
|
jz cube_corner_pips
|
|
invoke DrawCubePip3D, 32768, 32768, pipRadius
|
|
cube_corner_pips:
|
|
cmp ebx, 2
|
|
jl cube_next_face
|
|
invoke DrawCubePip3D, 16384, 16384, pipRadius
|
|
invoke DrawCubePip3D, 49152, 49152, pipRadius
|
|
cmp ebx, 4
|
|
jl cube_next_face
|
|
invoke DrawCubePip3D, 49152, 16384, pipRadius
|
|
invoke DrawCubePip3D, 16384, 49152, pipRadius
|
|
cmp ebx, 6
|
|
jl cube_next_face
|
|
invoke DrawCubePip3D, 16384, 32768, pipRadius
|
|
invoke DrawCubePip3D, 49152, 32768, pipRadius
|
|
cube_next_face:
|
|
inc face
|
|
cmp face, 6
|
|
jb cube_face_loop
|
|
ret
|
|
DrawTumblingDie3D ENDP
|
|
|
|
RenderDiceThrow3D PROC uses ebx esi edi
|
|
local t:DWORD,ground:DWORD,lift:DWORD,pitch:DWORD,yaw:DWORD,roll:DWORD
|
|
local cx1:DWORD,cx2:DWORD,cy:DWORD,cy2:DWORD,oldScale:DWORD,shadowAlpha:DWORD
|
|
; Held dice are painted into the cupped palm: no second pair over skin.
|
|
cmp diceArtReady3D,1
|
|
jne throw_begin
|
|
cmp dice3d_state,0
|
|
je throw_done
|
|
cmp dice3d_state,1
|
|
jne throw_begin
|
|
cmp dice3d_timer,240
|
|
jb throw_done
|
|
throw_begin:
|
|
mov eax,cubeScale3D
|
|
mov oldScale,eax
|
|
mov t,0
|
|
cmp dice3d_state,2
|
|
jne @F
|
|
mov t,1600
|
|
@@:
|
|
cmp dice3d_state, 1
|
|
jne throw_pose
|
|
mov eax, dice3d_timer
|
|
sub eax,240
|
|
jns @F
|
|
xor eax,eax
|
|
@@:
|
|
cmp eax,1360
|
|
jbe @F
|
|
mov eax,1360
|
|
@@:
|
|
imul eax,1600
|
|
xor edx,edx
|
|
mov ecx,1360
|
|
div ecx
|
|
mov t, eax
|
|
throw_pose:
|
|
mov cubeScale3D,12
|
|
mov eax,t
|
|
imul eax, DICE_RELEASE_Y1-146
|
|
xor edx, edx
|
|
mov ecx, 1600
|
|
div ecx
|
|
mov ebx, DICE_RELEASE_Y1
|
|
sub ebx, eax
|
|
mov ground, ebx
|
|
mov lift, 0
|
|
mov eax, t
|
|
cmp eax, 500
|
|
jae throw_bounce2
|
|
mov edx, 500
|
|
sub edx, eax
|
|
imul eax, edx
|
|
imul eax, 160
|
|
xor edx, edx
|
|
mov ecx, 250000
|
|
div ecx
|
|
mov lift, eax
|
|
jmp throw_position
|
|
throw_bounce2:
|
|
cmp eax, 950
|
|
jae throw_bounce3
|
|
sub eax, 500
|
|
mov edx, 450
|
|
sub edx, eax
|
|
imul eax, edx
|
|
imul eax, 56
|
|
xor edx, edx
|
|
mov ecx, 202500
|
|
div ecx
|
|
mov lift, eax
|
|
jmp throw_position
|
|
throw_bounce3:
|
|
cmp eax, 1300
|
|
jae throw_position
|
|
sub eax, 950
|
|
mov edx, 350
|
|
sub edx, eax
|
|
imul eax, edx
|
|
imul eax, 24
|
|
xor edx, edx
|
|
mov ecx, 122500
|
|
div ecx
|
|
mov lift, eax
|
|
throw_position:
|
|
mov eax, ground
|
|
sub eax, lift
|
|
mov cy, eax
|
|
mov eax, t
|
|
imul eax, DICE_RELEASE_X1-134
|
|
xor edx, edx
|
|
mov ecx, 1600
|
|
div ecx
|
|
mov ebx, DICE_RELEASE_X1
|
|
sub ebx, eax
|
|
mov cx1, ebx
|
|
mov eax,t
|
|
imul eax,DICE_RELEASE_X2-186
|
|
xor edx,edx
|
|
mov ecx,1600
|
|
div ecx
|
|
mov ebx,DICE_RELEASE_X2
|
|
sub ebx,eax
|
|
mov cx2,ebx
|
|
mov eax, 1600
|
|
sub eax, t
|
|
imul eax,eax
|
|
imul eax,1024
|
|
xor edx, edx
|
|
mov ecx,2560000
|
|
div ecx
|
|
mov esi,1024
|
|
sub esi,eax
|
|
mov roll,esi
|
|
mov eax,esi
|
|
add eax,70
|
|
mov pitch,eax
|
|
mov eax,esi
|
|
shr eax,1
|
|
add eax,44
|
|
mov yaw,eax
|
|
mov cubeContactShadow3D,0
|
|
cmp t,1600
|
|
jne @F
|
|
mov cubeContactShadow3D,1
|
|
@@:
|
|
mov eax,t
|
|
imul eax,DICE_RELEASE_Y1-DICE_RELEASE_Y2
|
|
xor edx,edx
|
|
mov ecx,1600
|
|
div ecx
|
|
add eax,cy
|
|
sub eax,DICE_RELEASE_Y1-DICE_RELEASE_Y2
|
|
mov cy2,eax
|
|
cmp dice3d_state,0
|
|
je throw_cubes
|
|
cmp dice3d_state,1
|
|
jne throw_shadows
|
|
cmp dice3d_timer,240
|
|
jb throw_cubes
|
|
throw_shadows:
|
|
cmp diceShadowPass3D,0
|
|
je throw_cubes
|
|
mov eax,85
|
|
sub eax,lift
|
|
mov shadowAlpha,eax
|
|
mov eax,cx1
|
|
shl eax,1
|
|
mov edx,cubeScale3D
|
|
shr edx,2
|
|
add edx,ground
|
|
shl edx,1
|
|
invoke DrawCoinShadow3D,eax,edx,cubeScale3D,6,shadowAlpha
|
|
mov eax,cx2
|
|
shl eax,1
|
|
mov edx,cubeScale3D
|
|
shr edx,2
|
|
add edx,ground
|
|
shl edx,1
|
|
invoke DrawCoinShadow3D,eax,edx,cubeScale3D,6,shadowAlpha
|
|
throw_cubes:
|
|
cmp diceShadowPass3D,0
|
|
jne throw_restore
|
|
invoke DrawTumblingDie3D, cx1, cy, pitch, yaw, roll, dice3d_val1
|
|
mov eax,roll
|
|
neg eax
|
|
invoke DrawTumblingDie3D, cx2, cy2, pitch, yaw, eax, dice3d_val2
|
|
throw_restore:
|
|
mov eax,oldScale
|
|
mov cubeScale3D,eax
|
|
mov cubeContactShadow3D,0
|
|
throw_done:
|
|
ret
|
|
RenderDiceThrow3D ENDP
|