- 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
975 lines
26 KiB
PHP
975 lines
26 KiB
PHP
; ==============================================================================
|
||
; 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
|