KAZIK/src_graphics/bowling_physics.inc
Artvasil09 7e081beeca feat: enhance bowling physics, audio, ball weight selection, and visitor cast routines
- 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
2026-11-04 18:44:12 +03:00

482 lines
10 KiB
PHP

; Symmetric normal impulses and overlap correction follow the existing billiards
; solver. Four 4-ms substeps prevent tunnelling; angular rocking is separate.
include src_graphics\bowling_deck.inc
NormalizeBowlingPinAxis3D PROC uses esi pin:DWORD
local axisLength:REAL8
mov esi,pin
mov eax,bpPinAxisX3D[esi*4]
or eax,bpPinAxisY3D[esi*4]
jnz bp_axis_length
mov bpPinAxisY3D[esi*4],-FP_1
ret
bp_axis_length:
fild bpPinAxisX3D[esi*4]
fmul st,st
fild bpPinAxisY3D[esi*4]
fmul st,st
faddp st(1),st
fsqrt
fstp axisLength
fild bpPinAxisX3D[esi*4]
fdiv axisLength
fmul roofFloatFP3D
fistp bpPinAxisX3D[esi*4]
fild bpPinAxisY3D[esi*4]
fdiv axisLength
fmul roofFloatFP3D
fistp bpPinAxisY3D[esi*4]
ret
NormalizeBowlingPinAxis3D ENDP
BowlingPlayHit3D PROC pin:DWORD,vx:DWORD,vy:DWORD
invoke BowlingPlayKick3D,pin,vx,vy
ret
BowlingPlayHit3D ENDP
BowlingPlayKick3D PROC uses ebx esi edi pin:DWORD,vx:DWORD,vy:DWORD
local energy:DWORD
mov esi,pin
cmp esi,10
jae bp_kick_done
; Preserve fractional impulses: signed pre-rounding can collapse the basis.
fild vx
fmul st,st
fild vy
fmul st,st
faddp st(1),st
fsqrt
fistp energy
mov eax,energy
cmp eax,128
jb bp_kick_done
cmp eax,bpImpactEnergy3D
jbe @F
mov bpImpactEnergy3D,eax
@@:
cmp eax,128
jb bp_kick_done
mov edx,bpPhysicsTicks3D
mov bpPinContactTick3D[esi*4],edx
mov ecx,2
cdq
idiv ecx
cmp eax,2000
jbe @F
mov eax,2000
@@:
add bpPinTiltV3D[esi*4],eax
mov eax,bpPinTiltV3D[esi*4]
cmp eax,2400
jle @F
mov bpPinTiltV3D[esi*4],2400
@@:
cmp bpPinTilt3D[esi*4],64*256
jae bp_kick_done
mov eax,vx
mov ecx,FP_1
imul ecx
idiv energy
mov bpPinAxisX3D[esi*4],eax
mov eax,vy
imul ecx
idiv energy
mov bpPinAxisY3D[esi*4],eax
invoke NormalizeBowlingPinAxis3D,esi
mov eax,vx
sub eax,vy
sar eax,10
mov bpPinSpin3D[esi*4],eax
bp_kick_done:
ret
BowlingPlayKick3D ENDP
BowlingPlayContact3D PROC uses ebx esi edi a:DWORD,b:DWORD
local deltaX:DWORD,deltaY:DWORD,radius:DWORD,distance:DWORD,nx:DWORD,ny:DWORD
local impulse:DWORD,changeA:DWORD,changeB:DWORD,ix:DWORD,iy:DWORD,massSum:DWORD
local contactLength:REAL8
mov esi,a
mov edi,b
mov eax,bpRadius3D[esi*4]
add eax,bpRadius3D[edi*4]
mov radius,eax
shl eax,8
mov ebx,eax
mov eax,bpPinX3D[edi*4]
sub eax,bpPinX3D[esi*4]
cmp eax,ebx
jg bp_contact_done
neg ebx
cmp eax,ebx
jl bp_contact_done
mov deltaX,eax
mov eax,bpPinY3D[edi*4]
sub eax,bpPinY3D[esi*4]
cmp eax,ebx
jl bp_contact_done
neg ebx
cmp eax,ebx
jg bp_contact_done
mov deltaY,eax
sar eax,8
imul eax,eax
mov ebx,deltaX
sar ebx,8
imul ebx,ebx
add eax,ebx
mov ebx,radius
imul ebx,ebx
cmp eax,ebx
jae bp_contact_done
fild deltaX
fmul st,st
fild deltaY
fmul st,st
faddp st(1),st
fsqrt
fst contactLength
fistp distance
cmp distance,0
jne @F
mov deltaX,1
mov deltaY,0
mov distance,1
fild distance
fstp contactLength
@@:
mov eax,radius
shl eax,8
cmp distance,eax
jae bp_contact_done
fild deltaX
fdiv contactLength
fmul roofFloatFP3D
fistp nx
fild deltaY
fdiv contactLength
fmul roofFloatFP3D
fistp ny
mov eax,bpInvMass3D[esi*4]
add eax,bpInvMass3D[edi*4]
mov massSum,eax
mov eax,bpPinVX3D[edi*4]
sub eax,bpPinVX3D[esi*4]
imul nx
shrd eax,edx,16
mov ebx,eax
mov eax,bpPinVY3D[edi*4]
sub eax,bpPinVY3D[esi*4]
imul ny
shrd eax,edx,16
add eax,ebx
test eax,eax
jns bp_contact_separate
neg eax
mov ecx,FP_1*3/2
imul ecx
idiv massSum
mov impulse,eax
imul bpInvMass3D[esi*4]
shrd eax,edx,16
mov changeA,eax
mov eax,impulse
imul bpInvMass3D[edi*4]
shrd eax,edx,16
mov changeB,eax
mov eax,changeA
imul nx
shrd eax,edx,16
sub bpPinVX3D[esi*4],eax
neg eax
mov ix,eax
mov eax,changeA
imul ny
shrd eax,edx,16
sub bpPinVY3D[esi*4],eax
neg eax
invoke BowlingPlayKick3D,esi,ix,eax
mov eax,changeB
imul nx
shrd eax,edx,16
add bpPinVX3D[edi*4],eax
mov ix,eax
mov eax,changeB
imul ny
shrd eax,edx,16
add bpPinVY3D[edi*4],eax
invoke BowlingPlayKick3D,edi,ix,eax
bp_contact_separate:
mov eax,radius
shl eax,8
sub eax,distance
jle bp_contact_done
imul eax,3
sar eax,2
mov impulse,eax
imul bpInvMass3D[esi*4]
idiv massSum
mov changeA,eax
mov eax,impulse
imul bpInvMass3D[edi*4]
idiv massSum
mov changeB,eax
mov eax,changeA
imul nx
shrd eax,edx,16
sub bpPinX3D[esi*4],eax
mov eax,changeA
imul ny
shrd eax,edx,16
sub bpPinY3D[esi*4],eax
mov eax,changeB
imul nx
shrd eax,edx,16
add bpPinX3D[edi*4],eax
mov eax,changeB
imul ny
shrd eax,edx,16
add bpPinY3D[edi*4],eax
bp_contact_done:
ret
BowlingPlayContact3D ENDP
BowlingPlayStep3D PROC uses ebx esi edi
local substep:DWORD,rack:DWORD
mov esi,bpLane3D
mov eax,bwRack3D[esi*4]
or eax,1024
mov rack,eax
mov eax,bpBallX3D
mov bpPinX3D[40],eax
mov eax,bpBallY3D
mov bpPinY3D[40],eax
mov eax,bpBallVX3D
mov bpPinVX3D[40],eax
mov eax,bpBallVY3D
mov bpPinVY3D[40],eax
mov substep,0
bp_physics_substep:
xor esi,esi
bp_physics_integrate:
bt rack,esi
jnc bp_physics_integrate_next
mov eax,bpPinVX3D[esi*4]
sar eax,2
add bpPinX3D[esi*4],eax
mov eax,bpPinVY3D[esi*4]
sar eax,2
add bpPinY3D[esi*4],eax
cmp esi,10
jne bp_physics_integrate_next
cmp bpPinY3D[40],FP_1*28/10
jge @F
mov bpPinVX3D[40],0
mov bpPinVY3D[40],0
@@:
mov eax,bpPinX3D[40]
cdq
xor eax,edx
sub eax,edx
cmp eax,FP_1*74/100
jbe bp_physics_integrate_next
mov bpGutter3D,1
mov eax,FP_1*87/100
cmp bpPinX3D[40],0
jge @F
neg eax
@@:
mov bpPinX3D[40],eax
mov bpPinVX3D[40],0
bp_physics_integrate_next:
inc esi
cmp esi,BP_BODY_COUNT
jb bp_physics_integrate
xor esi,esi
bp_physics_pair_a:
bt rack,esi
jnc bp_physics_pair_next_a
lea edi,[esi+1]
bp_physics_pair_b:
bt rack,edi
jnc bp_physics_pair_next_b
cmp edi,10
jne @F
cmp bpGutter3D,0
jne bp_physics_pair_next_b
@@:
invoke BowlingPlayContact3D,esi,edi
bp_physics_pair_next_b:
inc edi
cmp edi,BP_BODY_COUNT
jb bp_physics_pair_b
bp_physics_pair_next_a:
inc esi
cmp esi,10
jb bp_physics_pair_a
xor esi,esi
bp_physics_substep_limits:
bt rack,esi
jnc @F
invoke BowlingPlayTether3D,esi
invoke BowlingPlayDeckBounds3D,esi
@@:
inc esi
cmp esi,10
jb bp_physics_substep_limits
inc substep
cmp substep,4
jb bp_physics_substep
xor esi,esi
bp_physics_pin:
bt rack,esi
jnc bp_physics_pin_next
mov ecx,246
mov eax,bpPhysicsTicks3D
sub eax,bpPinContactTick3D[esi*4]
cmp eax,10
jb @F
bt bpHitMask3D,esi
jnc @F
mov ecx,224
@@:
mov eax,bpPinVX3D[esi*4]
imul eax,ecx
sar eax,8
mov bpPinVX3D[esi*4],eax
mov eax,bpPinVY3D[esi*4]
imul eax,ecx
sar eax,8
mov bpPinVY3D[esi*4],eax
mov eax,bpPinTilt3D[esi*4]
cmp eax,24*256
jae bp_physics_topple
mov edx,eax
sar edx,6
sub bpPinTiltV3D[esi*4],edx
jmp bp_physics_tilt
bp_physics_topple:
add bpPinTiltV3D[esi*4],160
bp_physics_tilt:
mov edx,bpPinTiltV3D[esi*4]
imul edx,245
sar edx,8
mov bpPinTiltV3D[esi*4],edx
add eax,edx
test eax,eax
jns @F
xor eax,eax
mov bpPinTiltV3D[esi*4],0
@@:
cmp eax,128*256
jbe @F
mov eax,128*256
mov edx,bpPinTiltV3D[esi*4]
neg edx
sar edx,2
cmp edx,-80
jl bp_physics_bounce
xor edx,edx
bp_physics_bounce:
mov bpPinTiltV3D[esi*4],edx
@@:
mov bpPinTilt3D[esi*4],eax
cmp eax,64*256
jb bp_physics_pin_next
bts bpHitMask3D,esi
mov bpRadius3D[esi*4],48
; Slow rolling yaw, independent of the fall's vertical angle.
mov ecx,bpPinSpin3D[esi*4]
and ecx,511
mov eax,bpPinAxisX3D[esi*4]
imul tableCos[ecx*4]
shrd eax,edx,16
mov ebx,eax
mov eax,bpPinAxisY3D[esi*4]
imul tableSin[ecx*4]
shrd eax,edx,16
sub ebx,eax
mov eax,bpPinAxisX3D[esi*4]
imul tableSin[ecx*4]
shrd eax,edx,16
mov edi,eax
mov eax,bpPinAxisY3D[esi*4]
imul tableCos[ecx*4]
shrd eax,edx,16
add eax,edi
mov bpPinAxisY3D[esi*4],eax
mov bpPinAxisX3D[esi*4],ebx
invoke NormalizeBowlingPinAxis3D,esi
mov eax,bpPinSpin3D[esi*4]
imul eax,230
test eax,eax
jns @F
add eax,255
@@:
sar eax,8
mov bpPinSpin3D[esi*4],eax
bp_physics_pin_next:
bt rack,esi
jnc @F
invoke BowlingPlayTether3D,esi
invoke BowlingPlayDeckBounds3D,esi
@@:
inc esi
cmp esi,10
jb bp_physics_pin
mov eax,bpPinX3D[40]
mov bpBallX3D,eax
mov eax,bpPinY3D[40]
mov bpBallY3D,eax
mov eax,bpPinVX3D[40]
mov bpBallVX3D,eax
mov eax,bpPinVY3D[40]
mov bpBallVY3D,eax
inc bpPhysicsTicks3D
cmp bpBallY3D,3*FP_1
jge @F
inc bpEndTicks3D
@@:
ret
BowlingPlayStep3D ENDP
BowlingPlayReady3D PROC uses esi
cmp bpPhysicsTicks3D,900
jae bp_physics_ready
cmp bpEndTicks3D,100
jb bp_physics_not_ready
xor esi,esi
bp_physics_quiet:
mov eax,bpPinVX3D[esi*4]
cdq
xor eax,edx
sub eax,edx
cmp eax,96
ja bp_physics_not_ready
mov eax,bpPinTilt3D[esi*4]
cmp eax,128*256
jae @F
cmp eax,24*256
jae bp_physics_not_ready
mov eax,bpPinTiltV3D[esi*4]
cdq
xor eax,edx
sub eax,edx
cmp eax,32
ja bp_physics_not_ready
@@:
mov eax,bpPinVY3D[esi*4]
cdq
xor eax,edx
sub eax,edx
cmp eax,96
ja bp_physics_not_ready
inc esi
cmp esi,10
jb bp_physics_quiet
bp_physics_ready:
mov eax,1
ret
bp_physics_not_ready:
xor eax,eax
ret
BowlingPlayReady3D ENDP