- 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
475 lines
12 KiB
PHP
475 lines
12 KiB
PHP
PyramidBall3D PROC uses ebx esi ball:DWORD,x:DWORD,y:DWORD,sizePx:DWORD
|
|
mov ebx,ball
|
|
cmp poolVariant3D,1
|
|
jne pyr_ball_palette
|
|
mov eax,sizePx
|
|
shr eax,1
|
|
mov edx,x
|
|
sub edx,eax
|
|
mov ecx,y
|
|
sub ecx,eax
|
|
invoke DrawAnimSprite3D,OFFSET poolEightPack3D,ebx,edx,ecx,sizePx,sizePx
|
|
jmp pyr_ball_number
|
|
pyr_ball_palette:
|
|
mov eax,pyrRoll3D[ebx*4]
|
|
shr eax,17
|
|
and eax,3
|
|
test ebx,ebx
|
|
jnz @F
|
|
add eax,4
|
|
@@:
|
|
mov esi,eax
|
|
mov eax,sizePx
|
|
shr eax,1
|
|
mov edx,x
|
|
sub edx,eax
|
|
mov ecx,y
|
|
sub ecx,eax
|
|
invoke DrawAnimSprite3D,OFFSET pyrBallsPack3D,esi,edx,ecx,sizePx,sizePx
|
|
pyr_ball_number:
|
|
cmp sizePx,12
|
|
jne pyr_ball_done
|
|
test ebx,ebx
|
|
jz pyr_ball_done
|
|
mov esi,x
|
|
sub esi,1
|
|
mov eax,y
|
|
sub eax,2
|
|
cmp ebx,10
|
|
jb @F
|
|
sub esi,2
|
|
invoke DrawWheelDigit3D,esi,eax,1,1,003B3933h
|
|
add esi,4
|
|
mov eax,y
|
|
sub eax,2
|
|
sub ebx,10
|
|
@@:
|
|
invoke DrawWheelDigit3D,esi,eax,ebx,1,003B3933h
|
|
pyr_ball_done:
|
|
ret
|
|
PyramidBall3D ENDP
|
|
|
|
; A swept aim preview terminates on the first real ball or cushion.
|
|
PyramidGuide3D PROC uses ebx esi edi
|
|
local px:DWORD,py:DWORD,pointX:DWORD,pointY:DWORD
|
|
mov pyrTarget3D,-1
|
|
mov ebx,pyrCue3D
|
|
mov eax,poolX3D[ebx*4]
|
|
mov px,eax
|
|
mov eax,poolY3D[ebx*4]
|
|
mov py,eax
|
|
mov esi,6
|
|
pyr_guide_step:
|
|
mov eax,pyrDirX3D
|
|
imul esi
|
|
sar eax,1
|
|
add eax,px
|
|
mov pointX,eax
|
|
mov eax,pyrDirY3D
|
|
imul esi
|
|
sar eax,1
|
|
add eax,py
|
|
mov pointY,eax
|
|
cmp pointX,30*FP_1+POOL_RADIUS
|
|
jl pyr_guide_done
|
|
cmp pointX,290*FP_1-POOL_RADIUS
|
|
jg pyr_guide_done
|
|
cmp pointY,50*FP_1+POOL_RADIUS
|
|
jl pyr_guide_done
|
|
cmp pointY,180*FP_1-POOL_RADIUS
|
|
jg pyr_guide_done
|
|
xor edi,edi
|
|
pyr_guide_obstacle:
|
|
cmp edi,pyrCue3D
|
|
je pyr_guide_next_obstacle
|
|
cmp poolActive3D[edi*4],1
|
|
jne pyr_guide_next_obstacle
|
|
mov eax,pointX
|
|
sub eax,poolX3D[edi*4]
|
|
sar eax,12
|
|
imul eax,eax
|
|
mov ebx,eax
|
|
mov eax,pointY
|
|
sub eax,poolY3D[edi*4]
|
|
sar eax,12
|
|
imul eax,eax
|
|
add eax,ebx
|
|
cmp eax,25*16*16
|
|
jb pyr_guide_hit
|
|
pyr_guide_next_obstacle:
|
|
inc edi
|
|
cmp edi,16
|
|
jb pyr_guide_obstacle
|
|
test esi,7
|
|
jnz pyr_guide_next
|
|
mov eax,pointX
|
|
sar eax,16
|
|
mov ebx,pointY
|
|
sar ebx,16
|
|
invoke DrawPixel,eax,ebx,00B1D7CFh
|
|
pyr_guide_next:
|
|
inc esi
|
|
cmp esi,560
|
|
jb pyr_guide_step
|
|
pyr_guide_done:
|
|
ret
|
|
pyr_guide_hit:
|
|
mov pyrTarget3D,edi
|
|
mov eax,pointX
|
|
mov pyrGuideX3D,eax
|
|
sar eax,16
|
|
mov ebx,pointY
|
|
mov pyrGuideY3D,ebx
|
|
sar ebx,16
|
|
invoke DrawCircle,eax,ebx,3,00B1D7CFh
|
|
mov eax,pointX
|
|
sar eax,16
|
|
mov ebx,pointY
|
|
sar ebx,16
|
|
invoke DrawCircle,eax,ebx,2,00295041h
|
|
ret
|
|
PyramidGuide3D ENDP
|
|
|
|
RenderPool3D PROC uses ebx esi edi
|
|
local px:DWORD,py:DWORD,tip:DWORD,dirx:DWORD,diry:DWORD
|
|
mov esi,pyrTablePack3D.pixels
|
|
test esi,esi
|
|
jz pyr_render_missing
|
|
lea edi,screenBuffer
|
|
mov ecx,SCREEN_SIZE
|
|
rep movsd
|
|
cmp poolState3D,POOL_SELECT
|
|
jne pyr_render_game
|
|
invoke DrawBox,0,0,320,35,00151D20h
|
|
invoke DrawString8x8,16,12,OFFSET poolSelectTitle3D,00E8D7ADh
|
|
invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1
|
|
invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h
|
|
invoke DrawBoxBorder,40,80,240,48,00192720h,00D6B971h,2
|
|
invoke DrawString8x8,68,99,OFFSET poolSelectPyramid3D,00FFFFFFh
|
|
invoke DrawBoxBorder,40,144,240,48,00192720h,00D6B971h,2
|
|
invoke DrawString8x8,58,163,OFFSET poolSelectEight3D,00FFFFFFh
|
|
ret
|
|
pyr_render_game:
|
|
call EightAutoCall3D
|
|
xor esi,esi
|
|
pyr_render_mouths:
|
|
mov eax,poolPocketX3D[esi*4]
|
|
sar eax,16
|
|
mov ebx,poolPocketY3D[esi*4]
|
|
sar ebx,16
|
|
mov px,eax
|
|
mov py,ebx
|
|
invoke DrawCircle,eax,ebx,3,000B1010h
|
|
cmp poolVariant3D,1
|
|
jne @F
|
|
mov eax,poolPocketX3D[esi*4]
|
|
sar eax,16
|
|
mov ebx,poolPocketY3D[esi*4]
|
|
sar ebx,16
|
|
invoke DrawCircle,px,py,5,000B1010h
|
|
cmp esi,poolCalledPocket3D
|
|
jne @F
|
|
invoke DrawCircle,px,py,6,00D6B971h
|
|
invoke DrawCircle,px,py,4,000B1010h
|
|
@@:
|
|
inc esi
|
|
cmp esi,6
|
|
jb pyr_render_mouths
|
|
invoke DrawPixel,95,115,00838C73h
|
|
invoke DrawPixel,160,115,00838C73h
|
|
invoke DrawPixel,225,115,00838C73h
|
|
cmp poolBreak3D,0
|
|
je @F
|
|
invoke DrawBox,95,53,1,124,003C7261h
|
|
@@:
|
|
cmp poolState3D,POOL_AIM
|
|
jne pyr_render_objects
|
|
call PyramidDirection3D
|
|
cmp pyrGuideOn3D,0
|
|
je pyr_render_objects
|
|
call PoolDrawPrediction3D
|
|
pyr_render_objects:
|
|
xor esi,esi
|
|
pyr_render_ball:
|
|
cmp poolActive3D[esi*4],1
|
|
jne pyr_render_sunk
|
|
mov eax,poolX3D[esi*4]
|
|
sar eax,15
|
|
mov px,eax
|
|
mov eax,poolY3D[esi*4]
|
|
sar eax,15
|
|
mov py,eax
|
|
cmp poolVariant3D,1
|
|
jne @F
|
|
cmp esi,poolCalled3D
|
|
jne @F
|
|
mov eax,px
|
|
sar eax,1
|
|
mov ebx,py
|
|
sar ebx,1
|
|
invoke DrawCircle,eax,ebx,4,00D6B971h
|
|
@@:
|
|
cmp esi,pyrCue3D
|
|
jne @F
|
|
cmp poolState3D,POOL_AIM
|
|
jne @F
|
|
mov eax,px
|
|
sar eax,1
|
|
mov ebx,py
|
|
sar ebx,1
|
|
invoke DrawCircle,eax,ebx,4,007BAFACh
|
|
@@:
|
|
invoke PyramidBall3D,esi,px,py,12
|
|
jmp pyr_render_next
|
|
pyr_render_sunk:
|
|
cmp poolSinkTime3D[esi*4],0
|
|
je pyr_render_next
|
|
mov ecx,poolPocket3D[esi*4]
|
|
cmp ecx,5
|
|
ja pyr_render_next
|
|
mov eax,poolPocketX3D[ecx*4]
|
|
sar eax,15
|
|
mov px,eax
|
|
mov eax,poolPocketY3D[ecx*4]
|
|
sar eax,15
|
|
mov py,eax
|
|
mov eax,poolSinkTime3D[esi*4]
|
|
imul eax,12
|
|
xor edx,edx
|
|
mov ecx,220
|
|
div ecx
|
|
test eax,eax
|
|
jz pyr_render_next
|
|
invoke PyramidBall3D,esi,px,py,eax
|
|
pyr_render_next:
|
|
inc esi
|
|
cmp esi,16
|
|
jb pyr_render_ball
|
|
cmp poolState3D,POOL_AIM
|
|
je pyr_render_cue
|
|
cmp poolState3D,POOL_STRIKE
|
|
jne pyr_render_hud
|
|
pyr_render_cue:
|
|
mov ebx,pyrCue3D
|
|
mov eax,poolX3D[ebx*4]
|
|
mov px,eax
|
|
mov eax,poolY3D[ebx*4]
|
|
mov py,eax
|
|
mov eax,pyrDirX3D
|
|
mov dirx,eax
|
|
mov eax,pyrDirY3D
|
|
mov diry,eax
|
|
mov tip,5
|
|
cmp poolState3D,POOL_STRIKE
|
|
jne @F
|
|
mov tip,3
|
|
mov eax,240
|
|
sub eax,poolTime3D
|
|
cmp eax,0
|
|
jge pyr_cue_time
|
|
xor eax,eax
|
|
pyr_cue_time:
|
|
shr eax,4
|
|
add tip,eax
|
|
@@:
|
|
mov esi,tip
|
|
mov edi,44
|
|
pyr_cue_draw:
|
|
mov eax,dirx
|
|
imul esi
|
|
neg eax
|
|
add eax,px
|
|
sar eax,16
|
|
mov ebx,eax
|
|
mov eax,diry
|
|
imul esi
|
|
neg eax
|
|
add eax,py
|
|
sar eax,16
|
|
mov tip,eax
|
|
invoke DrawCircle,ebx,eax,1,003E2E23h
|
|
invoke DrawPixel,ebx,tip,00DCC59Ah
|
|
inc esi
|
|
dec edi
|
|
jnz pyr_cue_draw
|
|
pyr_render_hud:
|
|
invoke DrawBox,0,0,320,20,00151D20h
|
|
mov ebx,OFFSET pyrTitle3D
|
|
cmp poolVariant3D,0
|
|
je @F
|
|
mov ebx,OFFSET poolTitle3D
|
|
@@:
|
|
invoke DrawString8x8,8,6,ebx,00E8D7ADh
|
|
invoke DrawNumber,112,6,pyrScore3D,00F4F3E8h
|
|
invoke DrawString8x8,128,6,OFFSET pyrScoreSep3D,00E8D7ADh
|
|
invoke DrawNumber,144,6,pyrScore3D[4],00F4F3E8h
|
|
cmp poolVariant3D,1
|
|
jne @F
|
|
invoke DrawString8x8,88,6,OFFSET pyrPlayerName3D,00E8D7ADh
|
|
invoke DrawString8x8,160,6,OFFSET pyrAIName3D,00E8D7ADh
|
|
@@:
|
|
mov ebx,OFFSET pyrPlayerName3D
|
|
cmp poolPlayer3D,0
|
|
je @F
|
|
mov ebx,OFFSET pyrAIName3D
|
|
@@:
|
|
invoke DrawString8x8,184,6,ebx,00A8DDB9h
|
|
invoke DrawBoxBorder,252,3,60,14,002C3637h,00687672h,1
|
|
invoke DrawString8x8,258,6,OFFSET cardExitButton3D,00E9D8B0h
|
|
mov ebx,OFFSET pyrTurnText3D
|
|
cmp poolBreak3D,0
|
|
je @F
|
|
mov ebx,OFFSET pyrBreakText3D
|
|
@@:
|
|
cmp poolState3D,POOL_PENALTY
|
|
jne @F
|
|
mov ebx,OFFSET pyrPenaltyText3D
|
|
@@:
|
|
cmp poolState3D,POOL_CHOICE
|
|
jne @F
|
|
mov ebx,OFFSET pyrChoiceText3D
|
|
@@:
|
|
cmp poolState3D,POOL_MOVING
|
|
jne @F
|
|
mov ebx,OFFSET poolMovingText3D
|
|
@@:
|
|
cmp poolState3D,POOL_STRIKE
|
|
jne @F
|
|
mov ebx,OFFSET poolShotText3D
|
|
@@:
|
|
cmp poolState3D,POOL_HAND
|
|
jne @F
|
|
mov ebx,OFFSET poolPlaceText3D
|
|
@@:
|
|
invoke DrawBox,0,22,320,15,00151D20h
|
|
invoke DrawString8x8,8,26,ebx,00E8D7ADh
|
|
cmp poolVariant3D,1
|
|
jne @F
|
|
mov ecx,poolPlayer3D
|
|
mov ecx,poolGroups3D[ecx*4]
|
|
mov eax,poolGroupTexts3D[ecx*4]
|
|
invoke DrawString8x8,176,26,eax,00E8D7ADh
|
|
@@:
|
|
cmp poolState3D,POOL_PENALTY
|
|
je @F
|
|
cmp poolState3D,POOL_CHOICE
|
|
jne pyr_render_footer
|
|
@@:
|
|
mov ecx,pyrFoulReason3D
|
|
mov eax,pyrStatusNames3D[ecx*4]
|
|
invoke DrawString8x8,176,26,eax,00EAAD9Ah
|
|
pyr_render_footer:
|
|
invoke DrawBox,0,186,320,54,00151D20h
|
|
xor esi,esi
|
|
mov ebx,20
|
|
mov edi,174
|
|
pyr_render_shelves:
|
|
mov eax,pyrOwner3D[esi*4]
|
|
test eax,eax
|
|
js pyr_shelf_next
|
|
cmp eax,1
|
|
jne pyr_shelf_player
|
|
invoke PyramidBall3D,esi,edi,381,10
|
|
add edi,12
|
|
jmp pyr_shelf_next
|
|
pyr_shelf_player:
|
|
invoke PyramidBall3D,esi,ebx,381,10
|
|
add ebx,12
|
|
pyr_shelf_next:
|
|
inc esi
|
|
cmp esi,16
|
|
jb pyr_render_shelves
|
|
invoke DrawString8x8,202,187,OFFSET poolPowerText3D,00CCBE94h
|
|
mov eax,poolPower3D
|
|
sub eax,8000
|
|
imul eax,100
|
|
xor edx,edx
|
|
mov ecx,82000
|
|
div ecx
|
|
invoke DrawNumber,254,187,eax,00FFFFFFh
|
|
mov eax,poolPower3D
|
|
sub eax,8000
|
|
imul eax,106
|
|
xor edx,edx
|
|
mov ecx,82000
|
|
div ecx
|
|
mov tip,eax
|
|
invoke DrawBox,202,201,106,5,00363D36h
|
|
invoke DrawBox,202,201,tip,5,00D5BB73h
|
|
mov eax,tip
|
|
add eax,201
|
|
invoke DrawBox,eax,199,2,9,00F4F0DDh
|
|
invoke DrawBoxBorder,12,215,74,22,0039412Fh,00AC9862h,1
|
|
cmp poolVariant3D,1
|
|
je eight_render_call
|
|
invoke DrawString8x8,18,222,OFFSET pyrCueText3D,00FFFFFFh
|
|
invoke DrawNumber,62,222,pyrCue3D,00EAD19Bh
|
|
jmp eight_render_call_done
|
|
eight_render_call:
|
|
invoke DrawString8x8,18,222,OFFSET poolCallText3D,00FFFFFFh
|
|
cmp poolCalled3D,0
|
|
je eight_render_no_call
|
|
invoke DrawNumber,64,222,poolCalled3D,00EAD19Bh
|
|
jmp eight_render_pocket
|
|
eight_render_no_call:
|
|
invoke DrawString8x8,64,222,OFFSET poolUnsetText3D,00EAD19Bh
|
|
eight_render_pocket:
|
|
mov eax,poolCalledPocket3D
|
|
inc eax
|
|
jz eight_render_no_pocket
|
|
invoke DrawNumber,173,187,eax,00EAD19Bh
|
|
jmp eight_render_pocket_label
|
|
eight_render_no_pocket:
|
|
invoke DrawString8x8,173,187,OFFSET poolUnsetText3D,00EAD19Bh
|
|
eight_render_pocket_label:
|
|
invoke DrawString8x8,129,187,OFFSET poolPocketText3D,00FFFFFFh
|
|
eight_render_call_done:
|
|
mov ebx,0039412Fh
|
|
cmp pyrGuideOn3D,0
|
|
jne @F
|
|
mov ebx,00242A2Ch
|
|
@@:
|
|
invoke DrawBoxBorder,92,215,104,22,ebx,00AC9862h,1
|
|
invoke DrawString8x8,106,222,OFFSET pyrGuideText3D,00FFFFFFh
|
|
invoke DrawBoxBorder,202,215,106,22,00425232h,00BBA76Fh,1
|
|
mov ebx,OFFSET poolShotText3D
|
|
cmp poolState3D,POOL_PENALTY
|
|
jne @F
|
|
mov ebx,OFFSET pyrSkipText3D
|
|
@@:
|
|
cmp poolState3D,POOL_RESULT
|
|
jne @F
|
|
mov ebx,OFFSET poolRackText3D
|
|
@@:
|
|
invoke DrawString8x8,226,222,ebx,00FFFFFFh
|
|
cmp poolState3D,POOL_CHOICE
|
|
jne pyr_render_result
|
|
invoke DrawBox,0,211,320,29,00151D20h
|
|
invoke DrawBoxBorder,8,215,70,22,0039412Fh,00AC9862h,1
|
|
invoke DrawString8x8,19,222,OFFSET pyrPlayText3D,00FFFFFFh
|
|
invoke DrawBoxBorder,86,215,70,22,0039412Fh,00AC9862h,1
|
|
invoke DrawString8x8,89,222,OFFSET pyrPassText3D,00FFFFFFh
|
|
cmp pyrIllegalBreak3D,0
|
|
je pyr_render_result
|
|
invoke DrawBoxBorder,164,215,70,22,0039412Fh,00AC9862h,1
|
|
invoke DrawString8x8,167,222,OFFSET pyrRackText3D,00FFFFFFh
|
|
invoke DrawBoxBorder,242,215,70,22,0039412Fh,00AC9862h,1
|
|
invoke DrawString8x8,249,222,OFFSET pyrTheirBreakText3D,00FFFFFFh
|
|
pyr_render_result:
|
|
cmp poolState3D,POOL_RESULT
|
|
jne pyr_render_done
|
|
invoke DrawBoxBorder,76,88,168,43,00192720h,00D6B971h,2
|
|
mov ebx,OFFSET pyrPlayerName3D
|
|
cmp poolWinner3D,0
|
|
je @F
|
|
mov ebx,OFFSET pyrAIName3D
|
|
@@:
|
|
invoke DrawString8x8,92,100,ebx,00FFFFFFh
|
|
invoke DrawString8x8,92,115,OFFSET poolWinText3D,00E8D7ADh
|
|
pyr_render_done:
|
|
ret
|
|
pyr_render_missing:
|
|
invoke DrawBox,0,0,320,240,00151D20h
|
|
invoke DrawString8x8,56,108,OFFSET unavailableText3D,00E8D7ADh
|
|
ret
|
|
RenderPool3D ENDP
|