KAZIK/src_graphics/fortune_dialog.inc
Artvasil09 41ba8f46ed feat: add rooftop city and optimize native terrace rendering
Add rooftop elevator, lounge, volumetric city, river and animated traffic. Prune invisible mesh faces, clip CPU surfaces, streamline compositing and add automatic/F8 roof quality profiles with renderer diagnostics.

Include dartboard/reticle improvements, tracked fortune orb numerals and fate-session visuals, native regression tests, compatible jukebox IDs and updated shipping executables.
2026-10-26 23:20:35 +03:00

1259 lines
30 KiB
PHP

; Seated fortune session. All timing, input, dealing and rendering are native MASM.
BeginFortuneDialog3D PROC uses ebx esi edi
call StopFortuneWorker3D
lea esi,screenBuffer
lea edi,fortuneBackground3D
mov ecx,SCREEN_SIZE
rep movsd
xor ebx,ebx
lea esi,fortuneSessionPacks3D
fortune_session_load:
invoke LoadAnimPack3D,esi,fortuneSessionPaths3D[ebx*4]
add esi,SIZEOF AnimPack3D
inc ebx
cmp ebx,FORTUNE_SESSION_PACK_COUNT
jb fortune_session_load
mov engineMode,MODE_FORTUNE
mov paused3D,0
mov fortuneSubMode3D,0
mov fortunePhase3D,0
mov fortunePhaseTime3D,0
mov fortuneDealt3D,0
mov fortuneRevealed3D,0
mov fortuneCardsDrawn3D,0
mov fortuneQuestionLength3D,0
mov fortuneQuestion3D,0
mov fortuneWorkerState3D,0
call ResetFortuneFate3D
mov eax,animationClock3D
mov fortuneSessionClock3D,eax
invoke SetFortuneSpeech3D,OFFSET fortuneWelcome3D
call ClearKeys3D
mov mouseClick3D,0
ret
BeginFortuneDialog3D ENDP
; Kept as the public exit/shutdown hook. No inference process is launched.
StopFortuneWorker3D PROC uses ebx esi
lea esi,fortuneSessionPacks3D
mov ebx,FORTUNE_SESSION_PACK_COUNT
fortune_session_free:
invoke FreeAnimPack3D,esi
add esi,SIZEOF AnimPack3D
dec ebx
jnz fortune_session_free
mov fortuneWorkerState3D,0
call ResetFortuneFate3D
ret
StopFortuneWorker3D ENDP
PollFortuneWorker3D PROC
ret
PollFortuneWorker3D ENDP
SetFortuneSpeech3D PROC uses esi edi text:DWORD
mov esi,text
lea edi,fortuneSpeech3D
xor ecx,ecx
fortune_speech_copy:
mov al,[esi+ecx]
mov [edi+ecx],al
test al,al
jz fortune_speech_copied
inc ecx
cmp ecx,255
jb fortune_speech_copy
mov BYTE PTR [edi+255],0
fortune_speech_copied:
mov fortuneSpeechLength3D,ecx
mov fortuneSpeechTime3D,0
mov fortuneSpeechVisible3D,0
ret
SetFortuneSpeech3D ENDP
FortuneCardSpeech3D PROC uses ebx esi edi cardSlot:DWORD
mov eax,cardSlot
mov ebx,fortuneDrawCards3D[eax*4]
mov eax,ebx
xor edx,edx
mov ecx,22
div ecx
mov esi,fortuneCardNames3D[edx*4]
lea edi,fortuneSpeech3D
fortune_card_name_copy:
lodsb
test al,al
jz fortune_card_position
stosb
jmp fortune_card_name_copy
fortune_card_position:
mov al,10
stosb
mov esi,OFFSET fortuneUpright3D
cmp ebx,22
jb @F
mov esi,OFFSET fortuneReversed3D
@@:
lodsb
test al,al
jz fortune_card_placeholder
stosb
jmp @B
fortune_card_placeholder:
mov al,10
stosb
mov esi,OFFSET fortuneUnavailable3D
fortune_card_placeholder_copy:
lodsb
stosb
test al,al
jnz fortune_card_placeholder_copy
sub edi,OFFSET fortuneSpeech3D+1
mov fortuneSpeechLength3D,edi
mov fortuneSpeechTime3D,0
mov fortuneSpeechVisible3D,0
ret
FortuneCardSpeech3D ENDP
FortuneChar3D PROC character:DWORD
cmp engineMode,MODE_FORTUNE
jne fortune_char_done
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
jne fortune_char_question
cmp character,'1'
je fortune_char_tarot
cmp character,'2'
je fortune_char_orb
ret
fortune_char_tarot:
mov fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
invoke SetFortuneSpeech3D,OFFSET fortuneReady3D
ret
fortune_char_orb:
mov fortuneSubMode3D,FORTUNE_SUBMODE_ORB
call ResetFortuneFate3D
mov fortunePhase3D,0
mov fortunePhaseTime3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneFateReady3D
ret
fortune_char_question:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne @F
invoke FortuneFateChar3D,character
ret
@@:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_char_done
cmp fortunePhase3D,0
jne fortune_char_done
mov eax,character
cmp eax,8
je fortune_char_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_char_backspace:
mov ecx,fortuneQuestionLength3D
test ecx,ecx
jz fortune_char_done
dec ecx
mov fortuneQuestionLength3D,ecx
mov fortuneQuestion3D[ecx],0
fortune_char_done:
ret
FortuneChar3D ENDP
SubmitFortuneQuestion3D PROC uses ebx esi
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_submit_done
cmp fortunePhase3D,0
jne fortune_submit_done
cmp fortuneQuestionLength3D,0
je fortune_submit_done
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
inc esi
cmp esi,3
jb fortune_draw_loop
mov fortunePhase3D,1
mov fortunePhaseTime3D,0
mov fortuneDealt3D,0
mov fortuneRevealed3D,0
mov fortuneCardsDrawn3D,1
mov eax,animationClock3D
mov fortuneSessionClock3D,eax
invoke SetFortuneSpeech3D,OFFSET fortuneShuffle3D
fortune_submit_done:
ret
SubmitFortuneQuestion3D ENDP
; Elapsed clock, not render count: repeated renders cannot accelerate a session.
UpdateFortuneSession3D PROC uses ebx
mov eax,animationClock3D
mov edx,eax
sub eax,fortuneSessionClock3D
mov fortuneSessionClock3D,edx
cmp eax,100
jbe @F
mov eax,100
@@:
add fortuneSpeechTime3D,eax
add fortunePhaseTime3D,eax
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_update_orb
mov ebx,fortunePhase3D
test ebx,ebx
jz fortune_update_done
cmp ebx,12
jae fortune_update_done
mov eax,fortuneDurations3D[ebx*4]
cmp fortunePhaseTime3D,eax
jb fortune_update_done
inc ebx
mov fortunePhase3D,ebx
mov fortunePhaseTime3D,0
cmp ebx,2
jb fortune_update_done
cmp ebx,5
ja fortune_update_reveal
mov eax,ebx
sub eax,2
mov fortuneDealt3D,eax
invoke SetFortuneSpeech3D,OFFSET fortuneDeal3D
jmp fortune_update_done
fortune_update_reveal:
cmp ebx,6
je fortune_explain_one
cmp ebx,8
je fortune_explain_two
cmp ebx,10
je fortune_explain_three
cmp ebx,11
jne fortune_update_done
invoke SetFortuneSpeech3D,OFFSET fortuneSummary3D
jmp fortune_update_done
fortune_explain_one:
mov fortuneRevealed3D,1
invoke FortuneCardSpeech3D,0
jmp fortune_update_done
fortune_explain_two:
mov fortuneRevealed3D,2
invoke FortuneCardSpeech3D,1
jmp fortune_update_done
fortune_explain_three:
mov fortuneRevealed3D,3
invoke FortuneCardSpeech3D,2
jmp fortune_update_done
fortune_update_orb:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne fortune_update_done
cmp fortunePhase3D,1
jne fortune_orb_swirl
cmp fortunePhaseTime3D,1400
jb fortune_update_done
mov fortunePhase3D,2
mov fortunePhaseTime3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneFateSwirl3D
jmp fortune_update_done
fortune_orb_swirl:
cmp fortunePhase3D,2
jne fortune_update_done
cmp fortunePhaseTime3D,5000
jb fortune_update_done
mov fortunePhase3D,3
mov fortunePhaseTime3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneFateReveal3D
fortune_update_done:
ret
UpdateFortuneSession3D ENDP
HandleFortuneDialog3D PROC
call UpdateFortuneSession3D
invoke Pressed3D,1Bh
test eax,eax
jnz fortune_handle_exit
invoke Pressed3D,0Dh
test eax,eax
jnz fortune_handle_action
cmp mouseClick3D,0
je fortune_handle_done
mov mouseClick3D,0
cmp mouseY3D,227
jb fortune_handle_menu_click
cmp mouseY3D,239
ja fortune_handle_done
cmp mouseX3D,240
jae fortune_handle_exit
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_handle_done
cmp mouseX3D,172
jae fortune_handle_menu
cmp mouseX3D,88
jae fortune_handle_reset
jmp fortune_handle_action
fortune_handle_menu_click:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne fortune_handle_selection_click
cmp fortunePhase3D,0
jne fortune_handle_done
; Form uses physical pixels; mouse input here uses half-resolution units.
mov eax,mouseY3D
sub eax,162
jb fortune_handle_done
xor edx,edx
mov ecx,21
div ecx
cmp eax,2
ja fortune_handle_done
cmp edx,11
ja fortune_handle_done
shl eax,1
cmp mouseX3D,156
jb fortune_handle_form_left
cmp mouseX3D,168
jb fortune_handle_done
cmp mouseX3D,312
ja fortune_handle_done
inc eax
jmp fortune_handle_form_focus
fortune_handle_form_left:
cmp mouseX3D,8
jb fortune_handle_done
fortune_handle_form_focus:
mov fortuneFateField3D,eax
ret
fortune_handle_selection_click:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
jne fortune_handle_done
cmp mouseY3D,196
jb fortune_handle_done
cmp mouseY3D,214
ja fortune_handle_done
cmp mouseX3D,160
jae fortune_handle_orb
fortune_handle_tarot:
invoke FortuneChar3D,'1'
ret
fortune_handle_orb:
invoke FortuneChar3D,'2'
ret
fortune_handle_action:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_handle_tarot
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne @F
call SubmitFortuneFate3D
ret
@@:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_handle_done
cmp fortunePhase3D,0
je fortune_handle_submit
; Continue only after this speech is fully visible. Never skip dealing/flips.
mov eax,fortuneSpeechLength3D
imul eax,28
cmp fortuneSpeechTime3D,eax
jb fortune_handle_done
mov eax,fortunePhase3D
cmp eax,6
je fortune_handle_advance
cmp eax,8
je fortune_handle_advance
cmp eax,10
je fortune_handle_advance
cmp eax,11
jne fortune_handle_done
fortune_handle_advance:
mov eax,fortuneDurations3D[eax*4]
mov fortunePhaseTime3D,eax
ret
fortune_handle_submit:
call SubmitFortuneQuestion3D
ret
fortune_handle_menu:
mov fortuneSubMode3D,FORTUNE_SUBMODE_MENU
mov fortunePhase3D,0
mov fortuneDealt3D,0
mov fortuneRevealed3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneWelcome3D
ret
fortune_handle_reset:
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne @F
cmp fortunePhase3D,3
jne fortune_handle_done
cmp fortunePhaseTime3D,1200
jb fortune_handle_done
mov fortunePhase3D,0
mov fortunePhaseTime3D,0
mov fortuneFateResult3D,-1
invoke SetFortuneSpeech3D,OFFSET fortuneFateReady3D
ret
@@:
cmp fortunePhase3D,12
jne fortune_handle_done
mov fortunePhase3D,0
mov fortuneDealt3D,0
mov fortuneRevealed3D,0
mov fortuneQuestionLength3D,0
mov fortuneQuestion3D,0
invoke SetFortuneSpeech3D,OFFSET fortuneReady3D
ret
fortune_handle_exit:
call StopFortuneWorker3D
mov engineMode,MODE_WALK
call ClearKeys3D
fortune_handle_done:
ret
HandleFortuneDialog3D ENDP
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
; The bubble grows with visible glyphs, rather than allocating a full-screen panel.
DrawFortuneSpeech3D PROC uses ebx esi edi
local column:DWORD,row:DWORD,maxColumn:DWORD,visible:DWORD,glyphX:DWORD,glyphY:DWORD
mov eax,fortuneSpeechTime3D
xor edx,edx
mov ecx,28
div ecx
cmp eax,fortuneSpeechLength3D
jbe @F
mov eax,fortuneSpeechLength3D
@@:
mov visible,eax
mov fortuneSpeechVisible3D,eax
test eax,eax
jz fortune_bubble_done
mov column,0
mov row,0
mov maxColumn,0
xor esi,esi
fortune_bubble_measure:
cmp esi,visible
jae fortune_bubble_box
cmp fortuneSpeech3D[esi],10
je fortune_bubble_newline
inc column
mov eax,column
cmp eax,maxColumn
jbe @F
mov maxColumn,eax
@@:
cmp column,23
jb fortune_bubble_measure_next
fortune_bubble_newline:
mov column,0
inc row
fortune_bubble_measure_next:
inc esi
jmp fortune_bubble_measure
fortune_bubble_box:
mov eax,maxColumn
imul eax,8
add eax,20
mov fortuneSpeechWidth3D,eax
shr eax,1
mov ebx,eax
mov eax,row
inc eax
imul eax,12
add eax,20
mov fortuneSpeechHeight3D,eax
shr eax,1
invoke DrawBoxBorder,208,30,ebx,eax,000A1829h,006E9DB8h,1
mov column,0
mov row,0
xor esi,esi
fortune_bubble_glyph:
cmp esi,visible
jae fortune_bubble_done
mov al,fortuneSpeech3D[esi]
cmp al,10
je fortune_bubble_glyph_newline
mov fortuneGlyph3D,al
mov eax,column
imul eax,8
add eax,426
mov glyphX,eax
mov ebx,row
imul ebx,12
add ebx,70
mov eax,esi
inc eax
imul eax,28
mov edx,fortuneSpeechTime3D
sub edx,eax
cmp edx,84
jae @F
mov eax,84
sub eax,edx
shr eax,5
sub ebx,eax
@@:
mov glyphY,ebx
invoke DrawBuckshotText3D,glyphX,ebx,OFFSET fortuneGlyph3D,00D2E8F2h
inc column
cmp column,23
jb fortune_bubble_glyph_next
fortune_bubble_glyph_newline:
mov column,0
inc row
fortune_bubble_glyph_next:
inc esi
jmp fortune_bubble_glyph
fortune_bubble_done:
ret
DrawFortuneSpeech3D ENDP
DrawFortuneSessionCard3D PROC uses ebx esi edi slot:DWORD
local px:DWORD,py:DWORD,cw:DWORD,cardHeight:DWORD,face:DWORD,amount:DWORD
mov esi,slot
mov eax,esi
imul eax,100
add eax,198
mov px,eax
mov py,302
mov cw,72
mov cardHeight,96
mov face,44
cmp esi,fortuneRevealed3D
jae @F
mov eax,fortuneDrawCards3D[esi*4]
mov face,eax
@@:
cmp esi,fortuneDealt3D
jb fortune_card_flip_check
mov eax,fortunePhase3D
sub eax,2
cmp eax,esi
jne fortune_card_done
; Release at 40%, then carry the card from the hand to its table slot.
mov ebx,fortunePhaseTime3D
sub ebx,400
js fortune_card_done
cmp ebx,600
jbe @F
mov ebx,600
@@:
mov eax,px
sub eax,220
imul eax,ebx
cdq
mov ecx,600
idiv ecx
add eax,220
mov px,eax
mov eax,ebx
imul eax,40
xor edx,edx
div ecx
add eax,262
mov py,eax
jmp fortune_card_draw
fortune_card_flip_check:
mov eax,fortunePhase3D
sub eax,5
js fortune_card_draw
test eax,1
jnz fortune_card_draw
shr eax,1
cmp eax,esi
jne fortune_card_draw
cmp fortunePhase3D,9
ja fortune_card_draw
mov ebx,fortunePhaseTime3D
cmp ebx,400
jb fortune_card_flip_back
mov eax,fortuneDrawCards3D[esi*4]
mov face,eax
sub ebx,400
jmp fortune_card_flip_width
fortune_card_flip_back:
mov eax,400
sub eax,ebx
mov ebx,eax
fortune_card_flip_width:
imul ebx,72
mov eax,ebx
xor edx,edx
mov ecx,400
div ecx
cmp eax,2
jae @F
mov eax,2
@@:
mov cw,eax
mov ebx,72
sub ebx,eax
shr ebx,1
add px,ebx
fortune_card_draw:
invoke DrawAnimSprite3D,OFFSET fortuneSessionCards3D,face,px,py,cw,cardHeight
fortune_card_done:
ret
DrawFortuneSessionCard3D ENDP
RenderFortuneDialog3D PROC uses ebx esi edi
lea esi,fortuneBackground3D
lea edi,screenBuffer
mov ecx,SCREEN_SIZE
rep movsd
invoke DrawAnimSprite3D,OFFSET fortuneSessionRoom3D,0,0,0,640,480
cmp fortuneSessionRoom3D.pixels,0
jne @F
invoke DrawBoxBorder,4,4,312,36,000A1829h,006E9DB8h,1
invoke DrawBuckshotText3D,24,24,OFFSET fortuneMissing3D,00FFFFFFh
@@:
mov ebx,OFFSET fortuneSessionShuffle3D
xor esi,esi
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
je fortune_render_orb_hands
mov eax,fortunePhase3D
cmp eax,1
jne fortune_render_hand_deal
mov eax,fortunePhaseTime3D
xor edx,edx
mov ecx,25
div ecx
and eax,63
mov esi,eax
jmp fortune_render_hands
fortune_render_hand_deal:
cmp eax,2
jb fortune_render_hands
cmp eax,4
ja fortune_render_hand_gesture
mov ebx,OFFSET fortuneSessionDeal3D
mov eax,fortunePhaseTime3D
xor edx,edx
mov ecx,32
div ecx
cmp eax,31
jbe @F
mov eax,31
@@:
mov esi,eax
jmp fortune_render_hands
fortune_render_hand_gesture:
mov ebx,OFFSET fortuneSessionGesture3D
mov eax,fortunePhaseTime3D
shr eax,5
and eax,31
mov esi,eax
jmp fortune_render_hands
fortune_render_orb_hands:
cmp fortunePhase3D,0
je fortune_render_hands
mov ebx,OFFSET fortuneSessionOrbHands3D
mov eax,fortunePhaseTime3D
shr eax,5
and eax,31
mov esi,eax
fortune_render_hands:
invoke DrawAnimSprite3D,ebx,esi,134,32,280,250
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_render_menu
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
je fortune_render_orb
cmp fortunePhase3D,0
je fortune_render_input
invoke DrawAnimSprite3D,OFFSET fortuneSessionCards3D,44,142,300,30,40
xor esi,esi
fortune_render_cards:
invoke DrawFortuneSessionCard3D,esi
cmp esi,fortuneRevealed3D
jae @F
mov eax,esi
imul eax,100
add eax,198
invoke DrawBuckshotText3D,eax,288,fortuneRoleTexts3D[esi*4],00B9D4E7h
@@:
inc esi
cmp esi,3
jb fortune_render_cards
fortune_render_input:
invoke DrawBoxBorder,8,199,304,24,00081322h,0046637Fh,1
mov fortuneCaretX3D,24
mov fortuneCaretY3D,402
invoke FortuneWrap3D,OFFSET fortuneQuestion3D,402,4,0,00E8EFF4h
cmp fortunePhase3D,0
jne fortune_render_footer
test animationClock3D,200h
jnz fortune_render_footer
invoke DrawBuckshotText3D,fortuneCaretX3D,fortuneCaretY3D,OFFSET fortuneCaret3D,00FFFFFFh
jmp fortune_render_footer
fortune_render_menu:
invoke DrawBoxBorder,8,196,148,18,000D2136h,005D86A0h,1
invoke DrawBuckshotText3D,100,404,OFFSET fortuneTarot3D,00D2E8F2h
invoke DrawBoxBorder,164,196,148,18,000D2136h,005D86A0h,1
invoke DrawBuckshotText3D,364,404,OFFSET fortuneFate3D,00D2E8F2h
jmp fortune_render_footer
fortune_render_orb:
cmp fortunePhase3D,0
jne fortune_render_orb_active
call DrawFortuneFateForm3D
jmp fortune_render_footer
fortune_render_orb_active:
call ResolveFortuneOrb3D
invoke DrawAnimSprite3D,OFFSET fortuneSessionMist3D,fortuneOrbFrame3D,fortuneOrbX3D,fortuneOrbY3D,128,128
cmp fortunePhase3D,3
jne @F
call DrawFortuneFateResult3D
@@:
call DrawFortuneFateIdentity3D
fortune_render_footer:
call DrawFortuneSpeech3D
cmp fortuneSubMode3D,FORTUNE_SUBMODE_MENU
je fortune_render_exit_button
cmp fortuneSubMode3D,FORTUNE_SUBMODE_TAROT
jne fortune_render_fate_button
invoke DrawBoxBorder,8,227,76,12,000B1E30h,00445F75h,1
mov esi,OFFSET fortuneAsk3D
cmp fortunePhase3D,0
je @F
mov esi,OFFSET fortuneContinue3D
@@:
invoke DrawBuckshotText3D,24,458,esi,00CCE4F4h
jmp fortune_render_again_button
fortune_render_fate_button:
cmp fortunePhase3D,0
jne fortune_render_again_button
invoke DrawBoxBorder,8,227,76,12,000B1E30h,00445F75h,1
invoke DrawBuckshotText3D,24,458,OFFSET fortuneFateStart3D,00CCE4F4h
fortune_render_again_button:
invoke DrawBoxBorder,88,227,76,12,000B1E30h,00445F75h,1
mov esi,OFFSET fortuneAgain3D
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne @F
mov esi,OFFSET fortuneFateEdit3D
@@:
invoke DrawBuckshotText3D,192,458,esi,0091A8BCh
invoke DrawBoxBorder,172,227,64,12,000B1E30h,00445F75h,1
invoke DrawBuckshotText3D,368,458,OFFSET fortuneMenu3D,00CCE4F4h
fortune_render_exit_button:
invoke DrawBoxBorder,240,227,72,12,000B1E30h,00445F75h,1
invoke DrawBuckshotText3D,516,458,OFFSET fortuneExit3D,00CCE4F4h
ret
RenderFortuneDialog3D ENDP
ResetFortuneFate3D PROC uses edi
lea edi,fortuneFateLengths3D
xor eax,eax
mov ecx,6
rep stosd
lea edi,fortuneFateFields3D
mov ecx,96
rep stosd
mov fortuneFateField3D,0
mov fortuneFateResult3D,-1
mov fortuneFateFields3D[256],'9'
mov fortuneFateFields3D[320],'1'
mov fortuneFateFields3D[321],'0'
mov fortuneFateLengths3D[16],1
mov fortuneFateLengths3D[20],2
ret
ResetFortuneFate3D ENDP
FortuneFateChar3D PROC uses ebx esi edi character:DWORD
cmp fortunePhase3D,0
jne fate_char_done
mov ebx,fortuneFateField3D
cmp ebx,6
jae fate_char_done
mov eax,character
cmp eax,9
je fate_char_next
mov esi,ebx
shl esi,6
lea esi,fortuneFateFields3D[esi]
mov ecx,fortuneFateLengths3D[ebx*4]
cmp eax,8
je fate_char_backspace
cmp eax,32
jb fate_char_done
cmp eax,255
ja fate_char_done
cmp eax,127
je fate_char_done
cmp ecx,fortuneFateLimits3D[ebx*4]
jae fate_char_done
cmp ebx,2
je fate_char_date
cmp ebx,4
jae fate_char_digit
cmp eax,32
jne fate_char_store
test ecx,ecx
jz fate_char_done
cmp BYTE PTR [esi+ecx-1],32
je fate_char_done
jmp fate_char_store
fate_char_date:
cmp eax,'/'
jne @F
mov eax,'.'
@@:
cmp eax,'.'
jne fate_char_date_digit
cmp ecx,2
je fate_char_store
cmp ecx,5
je fate_char_store
jmp fate_char_done
fate_char_date_digit:
cmp eax,'0'
jb fate_char_done
cmp eax,'9'
ja fate_char_done
cmp ecx,2
je fate_char_date_dot
cmp ecx,5
jne fate_char_store
fate_char_date_dot:
mov BYTE PTR [esi+ecx],'.'
inc ecx
jmp fate_char_store
fate_char_digit:
cmp eax,'0'
jb fate_char_done
cmp eax,'9'
ja fate_char_done
fate_char_store:
mov [esi+ecx],al
inc ecx
mov fortuneFateLengths3D[ebx*4],ecx
mov BYTE PTR [esi+ecx],0
ret
fate_char_backspace:
test ecx,ecx
jz fate_char_done
dec ecx
mov fortuneFateLengths3D[ebx*4],ecx
mov BYTE PTR [esi+ecx],0
ret
fate_char_next:
inc ebx
cmp ebx,6
jb @F
xor ebx,ebx
@@:
mov fortuneFateField3D,ebx
fate_char_done:
ret
FortuneFateChar3D ENDP
; Validation is calendar-based, including leap years, not a birth-date heuristic.
ValidateFortuneBirth3D PROC uses ebx esi edi
local dayValue:DWORD,monthValue:DWORD
cmp fortuneFateLengths3D[8],10
jne fate_birth_bad
lea esi,fortuneFateFields3D[128]
cmp BYTE PTR [esi+2],'.'
jne fate_birth_bad
cmp BYTE PTR [esi+5],'.'
jne fate_birth_bad
xor ebx,ebx
xor edi,edi
fate_birth_parse:
movzx eax,BYTE PTR [esi+edi]
cmp edi,2
je fate_birth_day
cmp edi,5
je fate_birth_month
sub eax,'0'
cmp eax,9
ja fate_birth_bad
imul ebx,10
add ebx,eax
jmp fate_birth_next
fate_birth_day:
mov dayValue,ebx
xor ebx,ebx
jmp fate_birth_next
fate_birth_month:
mov monthValue,ebx
xor ebx,ebx
fate_birth_next:
inc edi
cmp edi,10
jb fate_birth_parse
cmp ebx,1900
jb fate_birth_bad
cmp ebx,2099
ja fate_birth_bad
mov eax,monthValue
dec eax
cmp eax,11
ja fate_birth_bad
movzx ecx,fortuneFateMonthDays3D[eax]
cmp eax,1
jne fate_birth_check_day
test ebx,3
jnz fate_birth_check_day
cmp ebx,1900
je fate_birth_check_day
inc ecx
fate_birth_check_day:
cmp dayValue,1
jb fate_birth_bad
cmp dayValue,ecx
ja fate_birth_bad
mov eax,1
ret
fate_birth_bad:
xor eax,eax
ret
ValidateFortuneBirth3D ENDP
ParseFortuneFateNumber3D PROC uses ebx esi slot:DWORD
mov eax,slot
mov ecx,fortuneFateLengths3D[eax*4]
test ecx,ecx
jz fate_number_bad
cmp ecx,3
ja fate_number_bad
shl eax,6
lea esi,fortuneFateFields3D[eax]
xor eax,eax
fate_number_parse:
movzx ebx,BYTE PTR [esi]
sub ebx,'0'
cmp ebx,9
ja fate_number_bad
imul eax,10
add eax,ebx
inc esi
loop fate_number_parse
cmp eax,100
ja fate_number_bad
ret
fate_number_bad:
mov eax,-1
ret
ParseFortuneFateNumber3D ENDP
SubmitFortuneFate3D PROC uses ebx
cmp fortuneSubMode3D,FORTUNE_SUBMODE_ORB
jne fate_submit_done
cmp fortunePhase3D,0
jne fate_submit_done
xor ebx,ebx
fate_submit_required:
cmp fortuneFateLengths3D[ebx*4],0
je fate_submit_missing
inc ebx
cmp ebx,6
jb fate_submit_required
call ValidateFortuneBirth3D
test eax,eax
jz fate_submit_date
invoke ParseFortuneFateNumber3D,4
cmp eax,-1
je fate_submit_low
mov fortuneFateLowValue3D,eax
invoke ParseFortuneFateNumber3D,5
cmp eax,-1
je fate_submit_high
cmp eax,fortuneFateLowValue3D
jb fate_submit_high
mov fortuneFateHighValue3D,eax
sub eax,fortuneFateLowValue3D
inc eax
; Exactly one draw, independent of identity. Renders and double clicks never reroll.
invoke RandomRange3D,eax
add eax,fortuneFateLowValue3D
mov fortuneFateResult3D,eax
mov fortunePhase3D,1
mov fortunePhaseTime3D,0
mov eax,animationClock3D
mov fortuneSessionClock3D,eax
invoke SetFortuneSpeech3D,OFFSET fortuneFateRising3D
fate_submit_done:
ret
fate_submit_missing:
mov fortuneFateField3D,ebx
invoke SetFortuneSpeech3D,OFFSET fortuneFateRequired3D
ret
fate_submit_date:
mov fortuneFateField3D,2
invoke SetFortuneSpeech3D,OFFSET fortuneFateDateError3D
ret
fate_submit_low:
mov fortuneFateField3D,4
jmp fate_submit_range
fate_submit_high:
mov fortuneFateField3D,5
fate_submit_range:
invoke SetFortuneSpeech3D,OFFSET fortuneFateRangeError3D
ret
SubmitFortuneFate3D ENDP
DrawFortuneFateForm3D PROC uses ebx esi edi
local px:DWORD,py:DWORD,edgeInk:DWORD
invoke DrawBoxBorder,8,149,304,74,00081322h,0046637Fh,1
invoke DrawBuckshotText3D,24,304,OFFSET fortuneFatePlay3D,0086ABBCh
xor esi,esi
fate_form_field:
mov eax,fortuneFateXs3D[esi*4]
mov px,eax
shr eax,1
mov ebx,fortuneFateYs3D[esi*4]
mov py,ebx
shr ebx,1
mov edgeInk,00314D65h
cmp esi,fortuneFateField3D
jne @F
mov edgeInk,0088DDEAh
@@:
invoke DrawBoxBorder,eax,ebx,144,11,000B1D30h,edgeInk,1
mov eax,px
add eax,8
mov ebx,py
sub ebx,9
invoke DrawBuckshotText3D,eax,ebx,fortuneFateLabels3D[esi*4],00A9C8D8h
mov edi,esi
shl edi,6
add edi,OFFSET fortuneFateFields3D
mov eax,px
add eax,8
mov ebx,py
add ebx,7
cmp esi,2
jne fate_form_value
cmp fortuneFateLengths3D[8],0
jne fate_form_value
invoke DrawBuckshotText3D,eax,ebx,OFFSET fortuneFateHint3D,005A7A95h
jmp fate_form_caret
fate_form_value:
invoke DrawBuckshotText3D,eax,ebx,edi,00E8EFF4h
fate_form_caret:
cmp esi,fortuneFateField3D
jne fate_form_next
test animationClock3D,200h
jnz fate_form_next
mov eax,fortuneFateLengths3D[esi*4]
shl eax,3
add eax,px
add eax,8
mov ebx,py
add ebx,7
invoke DrawBuckshotText3D,eax,ebx,OFFSET fortuneCaret3D,00B8F3FFh
fate_form_next:
inc esi
cmp esi,6
jb fate_form_field
ret
DrawFortuneFateForm3D ENDP
DrawFortuneFateIdentity3D PROC uses ebx esi edi
invoke DrawBoxBorder,8,190,304,33,00081322h,0046637Fh,1
xor esi,esi
fate_identity_field:
mov eax,fortuneFateXs3D[esi*4]
add eax,8
mov ebx,esi
shr ebx,1
imul ebx,20
add ebx,388
mov edi,esi
shl edi,6
add edi,OFFSET fortuneFateFields3D
cmp esi,4
jb @F
invoke DrawBuckshotText3D,eax,ebx,fortuneFateLabels3D[esi*4],0086ABBCh
mov eax,fortuneFateXs3D[esi*4]
add eax,40
@@:
invoke DrawBuckshotText3D,eax,ebx,edi,00E8EFF4h
inc esi
cmp esi,6
jb fate_identity_field
ret
DrawFortuneFateIdentity3D ENDP
; One resolver supplies the frame, sprite placement and its measured glass centre.
ResolveFortuneOrb3D PROC uses ebx
mov eax,fortunePhaseTime3D
shr eax,6
and eax,15
mov fortuneOrbFrame3D,eax
mov ebx,eax
mov fortuneOrbX3D,214
mov fortuneOrbY3D,195
cmp fortunePhase3D,1
jne fate_orb_anchor
mov eax,fortunePhaseTime3D
cmp eax,1400
jbe @F
mov eax,1400
@@:
imul eax,135
xor edx,edx
mov ecx,1400
div ecx
mov ecx,330
sub ecx,eax
mov fortuneOrbY3D,ecx
fate_orb_anchor:
mov eax,fortuneOrbAnchorX3D[ebx*4]
add eax,128
shr eax,8
add eax,fortuneOrbX3D
mov fortuneOrbCenterX3D,eax
mov eax,fortuneOrbAnchorY3D[ebx*4]
add eax,128
shr eax,8
add eax,fortuneOrbY3D
mov fortuneOrbCenterY3D,eax
ret
ResolveFortuneOrb3D ENDP
DrawFortuneFateResult3D PROC uses ebx esi edi
local numberX:DWORD,numberY:DWORD
cmp fortuneFateResult3D,100
ja fate_result_done
invoke FormatNumber,fortuneFateResult3D,OFFSET fortuneFateNumber3D
lea edi,fortuneFateNumber3D
xor ebx,ebx
fate_result_length:
cmp BYTE PTR [edi+ebx],0
je fate_result_place
inc ebx
jmp fate_result_length
fate_result_place:
dec ebx
imul ebx,20
add ebx,32
shr ebx,1
neg ebx
add ebx,fortuneOrbCenterX3D
mov numberX,ebx
mov eax,fortuneOrbCenterY3D
sub eax,24
mov numberY,eax
; Fade into the mist at a constant size; preserve opacity for later draws.
push animOpacity3D
mov eax,fortunePhaseTime3D
cmp eax,900
jbe @F
mov eax,900
@@:
imul eax,255
xor edx,edx
mov ecx,900
div ecx
mov animOpacity3D,eax
fate_result_digit:
movzx esi,BYTE PTR [edi]
test esi,esi
jz fate_result_restore
sub esi,'0'
invoke DrawAnimSprite3D,OFFSET fortuneSessionNumerals3D,esi,numberX,numberY,32,48
add numberX,20
inc edi
jmp fate_result_digit
fate_result_restore:
pop animOpacity3D
fate_result_done:
ret
DrawFortuneFateResult3D ENDP