KAZIK/src_graphics/bowling_play_render.inc
Artvasil09 3150d217b5 feat: add playable bowling match mode and calibrate rooftop character scaling
- Add playable ten-frame bowling against bot with two timing gates (direction/power) and fixed-step physics

- Add lane match interaction, shaded ball surface, pin collisions, bonus balls, and live score sheet

- Scale rooftop terrace visitor sprites to eye level according to the taller rooftop standing eye height

- Resolve mode and interaction ID conflicts with Hell FPS (MODE_BOWLING=30, INTERACT_BOWL_PLAY=56)

- Update launcher hash, installer package, and expansion regression test suites
2026-11-01 22:50:33 +03:00

459 lines
10 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
ret
InitBowlingBallSurface3D ENDP
DrawBowlingPlayPin3D PROC uses ebx esi edi pin:DWORD,centre:DWORD
local x:DWORD,y:DWORD,z:DWORD,headY:DWORD,ry:DWORD,rz:DWORD
mov esi,pin
mov ecx,esi
mov ebx,1
shl ebx,cl
mov edi,bpLane3D
test bwRack3D[edi*4],ebx
jz bp_pin_done
mov eax,bpPinX3D[esi*4]
add eax,centre
mov x,eax
mov eax,bpPinY3D[esi*4]
mov y,eax
mov headY,eax
mov z,FP_1*15/100
mov ry,FP_1/10
mov rz,FP_1*13/100
test bpHitMask3D,ebx
jz bp_pin_draw
mov z,FP_1*7/100
mov ry,FP_1*23/100
mov rz,FP_1*6/100
sub headY,FP_1/4
bp_pin_draw:
invoke DrawRoofEllipsoid3D,x,y,z,FP_1/10,ry,rz,239
mov eax,FP_1*34/100
test bpHitMask3D,ebx
jz @F
mov eax,FP_1*7/100
@@:
invoke DrawRoofEllipsoid3D,x,headY,eax,FP_1*65/1000,FP_1*65/1000,FP_1*6/100,239
mov eax,z
add eax,rz
invoke DrawRoofEllipsoid3D,x,headY,eax,FP_1*45/1000,FP_1*45/1000,FP_1*25/1000,240
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
DrawBowlingPlayScores3D PROC uses ebx esi edi
local x:DWORD,y:DWORD,owner:DWORD
invoke DrawBoxBorder,4,47,312,139,00151F26h,005BC9BEh,1
invoke DrawString8x8,12,55,OFFSET bpScoreText,00E8D7ADh
xor esi,esi
bp_score_heading:
imul eax,esi,26
add eax,44
mov x,eax
lea eax,[esi+1]
invoke FormatNumber,eax,OFFSET bpText3D
invoke DrawString8x8,x,73,OFFSET bpText3D,00AABDB6h
inc esi
cmp esi,10
jb bp_score_heading
xor edi,edi
bp_score_owner:
lea eax,[edi*2]
imul eax,18
add eax,96
mov y,eax
mov eax,OFFSET bpYou
test edi,edi
jz @F
mov eax,OFFSET bpBot
@@:
invoke DrawString8x8,9,y,eax,005BC9BEh
mov eax,bpLane3D
shl eax,1
add eax,edi
mov owner,eax
xor esi,esi
bp_score_cell:
imul eax,esi,26
add eax,44
mov x,eax
invoke BowlingFrameTotal3D,owner,esi
cmp eax,-1
je bp_score_empty
invoke FormatNumber,eax,OFFSET bpText3D
invoke DrawString8x8,x,y,OFFSET bpText3D,00FFFFFFh
jmp bp_score_next
bp_score_empty:
invoke DrawBox,x,y,8,1,005C727Bh
bp_score_next:
inc esi
cmp esi,10
jb bp_score_cell
inc edi
cmp edi,2
jb bp_score_owner
ret
DrawBowlingPlayScores3D ENDP
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
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
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_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
imul eax,ebx,FP_1*7/20
cdq
idiv ecx
mov edx,HALL_STANDING_EYE
sub edx,eax
mov viewEye3D,edx
bp_camera_ready:
call UpdateCamera3D
call RenderBowling3D
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:
cmp bpState3D,BP_FINISHED
je bp_render_hud
mov eax,bpBallX3D
add eax,bpCentre3D
invoke DrawBowlingBall3D,eax,bpBallY3D,253
bp_render_hud:
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
jne @F
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_POWER
je bp_render_power
cmp bpState3D,BP_SETTLE
je bp_render_result
cmp bpState3D,BP_FINISHED
je bp_render_finished
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,246,62,OFFSET bpPowerText,00E8D7ADh
invoke DrawBoxBorder,276,79,13,124,00121B20h,00AABDB6h,1
invoke DrawBox,278,82,9,118,00D67057h
invoke DrawBox,278,128,9,38,00E7C455h
invoke DrawBox,278,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,270,y,25,2,00FFFFFFh
invoke FormatNumber,bpPower3D,OFFSET bpText3D
invoke DrawString8x8,246,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:
cmp bpScoreOpen3D,0
je @F
call DrawBowlingPlayScores3D
@@:
ret
RenderBowlingPlay3D ENDP