KAZIK/src_graphics/fortune_ai.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

399 lines
11 KiB
PHP

; Anonymous pipes only. Polling never waits for model inference or partial frames.
CloseFortuneInference3D PROC uses esi
cmp fortuneProcess3D,0
je @F
invoke TerminateProcess,fortuneProcess3D,0
invoke CloseHandle,fortuneProcess3D
@@:
mov fortuneProcess3D,0
cmp fortuneProcess3D[4],0
je @F
invoke CloseHandle,fortuneProcess3D[4]
@@:
mov fortuneProcess3D[4],0
mov fortuneProcess3D[8],0
mov fortuneProcess3D[12],0
cmp fortuneRead3D,0
je @F
invoke CloseHandle,fortuneRead3D
@@:
mov fortuneRead3D,0
cmp fortuneWrite3D,0
je @F
invoke CloseHandle,fortuneWrite3D
@@:
mov fortuneWrite3D,0
lea esi,fortuneChildRead3D
mov ecx,3
fortune_ai_close_child:
push ecx
cmp DWORD PTR [esi],0
je @F
invoke CloseHandle,DWORD PTR [esi]
@@:
mov DWORD PTR [esi],0
add esi,4
pop ecx
loop fortune_ai_close_child
mov fortuneReceiveLength3D,-1
mov fortunePending3D,0
mov fortuneWorkerState3D,0
mov fortuneReadingShown3D,0
mov fortuneReadingOffset3D,0
mov fortuneReadingNext3D,0
mov fortuneAnswerLength3D,0
mov fortuneAnswer3D,0
mov fortuneSections3D,0
mov fortuneSections3D[4],0
mov fortuneSections3D[8],0
mov fortuneSections3D[12],0
ret
CloseFortuneInference3D ENDP
FailFortuneInference3D PROC
call CloseFortuneInference3D
mov fortuneWorkerState3D,4
mov fortuneErrorText3D,OFFSET fortuneAiError3D
mov fortuneAnswerLength3D,0
mov fortuneAnswer3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneAiError3D
ret
FailFortuneInference3D ENDP
StartFortuneWorker3D PROC uses edi
call CloseFortuneInference3D
mov fortuneAnswerLength3D,0
mov fortuneAnswer3D,0
mov fortuneReadingShown3D,0
; Fail immediately and visibly when a source checkout lacks bundled weights.
invoke CreateFileA,OFFSET fortuneModelPath3D,80000000h,1,0,3,80h,0
cmp eax,-1
jne @F
mov fortuneWorkerState3D,4
mov fortuneErrorText3D,OFFSET fortuneAiMissing3D
invoke SetFortuneSpeech3D,OFFSET fortuneAiMissing3D
ret
@@:
invoke CloseHandle,eax
invoke CreatePipe,OFFSET fortuneChildRead3D,OFFSET fortuneWrite3D,OFFSET fortunePipeSecurity3D,16384
test eax,eax
jz fortune_ai_start_fail
invoke SetHandleInformation,fortuneWrite3D,1,0
test eax,eax
jz fortune_ai_start_fail
invoke CreatePipe,OFFSET fortuneRead3D,OFFSET fortuneChildWrite3D,OFFSET fortunePipeSecurity3D,16384
test eax,eax
jz fortune_ai_start_fail
invoke SetHandleInformation,fortuneRead3D,1,0
test eax,eax
jz fortune_ai_start_fail
invoke CreateFileA,OFFSET fortuneNullName3D,40000000h,3,OFFSET fortunePipeSecurity3D,3,80h,0
cmp eax,-1
je fortune_ai_start_fail
mov fortuneNull3D,eax
lea edi,fortuneStartup3D
xor eax,eax
mov ecx,17
rep stosd
mov fortuneStartup3D,68
mov fortuneStartup3D[44],100h
mov eax,fortuneChildRead3D
mov fortuneStartup3D[56],eax
mov eax,fortuneChildWrite3D
mov fortuneStartup3D[60],eax
mov eax,fortuneNull3D
mov fortuneStartup3D[64],eax
invoke CreateProcessA,OFFSET fortuneWorkerPath3D,OFFSET fortuneWorkerCommand3D,0,0,1,08000000h,0,0,OFFSET fortuneStartup3D,OFFSET fortuneProcess3D
test eax,eax
jz fortune_ai_start_fail
invoke CloseHandle,fortuneProcess3D[4]
mov fortuneProcess3D[4],0
invoke CloseHandle,fortuneChildRead3D
mov fortuneChildRead3D,0
invoke CloseHandle,fortuneChildWrite3D
mov fortuneChildWrite3D,0
invoke CloseHandle,fortuneNull3D
mov fortuneNull3D,0
mov fortuneWorkerState3D,1
mov fortunePending3D,1
invoke GetTickCount
mov fortuneWorkerTick3D,eax
ret
fortune_ai_start_fail:
call FailFortuneInference3D
ret
StartFortuneWorker3D ENDP
SendFortuneRequest3D PROC uses esi
mov fortuneRequest3D,31514346h
mov eax,fortuneQuestionLength3D
mov fortuneRequest3D[4],eax
xor esi,esi
fortune_ai_request_cards:
mov eax,fortuneDrawCards3D[esi*4]
mov fortuneRequest3D[esi*4+8],eax
inc esi
cmp esi,3
jb fortune_ai_request_cards
invoke WriteFile,fortuneWrite3D,OFFSET fortuneRequest3D,20,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_ai_send_fail
cmp fortuneIo3D,20
jne fortune_ai_send_fail
invoke WriteFile,fortuneWrite3D,OFFSET fortuneQuestion3D,fortuneQuestionLength3D,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_ai_send_fail
mov eax,fortuneQuestionLength3D
cmp fortuneIo3D,eax
jne fortune_ai_send_fail
mov fortuneWorkerState3D,3
mov fortunePending3D,0
invoke GetTickCount
mov fortuneWorkerTick3D,eax
ret
fortune_ai_send_fail:
call FailFortuneInference3D
ret
SendFortuneRequest3D ENDP
PollFortuneWorker3D PROC
cmp fortuneWorkerState3D,1
je fortune_ai_poll
cmp fortuneWorkerState3D,3
jne fortune_ai_poll_done
fortune_ai_poll:
invoke PeekNamedPipe,fortuneRead3D,0,0,0,OFFSET fortuneAvailable3D,0
test eax,eax
jz fortune_ai_poll_fail
cmp fortuneReceiveLength3D,-1
jne fortune_ai_poll_body
cmp fortuneAvailable3D,12
jb fortune_ai_poll_timeout
invoke ReadFile,fortuneRead3D,OFFSET fortuneReceiveHeader3D,12,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_ai_poll_fail
cmp fortuneIo3D,12
jne fortune_ai_poll_fail
cmp fortuneReceiveHeader3D,31524346h
jne fortune_ai_poll_fail
mov eax,fortuneReceiveHeader3D[8]
cmp eax,8192
ja fortune_ai_poll_fail
mov fortuneReceiveLength3D,eax
sub fortuneAvailable3D,12
fortune_ai_poll_body:
mov eax,fortuneReceiveLength3D
cmp fortuneAvailable3D,eax
jb fortune_ai_poll_timeout
test eax,eax
jz fortune_ai_poll_status
invoke ReadFile,fortuneRead3D,OFFSET fortuneAnswer3D,eax,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_ai_poll_fail
mov eax,fortuneReceiveLength3D
cmp fortuneIo3D,eax
jne fortune_ai_poll_fail
fortune_ai_poll_status:
mov eax,fortuneReceiveLength3D
mov fortuneAnswer3D[eax],0
mov fortuneAnswerLength3D,eax
mov fortuneReceiveLength3D,-1
cmp fortuneWorkerState3D,1
jne fortune_ai_poll_answer
cmp fortuneReceiveHeader3D[4],0
jne fortune_ai_poll_fail
test eax,eax
jnz fortune_ai_poll_fail
cmp fortunePending3D,1
jne fortune_ai_poll_fail
call SendFortuneRequest3D
ret
fortune_ai_poll_answer:
; Truncated output is an error, never a successful complete reading.
cmp fortuneReceiveHeader3D[4],1
jne fortune_ai_poll_fail
call ParseFortuneAnswer3D
test eax,eax
jz fortune_ai_poll_fail
mov fortuneWorkerState3D,5
ret
fortune_ai_poll_timeout:
invoke GetTickCount
sub eax,fortuneWorkerTick3D
cmp eax,180000
jae fortune_ai_poll_fail
ret
fortune_ai_poll_fail:
call FailFortuneInference3D
fortune_ai_poll_done:
ret
PollFortuneWorker3D ENDP
; Four bounded, nonempty lines: one interpretation per card, then synthesis.
ParseFortuneAnswer3D PROC uses ebx esi edi
mov eax,fortuneAnswerLength3D
test eax,eax
jz fortune_ai_parse_fail
cmp eax,8192
ja fortune_ai_parse_fail
mov fortuneAnswer3D[eax],0
lea esi,fortuneAnswer3D
lea edi,fortuneSections3D
mov [edi],esi
mov ebx,1
xor ecx,ecx
fortune_ai_parse_byte:
cmp ecx,fortuneAnswerLength3D
jae fortune_ai_parse_end
mov al,[esi+ecx]
test al,al
jz fortune_ai_parse_fail
cmp al,10
jne fortune_ai_parse_next
cmp ebx,4
jae fortune_ai_parse_fail
test ecx,ecx
jz fortune_ai_parse_fail
cmp BYTE PTR [esi+ecx-1],0
je fortune_ai_parse_fail
mov BYTE PTR [esi+ecx],0
lea eax,[esi+ecx+1]
mov [edi+ebx*4],eax
inc ebx
fortune_ai_parse_next:
inc ecx
jmp fortune_ai_parse_byte
fortune_ai_parse_end:
cmp ebx,4
jne fortune_ai_parse_fail
mov eax,[edi+12]
cmp BYTE PTR [eax],0
je fortune_ai_parse_fail
mov eax,1
ret
fortune_ai_parse_fail:
xor eax,eax
ret
ParseFortuneAnswer3D ENDP
; Pages stay inside the existing 23-column, ten-row speech bubble.
ShowFortuneReading3D PROC uses ebx esi edi section:DWORD
local column:DWORD,row:DWORD,wordLength:DWORD
mov eax,section
cmp eax,3
ja fortune_ai_show_done
mov fortuneSection3D,eax
mov esi,fortuneSections3D[eax*4]
test esi,esi
jz fortune_ai_show_done
add esi,fortuneReadingOffset3D
lea edi,fortuneSpeech3D
xor ecx,ecx
mov column,0
mov row,0
fortune_ai_page_word:
mov al,[esi]
test al,al
jz fortune_ai_page_end
cmp al,32
jne fortune_ai_word_measure
inc esi
jmp fortune_ai_page_word
fortune_ai_word_measure:
xor ebx,ebx
fortune_ai_word_scan:
mov al,[esi+ebx]
test al,al
jz fortune_ai_word_measured
cmp al,32
je fortune_ai_word_measured
inc ebx
jmp fortune_ai_word_scan
fortune_ai_word_measured:
mov wordLength,ebx
cmp column,23
jne @F
cmp row,8
jae fortune_ai_page_split
inc row
mov column,0
@@:
cmp column,0
je fortune_ai_word_copy
mov eax,column
add eax,ebx
inc eax
cmp eax,23
jbe fortune_ai_word_space
cmp row,8
jae fortune_ai_page_split
mov BYTE PTR [edi+ecx],10
inc ecx
inc row
mov column,0
jmp fortune_ai_word_copy
fortune_ai_word_space:
mov BYTE PTR [edi+ecx],32
inc ecx
inc column
fortune_ai_word_copy:
cmp wordLength,0
je fortune_ai_page_word
cmp column,23
jb fortune_ai_word_character
; The renderer already wraps a full 23-column line. No extra newline.
cmp row,8
jae fortune_ai_page_split
inc row
mov column,0
fortune_ai_word_character:
mov al,[esi]
mov [edi+ecx],al
inc esi
inc ecx
inc column
dec wordLength
jmp fortune_ai_word_copy
fortune_ai_page_split:
mov eax,section
mov eax,fortuneSections3D[eax*4]
neg eax
add eax,esi
mov fortuneReadingNext3D,eax
jmp fortune_ai_page_ready
fortune_ai_page_end:
mov fortuneReadingNext3D,0
fortune_ai_page_ready:
mov BYTE PTR [edi+ecx],0
mov fortuneSpeechLength3D,ecx
mov fortuneSpeechTime3D,0
mov fortuneSpeechVisible3D,0
mov fortunePhaseTime3D,0
mov fortuneReadingShown3D,1
fortune_ai_show_done:
ret
ShowFortuneReading3D ENDP
ShowFortuneStatus3D PROC
cmp fortuneWorkerState3D,4
jne fortune_ai_status_wait
invoke SetFortuneSpeech3D,fortuneErrorText3D
ret
fortune_ai_status_wait:
invoke SetFortuneSpeech3D,OFFSET fortuneAiThinking3D
ret
ShowFortuneStatus3D ENDP
AdvanceFortuneReading3D PROC
cmp fortuneReadingNext3D,0
je fortune_ai_advance_phase
mov eax,fortuneReadingNext3D
mov fortuneReadingOffset3D,eax
invoke ShowFortuneReading3D,fortuneSection3D
ret
fortune_ai_advance_phase:
mov fortuneReadingShown3D,2
mov fortuneReadingOffset3D,0
mov fortunePhaseTime3D,7FFFFFFFh
ret
AdvanceFortuneReading3D ENDP