KAZIK/src_graphics/fortune_mind.inc
Artvasil09 ce06659ab2 feat: implement offline neural fortune teller and native tarot divination
- Offline neural worker based on llama.cpp (fortune-engine.exe) with local Qwen3-4B model support

- Native assembly Tarot 3-card spread divination and teacher grade divination mode

- Text input dialog in MODE_FORTUNE communicating over anonymous pipes

- Clean process lifecycle management, WM_CHAR dispatch and fallback handling

- Test suites and packaging tools for offline release
2026-10-21 13:53:06 +03:00

612 lines
16 KiB
PHP

; ==============================================================================
; FORTUNE MIND CODE - MASM32 / CP1251
; Algorithmic Oracle Logic, String Assembly & Student Grade Decision Engine
; ==============================================================================
.code
; StrLen: Returns string length in EAX
FortuneStrLen PROC uses esi strPtr:DWORD
mov esi, strPtr
xor eax, eax
test esi, esi
jz @F
fortune_strlen_loop:
cmp BYTE PTR [esi+eax], 0
je @F
inc eax
jmp fortune_strlen_loop
@@:
ret
FortuneStrLen ENDP
; StrCat: Appends src to dst, returns new end pointer in EAX
FortuneStrCat PROC uses esi edi dst:DWORD, src:DWORD
mov edi, dst
test edi, edi
jz fortune_strcat_done
xor eax, eax
mov ecx, -1
repne scasb
dec edi
mov esi, src
test esi, esi
jz fortune_strcat_ret
fortune_strcat_copy:
lodsb
stosb
test al, al
jnz fortune_strcat_copy
dec edi
fortune_strcat_ret:
mov eax, edi
fortune_strcat_done:
ret
FortuneStrCat ENDP
; SubStrI3D: Case-insensitive substring search for CP1251
SubStrI3D PROC uses ebx esi edi hHaystack:DWORD, hNeedle:DWORD
mov esi, hHaystack
mov edi, hNeedle
test esi, esi
jz substr_fail
test edi, edi
jz substr_fail
substr_outer:
mov al, [esi]
test al, al
jz substr_fail
push esi
push edi
substr_inner:
mov al, [esi]
mov bl, [edi]
test bl, bl
jz substr_found
test al, al
jz substr_next_outer
; Lowercase compare
cmp al, "A"
jb @F
cmp al, "Z"
ja @F
add al, 32
@@:
cmp al, 192 ; CP1251 À..ß
jb @F
cmp al, 223
ja @F
add al, 32
@@:
cmp bl, "A"
jb @F
cmp bl, "Z"
ja @F
add bl, 32
@@:
cmp bl, 192
jb @F
cmp bl, 223
ja @F
add bl, 32
@@:
cmp al, bl
jne substr_next_outer
inc esi
inc edi
jmp substr_inner
substr_next_outer:
pop edi
pop esi
inc esi
jmp substr_outer
substr_found:
pop edi
pop esi
mov eax, 1
ret
substr_fail:
xor eax, eax
ret
SubStrI3D ENDP
; InitFortuneMindState3D: Clears buffers and sets up defaults
InitFortuneMindState3D PROC uses esi edi
mov fortuneSubMode3D, FORTUNE_SUBMODE_MENU
mov fortuneCardsDrawn3D, 0
mov studentDone3D, 0
mov studentField3D, 0
mov studentChoice3D, 0
; Setup default student name if empty
cmp studentName3D[0], 0
jne @F
lea edi, studentName3D
lea esi, strDefaultStudentName
fortune_copy_def_name:
lodsb
stosb
test al, al
jnz fortune_copy_def_name
invoke FortuneStrLen, OFFSET studentName3D
mov studentNameLen3D, eax
@@:
cmp studentYear3D[0], 0
jne @F
lea edi, studentYear3D
lea esi, strDefaultStudentYear
fortune_copy_def_year:
lodsb
stosb
test al, al
jnz fortune_copy_def_year
invoke FortuneStrLen, OFFSET studentYear3D
mov studentYearLen3D, eax
@@:
ret
InitFortuneMindState3D ENDP
; DetectTopic3D: Scans question for keywords
; Returns: 0=General, 1=Casino, 2=Love, 3=Study, 4=Future
DetectTopic3D PROC uses ebx esi edi qStr:DWORD
mov esi, qStr
test esi, esi
jz topic_general
; Simple substring check for Russian CP1251 keywords
; Check Casino: "ïîêåð", "äåíüã", "áàíê", "ñòàâê", "êàçèíî"
invoke SubStrI3D, esi, OFFSET kwPoker
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwMoney
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwBank
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwBet
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwCasino
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwWin
test eax, eax
jnz topic_casino
invoke SubStrI3D, esi, OFFSET kwRoulette
test eax, eax
jnz topic_casino
; Check Love: "ëþáîâ", "äåâóøê", "ïàðåí", "÷óâñòâ", "îòíîøåí"
invoke SubStrI3D, esi, OFFSET kwLove
test eax, eax
jnz topic_love
invoke SubStrI3D, esi, OFFSET kwGirl
test eax, eax
jnz topic_love
invoke SubStrI3D, esi, OFFSET kwBoy
test eax, eax
jnz topic_love
invoke SubStrI3D, esi, OFFSET kwRel
test eax, eax
jnz topic_love
; Check Study: "ó÷åá", "ýêçàìåí", "ñåññè", "áàëë", "îöåíê", "ëàá"
invoke SubStrI3D, esi, OFFSET kwStudy
test eax, eax
jnz topic_study
invoke SubStrI3D, esi, OFFSET kwExam
test eax, eax
jnz topic_study
invoke SubStrI3D, esi, OFFSET kwSession
test eax, eax
jnz topic_study
invoke SubStrI3D, esi, OFFSET kwScore
test eax, eax
jnz topic_study
invoke SubStrI3D, esi, OFFSET kwGrade
test eax, eax
jnz topic_study
; Check Future: "áóäóù", "ñóäüá", "âûáîð", "ñòîèò ëè", "÷òî æäåò"
invoke SubStrI3D, esi, OFFSET kwFuture
test eax, eax
jnz topic_future
invoke SubStrI3D, esi, OFFSET kwFate
test eax, eax
jnz topic_future
invoke SubStrI3D, esi, OFFSET kwChoice
test eax, eax
jnz topic_future
topic_general:
xor eax, eax
ret
topic_casino:
mov eax, 1
ret
topic_love:
mov eax, 2
ret
topic_study:
mov eax, 3
ret
topic_future:
mov eax, 4
ret
DetectTopic3D ENDP
; GenerateTarotReadingMind3D: Builds full 3-card reading in fortuneAnswer3D
GenerateTarotReadingMind3D PROC uses ebx esi edi
local c1:DWORD, c2:DWORD, c3:DWORD
local r1:DWORD, r2:DWORD, r3:DWORD
local topic:DWORD
mov eax, fortuneDrawCards3D[0]
xor edx, edx
mov ecx, 22
div ecx
mov c1, edx
cmp fortuneDrawCards3D[0], 22
setae al
movzx eax, al
mov r1, eax ; 1 if reversed, 0 if upright
mov eax, fortuneDrawCards3D[4]
xor edx, edx
mov ecx, 22
div ecx
mov c2, edx
cmp fortuneDrawCards3D[4], 22
setae al
movzx eax, al
mov r2, eax
mov eax, fortuneDrawCards3D[8]
xor edx, edx
mov ecx, 22
div ecx
mov c3, edx
cmp fortuneDrawCards3D[8], 22
setae al
movzx eax, al
mov r3, eax
invoke DetectTopic3D, OFFSET fortuneQuestion3D
mov topic, eax
; Reset answer buffer
mov fortuneAnswer3D[0], 0
; Header
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strReadingHeading
; Card 1: Situation
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strReadingSit
mov eax, c1
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r1, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
jmp fortune_c1_interp
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
fortune_c1_interp:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c1
cmp r1, 0
je @F
mov eax, cardSitRTable[eax*4]
jmp fortune_c1_add
@@:
mov eax, cardSitUTable[eax*4]
fortune_c1_add:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
; Card 2: Obstacle
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strReadingObs
mov eax, c2
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r2, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
jmp fortune_c2_interp
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
fortune_c2_interp:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c2
cmp r2, 0
je @F
mov eax, cardObsRTable[eax*4]
jmp fortune_c2_add
@@:
mov eax, cardObsUTable[eax*4]
fortune_c2_add:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
; Card 3: Outcome
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strReadingOut
mov eax, c3
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r3, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
jmp fortune_c3_interp
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
fortune_c3_interp:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c3
cmp r3, 0
je @F
mov eax, cardOutRTable[eax*4]
jmp fortune_c3_add
@@:
mov eax, cardOutUTable[eax*4]
fortune_c3_add:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
; Synthesis & Topic
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strReadingSynth
cmp topic, 1
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strTopicCasino
@@:
cmp topic, 2
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strTopicLove
@@:
cmp topic, 3
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strTopicStudy
@@:
cmp topic, 4
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strTopicFuture
@@:
ret
GenerateTarotReadingMind3D ENDP
; GenerateStudentGradeMind3D: Evaluates borderline student grade
GenerateStudentGradeMind3D PROC uses ebx esi edi
local c1:DWORD, c2:DWORD, c3:DWORD
local r1:DWORD, r2:DWORD, r3:DWORD
local karma:DWORD
local pickHigh:DWORD
mov eax, fortuneDrawCards3D[0]
xor edx, edx
mov ecx, 22
div ecx
mov c1, edx
cmp fortuneDrawCards3D[0], 22
setae al
movzx eax, al
mov r1, eax
mov eax, fortuneDrawCards3D[4]
xor edx, edx
mov ecx, 22
div ecx
mov c2, edx
cmp fortuneDrawCards3D[4], 22
setae al
movzx eax, al
mov r2, eax
mov eax, fortuneDrawCards3D[8]
xor edx, edx
mov ecx, 22
div ecx
mov c3, edx
cmp fortuneDrawCards3D[8], 22
setae al
movzx eax, al
mov r3, eax
; Calculate karma points from cards + name letters
xor ebx, ebx
; Card 1: upright = +2, rev = -1
cmp r1, 0
jne @F
add ebx, 2
jmp fortune_karma_c2
@@:
dec ebx
fortune_karma_c2:
; Card 2: obstacle reversed = inner struggle (-2), upright = challenge (+1)
cmp r2, 0
jne @F
inc ebx
jmp fortune_karma_c3
@@:
sub ebx, 2
fortune_karma_c3:
; Card 3: final outcome card karma influence
mov eax, c3
mov eax, cardKarmaTable[eax*4]
cmp r3, 0
je @F
neg eax
@@:
add ebx, eax
; Name letters influence (hash sum)
xor ecx, ecx
lea esi, studentName3D
fortune_name_hash:
lodsb
test al, al
jz fortune_name_hash_done
movzx eax, al
add ecx, eax
jmp fortune_name_hash
fortune_name_hash_done:
test ecx, 1
jz @F
inc ebx ; Odd letter hash gives +1 karma boost
@@:
mov karma, ebx
mov studentKarmaSum3D, ebx
; Determine if high or low grade wins
; If karma >= 1 -> higher grade, else lower grade
cmp ebx, 1
jge fortune_pick_high
mov pickHigh, 0
jmp fortune_format_student
fortune_pick_high:
mov pickHigh, 1
fortune_format_student:
mov fortuneAnswer3D[0], 0
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strHeadingStudent
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strLabelStudent
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET studentName3D
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strLabelBorn
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET studentYear3D
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strLabelBornEnd
mov eax, studentChoice3D
cmp eax, 5
jb @F
xor eax, eax
@@:
mov eax, gradeChoicesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
; Card 1: Study Habits
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCard1Prefix
mov eax, c1
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r1, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c1
mov eax, cardStudNTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
jmp fortune_stud_c2
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c1
mov eax, cardStudPTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
fortune_stud_c2:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCard2Prefix
mov eax, c2
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r2, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c2
mov eax, cardStudNTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
jmp fortune_stud_c3
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c2
mov eax, cardStudPTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
fortune_stud_c3:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strNewLine
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCard3Prefix
mov eax, c3
mov eax, cardNamesTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strSpace
cmp r3, 0
je @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardReversed
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c3
mov eax, cardOutRTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
jmp fortune_stud_verdict
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strCardUpright
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strDashSpace
mov eax, c3
mov eax, cardOutUTable[eax*4]
invoke FortuneStrCat, OFFSET fortuneAnswer3D, eax
fortune_stud_verdict:
cmp pickHigh, 1
jne fortune_verdict_low
; High Verdict (e.g. 10 or 9 or 8 or 5 or 6)
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strVerdictHighPrefix
mov eax, studentChoice3D
cmp eax, 0
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore10
jmp fortune_verdict_high_done
@@:
cmp eax, 1
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore9
jmp fortune_verdict_high_done
@@:
cmp eax, 2
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore8
jmp fortune_verdict_high_done
@@:
cmp eax, 3
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore5
jmp fortune_verdict_high_done
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore6
fortune_verdict_high_done:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strVerdictSuffix
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strAdviceHigh
jmp fortune_stud_end
fortune_verdict_low:
; Low Verdict (e.g. 9 or 8 or 7 or 4 or 5)
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strVerdictLowPrefix
mov eax, studentChoice3D
cmp eax, 0
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore9
jmp fortune_verdict_low_done
@@:
cmp eax, 1
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore8
jmp fortune_verdict_low_done
@@:
cmp eax, 2
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore7
jmp fortune_verdict_low_done
@@:
cmp eax, 3
jne @F
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore4
jmp fortune_verdict_low_done
@@:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strScore5
fortune_verdict_low_done:
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strVerdictSuffix
invoke FortuneStrCat, OFFSET fortuneAnswer3D, OFFSET strAdviceLow
fortune_stud_end:
ret
GenerateStudentGradeMind3D ENDP