KAZIK/src_graphics/pyramid_play.inc
Artvasil09 23dc40ee5c feat: implement native darts mini-game, AI observer mode, and fortune session assets
- Darts: native 500-point match against Max with sway/fatigue mouse aim, parabolic throw camera, raster arm animations, and 16 camera-relative flying dart views

- AI Observer: autonomous spectator mode for Hold'em, Blackjack, Durak, and Billiards with profile isolation and playback controls

- Fortune Session: raster sprite packs, mist/orb animations, tarot divination spreads, and pack tools

- Hall Integration: wall dartboard in lounge, observer terminal dispatch, and bot turn hooks

- Packaging & Verification: updated installer streaming hash, synchronized launcher, passing check suites and release smoke checks
2026-10-24 22:10:25 +03:00

847 lines
17 KiB
PHP

PyramidSelect3D PROC uses ebx ball:DWORD
cmp poolVariant3D,1
jne @F
mov pyrCue3D,0
ret
@@:
cmp poolBreak3D,0
je @F
mov pyrCue3D,0
ret
@@:
mov ebx,ball
cmp ebx,15
ja pyr_select_default
cmp poolActive3D[ebx*4],1
jne pyr_select_default
mov pyrCue3D,ebx
mov poolCalled3D,ebx
ret
pyr_select_default:
mov ebx,pyrCue3D
cmp poolActive3D[ebx*4],1
je pyr_select_done
xor ebx,ebx
pyr_select_scan:
cmp poolActive3D[ebx*4],1
je pyr_select_found
inc ebx
cmp ebx,16
jb pyr_select_scan
ret
pyr_select_found:
mov pyrCue3D,ebx
mov poolCalled3D,ebx
pyr_select_done:
ret
PyramidSelect3D ENDP
PyramidPick3D PROC uses ebx esi px:DWORD,py:DWORD
xor esi,esi
pyr_pick_ball:
cmp poolActive3D[esi*4],1
jne pyr_pick_next
mov eax,px
sub eax,poolX3D[esi*4]
sar eax,12
imul eax,eax
mov ebx,eax
mov eax,py
sub eax,poolY3D[esi*4]
sar eax,12
imul eax,eax
add eax,ebx
cmp eax,36*16*16
ja pyr_pick_next
mov eax,esi
ret
pyr_pick_next:
inc esi
cmp esi,16
jb pyr_pick_ball
mov eax,-1
ret
PyramidPick3D ENDP
PyramidDirection3D PROC uses ebx esi
mov ecx,poolAngle3D
and ecx,511
cmp pyrFineActive3D,0
jne pyr_direction_fine
mov eax,tableCos[ecx*4]
mov pyrDirX3D,eax
mov eax,tableSin[ecx*4]
mov pyrDirY3D,eax
ret
pyr_direction_fine:
mov ecx,pyrFine3D
and ecx,4095
mov ebx,ecx
and ebx,7
shr ecx,3
lea esi,[ecx+1]
and esi,511
mov eax,tableCos[esi*4]
sub eax,tableCos[ecx*4]
imul eax,ebx
sar eax,3
add eax,tableCos[ecx*4]
mov pyrDirX3D,eax
mov eax,tableSin[esi*4]
sub eax,tableSin[ecx*4]
imul eax,ebx
sar eax,3
add eax,tableSin[ecx*4]
mov pyrDirY3D,eax
ret
PyramidDirection3D ENDP
PoolAimPoint3D PROC uses ebx px:DWORD,py:DWORD
local deltaX:DWORD,deltaY:DWORD,phase:DWORD
mov ebx,pyrCue3D
mov eax,px
sub eax,poolX3D[ebx*4]
mov deltaX,eax
mov ecx,py
sub ecx,poolY3D[ebx*4]
mov deltaY,ecx
or eax,ecx
jz pyr_aim_done
fild deltaY
fild deltaX
fpatan
fmul pyrAimFactor3D
fistp phase
mov eax,phase
and eax,4095
mov pyrFine3D,eax
mov pyrFineActive3D,1
call PyramidDirection3D
pyr_aim_done:
ret
PoolAimPoint3D ENDP
PoolShoot3D PROC uses ebx esi
cmp poolState3D,POOL_AIM
jne pyr_shoot_done
mov ebx,pyrCue3D
cmp ebx,15
ja pyr_shoot_done
cmp poolActive3D[ebx*4],1
jne pyr_shoot_done
cmp pyrTablePack3D.pixels,0
je pyr_shoot_done
cmp pyrBallsPack3D.pixels,0
je pyr_shoot_done
cmp poolBreak3D,0
je @F
test ebx,ebx
jnz pyr_shoot_done
cmp poolX3D,95*FP_1
jge pyr_shoot_done
@@:
call PoolCountGroup3D
call EightAutoCall3D
mov poolFirst3D,-1
mov poolRail3D,0
mov poolBreakRails3D,0
mov poolPotted3D,0
mov poolFoul3D,0
mov pyrFoulReason3D,0
mov pyrValidEnd3D,0
mov pyrSettled3D,0
mov poolAccumulator3D,0
mov poolTime3D,0
mov poolState3D,POOL_STRIKE
xor esi,esi
pyr_shoot_history:
mov pyrHistoryRails3D[esi*4],0
mov pyrHistoryCross3D[esi*4],0
mov pyrRailHalf3D[esi*4],0
inc esi
cmp esi,16
jb pyr_shoot_history
call PyramidDirection3D
pyr_shoot_done:
ret
PoolShoot3D ENDP
; Obstruction checks use Q4 geometry with a 64-bit projection numerator.
PyramidPathClear3D PROC uses ebx esi edi sx:DWORD,sy:DWORD,ex:DWORD,ey:DWORD,skipA:DWORD,skipB:DWORD
local deltaX:DWORD,deltaY:DWORD,length2:DWORD,projection:DWORD,wx:DWORD,wy:DWORD
mov eax,ex
sub eax,sx
sar eax,12
mov deltaX,eax
imul eax,eax
mov ebx,eax
mov eax,ey
sub eax,sy
sar eax,12
mov deltaY,eax
imul eax,eax
add eax,ebx
mov length2,eax
test eax,eax
jz pyr_path_bad
xor esi,esi
pyr_path_ball:
cmp esi,skipA
je pyr_path_next
cmp esi,skipB
je pyr_path_next
cmp poolActive3D[esi*4],1
jne pyr_path_next
mov eax,poolX3D[esi*4]
sub eax,sx
sar eax,12
mov wx,eax
imul eax,deltaX
mov ebx,eax
mov eax,poolY3D[esi*4]
sub eax,sy
sar eax,12
mov wy,eax
imul eax,deltaY
add eax,ebx
test eax,eax
jle pyr_path_next
cmp eax,length2
jge pyr_path_next
mov ecx,FP_1
imul ecx
idiv length2
mov projection,eax
imul deltaX
shrd eax,edx,16
sub eax,wx
imul eax,eax
mov ebx,eax
mov eax,projection
imul deltaY
shrd eax,edx,16
sub eax,wy
imul eax,eax
add eax,ebx
cmp eax,25*16*16
jb pyr_path_bad
pyr_path_next:
inc esi
cmp esi,16
jb pyr_path_ball
mov eax,1
ret
pyr_path_bad:
xor eax,eax
ret
PyramidPathClear3D ENDP
; Search every cue/target/pocket triple; no hidden outcomes or teleported pots.
PoolChooseAI3D PROC uses ebx esi edi
local cue:DWORD,target:DWORD,pocket:DWORD,deltaX:DWORD,deltaY:DWORD,distance:DWORD
local gx:DWORD,gy:DWORD,best:DWORD,bestCue:DWORD,bestX:DWORD,bestY:DWORD,bestPower:DWORD
local shotLength:DWORD
local bestTarget:DWORD,bestPocket:DWORD
call PoolCountGroup3D
cmp poolBreak3D,0
je pyr_ai_search
mov pyrCue3D,0
mov poolAngle3D,0
mov pyrFineActive3D,0
mov poolPower3D,85000
ret
pyr_ai_search:
mov best,7FFFFFFFh
mov bestCue,-1
mov cue,0
pyr_ai_cue:
mov ecx,cue
cmp poolVariant3D,1
jne @F
test ecx,ecx
jnz pyr_ai_search_done
@@:
cmp poolActive3D[ecx*4],1
jne pyr_ai_next_cue
mov target,0
pyr_ai_target:
mov esi,target
cmp esi,cue
je pyr_ai_next_target
cmp poolActive3D[esi*4],1
jne pyr_ai_next_target
cmp poolVariant3D,1
jne @F
invoke EightLegal3D,esi
test eax,eax
jz pyr_ai_next_target
@@:
mov pocket,0
pyr_ai_pocket:
mov edi,pocket
mov eax,poolPocketX3D[edi*4]
sub eax,poolX3D[esi*4]
mov deltaX,eax
mov eax,poolPocketY3D[edi*4]
sub eax,poolY3D[esi*4]
mov deltaY,eax
invoke PyramidDistance3D,deltaX,deltaY
test eax,eax
jz pyr_ai_next_pocket
mov distance,eax
mov eax,deltaX
mov ecx,POOL_DIAMETER
imul ecx
idiv distance
mov ebx,poolX3D[esi*4]
sub ebx,eax
mov gx,ebx
mov eax,deltaY
mov ecx,POOL_DIAMETER
imul ecx
idiv distance
mov ebx,poolY3D[esi*4]
sub ebx,eax
mov gy,ebx
cmp gx,30*FP_1+POOL_RADIUS
jl pyr_ai_next_pocket
cmp gx,290*FP_1-POOL_RADIUS
jg pyr_ai_next_pocket
cmp gy,50*FP_1+POOL_RADIUS
jl pyr_ai_next_pocket
cmp gy,180*FP_1-POOL_RADIUS
jg pyr_ai_next_pocket
mov ecx,cue
mov eax,gx
sub eax,poolX3D[ecx*4]
sar eax,12
mov ebx,deltaX
sar ebx,12
imul eax,ebx
mov ebx,eax
mov eax,gy
sub eax,poolY3D[ecx*4]
sar eax,12
mov edx,deltaY
sar edx,12
imul eax,edx
add eax,ebx
test eax,eax
jle pyr_ai_next_pocket
invoke PyramidPathClear3D,poolX3D[ecx*4],poolY3D[ecx*4],gx,gy,cue,target
test eax,eax
jz pyr_ai_next_pocket
mov edi,pocket
invoke PyramidPathClear3D,poolX3D[esi*4],poolY3D[esi*4],poolPocketX3D[edi*4],poolPocketY3D[edi*4],cue,target
test eax,eax
jz pyr_ai_next_pocket
mov ecx,cue
mov eax,gx
sub eax,poolX3D[ecx*4]
mov ebx,gy
sub ebx,poolY3D[ecx*4]
invoke PyramidDistance3D,eax,ebx
mov shotLength,eax
add eax,distance
cmp eax,best
jae pyr_ai_next_pocket
mov best,eax
mov ecx,cue
mov bestCue,ecx
mov ecx,gx
mov bestX,ecx
mov ecx,gy
mov bestY,ecx
mov ecx,target
mov bestTarget,ecx
mov ecx,pocket
mov bestPocket,ecx
; v^2/(2*rolling loss) estimates the travel budget, with margin for a cut.
sar eax,16
imul eax,220
add eax,22000
cmp eax,85000
jbe @F
mov eax,85000
@@:
mov bestPower,eax
pyr_ai_next_pocket:
inc pocket
cmp pocket,6
jb pyr_ai_pocket
pyr_ai_next_target:
inc target
cmp target,16
jb pyr_ai_target
pyr_ai_next_cue:
inc cue
cmp cue,16
jb pyr_ai_cue
pyr_ai_search_done:
cmp bestCue,-1
je pyr_ai_safety
mov eax,bestCue
mov pyrCue3D,eax
invoke PoolAimPoint3D,bestX,bestY
mov eax,bestPower
mov poolPower3D,eax
cmp poolVariant3D,1
jne @F
mov eax,bestTarget
mov poolCalled3D,eax
mov eax,bestPocket
mov poolCalledPocket3D,eax
mov poolCallManual3D,3
@@:
ret
pyr_ai_safety:
mov poolCallManual3D,0
invoke PyramidSelect3D,-1
mov esi,pyrCue3D
xor edi,edi
pyr_ai_safety_target:
cmp edi,esi
je @F
cmp poolActive3D[edi*4],1
jne @F
invoke PoolBallLegal3D,edi
test eax,eax
jnz pyr_ai_safety_found
@@:
inc edi
cmp edi,16
jb pyr_ai_safety_target
ret
pyr_ai_safety_found:
invoke PoolAimPoint3D,poolX3D[edi*4],poolY3D[edi*4]
mov poolPower3D,65000
ret
PoolChooseAI3D ENDP
HandlePool3D PROC uses ebx esi edi
cmp poolState3D,POOL_SELECT
jne pyr_normal_input
invoke Pressed3D,31h
test eax,eax
jnz pyr_start_pyramid
invoke Pressed3D,32h
test eax,eax
jnz pyr_start_eight
cmp mouseClick3D,0
je pyr_handle_done
mov mouseClick3D,0
cmp mouseX3D,252
jb @F
cmp mouseY3D,17
jb pyr_selector_exit
@@:
cmp mouseX3D,40
jb pyr_handle_done
cmp mouseX3D,280
jae pyr_handle_done
cmp mouseY3D,80
jb pyr_handle_done
cmp mouseY3D,128
jb pyr_start_pyramid
cmp mouseY3D,144
jb pyr_handle_done
cmp mouseY3D,192
jae pyr_handle_done
pyr_start_eight:
invoke StartBilliards3D,1
ret
pyr_start_pyramid:
invoke StartBilliards3D,0
ret
pyr_selector_exit:
mov engineMode,MODE_WALK
call ClearKeys3D
ret
pyr_normal_input:
xor esi,esi
pyr_sink_tick:
mov eax,deltaTime3D
sub poolSinkTime3D[esi*4],eax
jnc @F
mov poolSinkTime3D[esi*4],0
@@:
inc esi
cmp esi,16
jb pyr_sink_tick
mov eax,deltaTime3D
add poolTime3D,eax
cmp mouseClick3D,0
je pyr_update
cmp mouseY3D,3
jb pyr_update
cmp mouseY3D,17
jae pyr_update
cmp mouseX3D,252
jb pyr_update
cmp mouseX3D,312
jae pyr_update
mov engineMode,MODE_WALK
call ClearKeys3D
call SaveProgress3D
ret
pyr_update:
mov eax,deltaTime3D
cmp poolState3D,POOL_MOVING
jne pyr_strike
add poolAccumulator3D,eax
pyr_fixed_tick:
cmp poolAccumulator3D,2
jb pyr_handle_done
sub poolAccumulator3D,2
call PoolStep3D
cmp poolStill3D,0
je pyr_fixed_tick
call PoolFinishShot3D
ret
pyr_strike:
cmp poolState3D,POOL_STRIKE
jne pyr_idle
cmp poolTime3D,240
jb pyr_handle_done
mov ebx,pyrCue3D
mov eax,pyrDirX3D
imul poolPower3D
shrd eax,edx,16
mov poolVX3D[ebx*4],eax
mov eax,pyrDirY3D
imul poolPower3D
shrd eax,edx,16
mov poolVY3D[ebx*4],eax
mov poolState3D,POOL_MOVING
mov poolAccumulator3D,0
ret
pyr_idle:
cmp poolState3D,POOL_RESULT
jne pyr_actor
invoke Pressed3D,20h
test eax,eax
jnz pyr_restart
cmp mouseClick3D,0
je pyr_handle_done
cmp mouseY3D,211
jb pyr_handle_done
cmp mouseX3D,202
jb pyr_handle_done
pyr_restart:
call ResetPool3D
ret
pyr_actor:
cmp poolState3D,POOL_HAND
jne @F
call EightHand3D
ret
@@:
cmp poolPlayer3D,1
je pyr_actor_ai_check
cmp obsActive3D,0
jne pyr_actor_ai_check
jmp pyr_human
pyr_actor_ai_check:
cmp poolAI3D,0
je pyr_human
cmp poolTime3D,1000
jb pyr_handle_done
cmp poolState3D,POOL_PENALTY
jne @F
xor esi,esi
pyr_ai_penalty:
cmp poolActive3D[esi*4],1
je pyr_ai_penalty_pick
inc esi
cmp esi,16
jb pyr_ai_penalty
ret
pyr_ai_penalty_pick:
invoke PyramidPenalty3D,esi
ret
@@:
cmp poolState3D,POOL_CHOICE
jne @F
invoke PyramidChoice3D,0
ret
@@:
call PoolChooseAI3D
call PoolShoot3D
ret
pyr_human:
cmp poolState3D,POOL_CHOICE
jne pyr_human_penalty
mov esi,0
pyr_choice_key:
lea eax,[esi+31h]
invoke Pressed3D,eax
test eax,eax
jnz pyr_choice_selected
inc esi
cmp esi,4
jb pyr_choice_key
invoke Pressed3D,0Dh
test eax,eax
jz @F
xor esi,esi
jmp pyr_choice_selected
@@:
cmp mouseClick3D,0
je pyr_handle_done
cmp mouseY3D,215
jb pyr_handle_done
cmp mouseY3D,237
jae pyr_handle_done
mov eax,mouseX3D
sub eax,8
js pyr_handle_done
xor edx,edx
mov ecx,78
div ecx
cmp edx,70
jae pyr_handle_done
mov esi,eax
pyr_choice_selected:
invoke PyramidChoice3D,esi
ret
pyr_human_penalty:
cmp poolState3D,POOL_PENALTY
jne pyr_human_aim
invoke Pressed3D,0Dh
test eax,eax
jnz pyr_penalty_skip
cmp mouseClick3D,0
je pyr_handle_done
cmp mouseY3D,215
jb @F
cmp mouseY3D,238
jae @F
cmp mouseX3D,202
jae pyr_penalty_skip
@@:
mov eax,mouseX3D
shl eax,16
mov ebx,mouseY3D
shl ebx,16
invoke PyramidPick3D,eax,ebx
cmp eax,-1
je pyr_handle_done
invoke PyramidPenalty3D,eax
ret
pyr_penalty_skip:
mov poolState3D,POOL_CHOICE
ret
pyr_human_aim:
cmp mouseClick3D,0
je pyr_keys
mov mouseClick3D,0
mov eax,mouseX3D
mov ebx,mouseY3D
cmp ebx,50
jb pyr_keys
cmp ebx,180
ja pyr_mouse_footer
shl eax,16
shl ebx,16
cmp pyrPickClick3D,0
je @F
mov pyrPickClick3D,0
cmp poolVariant3D,1
jne pyr_pick_object
xor esi,esi
eight_pick_pocket:
mov ecx,eax
sub ecx,poolPocketX3D[esi*4]
sar ecx,12
imul ecx,ecx
mov edx,ebx
sub edx,poolPocketY3D[esi*4]
sar edx,12
imul edx,edx
add ecx,edx
cmp ecx,81*16*16
jbe eight_pick_pocket_found
inc esi
cmp esi,6
jb eight_pick_pocket
pyr_pick_object:
invoke PyramidPick3D,eax,ebx
cmp eax,-1
je pyr_handle_done
cmp poolVariant3D,1
jne pyr_pick_pyramid
mov ebx,eax
call EightCount3D
invoke EightLegal3D,ebx
test eax,eax
jz pyr_handle_done
mov poolCalled3D,ebx
or poolCallManual3D,1
ret
pyr_pick_pyramid:
invoke PyramidSelect3D,eax
ret
eight_pick_pocket_found:
mov poolCalledPocket3D,esi
or poolCallManual3D,2
ret
@@:
cmp poolBreak3D,0
je pyr_mouse_aim
cmp keys3D[10h],0
je pyr_mouse_aim
cmp eax,95*FP_1
jge pyr_handle_done
invoke PoolPlaceCue3D,eax,ebx
ret
pyr_mouse_aim:
invoke PoolAimPoint3D,eax,ebx
ret
pyr_mouse_footer:
cmp poolVariant3D,1
jne @F
cmp ebx,187
jb @F
cmp ebx,209
ja @F
cmp eax,128
jb @F
cmp eax,194
ja @F
inc poolCalledPocket3D
or poolCallManual3D,2
cmp poolCalledPocket3D,6
jb pyr_handle_done
mov poolCalledPocket3D,0
ret
@@:
cmp ebx,193
jb pyr_keys
cmp ebx,209
ja pyr_mouse_command
cmp eax,202
jb pyr_keys
cmp eax,308
ja pyr_keys
sub eax,202
imul eax,82000
xor edx,edx
mov ecx,106
div ecx
add eax,8000
mov poolPower3D,eax
ret
pyr_mouse_command:
cmp ebx,211
jb pyr_keys
cmp ebx,238
jae pyr_keys
cmp eax,86
jb pyr_cycle_cue
cmp eax,196
jb pyr_toggle_guide
call PoolShoot3D
ret
pyr_keys:
mov eax,deltaTime3D
imul eax,120
cmp keys3D[10h],0
je @F
mov eax,deltaTime3D
imul eax,30
@@:
add eax,pyrAimCarry3D
xor edx,edx
mov ecx,1000
div ecx
mov pyrAimCarry3D,edx
mov ebx,eax
cmp pyrFineActive3D,0
jne @F
mov eax,poolAngle3D
shl eax,3
mov pyrFine3D,eax
@@:
cmp keys3D[25h],0
je @F
sub pyrFine3D,ebx
mov pyrFineActive3D,1
@@:
cmp keys3D[27h],0
je @F
add pyrFine3D,ebx
mov pyrFineActive3D,1
@@:
and pyrFine3D,4095
mov eax,deltaTime3D
imul eax,100
cmp keys3D[26h],0
je @F
add poolPower3D,eax
@@:
cmp keys3D[28h],0
je @F
sub poolPower3D,eax
@@:
cmp poolPower3D,8000
jge @F
mov poolPower3D,8000
@@:
cmp poolPower3D,90000
jle @F
mov poolPower3D,90000
@@:
invoke Pressed3D,42h
test eax,eax
jnz pyr_cycle_cue
invoke Pressed3D,50h
test eax,eax
jnz pyr_toggle_guide
invoke Pressed3D,20h
test eax,eax
jz pyr_handle_done
call PoolShoot3D
ret
pyr_toggle_guide:
xor pyrGuideOn3D,1
ret
pyr_cycle_cue:
cmp poolVariant3D,1
je eight_cycle_call
cmp poolBreak3D,0
jne pyr_handle_done
mov esi,pyrCue3D
mov edi,16
pyr_cycle_scan:
inc esi
and esi,15
cmp poolActive3D[esi*4],1
je pyr_cycle_found
dec edi
jnz pyr_cycle_scan
ret
pyr_cycle_found:
invoke PyramidSelect3D,esi
ret
eight_cycle_call:
call EightCount3D
mov esi,poolCalled3D
mov edi,16
eight_cycle_scan:
inc esi
and esi,15
cmp poolActive3D[esi*4],0
je eight_cycle_next
invoke EightLegal3D,esi
test eax,eax
jnz eight_cycle_found
eight_cycle_next:
dec edi
jnz eight_cycle_scan
ret
eight_cycle_found:
mov poolCalled3D,esi
or poolCallManual3D,1
pyr_handle_done:
ret
HandlePool3D ENDP