- Bowling feel: impulse contact solver, string pinsetter cycle, in-world lengthwise return rack and visible ball return lift - Ball weights: 4/5/6/7 kg selection with equal launch work physics, momentum balance, and projected picking - Audio: dedicated MCI channels with 7 synthesized waveaudio cues (release, rolling, impacts, applause, pinsetter, return) - First-person animations: 33-frame player underarm throw/follow-through sequence (player-underarm-v2) - Visitors: 10 persistent shared cast identities with exclusive reservations, activity transitions, and chair sit/rise animations - Tests & verification: comprehensive native regression test suites and updated documentation - Synchronize binaries and update launcher hash to 536E23BED4055562BC63871826FF44FFED037923A9BE8E0F591131DB4FBD104B
566 lines
13 KiB
PHP
566 lines
13 KiB
PHP
; A small native marble surface avoids shipping a second copy of a ball sprite.
|
|
InitBowlingBallSurface3D PROC uses ebx esi edi
|
|
local stripe:DWORD
|
|
xor esi,esi
|
|
lea edi,bpBallSurface3D
|
|
bp_ball_tex_row:
|
|
xor ebx,ebx
|
|
bp_ball_tex_pixel:
|
|
mov eax,esi
|
|
shl eax,3
|
|
and eax,511
|
|
mov eax,tableSin[eax*4]
|
|
sar eax,11
|
|
lea eax,[eax+ebx*8]
|
|
and eax,511
|
|
mov eax,tableSin[eax*4]
|
|
add eax,FP_1
|
|
shr eax,12
|
|
mov stripe,eax
|
|
lea edx,[eax+5]
|
|
shl edx,16
|
|
lea eax,[eax*2+48]
|
|
shl eax,8
|
|
or edx,eax
|
|
mov eax,stripe
|
|
shl eax,1
|
|
add eax,155
|
|
or eax,edx
|
|
or eax,0FF000000h
|
|
stosd
|
|
inc ebx
|
|
cmp ebx,64
|
|
jb bp_ball_tex_pixel
|
|
inc esi
|
|
cmp esi,64
|
|
jb bp_ball_tex_row
|
|
xor esi,esi
|
|
bp_ball_tex_variants:
|
|
mov eax,bpBallSurface3D[esi*4]
|
|
invoke BowlingTintBallPixel3D,eax,4
|
|
mov bpBallSurface3D[esi*4+64*64*4],eax
|
|
mov eax,bpBallSurface3D[esi*4]
|
|
invoke BowlingTintBallPixel3D,eax,5
|
|
mov bpBallSurface3D[esi*4+2*64*64*4],eax
|
|
mov eax,bpBallSurface3D[esi*4]
|
|
invoke BowlingTintBallPixel3D,eax,7
|
|
mov bpBallSurface3D[esi*4+3*64*64*4],eax
|
|
inc esi
|
|
cmp esi,64*64
|
|
jb bp_ball_tex_variants
|
|
ret
|
|
InitBowlingBallSurface3D ENDP
|
|
|
|
include src_graphics\bowling_pin_shape.inc
|
|
include src_graphics\bowling_pinsetter.inc
|
|
|
|
DrawBowlingPlayPin3D PROC uses ebx esi edi pin:DWORD,centre:DWORD
|
|
local baseX:DWORD,baseY:DWORD,axisX:DWORD,axisY:DWORD,axisZ:DWORD
|
|
local x:DWORD,y:DWORD,z:DWORD,radius:DWORD
|
|
mov esi,pin
|
|
invoke BowlingPinsetterPose3D,esi
|
|
test eax,eax
|
|
jz bp_pin_done
|
|
mov eax,bpVisualPinX3D
|
|
add eax,centre
|
|
mov baseX,eax
|
|
mov eax,bpVisualPinY3D
|
|
mov baseY,eax
|
|
mov eax,bpVisualPinTilt3D
|
|
shr eax,8
|
|
cmp eax,128
|
|
jbe @F
|
|
mov eax,128
|
|
@@:
|
|
mov edi,tableSin[eax*4]
|
|
mov ecx,edi
|
|
neg ecx
|
|
mov bpRenderVZ3D,ecx
|
|
mov eax,tableCos[eax*4]
|
|
mov axisZ,eax
|
|
mov bpRenderNZ3D,eax
|
|
imul bpPinAxisX3D[esi*4]
|
|
shrd eax,edx,16
|
|
mov bpRenderVX3D,eax
|
|
mov eax,axisZ
|
|
imul bpPinAxisY3D[esi*4]
|
|
shrd eax,edx,16
|
|
mov bpRenderVY3D,eax
|
|
mov eax,bpPinAxisY3D[esi*4]
|
|
mov bpRenderUX3D,eax
|
|
mov eax,bpPinAxisX3D[esi*4]
|
|
neg eax
|
|
mov bpRenderUY3D,eax
|
|
mov eax,bpPinAxisX3D[esi*4]
|
|
imul edi
|
|
shrd eax,edx,16
|
|
mov axisX,eax
|
|
mov bpRenderNX3D,eax
|
|
mov eax,bpPinAxisY3D[esi*4]
|
|
imul edi
|
|
shrd eax,edx,16
|
|
mov axisY,eax
|
|
mov bpRenderNY3D,eax
|
|
xor ebx,ebx
|
|
bp_pin_section:
|
|
mov eax,bpPinSectionHeight3D[ebx*4]
|
|
imul axisX
|
|
shrd eax,edx,16
|
|
add eax,baseX
|
|
mov x,eax
|
|
mov eax,bpPinSectionHeight3D[ebx*4]
|
|
imul axisY
|
|
shrd eax,edx,16
|
|
add eax,baseY
|
|
mov y,eax
|
|
mov eax,bpPinSectionHeight3D[ebx*4]
|
|
imul axisZ
|
|
shrd eax,edx,16
|
|
add eax,FP_1*8/100
|
|
add eax,bpVisualPinLift3D
|
|
mov z,eax
|
|
mov eax,bpPinSectionRadius3D[ebx*4]
|
|
mov radius,eax
|
|
invoke DrawBowlingEllipsoid3D,x,y,z,radius,radius,bpPinSectionLength3D[ebx*4],bpPinSectionMaterial3D[ebx*4]
|
|
inc ebx
|
|
cmp ebx,4
|
|
jb bp_pin_section
|
|
bp_pin_done:
|
|
ret
|
|
DrawBowlingPlayPin3D ENDP
|
|
|
|
; A frame's cumulative score stays unresolved until all its bonuses are known.
|
|
BowlingFrameTotal3D PROC uses ebx esi edi owner:DWORD,wanted:DWORD
|
|
local total:DWORD,index:DWORD,available:DWORD,current:DWORD
|
|
mov ebx,owner
|
|
mov eax,bwRollCount3D[ebx*4]
|
|
mov available,eax
|
|
imul ebx,96
|
|
lea esi,bwRolls3D[ebx]
|
|
mov index,0
|
|
mov current,0
|
|
mov total,0
|
|
bp_frame_loop:
|
|
mov edi,index
|
|
cmp edi,available
|
|
jae bp_frame_pending
|
|
mov eax,[esi+edi*4]
|
|
mov ebx,eax
|
|
inc edi
|
|
cmp edi,available
|
|
jae bp_frame_pending
|
|
add eax,[esi+edi*4]
|
|
inc edi
|
|
cmp ebx,10
|
|
je bp_frame_bonus
|
|
cmp eax,10
|
|
jne bp_frame_open
|
|
bp_frame_bonus:
|
|
cmp edi,available
|
|
jae bp_frame_pending
|
|
add eax,[esi+edi*4]
|
|
bp_frame_open:
|
|
add total,eax
|
|
cmp ebx,10
|
|
jne @F
|
|
dec edi
|
|
@@:
|
|
mov index,edi
|
|
mov eax,current
|
|
cmp eax,wanted
|
|
je bp_frame_ready
|
|
inc current
|
|
jmp bp_frame_loop
|
|
bp_frame_ready:
|
|
mov eax,total
|
|
ret
|
|
bp_frame_pending:
|
|
mov eax,-1
|
|
ret
|
|
BowlingFrameTotal3D ENDP
|
|
|
|
include src_graphics\bowling_scorecard.inc
|
|
|
|
DrawBowlingGaugeLine3D PROC uses ebx esi edi x0:DWORD,y0:DWORD,x1:DWORD,y1:DWORD
|
|
local px:DWORD,py:DWORD,stepX:DWORD,stepY:DWORD
|
|
mov eax,x1
|
|
sub eax,x0
|
|
cdq
|
|
xor eax,edx
|
|
sub eax,edx
|
|
mov ebx,eax
|
|
mov eax,y1
|
|
sub eax,y0
|
|
cdq
|
|
xor eax,edx
|
|
sub eax,edx
|
|
cmp eax,ebx
|
|
jbe @F
|
|
mov ebx,eax
|
|
@@:
|
|
test ebx,ebx
|
|
jnz @F
|
|
inc ebx
|
|
@@:
|
|
mov eax,x1
|
|
sub eax,x0
|
|
shl eax,16
|
|
cdq
|
|
idiv ebx
|
|
mov stepX,eax
|
|
mov eax,y1
|
|
sub eax,y0
|
|
shl eax,16
|
|
cdq
|
|
idiv ebx
|
|
mov stepY,eax
|
|
mov eax,x0
|
|
shl eax,16
|
|
mov px,eax
|
|
mov eax,y0
|
|
shl eax,16
|
|
mov py,eax
|
|
inc ebx
|
|
bp_gauge_line:
|
|
mov eax,px
|
|
sar eax,16
|
|
mov edx,py
|
|
sar edx,16
|
|
invoke DrawBox,eax,edx,1,1,00D8F5B7h
|
|
mov eax,stepX
|
|
add px,eax
|
|
mov eax,stepY
|
|
add py,eax
|
|
dec ebx
|
|
jnz bp_gauge_line
|
|
ret
|
|
DrawBowlingGaugeLine3D ENDP
|
|
|
|
include src_graphics\bowling_performance.inc
|
|
|
|
RenderBowlingPlay3D PROC uses ebx esi edi
|
|
local x:DWORD,y:DWORD,color:DWORD,owner:DWORD,startY:DWORD
|
|
mov eax,bpCentre3D
|
|
mov playerX,eax
|
|
mov startY,FP_1*252/10
|
|
mov esi,bpLane3D
|
|
cmp bwTurn3D[esi*4],0
|
|
je @F
|
|
mov startY,FP_1*264/10
|
|
@@:
|
|
mov eax,startY
|
|
mov playerY,eax
|
|
mov playerAngle,384
|
|
call BowlingEye3D
|
|
cmp bpState3D,BP_ROLL
|
|
je bp_camera_follow
|
|
cmp bpState3D,BP_SETTLE
|
|
je bp_camera_follow
|
|
cmp bpState3D,BP_RESET
|
|
jne bp_camera_ready
|
|
bp_camera_follow:
|
|
mov eax,bpBallY3D
|
|
add eax,FP_1*27/10
|
|
cmp eax,7*FP_1
|
|
jge @F
|
|
mov eax,7*FP_1
|
|
@@:
|
|
mov playerY,eax
|
|
mov viewEye3D,FP_1*7/10
|
|
cmp bpState3D,BP_RESET
|
|
jne bp_camera_roll_blend
|
|
mov ebx,bpTime3D
|
|
cmp ebx,400
|
|
jbe @F
|
|
mov ebx,400
|
|
@@:
|
|
imul eax,ebx,2*FP_1
|
|
cdq
|
|
mov ecx,400
|
|
idiv ecx
|
|
add playerY,eax
|
|
mov eax,playerY
|
|
mov ebx,bpTime3D
|
|
sub ebx,BP_RESET_MS-800
|
|
jle bp_camera_ready
|
|
cmp ebx,800
|
|
jbe @F
|
|
mov ebx,800
|
|
@@:
|
|
mov edx,startY
|
|
sub edx,eax
|
|
mov eax,edx
|
|
imul eax,ebx
|
|
cdq
|
|
mov ecx,800
|
|
idiv ecx
|
|
add playerY,eax
|
|
imul eax,ebx,HALL_STANDING_EYE-FP_1*7/10
|
|
cdq
|
|
idiv ecx
|
|
add viewEye3D,eax
|
|
jmp bp_camera_ready
|
|
bp_camera_roll_blend:
|
|
cmp bpState3D,BP_ROLL
|
|
jne bp_camera_ready
|
|
mov ebx,bpTime3D
|
|
cmp ebx,500
|
|
jae bp_camera_ready
|
|
sub eax,startY
|
|
imul eax,ebx
|
|
cdq
|
|
mov ecx,500
|
|
idiv ecx
|
|
add eax,startY
|
|
mov playerY,eax
|
|
mov edx,HALL_STANDING_EYE
|
|
cmp bwTurn3D[esi*4],0
|
|
jne @F
|
|
mov edx,FP_1*55/100
|
|
@@:
|
|
mov x,edx
|
|
mov eax,FP_1*7/10
|
|
sub eax,edx
|
|
imul eax,ebx
|
|
cdq
|
|
idiv ecx
|
|
add eax,x
|
|
mov viewEye3D,eax
|
|
bp_camera_ready:
|
|
cmp bpState3D,BP_SELECT_BALL
|
|
jne @F
|
|
call BowlingRackCamera3D
|
|
@@:
|
|
cmp bpState3D,BP_RETURN
|
|
jne @F
|
|
invoke BowlingReturnCamera3D,startY
|
|
@@:
|
|
cmp bpState3D,BP_RELEASE
|
|
jne @F
|
|
cmp bwTurn3D[esi*4],0
|
|
jne @F
|
|
mov eax,bpTime3D
|
|
cmp eax,BP_RELEASE_MS
|
|
jbe bp_camera_release_time
|
|
mov eax,BP_RELEASE_MS
|
|
bp_camera_release_time:
|
|
imul eax,FP_1/2
|
|
cdq
|
|
mov ecx,BP_RELEASE_MS
|
|
idiv ecx
|
|
mov edx,HALL_STANDING_EYE
|
|
sub edx,eax
|
|
mov viewEye3D,edx
|
|
@@:
|
|
call UpdateCamera3D
|
|
call RenderBowling3D
|
|
call RenderBowlingPinsetter3D
|
|
mov esi,bpLane3D
|
|
cmp bwTurn3D[esi*4],1
|
|
jne bp_render_ball
|
|
cmp bpState3D,BP_BOT
|
|
je bp_render_bot_ready
|
|
cmp bpState3D,BP_RELEASE
|
|
je bp_render_bot_throw
|
|
cmp bpState3D,BP_ROLL
|
|
jne bp_render_ball
|
|
invoke ConfigureCharacter3D,OFFSET bwActor3D,6,CAST_THROW,2300,0,-FP_1
|
|
jmp bp_render_bot_draw
|
|
bp_render_bot_throw:
|
|
invoke ConfigureCharacter3D,OFFSET bwActor3D,6,CAST_THROW,bpTime3D,0,-FP_1
|
|
jmp bp_render_bot_draw
|
|
bp_render_bot_ready:
|
|
invoke ConfigureCharacter3D,OFFSET bwActor3D,6,CAST_IDLE,bpTime3D,0,0
|
|
bp_render_bot_draw:
|
|
mov eax,bpCentre3D
|
|
add eax,FP_1*38/100
|
|
mov bwActor3D.posX,eax
|
|
mov bwActor3D.posY,FP_1*235/10
|
|
invoke DrawCityObject3D,OFFSET bwActor3D,0
|
|
bp_render_ball:
|
|
call RenderBowlingReactions3D
|
|
cmp bpState3D,BP_SELECT_BALL
|
|
je bp_render_hud
|
|
cmp bpState3D,BP_FINISHED
|
|
je bp_render_hud
|
|
cmp bpState3D,BP_ROLL
|
|
je bp_render_real_ball
|
|
cmp bpState3D,BP_SETTLE
|
|
je bp_render_real_ball
|
|
cmp bpState3D,BP_RESET
|
|
je bp_render_hud
|
|
cmp bpState3D,BP_RETURN
|
|
je bp_render_hud
|
|
cmp bpHandArt3D.pixels,0
|
|
jne bp_render_hud
|
|
bp_render_real_ball:
|
|
cmp bpEndTicks3D,25
|
|
jae bp_render_hud
|
|
mov eax,bpBallX3D
|
|
add eax,bpCentre3D
|
|
mov x,eax
|
|
invoke BowlingBallMaterial3D,bpShotWeightKg3D
|
|
invoke DrawBowlingBall3D,x,bpBallY3D,eax
|
|
bp_render_hud:
|
|
call DrawBowlingPlayerHand3D
|
|
invoke DrawBox,0,0,320,17,00121B20h
|
|
invoke DrawString8x8,8,4,OFFSET bpTitle,00E8D7ADh
|
|
mov eax,bpLane3D
|
|
shl eax,1
|
|
mov owner,eax
|
|
mov esi,eax
|
|
invoke DrawString8x8,100,4,OFFSET bpYou,005BC9BEh
|
|
invoke FormatNumber,bwScores3D[esi*4],OFFSET bpText3D
|
|
invoke DrawString8x8,126,4,OFFSET bpText3D,00FFFFFFh
|
|
invoke DrawString8x8,205,4,OFFSET bpBot,00E8D7ADh
|
|
invoke FormatNumber,bwScores3D[esi*4+4],OFFSET bpText3D
|
|
invoke DrawString8x8,248,4,OFFSET bpText3D,00FFFFFFh
|
|
invoke DrawBox,0,221,320,19,00121B20h
|
|
invoke DrawString8x8,268,227,OFFSET bpExitText,00E8D7ADh
|
|
mov esi,bpLane3D
|
|
mov eax,bwTurn3D[esi*4]
|
|
add owner,eax
|
|
mov eax,OFFSET bpYou
|
|
cmp bwTurn3D[esi*4],0
|
|
je @F
|
|
mov eax,OFFSET bpBot
|
|
@@:
|
|
invoke DrawString8x8,8,227,eax,005BC9BEh
|
|
mov ebx,owner
|
|
mov eax,bwFrames3D[ebx*4]
|
|
cmp bpState3D,BP_SETTLE
|
|
je bp_frame_result
|
|
cmp bpState3D,BP_RESET
|
|
jne @F
|
|
bp_frame_result:
|
|
cmp bwFrameDone3D[esi*4],0
|
|
je @F
|
|
dec eax
|
|
@@:
|
|
inc eax
|
|
cmp eax,10
|
|
jbe @F
|
|
mov eax,10
|
|
@@:
|
|
invoke FormatNumber,eax,OFFSET bpText3D
|
|
invoke DrawString8x8,60,227,OFFSET bpFrameText,00AABDB6h
|
|
invoke DrawString8x8,116,227,OFFSET bpText3D,00FFFFFFh
|
|
cmp bpState3D,BP_DIRECTION
|
|
je bp_render_direction
|
|
cmp bpState3D,BP_SELECT_BALL
|
|
je bp_render_done
|
|
cmp bpState3D,BP_POWER
|
|
je bp_render_power
|
|
cmp bpState3D,BP_SETTLE
|
|
je bp_render_result
|
|
cmp bpState3D,BP_FINISHED
|
|
je bp_render_finished
|
|
cmp bpState3D,BP_RESET
|
|
jne @F
|
|
invoke DrawString8x8,104,197,OFFSET bpResetText,00E8D7ADh
|
|
jmp bp_render_done
|
|
@@:
|
|
cmp bpState3D,BP_RETURN
|
|
jne @F
|
|
invoke DrawString8x8,104,197,OFFSET bpReturnText,00E8D7ADh
|
|
jmp bp_render_done
|
|
@@:
|
|
invoke DrawString8x8,8,204,OFFSET bpRollText,00E8D7ADh
|
|
jmp bp_render_done
|
|
bp_render_direction:
|
|
invoke DrawString8x8,108,145,OFFSET bpDirectionText,00E8D7ADh
|
|
xor esi,esi
|
|
bp_render_arc:
|
|
lea eax,[esi-70]
|
|
imul eax,eax
|
|
xor edx,edx
|
|
mov ecx,380
|
|
div ecx
|
|
add eax,169
|
|
mov y,eax
|
|
mov color,00D67057h
|
|
cmp esi,27
|
|
jb @F
|
|
cmp esi,113
|
|
ja @F
|
|
mov color,00E7C455h
|
|
cmp esi,59
|
|
jb @F
|
|
cmp esi,81
|
|
ja @F
|
|
mov color,005BC98Ch
|
|
@@:
|
|
lea eax,[esi+90]
|
|
invoke DrawBox,eax,y,1,6,color
|
|
inc esi
|
|
cmp esi,141
|
|
jb bp_render_arc
|
|
mov eax,bpAim3D
|
|
imul eax,52
|
|
sar eax,16
|
|
add eax,160
|
|
mov x,eax
|
|
invoke DrawBowlingGaugeLine3D,160,205,eax,162
|
|
mov eax,x
|
|
lea ebx,[eax-5]
|
|
invoke DrawBowlingGaugeLine3D,eax,162,ebx,168
|
|
mov eax,x
|
|
lea ebx,[eax+5]
|
|
invoke DrawBowlingGaugeLine3D,eax,162,ebx,168
|
|
jmp bp_render_done
|
|
bp_render_power:
|
|
invoke DrawString8x8,16,62,OFFSET bpPowerText,00E8D7ADh
|
|
invoke DrawBoxBorder,30,79,13,124,00121B20h,00AABDB6h,1
|
|
invoke DrawBox,32,82,9,118,00D67057h
|
|
invoke DrawBox,32,128,9,38,00E7C455h
|
|
invoke DrawBox,32,82,9,46,005BC98Ch
|
|
mov eax,bpPower3D
|
|
imul eax,116
|
|
xor edx,edx
|
|
mov ecx,100
|
|
div ecx
|
|
mov edx,198
|
|
sub edx,eax
|
|
mov y,edx
|
|
invoke DrawBox,24,y,25,2,00FFFFFFh
|
|
invoke FormatNumber,bpPower3D,OFFSET bpText3D
|
|
invoke DrawString8x8,50,180,OFFSET bpText3D,00FFFFFFh
|
|
jmp bp_render_done
|
|
bp_render_result:
|
|
mov eax,OFFSET bpResultText
|
|
cmp bpGutter3D,0
|
|
je @F
|
|
mov eax,OFFSET bpGutterText
|
|
@@:
|
|
cmp bpLastKind3D,1
|
|
jne @F
|
|
mov eax,OFFSET bpStrikeText
|
|
@@:
|
|
cmp bpLastKind3D,2
|
|
jne @F
|
|
mov eax,OFFSET bpSpareText
|
|
@@:
|
|
invoke DrawString8x8,104,197,eax,00E8D7ADh
|
|
invoke FormatNumber,bpLast3D,OFFSET bpText3D
|
|
invoke DrawString8x8,192,197,OFFSET bpText3D,00FFFFFFh
|
|
jmp bp_render_done
|
|
bp_render_finished:
|
|
mov eax,bwScores3D[esi*8]
|
|
mov ebx,OFFSET bpDrawText
|
|
cmp eax,bwScores3D[esi*8+4]
|
|
je @F
|
|
mov ebx,OFFSET bpWinText
|
|
ja @F
|
|
mov ebx,OFFSET bpLoseText
|
|
@@:
|
|
invoke DrawBoxBorder,72,150,176,58,00121B20h,005BC9BEh,1
|
|
invoke DrawString8x8,88,161,ebx,00E8D7ADh
|
|
invoke DrawString8x8,136,187,OFFSET bpAgainText,00FFFFFFh
|
|
bp_render_done:
|
|
call DrawBowlingWeight3D
|
|
cmp bpScoreOpen3D,0
|
|
je @F
|
|
call DrawBowlingPlayScores3D
|
|
@@:
|
|
ret
|
|
RenderBowlingPlay3D ENDP
|