KAZIK/src_graphics/billiards.inc
Artvasil09 881a0061dc Add native NPC visitors with contracts, Clover slots, Pyramid, and party table scenes
Implement 32x32 BFS visitor navigation and daily contracts system with companion .npc journals; add native assembly scenes for Clover slots, Pyramid cards, Blackjack Party and Russian Party; package animation and sprite packs; add comprehensive offline test suites and rebuild shipping binaries.
2026-10-13 09:47:33 +03:00

508 lines
11 KiB
PHP

; Q16.16 simulation, velocities in cloth pixels per 2 ms fixed step.
PoolSqrt3D PROC squared:DWORD
local result:DWORD
fild squared
fsqrt
fistp result
mov eax, result
ret
PoolSqrt3D ENDP
InitPool3D PROC uses ebx esi edi
lea edi, poolVX3D
xor eax, eax
mov ecx, 32
rep stosd
xor esi, esi
pool_init_balls:
mov poolActive3D[esi*4], 1
mov poolPocket3D[esi*4], -1
mov poolSinkTime3D[esi*4], 0
inc esi
cmp esi, 16
jb pool_init_balls
mov poolX3D, 82*FP_1
mov poolY3D, 115*FP_1
xor esi, esi
xor ebx, ebx
pool_rack_row:
xor edi, edi
pool_rack_ball:
mov ecx, poolRackOrder3D[esi*4]
imul eax, ebx, FP_1*43302/10000
add eax, 225*FP_1
mov poolX3D[ecx*4], eax
imul eax, edi, 5*FP_1
imul edx, ebx, FP_1*5/2
sub eax, edx
add eax, 115*FP_1
mov poolY3D[ecx*4], eax
inc esi
inc edi
cmp edi, ebx
jbe pool_rack_ball
inc ebx
cmp ebx, 5
jb pool_rack_row
mov poolState3D, POOL_AIM
mov poolPlayer3D, 0
mov poolGroups3D, 0
mov poolGroups3D[4], 0
mov poolAngle3D, 0
mov poolPower3D, 80000
mov poolBreak3D, 1
mov poolAccumulator3D, 0
mov poolCharge3D, 0
mov poolTime3D, 0
mov poolFoul3D, 0
mov poolPotted3D, 0
mov poolStill3D, 1
mov poolCalled3D, 1
mov poolCalledPocket3D, 0
call InitPyramidState3D
ret
InitPool3D ENDP
; Symmetric equal-mass impulse plus separation; opening contacts never gain energy.
PoolCollide3D PROC uses ebx esi edi a:DWORD,b:DWORD
local deltaX:DWORD,deltaY:DWORD,length8:DWORD,nx:DWORD,ny:DWORD,impulse:DWORD,correction:DWORD
mov esi, a
mov edi, b
cmp poolActive3D[esi*4], 0
je pool_pair_done
cmp poolActive3D[edi*4], 0
je pool_pair_done
mov eax, poolX3D[edi*4]
sub eax, poolX3D[esi*4]
cmp eax, POOL_DIAMETER
jg pool_pair_done
cmp eax, -POOL_DIAMETER
jl pool_pair_done
mov deltaX, eax
mov eax, poolY3D[edi*4]
sub eax, poolY3D[esi*4]
cmp eax, POOL_DIAMETER
jg pool_pair_done
cmp eax, -POOL_DIAMETER
jl pool_pair_done
mov deltaY, eax
sar eax, 8
imul eax, eax
mov ebx, deltaX
sar ebx, 8
imul ebx, ebx
add eax, ebx
cmp eax, 25*256*256
jg pool_pair_done
test eax, eax
jnz @F
mov deltaX, 256
mov eax, 1
@@:
invoke PoolSqrt3D, eax
cmp eax, 1
jge @F
mov eax, 1
@@:
mov length8, eax
mov eax, deltaX
imul eax, 256
cdq
idiv length8
mov nx, eax
mov eax, deltaY
imul eax, 256
cdq
idiv length8
mov ny, eax
mov eax, poolVX3D[edi*4]
sub eax, poolVX3D[esi*4]
imul nx
shrd eax, edx, 16
mov ebx, eax
mov eax, poolVY3D[edi*4]
sub eax, poolVY3D[esi*4]
imul ny
shrd eax, edx, 16
add eax, ebx
test eax, eax
jns pool_pair_separate
imul eax, 99
cdq
mov ecx, 100
idiv ecx
mov impulse, eax
imul nx
shrd eax, edx, 16
add poolVX3D[esi*4], eax
sub poolVX3D[edi*4], eax
mov eax, impulse
imul ny
shrd eax, edx, 16
add poolVY3D[esi*4], eax
sub poolVY3D[edi*4], eax
invoke PyramidContact3D,esi,edi
cmp esi,pyrCue3D
je @F
cmp edi,pyrCue3D
jne pool_pair_separate
cmp poolFirst3D,-1
jne pool_pair_separate
mov poolFirst3D,esi
jmp pool_pair_separate
@@:
cmp poolFirst3D, -1
jne pool_pair_separate
mov poolFirst3D, edi
pool_pair_separate:
mov eax, length8
shl eax, 8
neg eax
add eax, POOL_DIAMETER
sar eax, 1
mov correction, eax
imul nx
shrd eax, edx, 16
sub poolX3D[esi*4], eax
add poolX3D[edi*4], eax
mov eax, correction
imul ny
shrd eax, edx, 16
sub poolY3D[esi*4], eax
add poolY3D[edi*4], eax
pool_pair_done:
ret
PoolCollide3D ENDP
PoolPocketBall3D PROC uses ebx esi ball:DWORD
mov esi, ball
cmp poolActive3D[esi*4],0
je pool_pocket_done
xor ebx, ebx
pool_pocket_test:
mov eax, poolX3D[esi*4]
sub eax, poolPocketX3D[ebx*4]
cmp eax,2*FP_1
jg pool_pocket_next
cmp eax,-2*FP_1
jl pool_pocket_next
sar eax, 8
imul eax, eax
mov ecx, eax
mov eax, poolY3D[esi*4]
sub eax, poolPocketY3D[ebx*4]
cmp eax,2*FP_1
jg pool_pocket_next
cmp eax,-2*FP_1
jl pool_pocket_next
sar eax, 8
imul eax, eax
add eax, ecx
; Capture is deep inside the narrow mouth; jaws are separate colliders.
cmp eax, 480*480
ja pool_pocket_next
pool_pocket_capture:
mov poolActive3D[esi*4], 0
mov poolVX3D[esi*4], 0
mov poolVY3D[esi*4], 0
mov poolPocket3D[esi*4], ebx
mov poolSinkTime3D[esi*4], 220
bts poolPotted3D, esi
ret
pool_pocket_next:
inc ebx
cmp ebx, 6
jb pool_pocket_test
pool_pocket_done:
ret
PoolPocketBall3D ENDP
PoolRailContact3D PROC ball:DWORD
mov ecx, ball
bts poolBreakRails3D, ecx
cmp poolFirst3D, -1
je @F
mov poolRail3D, 1
invoke PyramidRail3D,ball,pyrRailSide3D
@@:
ret
PoolRailContact3D ENDP
PoolJawContact3D PROC uses ebx esi edi ball:DWORD
local deltaX:DWORD,deltaY:DWORD,distance:DWORD,normX:DWORD,normY:DWORD,impulse:DWORD
mov esi, ball
xor edi, edi
pool_jaw_test:
mov eax, poolX3D[esi*4]
sub eax, poolJawX3D[edi*4]
cmp eax, 3*FP_1
jg pool_jaw_next
cmp eax, -3*FP_1
jl pool_jaw_next
mov deltaX, eax
mov eax, poolY3D[esi*4]
sub eax, poolJawY3D[edi*4]
cmp eax, 3*FP_1
jg pool_jaw_next
cmp eax, -3*FP_1
jl pool_jaw_next
mov deltaY, eax
sar eax, 8
imul eax, eax
mov ebx, deltaX
sar ebx, 8
imul ebx, ebx
add eax, ebx
cmp eax, 704*704
ja pool_jaw_next
test eax, eax
jnz @F
mov deltaX, 256
mov eax, 1
@@:
invoke PoolSqrt3D,eax
cmp eax, 1
jge @F
mov eax, 1
@@:
mov distance, eax
mov eax, deltaX
imul eax, 256
cdq
idiv distance
mov normX, eax
mov eax, deltaY
imul eax, 256
cdq
idiv distance
mov normY, eax
mov eax, poolVX3D[esi*4]
imul normX
shrd eax, edx, 16
mov ebx, eax
mov eax, poolVY3D[esi*4]
imul normY
shrd eax, edx, 16
add eax, ebx
test eax, eax
jns pool_jaw_separate
imul eax, 187
cdq
mov ecx, 100
idiv ecx
mov impulse, eax
imul normX
shrd eax, edx, 16
sub poolVX3D[esi*4], eax
mov eax, impulse
imul normY
shrd eax, edx, 16
sub poolVY3D[esi*4], eax
mov pyrRailSide3D,0
cmp edi,6
jb @F
mov pyrRailSide3D,1
@@:
cmp edi,1
je pyr_jaw_left_side
cmp edi,7
jne @F
pyr_jaw_left_side:
mov pyrRailSide3D,2
@@:
cmp edi,4
je pyr_jaw_right_side
cmp edi,10
jne @F
pyr_jaw_right_side:
mov pyrRailSide3D,3
@@:
invoke PoolRailContact3D,esi
pool_jaw_separate:
mov eax, distance
shl eax, 8
neg eax
add eax, FP_1*11/4
mov impulse, eax
imul normX
shrd eax, edx, 16
add poolX3D[esi*4], eax
mov eax, impulse
imul normY
shrd eax, edx, 16
add poolY3D[esi*4], eax
pool_jaw_next:
inc edi
cmp edi, 12
jb pool_jaw_test
ret
PoolJawContact3D ENDP
PoolStep3D PROC uses ebx esi edi
xor esi, esi
pool_step_ball:
cmp poolActive3D[esi*4], 0
je pool_step_next
mov eax,poolX3D[esi*4]
mov pyrPreviousX3D[esi*4],eax
mov eax, poolVX3D[esi*4]
add poolX3D[esi*4], eax
mov eax, poolVY3D[esi*4]
add poolY3D[esi*4], eax
invoke PyramidCross3D,esi
invoke PoolPocketBall3D, esi
cmp poolActive3D[esi*4], 0
je pool_step_next
invoke PoolJawContact3D,esi
; Leave the corner throats open. Solid cushions stop at their jaws.
mov ebx, 30*FP_1+POOL_RADIUS
mov edi, 290*FP_1-POOL_RADIUS
cmp poolY3D[esi*4], 57*FP_1
jle pool_rail_corner_x
cmp poolY3D[esi*4], 173*FP_1
jl pool_rail_test_x
pool_rail_corner_x:
mov ebx, 31*FP_1
mov edi, 289*FP_1
pool_rail_test_x:
cmp poolX3D[esi*4], ebx
jge pool_rail_right
mov poolX3D[esi*4], ebx
mov eax, poolVX3D[esi*4]
test eax, eax
jns pool_rail_y
jmp pool_rail_bounce_x
pool_rail_right:
cmp poolX3D[esi*4], edi
jle pool_rail_y
mov poolX3D[esi*4], edi
mov eax, poolVX3D[esi*4]
test eax, eax
jle pool_rail_y
pool_rail_bounce_x:
imul eax, -87
cdq
mov ecx, 100
idiv ecx
mov poolVX3D[esi*4], eax
mov pyrRailSide3D,2
cmp poolX3D[esi*4],160*FP_1
jl @F
mov pyrRailSide3D,3
@@:
invoke PoolRailContact3D, esi
pool_rail_y:
mov ebx, 50*FP_1+POOL_RADIUS
mov edi, 180*FP_1-POOL_RADIUS
cmp poolX3D[esi*4], 37*FP_1
jle pool_rail_throat_y
cmp poolX3D[esi*4], 283*FP_1
jge pool_rail_throat_y
cmp poolX3D[esi*4], 157*FP_1
jl pool_rail_test_y
cmp poolX3D[esi*4], 163*FP_1
jg pool_rail_test_y
pool_rail_throat_y:
mov ebx, 51*FP_1
mov edi, 179*FP_1
pool_rail_test_y:
cmp poolY3D[esi*4], ebx
jge pool_rail_bottom
mov poolY3D[esi*4], ebx
mov eax, poolVY3D[esi*4]
test eax, eax
jns pool_step_next
jmp pool_rail_bounce_y
pool_rail_bottom:
cmp poolY3D[esi*4], edi
jle pool_step_next
mov poolY3D[esi*4], edi
mov eax, poolVY3D[esi*4]
test eax, eax
jle pool_step_next
pool_rail_bounce_y:
imul eax, -87
cdq
mov ecx, 100
idiv ecx
mov poolVY3D[esi*4], eax
mov pyrRailSide3D,0
cmp poolY3D[esi*4],115*FP_1
jl @F
mov pyrRailSide3D,1
@@:
invoke PoolRailContact3D, esi
pool_step_next:
inc esi
cmp esi, 16
jb pool_step_ball
; Two contact passes stabilize the triangular break rack.
mov ebx, 2
pool_contact_pass:
xor esi, esi
pool_contact_outer:
lea edi, [esi+1]
pool_contact_inner:
invoke PoolCollide3D, esi,edi
inc edi
cmp edi, 16
jb pool_contact_inner
inc esi
cmp esi, 15
jb pool_contact_outer
dec ebx
jnz pool_contact_pass
xor esi, esi
mov poolStill3D, 1
pool_friction_ball:
cmp poolActive3D[esi*4],0
je pool_sleep_ball
mov eax,poolVX3D[esi*4]
test eax,eax
jns @F
neg eax
@@:
add pyrRoll3D[esi*4],eax
mov eax, poolVX3D[esi*4]
sar eax, 4
imul eax, eax
mov ecx, poolVY3D[esi*4]
sar ecx, 4
imul ecx, ecx
add eax, ecx
cmp eax, 64
jbe pool_sleep_ball
invoke PoolSqrt3D, eax
shl eax, 4
cmp eax, 128
jbe pool_sleep_ball
mov ecx, eax
sub eax, 16
xor edx, edx
shld edx, eax, 16
shl eax, 16
div ecx
mov ecx, eax
mov eax, poolVX3D[esi*4]
imul ecx
shrd eax, edx, 16
mov poolVX3D[esi*4], eax
mov eax, poolVY3D[esi*4]
imul ecx
shrd eax, edx, 16
mov poolVY3D[esi*4], eax
mov poolStill3D, 0
jmp pool_friction_next
pool_sleep_ball:
mov poolVX3D[esi*4], 0
mov poolVY3D[esi*4], 0
pool_friction_next:
inc esi
cmp esi, 16
jb pool_friction_ball
ret
PoolStep3D ENDP
include src_graphics\pyramid_rules.inc
include src_graphics\pyramid_play.inc
include src_graphics\pyramid_render.inc