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.
508 lines
11 KiB
PHP
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
|