KAZIK/tools/tests/fortune_dialog_test.inc
Игорь Федосеев 5dedaf459f fix: restore fortune AI and add model setup
Restore native inference, card-bound readings and paged dialogue.

Provide manual, checksum-verified model setup instead of Git LFS so
source checkouts work without uploading multi-gigabyte weights. The
game stays offline; complete release archives still bundle the model.
2026-10-31 00:37:36 +03:00

530 lines
17 KiB
PHP

.data
fortuneSessionBank dd 0
fortuneSessionAnswer db "Situation: begin with one small step.",10
db "Obstacle: avoid rushing and check your assumptions.",10
db "Direction: choose a clear and steady pace.",10
db "Advice: reflect before acting, then take one practical step.",0
fortuneSessionAnswerEnd LABEL BYTE
fortuneSessionPlayer dd 0
fortuneFateSavedResult dd 0
fortuneFateSavedSeed dd 0
fortuneFateTestText db "Ivan",0,"Petrov",0,"29022000",0,"IS-42",0
fortuneFateFormShot db "build\hall-expansion\fortune-fate-form.bmp",0
fortuneFateResultShot db "build\hall-expansion\fortune-fate-result.bmp",0
fortuneFateHundredShot db "build\hall-expansion\fortune-fate-hundred.bmp",0
fortuneFateMotion db "build\hall-expansion\fortune-fate-motion-"
fortuneFateDigits db "00.bmp",0
fortuneFateTracking db "build\hall-expansion\fortune-fate-track-"
fortuneFateTrackingDigits db "00.bmp",0
fortuneFateTrackingBase db "build\hall-expansion\fortune-fate-base-"
fortuneFateTrackingBaseDigits db "00.bmp",0
fortuneSessionMotion db "build\hall-expansion\fortune-session-motion-"
fortuneSessionDigits db "00.bmp",0
fortuneSessionQuestion db 193,243,228,229,242,32,235,232,32,231,224,226,242,240,224,32,228,238,230,228,252,63,0
fortuneSessionShot0 db "build\hall-expansion\fortune-session-input.bmp",0
fortuneSessionShot1 db "build\hall-expansion\fortune-session-shuffle.bmp",0
fortuneSessionShot2 db "build\hall-expansion\fortune-session-deal-one.bmp",0
fortuneSessionShot3 db "build\hall-expansion\fortune-session-deal-two.bmp",0
fortuneSessionShot4 db "build\hall-expansion\fortune-session-deal-three.bmp",0
fortuneSessionShot5 db "build\hall-expansion\fortune-session-flip-one.bmp",0
fortuneSessionShot6 db "build\hall-expansion\fortune-session-explain-one.bmp",0
fortuneSessionShot7 db "build\hall-expansion\fortune-session-flip-two.bmp",0
fortuneSessionShot8 db "build\hall-expansion\fortune-session-explain-two.bmp",0
fortuneSessionShot9 db "build\hall-expansion\fortune-session-flip-three.bmp",0
fortuneSessionShot10 db "build\hall-expansion\fortune-session-explain-three.bmp",0
fortuneSessionShot11 db "build\hall-expansion\fortune-session-summary.bmp",0
fortuneSessionShot12 db "build\hall-expansion\fortune-session-done.bmp",0
fortuneSessionShot13 db "build\hall-expansion\fortune-session-orb-rise.bmp",0
fortuneSessionShot14 db "build\hall-expansion\fortune-session-orb-mist.bmp",0
fortuneSessionShot15 db "build\hall-expansion\fortune-session-orb-final.bmp",0
fortuneSessionShots dd OFFSET fortuneSessionShot0,OFFSET fortuneSessionShot1,OFFSET fortuneSessionShot2,OFFSET fortuneSessionShot3
dd OFFSET fortuneSessionShot4,OFFSET fortuneSessionShot5,OFFSET fortuneSessionShot6,OFFSET fortuneSessionShot7
dd OFFSET fortuneSessionShot8,OFFSET fortuneSessionShot9,OFFSET fortuneSessionShot10,OFFSET fortuneSessionShot11
dd OFFSET fortuneSessionShot12
.code
FortuneSessionStepTest PROC
add animationClock3D,100
call UpdateFortuneSession3D
ret
FortuneSessionStepTest ENDP
FortuneDialogNativeTests PROC uses ebx esi edi
mov expansionStage,80
mov eax,bankroll
mov fortuneSessionBank,eax
mov eax,playerX
mov fortuneSessionPlayer,eax
call BeginFortuneDialog3D
cmp fortuneSessionShuffle3D.frames,64
jne fortune_session_fail
cmp fortuneSessionDeal3D.frames,32
jne fortune_session_fail
cmp fortuneSessionCards3D.frames,45
jne fortune_session_fail
cmp fortuneSessionNumerals3D.frames,10
jne fortune_session_fail
cmp fortuneProcess3D,0
jne fortune_session_fail
cmp fortuneRead3D,0
jne fortune_session_fail
invoke WindowEvents3D,0,102h,'1',0
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_session_fail
; Lower edge of the question box is not an Exit-button hit target.
mov mouseX3D,260
mov mouseY3D,222
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp engineMode,MODE_FORTUNE
jne fortune_session_fail
call SubmitFortuneQuestion3D
cmp fortunePhase3D,0
jne fortune_session_fail
mov esi,250
fortune_session_input_limit:
invoke WindowEvents3D,0,102h,'a',0
dec esi
jnz fortune_session_input_limit
cmp fortuneQuestionLength3D,240
jne fortune_session_fail
cmp fortuneQuestion3D[240],0
jne fortune_session_fail
invoke WindowEvents3D,0,102h,8,0
cmp fortuneQuestionLength3D,239
jne fortune_session_fail
mov fortuneQuestionLength3D,0
mov fortuneQuestion3D,0
mov esi,OFFSET fortuneSessionQuestion
fortune_session_input:
movzx eax,BYTE PTR [esi]
test eax,eax
jz fortune_session_input_done
invoke WindowEvents3D,0,102h,eax,0
inc esi
jmp fortune_session_input
fortune_session_input_done:
mov fortuneSpeechTime3D,3000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionShot0
call SubmitFortuneQuestion3D
cmp fortunePhase3D,1
jne fortune_session_fail
; Scene/render checks use a controlled answer, not CPU/model timing.
call CloseFortuneInference3D
lea esi,fortuneSessionAnswer
lea edi,fortuneAnswer3D
mov ecx,fortuneSessionAnswerEnd-fortuneSessionAnswer
rep movsb
mov fortuneAnswerLength3D,fortuneSessionAnswerEnd-fortuneSessionAnswer-1
call ParseFortuneAnswer3D
test eax,eax
jz fortune_session_fail
mov fortuneWorkerState3D,5
cmp fortuneDealt3D,0
jne fortune_session_fail
invoke WindowEvents3D,0,102h,'X',0
cmp fortuneQuestionLength3D,22
jne fortune_session_fail
call SubmitFortuneQuestion3D
cmp fortunePhase3D,1
jne fortune_session_fail
mov fortunePhaseTime3D,700
mov fortuneSpeechTime3D,1000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionShot1
cmp fortunePhaseTime3D,700
jne fortune_session_fail
xor edi,edi
fortune_session_motion:
mov eax,edi
xor edx,edx
mov ecx,10
div ecx
add al,'0'
add dl,'0'
mov fortuneSessionDigits[0],al
mov fortuneSessionDigits[1],dl
mov eax,edi
imul eax,25
mov fortunePhaseTime3D,eax
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionMotion
inc edi
cmp edi,64
jb fortune_session_motion
mov ebx,1
fortune_session_phases:
mov fortuneReadingShown3D,2
mov eax,fortuneDurations3D[ebx*4]
mov fortunePhaseTime3D,eax
call FortuneSessionStepTest
inc ebx
cmp fortunePhase3D,ebx
jne fortune_session_fail
cmp ebx,6
je fortune_session_reading
cmp ebx,8
je fortune_session_reading
cmp ebx,10
je fortune_session_reading
cmp ebx,11
jne fortune_session_render
fortune_session_reading:
call FortuneSessionStepTest
cmp fortuneReadingShown3D,1
jne fortune_session_fail
fortune_session_render:
mov fortunePhaseTime3D,600
mov fortuneSpeechTime3D,20000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,fortuneSessionShots[ebx*4]
cmp ebx,12
jb fortune_session_phases
cmp fortuneDealt3D,3
jne fortune_session_fail
cmp fortuneRevealed3D,3
jne fortune_session_fail
cmp fortuneQuestionLength3D,22
jne fortune_session_fail
mov eax,fortuneSpeechLength3D
cmp fortuneSpeechVisible3D,eax
jne fortune_session_fail
; Distinct underlying cards even when orientation differs.
xor esi,esi
fortune_session_unique_outer:
mov eax,fortuneDrawCards3D[esi*4]
xor edx,edx
mov ecx,22
div ecx
mov edi,edx
lea ebx,[esi+1]
fortune_session_unique_inner:
cmp ebx,3
jae fortune_session_unique_next
mov eax,fortuneDrawCards3D[ebx*4]
xor edx,edx
div ecx
cmp edx,edi
je fortune_session_fail
inc ebx
jmp fortune_session_unique_inner
fortune_session_unique_next:
inc esi
cmp esi,2
jb fortune_session_unique_outer
mov expansionStage,81
; Bubble grows as glyphs appear and cannot exceed the scene edge.
invoke SetFortuneSpeech3D,OFFSET fortuneSummary3D
mov fortuneSpeechTime3D,280
call RenderFortuneDialog3D
mov esi,fortuneSpeechWidth3D
mov fortuneSpeechTime3D,3000
call RenderFortuneDialog3D
cmp fortuneSpeechWidth3D,esi
jbe fortune_session_fail
cmp fortuneSpeechWidth3D,204
ja fortune_session_fail
cmp fortuneSpeechHeight3D,140
ja fortune_session_fail
; The fictional crystal-ball lottery requires a form, not a neural worker.
mov mouseX3D,200
mov mouseY3D,232
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp fortuneSubMode3D,0
jne fortune_session_fail
invoke WindowEvents3D,0,102h,'2',0
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne fortune_session_fail
cmp fortunePhase3D,0
jne fortune_session_fail
call SubmitFortuneFate3D
cmp fortunePhase3D,0
jne fortune_session_fail
cmp fortuneFateField3D,0
jne fortune_session_fail
; CP1251, control filtering and maximum field widths use the real input path.
mov ebx,40
fortune_fate_name_limit:
invoke WindowEvents3D,0,102h,200,0
dec ebx
jnz fortune_fate_name_limit
cmp fortuneFateLengths3D,30
jne fortune_session_fail
cmp fortuneFateFields3D[30],0
jne fortune_session_fail
invoke FortuneChar3D,127
cmp fortuneFateLengths3D,30
jne fortune_session_fail
call ResetFortuneFate3D
mov esi,OFFSET fortuneFateTestText
xor ebx,ebx
fortune_fate_input_fields:
movzx eax,BYTE PTR [esi]
inc esi
test eax,eax
jz fortune_fate_input_next
invoke WindowEvents3D,0,102h,eax,0
jmp fortune_fate_input_fields
fortune_fate_input_next:
invoke WindowEvents3D,0,102h,9,0
inc ebx
cmp ebx,4
jb fortune_fate_input_fields
cmp fortuneFateLengths3D[8],10
jne fortune_session_fail
call ValidateFortuneBirth3D
cmp eax,1
jne fortune_session_fail
mov fortuneFateFields3D[137],'1'
call ValidateFortuneBirth3D
test eax,eax
jnz fortune_session_fail
call SubmitFortuneFate3D
cmp fortuneFateField3D,2
jne fortune_session_fail
cmp fortunePhase3D,0
jne fortune_session_fail
mov fortuneFateFields3D[137],'0'
mov fortuneFateField3D,4
invoke FortuneChar3D,'x'
cmp fortuneFateLengths3D[16],1
jne fortune_session_fail
; A value larger than 100 is rejected, not clamped or used as an outcome.
mov fortuneFateFields3D[320],'1'
mov fortuneFateFields3D[321],'0'
mov fortuneFateFields3D[322],'1'
mov fortuneFateLengths3D[20],3
call SubmitFortuneFate3D
cmp fortunePhase3D,0
jne fortune_session_fail
mov fortuneFateFields3D[320],'8'
mov fortuneFateFields3D[321],0
mov fortuneFateFields3D[322],0
mov fortuneFateLengths3D[20],1
call SubmitFortuneFate3D
cmp fortunePhase3D,0
jne fortune_session_fail
cmp fortuneFateField3D,5
jne fortune_session_fail
mov fortuneFateFields3D[320],'1'
mov fortuneFateFields3D[321],'0'
mov fortuneFateLengths3D[20],2
invoke SetFortuneSpeech3D,OFFSET fortuneFateReady3D
mov fortuneSpeechTime3D,3000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneFateFormShot
; Mouse focus and backspace obey per-field limits and reject control bytes.
mov mouseX3D,200
mov mouseY3D,168
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp fortuneFateField3D,1
jne fortune_session_fail
invoke FortuneChar3D,8
cmp fortuneFateLengths3D[4],5
jne fortune_session_fail
invoke FortuneChar3D,'v'
invoke WindowEvents3D,0,100h,0Dh,0
invoke WindowEvents3D,0,102h,0Dh,0
call HandleFortuneDialog3D
invoke WindowEvents3D,0,101h,0Dh,0
cmp fortunePhase3D,1
jne fortune_session_fail
mov eax,fortuneFateResult3D
cmp eax,9
jb fortune_session_fail
cmp eax,10
ja fortune_session_fail
mov fortuneFateSavedResult,eax
mov eax,rngSeed3D
mov fortuneFateSavedSeed,eax
call SubmitFortuneFate3D
invoke FortuneChar3D,'X'
cmp fortuneFateLengths3D[4],6
jne fortune_session_fail
mov eax,fortuneFateSavedResult
cmp fortuneFateResult3D,eax
jne fortune_session_fail
mov eax,rngSeed3D
cmp eax,fortuneFateSavedSeed
jne fortune_session_fail
; Again cannot bypass the ritual or reroll while hands are moving.
mov mouseX3D,120
mov mouseY3D,232
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp fortunePhase3D,1
jne fortune_session_fail
mov fortunePhaseTime3D,700
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionShot13
mov fortunePhaseTime3D,1400
call FortuneSessionStepTest
cmp fortunePhase3D,2
jne fortune_session_fail
mov fortunePhaseTime3D,1500
mov fortuneSpeechTime3D,3000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionShot14
xor edi,edi
fortune_fate_motion:
mov eax,edi
xor edx,edx
mov ecx,10
div ecx
add al,'0'
add dl,'0'
mov fortuneFateDigits[0],al
mov fortuneFateDigits[1],dl
mov eax,edi
imul eax,32
mov fortunePhaseTime3D,eax
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneFateMotion
mov eax,fortuneFateSavedResult
cmp fortuneFateResult3D,eax
jne fortune_session_fail
inc edi
cmp edi,32
jb fortune_fate_motion
mov fortunePhaseTime3D,5000
call FortuneSessionStepTest
cmp fortunePhase3D,3
jne fortune_session_fail
mov fortuneSpeechTime3D,3000
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneSessionShot15
mov fortunePhaseTime3D,1200
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneFateResultShot
xor edi,edi
fortune_fate_tracking_frames:
mov eax,edi
xor edx,edx
mov ecx,10
div ecx
add al,'0'
add dl,'0'
mov fortuneFateTrackingDigits[0],al
mov fortuneFateTrackingDigits[1],dl
mov fortuneFateTrackingBaseDigits[0],al
mov fortuneFateTrackingBaseDigits[1],dl
mov eax,edi
shl eax,6
add eax,2048
mov fortunePhaseTime3D,eax
call RenderFortuneDialog3D
cmp fortuneOrbFrame3D,edi
jne fortune_session_fail
mov eax,fortuneOrbAnchorX3D[edi*4]
add eax,128
shr eax,8
add eax,214
cmp fortuneOrbCenterX3D,eax
jne fortune_session_fail
mov eax,fortuneOrbAnchorY3D[edi*4]
add eax,128
shr eax,8
add eax,195
cmp fortuneOrbCenterY3D,eax
jne fortune_session_fail
cmp animOpacity3D,255
jne fortune_session_fail
invoke ExpansionSnapshot,OFFSET fortuneFateTracking
mov fortuneFateResult3D,-1
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneFateTrackingBase
mov eax,fortuneFateSavedResult
mov fortuneFateResult3D,eax
inc edi
cmp edi,16
jb fortune_fate_tracking_frames
mov mouseX3D,120
mov mouseY3D,232
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp fortunePhase3D,0
jne fortune_session_fail
cmp fortuneFateResult3D,-1
jne fortune_session_fail
cmp fortuneFateLengths3D[4],6
jne fortune_session_fail
; Test the full inclusive range, zero, fixed outcomes and both endpoints.
mov ebx,400
fortune_fate_range_samples:
mov fortunePhase3D,0
mov fortuneFateFields3D[256],'0'
mov fortuneFateLengths3D[16],1
mov fortuneFateFields3D[320],'1'
mov fortuneFateFields3D[321],'0'
mov fortuneFateFields3D[322],'0'
mov fortuneFateFields3D[323],0
mov fortuneFateLengths3D[20],3
call SubmitFortuneFate3D
cmp fortuneFateResult3D,100
ja fortune_session_fail
dec ebx
jnz fortune_fate_range_samples
; Endpoints are checked separately without relying on a random sample.
mov fortunePhase3D,0
mov fortuneFateFields3D[256],'0'
mov fortuneFateFields3D[320],'0'
mov fortuneFateFields3D[321],0
mov fortuneFateLengths3D[20],1
call SubmitFortuneFate3D
cmp fortuneFateResult3D,0
jne fortune_session_fail
mov fortunePhase3D,0
mov fortuneFateFields3D[256],'1'
mov fortuneFateFields3D[257],'0'
mov fortuneFateFields3D[258],'0'
mov fortuneFateLengths3D[16],3
mov fortuneFateFields3D[320],'1'
mov fortuneFateFields3D[321],'0'
mov fortuneFateFields3D[322],'0'
mov fortuneFateLengths3D[20],3
call SubmitFortuneFate3D
cmp fortuneFateResult3D,100
jne fortune_session_fail
mov fortunePhase3D,3
mov fortunePhaseTime3D,1200
call RenderFortuneDialog3D
invoke ExpansionSnapshot,OFFSET fortuneFateHundredShot
; Exit in the middle of an animation as well as after completion.
mov mouseX3D,260
mov mouseY3D,232
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp engineMode,MODE_WALK
jne fortune_session_fail
cmp fortuneSessionRoom3D.pixels,0
jne fortune_session_fail
cmp fortuneSessionNumerals3D.pixels,0
jne fortune_session_fail
cmp fortuneFateLengths3D,0
jne fortune_session_fail
cmp fortuneFateFields3D,0
jne fortune_session_fail
call BeginFortuneDialog3D
invoke FortuneChar3D,'1'
invoke FortuneChar3D,'a'
call SubmitFortuneQuestion3D
mov mouseX3D,260
mov mouseY3D,232
mov mouseClick3D,1
call HandleFortuneDialog3D
cmp engineMode,MODE_WALK
jne fortune_session_fail
cmp fortuneSessionShuffle3D.pixels,0
jne fortune_session_fail
mov eax,bankroll
cmp eax,fortuneSessionBank
jne fortune_session_fail
mov eax,playerX
cmp eax,fortuneSessionPlayer
jne fortune_session_fail
ret
fortune_session_fail:
invoke ExitProcess,expansionStage
ret
FortuneDialogNativeTests ENDP