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

975 lines
26 KiB
PHP
Raw Blame History

; ==============================================================================
; FORTUNE DIALOG - MASM32 / CP1251
; Interactive Tarot Divination & Teacher Grade Oracle
; ==============================================================================
include src_graphics\fortune_mind.inc
BeginFortuneDialog3D PROC uses esi edi
call StopFortuneWorker3D
lea esi,screenBuffer
lea edi,fortuneBackground3D
mov ecx,SCREEN_SIZE
rep movsd
mov engineMode,MODE_FORTUNE
mov paused3D,0
mov fortuneQuestionLength3D,0
mov fortuneQuestion3D[0],0
mov fortuneAnswer3D[0],0
mov fortunePage3D,0
mov fortuneShort3D,0
mov fortuneReceiveLength3D,-1
call ClearKeys3D
mov mouseClick3D,0
; Initialize Mind state (submode menu, student defaults)
call InitFortuneMindState3D
mov fortuneWorkerState3D,2 ; Instant Mind ready by default
; Try optional worker launch (non-blocking, pipes)
invoke CreatePipe,OFFSET fortuneChildRead3D,OFFSET fortuneWrite3D,OFFSET fortunePipeSecurity3D,16384
test eax,eax
jz fortune_worker_skip
invoke SetHandleInformation,fortuneWrite3D,1,0
test eax,eax
jz fortune_worker_skip
invoke CreatePipe,OFFSET fortuneRead3D,OFFSET fortuneChildWrite3D,OFFSET fortunePipeSecurity3D,16384
test eax,eax
jz fortune_worker_skip
invoke SetHandleInformation,fortuneRead3D,1,0
test eax,eax
jz fortune_worker_skip
invoke CreateFileA,OFFSET fortuneNullName3D,40000000h,3,OFFSET fortunePipeSecurity3D,3,80h,0
cmp eax,-1
je fortune_worker_skip
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_worker_skip
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
invoke GetTickCount
mov fortuneWorkerTick3D,eax
ret
fortune_worker_skip:
; Native Mind is always ready
mov fortuneWorkerState3D,2
ret
BeginFortuneDialog3D ENDP
StopFortuneWorker3D PROC uses esi
cmp fortuneProcess3D,0
je @F
invoke TerminateProcess,fortuneProcess3D,0
invoke CloseHandle,fortuneProcess3D
mov fortuneProcess3D,0
@@:
lea esi,fortuneRead3D
mov ecx,5
fortune_close_handle:
push ecx
cmp DWORD PTR [esi],0
je @F
invoke CloseHandle,DWORD PTR [esi]
mov DWORD PTR [esi],0
@@:
pop ecx
add esi,4
loop fortune_close_handle
mov fortuneReceiveLength3D,-1
ret
StopFortuneWorker3D ENDP
PollFortuneWorker3D PROC
cmp fortuneProcess3D,0
je fortune_poll_done
cmp fortuneWorkerState3D,1
je fortune_poll
cmp fortuneWorkerState3D,3
jne fortune_poll_done
fortune_poll:
invoke PeekNamedPipe,fortuneRead3D,0,0,0,OFFSET fortuneAvailable3D,0
test eax,eax
jz fortune_poll_done
cmp fortuneReceiveLength3D,-1
jne fortune_poll_body
cmp fortuneAvailable3D,12
jb fortune_poll_timeout
invoke ReadFile,fortuneRead3D,OFFSET fortuneReceiveHeader3D,12,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_poll_done
cmp fortuneIo3D,12
jne fortune_poll_done
cmp fortuneReceiveHeader3D,31524346h
jne fortune_poll_done
cmp fortuneReceiveHeader3D[8],8192
ja fortune_poll_done
mov eax,fortuneReceiveHeader3D[8]
mov fortuneReceiveLength3D,eax
sub fortuneAvailable3D,12
fortune_poll_body:
mov eax,fortuneReceiveLength3D
cmp fortuneAvailable3D,eax
jb fortune_poll_timeout
test eax,eax
jz fortune_poll_status
invoke ReadFile,fortuneRead3D,OFFSET fortuneAnswer3D,eax,OFFSET fortuneIo3D,0
test eax,eax
jz fortune_poll_done
mov eax,fortuneReceiveLength3D
cmp fortuneIo3D,eax
jne fortune_poll_done
mov fortuneAnswer3D[eax],0
fortune_poll_status:
mov fortuneReceiveLength3D,-1
cmp fortuneWorkerState3D,1
jne fortune_poll_answer
cmp fortuneReceiveHeader3D[4],0
jne fortune_poll_done
mov fortuneWorkerState3D,2
ret
fortune_poll_answer:
cmp fortuneReceiveHeader3D[4],1
je fortune_poll_answer_ready
cmp fortuneReceiveHeader3D[4],3
jne fortune_poll_done
mov fortuneShort3D,1
fortune_poll_answer_ready:
cmp fortuneReceiveHeader3D[8],0
je fortune_poll_done
mov fortuneWorkerState3D,2
mov fortunePage3D,0
ret
fortune_poll_timeout:
invoke GetTickCount
sub eax,fortuneWorkerTick3D
cmp eax,180000
ja fortune_poll_timeout_reset
fortune_poll_done:
ret
fortune_poll_timeout_reset:
mov fortuneWorkerState3D,2
ret
PollFortuneWorker3D ENDP
FortuneChar3D PROC character:DWORD
cmp engineMode,MODE_FORTUNE
jne fortune_char_done
; --- Mode 0: MENU ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
jne @F
mov eax,character
cmp eax,'1'
je fortune_menu_goto_tarot
cmp eax,'2'
je fortune_menu_goto_student
cmp eax,'0'
je fortune_menu_goto_exit
cmp eax,1Bh
je fortune_menu_goto_exit
ret
fortune_menu_goto_tarot:
mov fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
mov fortuneWorkerState3D,2
mov fortunePage3D,0
ret
fortune_menu_goto_student:
mov fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
mov studentField3D,0
mov fortunePage3D,0
ret
fortune_menu_goto_exit:
mov engineMode,MODE_WALK
call ClearKeys3D
ret
@@:
; --- Mode 1: TAROT ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne @F
mov eax,character
cmp eax,8
je fortune_tarot_backspace
cmp eax,32
jb fortune_char_done
cmp eax,255
ja fortune_char_done
cmp eax,127
je fortune_char_done
mov ecx,fortuneQuestionLength3D
cmp ecx,240
jae fortune_char_done
mov fortuneQuestion3D[ecx],al
inc ecx
mov fortuneQuestionLength3D,ecx
mov fortuneQuestion3D[ecx],0
ret
fortune_tarot_backspace:
mov ecx,fortuneQuestionLength3D
test ecx,ecx
jz fortune_char_done
dec ecx
mov fortuneQuestionLength3D,ecx
mov fortuneQuestion3D[ecx],0
ret
@@:
; --- Mode 2: STUDENT ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
jne fortune_char_done
cmp studentDone3D,1
je fortune_stud_done_keys
; Tab switches fields
mov eax,character
cmp eax,9
jne @F
inc studentField3D
cmp studentField3D,3
jb fortune_char_done
mov studentField3D,0
ret
@@:
cmp studentField3D,0
je fortune_stud_edit_name
cmp studentField3D,1
je fortune_stud_edit_year
cmp studentField3D,2
je fortune_stud_edit_choice
ret
fortune_stud_edit_name:
mov eax,character
cmp eax,8
je fortune_stud_name_bs
cmp eax,32
jb fortune_char_done
cmp eax,255
ja fortune_char_done
cmp eax,127
je fortune_char_done
mov ecx,studentNameLen3D
cmp ecx,50
jae fortune_char_done
mov studentName3D[ecx],al
inc ecx
mov studentNameLen3D,ecx
mov studentName3D[ecx],0
ret
fortune_stud_name_bs:
mov ecx,studentNameLen3D
test ecx,ecx
jz fortune_char_done
dec ecx
mov studentNameLen3D,ecx
mov studentName3D[ecx],0
ret
fortune_stud_edit_year:
mov eax,character
cmp eax,8
je fortune_stud_year_bs
cmp eax,'0'
jb fortune_char_done
cmp eax,'9'
ja fortune_char_done
mov ecx,studentYearLen3D
cmp ecx,6
jae fortune_char_done
mov studentYear3D[ecx],al
inc ecx
mov studentYearLen3D,ecx
mov studentYear3D[ecx],0
ret
fortune_stud_year_bs:
mov ecx,studentYearLen3D
test ecx,ecx
jz fortune_char_done
dec ecx
mov studentYearLen3D,ecx
mov studentYear3D[ecx],0
ret
fortune_stud_edit_choice:
mov eax,character
cmp eax,'1'
jb fortune_char_done
cmp eax,'5'
ja fortune_char_done
sub eax,'1'
mov studentChoice3D,eax
ret
fortune_stud_done_keys:
mov eax,character
cmp eax,'1'
je fortune_stud_reset_next
cmp eax,1Bh
je fortune_stud_to_menu
ret
fortune_stud_reset_next:
mov studentDone3D,0
mov fortuneCardsDrawn3D,0
ret
fortune_stud_to_menu:
mov fortuneSubMode3D,FORTUNE_SUBMODE_MENU
ret
fortune_char_done:
ret
FortuneChar3D ENDP
SubmitFortuneQuestion3D PROC uses ebx esi
; Draw 3 unique cards
xor esi,esi
fortune_draw_loop:
invoke RandomRange3D,22
mov ebx,eax
xor ecx,ecx
fortune_check_unique:
cmp ecx,esi
jae fortune_apply_orientation
mov eax,fortuneDrawCards3D[ecx*4]
xor edx,edx
push ecx
mov ecx,22
div ecx
pop ecx
cmp ebx,edx
je fortune_draw_loop
inc ecx
jmp fortune_check_unique
fortune_apply_orientation:
invoke RandomRange3D,2
imul eax,22
add eax,ebx
mov fortuneDrawCards3D[esi*4],eax
mov fortuneRequest3D[esi*4+8],eax
inc esi
cmp esi,3
jb fortune_draw_loop
mov fortuneCardsDrawn3D,1
; Native Mind generates instant reading
call GenerateTarotReadingMind3D
mov fortuneWorkerState3D,2
mov fortunePage3D,0
mov fortuneShort3D,0
; Optional: notify external child worker if running
cmp fortuneWrite3D,0
je fortune_submit_done
mov eax,fortuneQuestionLength3D
test eax,eax
jz fortune_submit_done
mov fortuneRequest3D[4],eax
invoke WriteFile,fortuneWrite3D,OFFSET fortuneRequest3D,20,OFFSET fortuneIo3D,0
invoke WriteFile,fortuneWrite3D,OFFSET fortuneQuestion3D,fortuneQuestionLength3D,OFFSET fortuneIo3D,0
fortune_submit_done:
ret
SubmitFortuneQuestion3D ENDP
SubmitStudentGrade3D PROC uses ebx esi
; Draw 3 cards for student
xor esi,esi
fortune_stud_draw_loop:
invoke RandomRange3D,22
mov ebx,eax
xor ecx,ecx
fortune_stud_check_unique:
cmp ecx,esi
jae fortune_stud_apply_orientation
mov eax,fortuneDrawCards3D[ecx*4]
xor edx,edx
push ecx
mov ecx,22
div ecx
pop ecx
cmp ebx,edx
je fortune_stud_draw_loop
inc ecx
jmp fortune_stud_check_unique
fortune_stud_apply_orientation:
invoke RandomRange3D,2
imul eax,22
add eax,ebx
mov fortuneDrawCards3D[esi*4],eax
inc esi
cmp esi,3
jb fortune_stud_draw_loop
mov fortuneCardsDrawn3D,1
call GenerateStudentGradeMind3D
mov studentDone3D,1
mov fortuneWorkerState3D,2
mov fortunePage3D,0
ret
SubmitStudentGrade3D ENDP
HandleFortuneDialog3D PROC
call PollFortuneWorker3D
; Check Escape (1Bh)
invoke Pressed3D,1Bh
test eax,eax
jz @F
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_handle_exit
mov fortuneSubMode3D,FORTUNE_SUBMODE_MENU
ret
@@:
; Check Enter (0Dh)
invoke Pressed3D,0Dh
test eax,eax
jz fortune_handle_mouse
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_handle_menu_enter
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
je fortune_handle_tarot_enter
cmp fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
je fortune_handle_stud_enter
ret
fortune_handle_menu_enter:
mov fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
ret
fortune_handle_tarot_enter:
call SubmitFortuneQuestion3D
ret
fortune_handle_stud_enter:
cmp studentDone3D,1
je fortune_stud_reset_enter
call SubmitStudentGrade3D
ret
fortune_stud_reset_enter:
mov studentDone3D,0
mov fortuneCardsDrawn3D,0
ret
fortune_handle_mouse:
cmp mouseClick3D,0
je fortune_handle_done
mov mouseClick3D,0
; --- Mode 0: MENU CLICKS ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
jne @F
; Option 1: Tarot (Y: 96..124, X: 20..300)
cmp mouseY3D,96
jb fortune_handle_menu_chk2
cmp mouseY3D,124
ja fortune_handle_menu_chk2
cmp mouseX3D,20
jb fortune_handle_done
cmp mouseX3D,300
ja fortune_handle_done
mov fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
ret
fortune_handle_menu_chk2:
; Option 2: Student (Y: 130..158, X: 20..300)
cmp mouseY3D,130
jb fortune_handle_menu_chk0
cmp mouseY3D,158
ja fortune_handle_menu_chk0
cmp mouseX3D,20
jb fortune_handle_done
cmp mouseX3D,300
ja fortune_handle_done
mov fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
ret
fortune_handle_menu_chk0:
; Option 0 / Exit (Y: 164..192, X: 20..300)
cmp mouseY3D,164
jb fortune_handle_menu_bottom
cmp mouseY3D,192
ja fortune_handle_menu_bottom
cmp mouseX3D,20
jb fortune_handle_done
cmp mouseX3D,300
ja fortune_handle_done
jmp fortune_handle_exit
fortune_handle_menu_bottom:
; Bottom Exit button
cmp mouseY3D,219
jb fortune_handle_done
cmp mouseY3D,235
jae fortune_handle_done
cmp mouseX3D,240
jae fortune_handle_exit
ret
@@:
; --- Mode 1: TAROT CLICKS ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne @F
cmp mouseY3D,219
jb fortune_handle_done
cmp mouseY3D,235
jae fortune_handle_done
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (8..86)
cmp mouseX3D,8
jb fortune_handle_done
cmp mouseX3D,86
jb fortune_handle_tarot_enter
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (90..180)
cmp mouseX3D,90
jb fortune_handle_done
cmp mouseX3D,180
jb fortune_tarot_reset
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (186..236)
cmp mouseX3D,186
jb fortune_handle_done
cmp mouseX3D,236
jb fortune_to_menu
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (242..310)
cmp mouseX3D,242
jae fortune_handle_exit
ret
fortune_tarot_reset:
mov fortuneCardsDrawn3D,0
mov fortuneQuestionLength3D,0
mov fortuneQuestion3D[0],0
mov fortuneAnswer3D[0],0
ret
fortune_to_menu:
mov fortuneSubMode3D,FORTUNE_SUBMODE_MENU
ret
@@:
; --- Mode 2: STUDENT CLICKS ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
jne fortune_handle_done
cmp studentDone3D,1
je fortune_stud_done_clicks
; Check field clicks
; Name box (Y: 44..66, X: 90..290)
cmp mouseY3D,44
jb @F
cmp mouseY3D,66
ja @F
cmp mouseX3D,90
jb @F
cmp mouseX3D,290
ja @F
mov studentField3D,0
ret
@@:
; Year box (Y: 74..96, X: 90..200)
cmp mouseY3D,74
jb @F
cmp mouseY3D,96
ja @F
cmp mouseX3D,90
jb @F
cmp mouseX3D,200
ja @F
mov studentField3D,1
ret
@@:
; Choices (Y: 104..128, X: 10..300)
cmp mouseY3D,104
jb @F
cmp mouseY3D,128
ja @F
mov studentField3D,2
; Click segments for 5 choices: ~58 px each
mov eax,mouseX3D
sub eax,10
cmp eax,290
jae @F
xor edx,edx
mov ecx,58
div ecx
cmp eax,5
jae @F
mov studentChoice3D,eax
ret
@@:
; Bottom buttons (Y: 219..235)
cmp mouseY3D,219
jb fortune_handle_done
cmp mouseY3D,235
jae fortune_handle_done
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (8..104)
cmp mouseX3D,8
jb fortune_handle_done
cmp mouseX3D,104
jb fortune_handle_stud_enter
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (110..170)
cmp mouseX3D,110
jb fortune_handle_done
cmp mouseX3D,170
jb fortune_to_menu
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (242..310)
cmp mouseX3D,242
jae fortune_handle_exit
ret
fortune_stud_done_clicks:
cmp mouseY3D,219
jb fortune_handle_done
cmp mouseY3D,235
jae fortune_handle_done
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (8..150)
cmp mouseX3D,8
jb fortune_handle_done
cmp mouseX3D,150
jb fortune_stud_reset_enter
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (154..214)
cmp mouseX3D,154
jb fortune_handle_done
cmp mouseX3D,214
jb fortune_to_menu
; [<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>] at (242..310)
cmp mouseX3D,242
jae fortune_handle_exit
ret
fortune_handle_exit:
call StopFortuneWorker3D
mov engineMode,MODE_WALK
call ClearKeys3D
fortune_handle_done:
ret
HandleFortuneDialog3D ENDP
; Word wrapping at 72 native pixels-wide glyph columns, with bounded paging
FortuneWrap3D PROC uses ebx esi edi source:DWORD,top:DWORD,lines:DWORD,skip:DWORD,ink:DWORD
local count:DWORD,lastSpace:DWORD,lineNumber:DWORD
mov esi,source
mov lineNumber,0
fortune_wrap_line:
cmp BYTE PTR [esi],0
je fortune_wrap_end
xor ebx,ebx
mov lastSpace,0
fortune_wrap_measure:
mov al,[esi+ebx]
test al,al
jz fortune_wrap_measured
cmp al,10
je fortune_wrap_measured
cmp al,32
jne @F
mov lastSpace,ebx
@@:
inc ebx
cmp ebx,72
jb fortune_wrap_measure
cmp BYTE PTR [esi+ebx],0
je fortune_wrap_measured
cmp lastSpace,0
je fortune_wrap_measured
mov ebx,lastSpace
fortune_wrap_measured:
mov count,ebx
mov eax,lineNumber
cmp eax,skip
jb fortune_wrap_advance
sub eax,skip
cmp eax,lines
jae fortune_wrap_more
imul eax,11
add eax,top
push eax
lea edi,fortuneLine3D
mov ecx,ebx
push esi
rep movsb
mov BYTE PTR [edi],0
pop esi
pop eax
mov fortuneCaretY3D,eax
mov edx,count
imul edx,8
add edx,24
mov fortuneCaretX3D,edx
invoke DrawBuckshotText3D,24,eax,OFFSET fortuneLine3D,ink
fortune_wrap_advance:
add esi,count
cmp BYTE PTR [esi],10
je fortune_wrap_skip_separator
cmp BYTE PTR [esi],32
jne fortune_wrap_next
fortune_wrap_skip_separator:
inc esi
fortune_wrap_next:
inc lineNumber
jmp fortune_wrap_line
fortune_wrap_more:
mov eax,1
ret
fortune_wrap_end:
xor eax,eax
ret
FortuneWrap3D ENDP
; Draw a stylized visual Tarot Card box on screen
DrawFortuneCardBox3D PROC uses ebx esi edi cxVal:DWORD,cyVal:DWORD,cwVal:DWORD,chVal:DWORD,cardIdx:DWORD,roleStr:DWORD
local cNum:DWORD,isRev:DWORD,bgCol:DWORD,brdCol:DWORD
; Split card number & orientation
mov eax,cardIdx
xor edx,edx
mov ecx,22
div ecx
mov cNum,edx
cmp cardIdx,22
setae al
movzx eax,al
mov isRev,eax
; Palette: upright=mystic teal/gold, reversed=dark purple/amber
cmp isRev,0
jne fortune_card_rev_pal
mov bgCol,000F2236h
mov brdCol,004CA0C8h
jmp fortune_card_draw_bg
fortune_card_rev_pal:
mov bgCol,002A1226h
mov brdCol,00C86488h
fortune_card_draw_bg:
invoke DrawBoxBorder,cxVal,cyVal,cwVal,chVal,bgCol,brdCol,1
; Coordinates in 640x480 space
mov eax,cxVal
shl eax,1
add eax,8 ; X offset
mov ebx,cyVal
shl ebx,1
add ebx,6 ; Y offset
; Role line (e.g. "1. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" or "1. <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>")
invoke DrawBuckshotText3D,eax,ebx,roleStr,00FFD700h
; Card name line (e.g. "XVI <20><><EFBFBD><EFBFBD><EFBFBD>")
add ebx,14
mov edx,cNum
mov edx,cardNamesTable[edx*4]
invoke DrawBuckshotText3D,eax,ebx,edx,00FFFFFFh
; Orientation indicator
add ebx,14
cmp isRev,0
jne @F
invoke DrawBuckshotText3D,eax,ebx,OFFSET strCardUpright,0088FFAAh
ret
@@:
invoke DrawBuckshotText3D,eax,ebx,OFFSET strCardReversed,00FF88AAh
ret
DrawFortuneCardBox3D ENDP
RenderFortuneDialog3D PROC uses esi edi
lea esi,fortuneBackground3D
lea edi,screenBuffer
mov ecx,SCREEN_SIZE
rep movsd
; Outer Border
invoke DrawBoxBorder,6,5,308,230,000A1726h,004C8CAAh,1
; --- Submode 0: SELECTION MENU ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
jne @F
invoke DrawBuckshotText3D,24,18,OFFSET fortuneMenuTitle3D,00D0EEFFh
invoke DrawBuckshotText3D,24,38,OFFSET fortuneDisclaimer3D,0087A8BDh
invoke DrawBoxBorder,9,30,302,175,000C1C30h,002C4D68h,1
invoke DrawBuckshotText3D,24,76,OFFSET fortuneMenuGreeting1_3D,00BEDCEEh
invoke DrawBuckshotText3D,24,96,OFFSET fortuneMenuGreeting2_3D,00BEDCEEh
; Option 1: Tarot
invoke DrawBoxBorder,20,96,280,26,00132337h,00416A87h,1
invoke DrawBuckshotText3D,48,200,OFFSET fortuneMenuOpt1_3D,00D0EEFFh
; Option 2: Student
invoke DrawBoxBorder,20,130,280,26,00132337h,00416A87h,1
invoke DrawBuckshotText3D,48,268,OFFSET fortuneMenuOpt2_3D,00D0EEFFh
; Option 0: Exit
invoke DrawBoxBorder,20,164,280,26,00132337h,00416A87h,1
invoke DrawBuckshotText3D,48,336,OFFSET fortuneMenuOpt0_3D,00D0EEFFh
; Bottom Exit button
invoke DrawBoxBorder,240,219,70,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,518,445,OFFSET fortuneExit3D,00D0EEFFh
ret
@@:
; --- Submode 1: TAROT DIVINATION ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne @F
invoke DrawBuckshotText3D,24,18,OFFSET fortuneTitle3D,00D0EEFFh
invoke DrawBuckshotText3D,24,38,OFFSET fortuneDisclaimer3D,0087A8BDh
cmp fortuneCardsDrawn3D,1
je fortune_render_tarot_drawn
; No cards drawn yet: intro prompt
invoke DrawBoxBorder,9,30,302,145,000C1C30h,002C4D68h,1
invoke DrawBuckshotText3D,24,76,OFFSET fortuneReady3D,00BEDCEEh
invoke DrawBuckshotText3D,24,106,OFFSET fortuneMenuOpt1_3D,009CCEE8h
invoke DrawBuckshotText3D,24,136,OFFSET strAskPrompt,00D0EEFFh
jmp fortune_render_tarot_input
fortune_render_tarot_drawn:
; Draw 3 Tarot Cards at top (Y=28, H=44)
invoke DrawFortuneCardBox3D,12,28,94,44,fortuneDrawCards3D[0],OFFSET strTarotRole1
invoke DrawFortuneCardBox3D,113,28,94,44,fortuneDrawCards3D[4],OFFSET strTarotRole2
invoke DrawFortuneCardBox3D,214,28,94,44,fortuneDrawCards3D[8],OFFSET strTarotRole3
; Reading text box below cards (Y=75, H=100)
invoke DrawBoxBorder,9,75,302,100,000C1C30h,002C4D68h,1
invoke FortuneWrap3D,OFFSET fortuneAnswer3D,160,17,fortunePage3D,00DCEBF4h
mov fortuneMore3D,eax
fortune_render_tarot_input:
; Question input box (Y=179, H=35)
invoke DrawBoxBorder,9,179,302,35,00132337h,00416A87h,1
mov fortuneCaretX3D,24
mov fortuneCaretY3D,366
invoke FortuneWrap3D,OFFSET fortuneQuestion3D,366,5,0,00FFFFFFh
; Caret animation
test animationClock3D,200h
jnz @F
invoke DrawBuckshotText3D,fortuneCaretX3D,fortuneCaretY3D,OFFSET fortuneCaret3D,00FFFFFFh
@@:
; Buttons (Y=219)
invoke DrawBoxBorder,8,219,76,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,20,445,OFFSET fortuneAsk3D,00D0EEFFh
invoke DrawBoxBorder,88,219,90,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,182,445,OFFSET strBtnNextStudent,00D0EEFFh
invoke DrawBoxBorder,182,219,54,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,374,445,OFFSET strBtnMenu,00D0EEFFh
invoke DrawBoxBorder,240,219,70,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,518,445,OFFSET fortuneExit3D,00D0EEFFh
ret
@@:
; --- Submode 2: STUDENT GRADE DIVINATION ---
cmp fortuneSubMode3D,FORTUNE_SUBMODE_STUDENT
jne fortune_render_done
invoke DrawBuckshotText3D,24,18,OFFSET strStudentTitle,00FFD700h
invoke DrawBuckshotText3D,24,38,OFFSET fortuneDisclaimer3D,0087A8BDh
cmp studentDone3D,1
je fortune_render_stud_verdict
; Input Form Box (Y=30, H=175)
invoke DrawBoxBorder,9,30,302,175,000C1C30h,002C4D68h,1
; Prompt 1: Student Name
invoke DrawBuckshotText3D,24,76,OFFSET strStudentPromptName,00BEDCEEh
cmp studentField3D,0
jne @F
invoke DrawBoxBorder,85,34,215,16,001A364Eh,0066CCFFh,1
jmp fortune_render_stud_name_text
@@:
invoke DrawBoxBorder,85,34,215,16,00132337h,00416A87h,1
fortune_render_stud_name_text:
invoke DrawBuckshotText3D,176,76,OFFSET studentName3D,00FFFFFFh
cmp studentField3D,0
jne @F
test animationClock3D,200h
jnz @F
mov eax,studentNameLen3D
shl eax,3
add eax,176
invoke DrawBuckshotText3D,eax,76,OFFSET fortuneCaret3D,00FFFFFFh
@@:
; Prompt 2: Birth Year
invoke DrawBuckshotText3D,24,116,OFFSET strStudentPromptYear,00BEDCEEh
cmp studentField3D,1
jne @F
invoke DrawBoxBorder,85,54,100,16,001A364Eh,0066CCFFh,1
jmp fortune_render_stud_year_text
@@:
invoke DrawBoxBorder,85,54,100,16,00132337h,00416A87h,1
fortune_render_stud_year_text:
invoke DrawBuckshotText3D,176,116,OFFSET studentYear3D,00FFFFFFh
cmp studentField3D,1
jne @F
test animationClock3D,200h
jnz @F
mov eax,studentYearLen3D
shl eax,3
add eax,176
invoke DrawBuckshotText3D,eax,116,OFFSET fortuneCaret3D,00FFFFFFh
@@:
; Prompt 3: Grade Choices
invoke DrawBuckshotText3D,24,156,OFFSET strStudentPromptChoice,00BEDCEEh
; Highlight chosen grade
mov eax,studentChoice3D
imul eax,116
add eax,48
cmp studentField3D,2
jne @F
invoke DrawBuckshotText3D,eax,176,OFFSET strCardUpright,00FFD700h
@@:
; Action instructions
invoke DrawBuckshotText3D,24,360,OFFSET strStudentAction,0087A8BDh
; Buttons (Y=219)
invoke DrawBoxBorder,8,219,96,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,20,445,OFFSET strStudentTitle,00D0EEFFh
invoke DrawBoxBorder,110,219,60,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,230,445,OFFSET strBtnMenu,00D0EEFFh
invoke DrawBoxBorder,240,219,70,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,518,445,OFFSET fortuneExit3D,00D0EEFFh
ret
fortune_render_stud_verdict:
; Top 3 Destiny Cards (Y=28, H=44)
invoke DrawFortuneCardBox3D,12,28,94,44,fortuneDrawCards3D[0],OFFSET strStudRole1
invoke DrawFortuneCardBox3D,113,28,94,44,fortuneDrawCards3D[4],OFFSET strStudRole2
invoke DrawFortuneCardBox3D,214,28,94,44,fortuneDrawCards3D[8],OFFSET strStudRole3
; Divination Verdict Text Box (Y=75, H=138)
invoke DrawBoxBorder,9,75,302,138,000C1C30h,002C4D68h,1
invoke FortuneWrap3D,OFFSET fortuneAnswer3D,160,25,fortunePage3D,00DCEBF4h
mov fortuneMore3D,eax
; Bottom Buttons
invoke DrawBoxBorder,8,219,140,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,20,445,OFFSET strBtnNextStudent,00D0EEFFh
invoke DrawBoxBorder,154,219,60,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,320,445,OFFSET strBtnMenu,00D0EEFFh
invoke DrawBoxBorder,240,219,70,15,001D3A50h,0076B0CDh,1
invoke DrawBuckshotText3D,518,445,OFFSET fortuneExit3D,00D0EEFFh
ret
fortune_render_done:
ret
RenderFortuneDialog3D ENDP