feat: add startup briefing and entry music
Sequence studio, texture AI disclosure and MASM code comparison before arrival. Show a typed hall briefing after admission. Start the jukebox at 50% user volume on hall entry. Apply positional gain before playback to avoid a full-volume startup burst.
This commit is contained in:
parent
3150d217b5
commit
24d66ddf0e
22 changed files with 1171 additions and 7 deletions
|
|
@ -33,11 +33,18 @@ $6,660; death/retry preserves the casino bank. See
|
||||||
|
|
||||||
## Native Entrance And Character Scenes
|
## Native Entrance And Character Scenes
|
||||||
|
|
||||||
The graphical startup now fades from Eblan Games into a first-person opening:
|
The graphical startup runs Eblan Games, a Russian AI-use disclosure and a
|
||||||
|
side-by-side C++/MASM code fact before the first-person opening:
|
||||||
eyes opening beneath a cloudy rainy sky, smoking in an alley, discarding the
|
eyes opening beneath a cloudy rainy sky, smoking in an alley, discarding the
|
||||||
cigarette, walking and turning through a separate city map, then meeting the
|
cigarette, walking and turning through a separate city map, then meeting the
|
||||||
guards and choosing a local profile before entering the walkable hall.
|
guards and choosing a local profile before entering the walkable hall.
|
||||||
The sequence resets on every launch; the intro advances automatically.
|
The sequence resets on every launch; the intro advances automatically.
|
||||||
|
Enter/Space advances one startup page; Escape skips to the opening scene.
|
||||||
|
After profile admission and entry into the hall, a centred cyberpunk briefing
|
||||||
|
unfolds from a point and types version 4.0, game information and controls.
|
||||||
|
The jukebox starts on entry at 50% volume, with normal positional attenuation.
|
||||||
|
Enter completes the text, then closes it; Escape closes immediately. Movement
|
||||||
|
is blocked while the briefing is open. See [startup and briefing](docs/STARTUP_PRESENTATION.md).
|
||||||
Sidorovich operates the native
|
Sidorovich operates the native
|
||||||
card-back shop. New character sheets contain 32 guard poses and 24 merchant
|
card-back shop. New character sheets contain 32 guard poses and 24 merchant
|
||||||
poses, with separate actions rather than a single repeated idle animation.
|
poses, with separate actions rather than a single repeated idle animation.
|
||||||
|
|
|
||||||
BIN
bin/poker.exe
BIN
bin/poker.exe
Binary file not shown.
|
|
@ -8,7 +8,7 @@ namespace AssemblerCasinoLauncher
|
||||||
{
|
{
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
const string ExpectedPokerSha256 = "2357F5876DA47FD6CD7FAE7216C71FCEDE6CCA79C1591E2BA6CFD2F3DB61694E";
|
const string ExpectedPokerSha256 = "3D0237E09CAED350548457BFAB24C4D67D6FAFC3D689C2D87C8BE360B64EC0AF";
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
|
|
|
||||||
Binary file not shown.
16
casino3d.inc
16
casino3d.inc
|
|
@ -150,6 +150,8 @@ include src_graphics\platform_data.inc
|
||||||
include src_graphics\casino_actions_data.inc
|
include src_graphics\casino_actions_data.inc
|
||||||
include src_graphics\audio_data.inc
|
include src_graphics\audio_data.inc
|
||||||
include src_graphics\startup_data.inc
|
include src_graphics\startup_data.inc
|
||||||
|
include src_graphics\presentation_text.inc
|
||||||
|
include src_graphics\presentation_data.inc
|
||||||
include src_graphics\card_tables_data.inc
|
include src_graphics\card_tables_data.inc
|
||||||
include src_graphics\native_durak_data.inc
|
include src_graphics\native_durak_data.inc
|
||||||
include src_graphics\scene_animation_data.inc
|
include src_graphics\scene_animation_data.inc
|
||||||
|
|
@ -4497,6 +4499,8 @@ unlock_done:
|
||||||
UnlockMouse3D ENDP
|
UnlockMouse3D ENDP
|
||||||
|
|
||||||
UpdateMouseLockState PROC
|
UpdateMouseLockState PROC
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne unlock_it
|
||||||
cmp engineMode,MODE_HELL_FPS
|
cmp engineMode,MODE_HELL_FPS
|
||||||
je lock_interior_check
|
je lock_interior_check
|
||||||
cmp engineMode,MODE_STAIRS
|
cmp engineMode,MODE_STAIRS
|
||||||
|
|
@ -5241,6 +5245,7 @@ include src_graphics\audio_code.inc
|
||||||
include src_graphics\dice_animation.inc
|
include src_graphics\dice_animation.inc
|
||||||
include src_graphics\russian_roulette.inc
|
include src_graphics\russian_roulette.inc
|
||||||
include src_graphics\startup_code.inc
|
include src_graphics\startup_code.inc
|
||||||
|
include src_graphics\presentation_code.inc
|
||||||
include src_graphics\card_table_assets.inc
|
include src_graphics\card_table_assets.inc
|
||||||
include src_graphics\poker_evaluator.inc
|
include src_graphics\poker_evaluator.inc
|
||||||
include src_graphics\native_poker.inc
|
include src_graphics\native_poker.inc
|
||||||
|
|
@ -5341,6 +5346,11 @@ engine_observer_skip:
|
||||||
invoke Pressed3D, 1Bh
|
invoke Pressed3D, 1Bh
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz engine_tick
|
jz engine_tick
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
je @F
|
||||||
|
call CloseWelcome3D
|
||||||
|
jmp engine_tick
|
||||||
|
@@:
|
||||||
cmp engineMode,MODE_HELL_FPS
|
cmp engineMode,MODE_HELL_FPS
|
||||||
jne @F
|
jne @F
|
||||||
call LeaveHellFPS3D
|
call LeaveHellFPS3D
|
||||||
|
|
@ -5441,6 +5451,12 @@ check_walk_mode:
|
||||||
@@:
|
@@:
|
||||||
cmp engineMode, MODE_WALK
|
cmp engineMode, MODE_WALK
|
||||||
jne check_slots_mode
|
jne check_slots_mode
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
je welcome_walk_ready
|
||||||
|
call HandleWelcome3D
|
||||||
|
call RenderWelcomeScene3D
|
||||||
|
jmp present_frame
|
||||||
|
welcome_walk_ready:
|
||||||
cmp brActive3D,0
|
cmp brActive3D,0
|
||||||
jne engine_backrooms
|
jne engine_backrooms
|
||||||
call UpdateHall3D
|
call UpdateHall3D
|
||||||
|
|
|
||||||
BIN
dist/Assembler Casino.exe
vendored
BIN
dist/Assembler Casino.exe
vendored
Binary file not shown.
84
docs/STARTUP_PRESENTATION.md
Normal file
84
docs/STARTUP_PRESENTATION.md
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# Startup presentation and hall briefing
|
||||||
|
|
||||||
|
All runtime presentation, text, timing, input and drawing are MASM32. No browser,
|
||||||
|
video player, Python runtime or additional graphics dependency is introduced.
|
||||||
|
|
||||||
|
## Startup order
|
||||||
|
|
||||||
|
1. Existing Eblan Games animated logo (7 seconds; its F2 variant is retained).
|
||||||
|
2. Russian AI-use disclosure (10 seconds): artificial intelligence technologies
|
||||||
|
were used to create some game textures; third-party resources retain their
|
||||||
|
authors and licences.
|
||||||
|
3. Code fact (11 seconds): side-by-side editor-style C++ and MASM panels for
|
||||||
|
clearing the same 640×480 framebuffer. C++ is explicitly an illustrative
|
||||||
|
equivalent, not a second game runtime. MASM shows the actual clear operation
|
||||||
|
from `src_graphics/startup_sequence.inc`.
|
||||||
|
4. Existing first-person city opening, guards and profile selection.
|
||||||
|
|
||||||
|
Pages advance automatically. **Enter/Space** advances one page, clearing held
|
||||||
|
input so it cannot skip several screens at once. **Escape** skips the startup
|
||||||
|
pages and begins the existing city scene. Starting again resets all pages.
|
||||||
|
Existing missing-logo fallback still works; the two new pages need no art files.
|
||||||
|
|
||||||
|
## Post-entry briefing
|
||||||
|
|
||||||
|
After a guest/existing/new profile is admitted and the player enters the hall,
|
||||||
|
the jukebox starts **Bolden - Art Deco** on repeat at **50% user volume** (5/10).
|
||||||
|
Existing distance/floor attenuation still applies, so it sounds quieter away
|
||||||
|
from the cabinet. Volume is applied before playback, avoiding a full-volume
|
||||||
|
startup burst. No jukebox music plays during startup/profile selection.
|
||||||
|
Closing the briefing does not restart the track or reset volume; the existing
|
||||||
|
jukebox controls and +/- volume keys remain available after closing it.
|
||||||
|
|
||||||
|
At the same entry point, the centred panel deploys from a point: horizontal
|
||||||
|
expansion for 200 ms, then
|
||||||
|
vertical ease-out for 400 ms. Cyan/magenta rails and a scanning marker frame the
|
||||||
|
dark panel. The hall is rendered by the normal ASM renderer and dimmed beneath
|
||||||
|
it; movement, interactions and camera input do not run until the modal closes.
|
||||||
|
|
||||||
|
After deployment, Russian text types at one character per 18 ms with a blinking
|
||||||
|
cursor: version **4.0 / Windows x86**, engine, activities, controls
|
||||||
|
and profile persistence. Version follows the existing 4.0 build identity; this
|
||||||
|
change does not introduce a new release/version bump or alter save formats.
|
||||||
|
|
||||||
|
- **Enter/Space**: complete the text; press again to close.
|
||||||
|
- **Escape**: close immediately, without opening pause.
|
||||||
|
- **Enter game** button: same complete/close behaviour, with mouse input.
|
||||||
|
- No automatic dismissal; the information remains readable.
|
||||||
|
- Shown once per admission on each launch, not on returning from tables or Hell.
|
||||||
|
|
||||||
|
The core remains assembly-only; the pre-existing C# packaging tools and the
|
||||||
|
approved C++ fortune inference worker are separate from the game engine.
|
||||||
|
|
||||||
|
## Copy and implementation
|
||||||
|
|
||||||
|
- `tools/generators/make_presentation_text.py`: editable Russian copy; emits
|
||||||
|
numeric CP1251 declarations into `src_graphics/presentation_text.inc`.
|
||||||
|
- `src_graphics/presentation_data.inc`: timings, page/briefing state and API.
|
||||||
|
- `src_graphics/presentation_code.inc`: native bitmap text, code windows,
|
||||||
|
unfolding modal and typewriter.
|
||||||
|
- `src_graphics/startup_code.inc`: three-page sequencing.
|
||||||
|
- `src_graphics/arrival_scene.inc`: briefing starts after admission/entry only.
|
||||||
|
- `casino3d.inc`: modal input gate, mouse unlock and Escape handling.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python tools/generators/make_presentation_text.py
|
||||||
|
python tools/tests/check_presentation.py
|
||||||
|
python tools/tests/check_presentation.py --window
|
||||||
|
```
|
||||||
|
|
||||||
|
Tests compile the production procedures with an isolated ASM entry point. They
|
||||||
|
check automatic and key transitions, restart/reset, existing city-scene handoff,
|
||||||
|
guest admission, delayed modal trigger, deployment, typing and manual completion,
|
||||||
|
button/close input cleanup, and unchanged bank, RNG and player save files.
|
||||||
|
They also query actual MCI playback and gain after entry, verify silence before
|
||||||
|
admission, retain a changed volume and playback position across modal closure,
|
||||||
|
then exercise manual track selection and Stop. MCI gain assertions allow device
|
||||||
|
rounding (four units out of 1000); both success and failure close `jboxmusic`.
|
||||||
|
`--window` also presents 150 real Win32 frames.
|
||||||
|
|
||||||
|
Outputs: `build/scratch/presentation-00..11.png`, `presentation-contact.png` and
|
||||||
|
`presentation-window.png`. Existing action/arrival tests also check the revised
|
||||||
|
startup order and the new admission trigger.
|
||||||
|
|
@ -2072,7 +2072,14 @@ ENDIF
|
||||||
IFDEF HELL_FPS_TEST
|
IFDEF HELL_FPS_TEST
|
||||||
include tools/tests/hell_fps_test.inc
|
include tools/tests/hell_fps_test.inc
|
||||||
ENDIF
|
ENDIF
|
||||||
|
IFDEF PRESENTATION_TEST
|
||||||
|
include tools/tests/presentation_test.inc
|
||||||
|
ENDIF
|
||||||
main PROC
|
main PROC
|
||||||
|
IFDEF PRESENTATION_TEST
|
||||||
|
call RunPresentationTest3D
|
||||||
|
invoke ExitProcess,eax
|
||||||
|
ENDIF
|
||||||
IFDEF HELL_FPS_TEST
|
IFDEF HELL_FPS_TEST
|
||||||
IFDEF HELL_FPS_WINDOW_TEST
|
IFDEF HELL_FPS_WINDOW_TEST
|
||||||
call RunHellFPSWindowTest
|
call RunHellFPSWindowTest
|
||||||
|
|
|
||||||
BIN
poker.exe
BIN
poker.exe
Binary file not shown.
BIN
poker.obj
BIN
poker.obj
Binary file not shown.
|
|
@ -128,6 +128,10 @@ arrival_entry:
|
||||||
mov interactTargetId, 0
|
mov interactTargetId, 0
|
||||||
mov interactPromptPtr, 0
|
mov interactPromptPtr, 0
|
||||||
call ClearKeys3D
|
call ClearKeys3D
|
||||||
|
call BeginWelcome3D
|
||||||
|
; Start only after admission, with the normal positional attenuation.
|
||||||
|
mov jboxUserVolume, 5
|
||||||
|
invoke PlayJukeboxTrack3D, 0
|
||||||
ret
|
ret
|
||||||
arrival_profile_input:
|
arrival_profile_input:
|
||||||
invoke Pressed3D, 26h
|
invoke Pressed3D, 26h
|
||||||
|
|
@ -309,4 +313,3 @@ entry_rows_done:
|
||||||
invoke DrawString8x8, 223, 207, OFFSET entryConfirm3D, 00FFFFFFh
|
invoke DrawString8x8, 223, 207, OFFSET entryConfirm3D, 00FFFFFFh
|
||||||
ret
|
ret
|
||||||
DrawEntryProfileRows3D ENDP
|
DrawEntryProfileRows3D ENDP
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,11 +118,18 @@ PlayJukeboxTrack3D PROC uses ebx trackIndex:DWORD
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz jbox_play_stop_selected
|
jz jbox_play_stop_selected
|
||||||
invoke mciSendStringA, eax, 0, 0, 0
|
invoke mciSendStringA, eax, 0, 0, 0
|
||||||
invoke mciSendStringA, OFFSET jboxPlayCmd, 0, 0, 0
|
test eax, eax
|
||||||
|
jnz jbox_play_stop_selected
|
||||||
mov jboxCurrentTrack, ebx
|
mov jboxCurrentTrack, ebx
|
||||||
mov jboxIsPlaying, 1
|
mov jboxIsPlaying, 1
|
||||||
mov jboxEffectiveVolume, -1
|
mov jboxEffectiveVolume, -1
|
||||||
|
; Apply volume before play: never start a newly opened device at full gain.
|
||||||
call UpdateJukeboxAudio3D
|
call UpdateJukeboxAudio3D
|
||||||
|
invoke mciSendStringA, OFFSET jboxPlayCmd, 0, 0, 0
|
||||||
|
test eax, eax
|
||||||
|
jz jbox_play_done
|
||||||
|
call StopJukeboxTrack3D
|
||||||
|
jbox_play_done:
|
||||||
ret
|
ret
|
||||||
jbox_play_stop_selected:
|
jbox_play_stop_selected:
|
||||||
mov jboxCurrentTrack, -1
|
mov jboxCurrentTrack, -1
|
||||||
|
|
|
||||||
358
src_graphics/presentation_code.inc
Normal file
358
src_graphics/presentation_code.inc
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
; Native-pixel, CP1251 bitmap text. Count includes newlines for typewriter timing.
|
||||||
|
; Unlike DrawString8x8's 320x240 coordinates, this uses the full 640x480 frame.
|
||||||
|
PresentationText3D PROC uses esi edi ebx x:DWORD,y:DWORD,text:DWORD,ink:DWORD,scale:DWORD,limit:DWORD
|
||||||
|
local px:DWORD,py:DWORD,row:DWORD,col:DWORD,bits:DWORD,repeatY:DWORD,repeatX:DWORD
|
||||||
|
mov esi,text
|
||||||
|
mov eax,x
|
||||||
|
mov px,eax
|
||||||
|
mov eax,y
|
||||||
|
mov py,eax
|
||||||
|
pres_text_char:
|
||||||
|
cmp limit,0
|
||||||
|
je pres_text_done
|
||||||
|
movzx eax,BYTE PTR [esi]
|
||||||
|
test eax,eax
|
||||||
|
jz pres_text_done
|
||||||
|
inc esi
|
||||||
|
dec limit
|
||||||
|
cmp eax,10
|
||||||
|
jne pres_text_glyph
|
||||||
|
mov eax,x
|
||||||
|
mov px,eax
|
||||||
|
mov eax,scale
|
||||||
|
imul eax,11
|
||||||
|
add py,eax
|
||||||
|
jmp pres_text_char
|
||||||
|
pres_text_glyph:
|
||||||
|
lea edi,font8x8[eax*8]
|
||||||
|
mov row,0
|
||||||
|
pres_text_row:
|
||||||
|
mov eax,row
|
||||||
|
movzx ebx,BYTE PTR [edi+eax]
|
||||||
|
mov bits,ebx
|
||||||
|
mov col,0
|
||||||
|
pres_text_col:
|
||||||
|
test bits,80h
|
||||||
|
jz pres_text_next_col
|
||||||
|
mov repeatY,0
|
||||||
|
pres_text_repeat_y:
|
||||||
|
mov eax,row
|
||||||
|
imul eax,scale
|
||||||
|
add eax,py
|
||||||
|
add eax,repeatY
|
||||||
|
cmp eax,SCREEN_H
|
||||||
|
jae pres_text_next_y
|
||||||
|
imul eax,SCREEN_W
|
||||||
|
mov ebx,eax
|
||||||
|
mov repeatX,0
|
||||||
|
pres_text_repeat_x:
|
||||||
|
mov eax,col
|
||||||
|
imul eax,scale
|
||||||
|
add eax,px
|
||||||
|
add eax,repeatX
|
||||||
|
cmp eax,SCREEN_W
|
||||||
|
jae pres_text_next_x
|
||||||
|
add eax,ebx
|
||||||
|
mov edx,ink
|
||||||
|
mov screenBuffer[eax*4],edx
|
||||||
|
pres_text_next_x:
|
||||||
|
inc repeatX
|
||||||
|
mov eax,repeatX
|
||||||
|
cmp eax,scale
|
||||||
|
jb pres_text_repeat_x
|
||||||
|
pres_text_next_y:
|
||||||
|
inc repeatY
|
||||||
|
mov eax,repeatY
|
||||||
|
cmp eax,scale
|
||||||
|
jb pres_text_repeat_y
|
||||||
|
pres_text_next_col:
|
||||||
|
shl bits,1
|
||||||
|
inc col
|
||||||
|
cmp col,8
|
||||||
|
jb pres_text_col
|
||||||
|
inc row
|
||||||
|
cmp row,8
|
||||||
|
jb pres_text_row
|
||||||
|
mov eax,scale
|
||||||
|
shl eax,3
|
||||||
|
add px,eax
|
||||||
|
jmp pres_text_char
|
||||||
|
pres_text_done:
|
||||||
|
ret
|
||||||
|
PresentationText3D ENDP
|
||||||
|
|
||||||
|
RenderStartupNotice3D PROC uses ebx esi edi
|
||||||
|
local lineY:DWORD,ink:DWORD
|
||||||
|
invoke DrawBox,0,0,320,240,00060912h
|
||||||
|
; Quiet terminal grid, fixed geometry: never consumes gameplay RNG.
|
||||||
|
mov ebx,12
|
||||||
|
pres_notice_grid:
|
||||||
|
invoke DrawBox,0,ebx,320,1,000C1722h
|
||||||
|
add ebx,16
|
||||||
|
cmp ebx,240
|
||||||
|
jb pres_notice_grid
|
||||||
|
invoke DrawBox,20,26,3,22,00FFCE54h
|
||||||
|
invoke DrawBox,26,26,274,1,002C6875h
|
||||||
|
invoke DrawBox,20,212,280,1,002C6875h
|
||||||
|
cmp startupPage3D,STARTUP_AI
|
||||||
|
jne pres_notice_code
|
||||||
|
invoke PresentationText3D,56,60,OFFSET presAITag,004FE5E2h,1,-1
|
||||||
|
invoke PresentationText3D,56,88,OFFSET presAIHeader,00FFDF82h,2,-1
|
||||||
|
invoke PresentationText3D,40,156,OFFSET presAIBody,00CFDCE4h,2,-1
|
||||||
|
invoke PresentationText3D,56,378,OFFSET presAIFooter,004FE5E2h,1,-1
|
||||||
|
jmp pres_notice_footer
|
||||||
|
pres_notice_code:
|
||||||
|
invoke PresentationText3D,56,64,OFFSET presCodeHeader,00FFDF82h,2,-1
|
||||||
|
invoke PresentationText3D,40,112,OFFSET presCodeSub,00CFDCE4h,2,-1
|
||||||
|
invoke DrawBoxBorder,12,80,144,90,00080F1Bh,002D7C92h,1
|
||||||
|
invoke DrawBoxBorder,164,80,144,90,00080F1Bh,003BE8CAh,1
|
||||||
|
invoke DrawBox,13,81,142,14,0017283Ch
|
||||||
|
invoke DrawBox,165,81,142,14,00143435h
|
||||||
|
invoke PresentationText3D,36,170,OFFSET presCodeLeft,00D0DDEBh,1,-1
|
||||||
|
invoke PresentationText3D,340,170,OFFSET presCodeRight,0062F3D3h,1,-1
|
||||||
|
mov esi,0
|
||||||
|
mov lineY,204
|
||||||
|
pres_code_line:
|
||||||
|
mov ink,00C9D9E8h
|
||||||
|
cmp esi,0
|
||||||
|
jne @F
|
||||||
|
mov ink,00657D92h
|
||||||
|
@@:
|
||||||
|
invoke PresentationText3D,36,lineY,presCppLines[esi*4],ink,1,-1
|
||||||
|
invoke PresentationText3D,340,lineY,presAsmLines[esi*4],ink,1,-1
|
||||||
|
add lineY,17
|
||||||
|
inc esi
|
||||||
|
cmp esi,7
|
||||||
|
jb pres_code_line
|
||||||
|
invoke PresentationText3D,24,356,OFFSET presCodeCaption,00FFDF82h,2,-1
|
||||||
|
invoke PresentationText3D,40,386,OFFSET presCodeNote,009FB8C8h,1,-1
|
||||||
|
pres_notice_footer:
|
||||||
|
invoke PresentationText3D,40,448,OFFSET presNext,006F939Fh,1,-1
|
||||||
|
; Fade the notice in, then out at its own page boundary.
|
||||||
|
mov eax,startupElapsed3D
|
||||||
|
cmp eax,300
|
||||||
|
jae pres_notice_fade_out
|
||||||
|
shl eax,8
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,300
|
||||||
|
div ecx
|
||||||
|
invoke FadeCityFrame3D,eax
|
||||||
|
ret
|
||||||
|
pres_notice_fade_out:
|
||||||
|
mov ecx,startupPage3D
|
||||||
|
mov ebx,startupDurations3D[ecx*4]
|
||||||
|
sub ebx,400
|
||||||
|
cmp eax,ebx
|
||||||
|
jb pres_notice_done
|
||||||
|
sub eax,ebx
|
||||||
|
cmp eax,400
|
||||||
|
jbe @F
|
||||||
|
mov eax,400
|
||||||
|
@@:
|
||||||
|
shl eax,8
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,400
|
||||||
|
div ecx
|
||||||
|
neg eax
|
||||||
|
add eax,256
|
||||||
|
invoke FadeCityFrame3D,eax
|
||||||
|
pres_notice_done:
|
||||||
|
ret
|
||||||
|
RenderStartupNotice3D ENDP
|
||||||
|
|
||||||
|
BeginWelcome3D PROC
|
||||||
|
mov welcomeActive3D,1
|
||||||
|
mov welcomeElapsed3D,0
|
||||||
|
mov welcomeChars3D,0
|
||||||
|
mov paused3D,0
|
||||||
|
mov interactTargetId,0
|
||||||
|
mov interactPromptPtr,0
|
||||||
|
call ClearKeys3D
|
||||||
|
call UnlockMouse3D
|
||||||
|
ret
|
||||||
|
BeginWelcome3D ENDP
|
||||||
|
|
||||||
|
CloseWelcome3D PROC
|
||||||
|
mov welcomeActive3D,0
|
||||||
|
mov paused3D,0
|
||||||
|
call ClearKeys3D
|
||||||
|
ret
|
||||||
|
CloseWelcome3D ENDP
|
||||||
|
|
||||||
|
HandleWelcome3D PROC
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
je welcome_handle_done
|
||||||
|
mov eax,deltaTime3D
|
||||||
|
add welcomeElapsed3D,eax
|
||||||
|
cmp welcomeElapsed3D,WELCOME_OPEN_MS
|
||||||
|
jb welcome_handle_done
|
||||||
|
; Once manually completed, do not rewind the typewriter on the next frame.
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jae welcome_input
|
||||||
|
mov eax,welcomeElapsed3D
|
||||||
|
sub eax,WELCOME_OPEN_MS
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,WELCOME_CHAR_MS
|
||||||
|
div ecx
|
||||||
|
cmp eax,welcomeTextLength3D
|
||||||
|
jbe @F
|
||||||
|
mov eax,welcomeTextLength3D
|
||||||
|
@@:
|
||||||
|
mov welcomeChars3D,eax
|
||||||
|
welcome_input:
|
||||||
|
invoke Pressed3D,0Dh
|
||||||
|
test eax,eax
|
||||||
|
jnz welcome_confirm
|
||||||
|
invoke Pressed3D,20h
|
||||||
|
test eax,eax
|
||||||
|
jnz welcome_confirm
|
||||||
|
cmp mouseClick3D,0
|
||||||
|
je welcome_handle_done
|
||||||
|
cmp mouseX3D,212
|
||||||
|
jb welcome_handle_done
|
||||||
|
cmp mouseX3D,292
|
||||||
|
jae welcome_handle_done
|
||||||
|
cmp mouseY3D,184
|
||||||
|
jb welcome_handle_done
|
||||||
|
cmp mouseY3D,198
|
||||||
|
jae welcome_handle_done
|
||||||
|
welcome_confirm:
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jae welcome_close
|
||||||
|
mov welcomeChars3D,welcomeTextLength3D
|
||||||
|
call ClearKeys3D
|
||||||
|
ret
|
||||||
|
welcome_close:
|
||||||
|
call CloseWelcome3D
|
||||||
|
welcome_handle_done:
|
||||||
|
ret
|
||||||
|
HandleWelcome3D ENDP
|
||||||
|
|
||||||
|
RenderWelcomeScene3D PROC
|
||||||
|
; Frozen playable hall, not a replacement screenshot or second game runtime.
|
||||||
|
call UpdateCamera3D
|
||||||
|
call RenderCeilingAndFloor
|
||||||
|
call RenderWalls
|
||||||
|
call PrepareCityDepth3D
|
||||||
|
call RenderSprites
|
||||||
|
call RenderHall3D
|
||||||
|
call RenderHUD
|
||||||
|
call RenderWelcome3D
|
||||||
|
ret
|
||||||
|
RenderWelcomeScene3D ENDP
|
||||||
|
|
||||||
|
RenderWelcome3D PROC uses ebx esi edi
|
||||||
|
local halfW:DWORD,halfH:DWORD,left:DWORD,top:DWORD,wide:DWORD,panelH:DWORD
|
||||||
|
local cursorX:DWORD,cursorY:DWORD
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
je welcome_render_done
|
||||||
|
invoke FadeCityFrame3D,90
|
||||||
|
; Two-stage deployment: point -> horizontal line -> centred panel.
|
||||||
|
mov eax,welcomeElapsed3D
|
||||||
|
cmp eax,200
|
||||||
|
jae welcome_open_vertical
|
||||||
|
imul eax,140
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,200
|
||||||
|
div ecx
|
||||||
|
inc eax
|
||||||
|
mov halfW,eax
|
||||||
|
mov halfH,1
|
||||||
|
jmp welcome_panel_bounds
|
||||||
|
welcome_open_vertical:
|
||||||
|
mov halfW,140
|
||||||
|
sub eax,200
|
||||||
|
cmp eax,400
|
||||||
|
jbe @F
|
||||||
|
mov eax,400
|
||||||
|
@@:
|
||||||
|
; Ease-out quadratic: 1 - (1-t)^2, with bounded integer operands.
|
||||||
|
neg eax
|
||||||
|
add eax,400
|
||||||
|
imul eax,eax
|
||||||
|
imul eax,81
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,160000
|
||||||
|
div ecx
|
||||||
|
neg eax
|
||||||
|
add eax,82
|
||||||
|
mov halfH,eax
|
||||||
|
welcome_panel_bounds:
|
||||||
|
mov eax,160
|
||||||
|
sub eax,halfW
|
||||||
|
mov left,eax
|
||||||
|
mov eax,120
|
||||||
|
sub eax,halfH
|
||||||
|
mov top,eax
|
||||||
|
mov eax,halfW
|
||||||
|
shl eax,1
|
||||||
|
mov wide,eax
|
||||||
|
mov eax,halfH
|
||||||
|
shl eax,1
|
||||||
|
mov panelH,eax
|
||||||
|
invoke DrawBoxBorder,left,top,wide,panelH,0008101Bh,003EE7D8h,1
|
||||||
|
mov eax,left
|
||||||
|
add eax,wide
|
||||||
|
sub eax,2
|
||||||
|
invoke DrawBox,eax,top,2,panelH,00DC4B9Bh
|
||||||
|
cmp welcomeElapsed3D,WELCOME_OPEN_MS
|
||||||
|
jb welcome_render_done
|
||||||
|
; Chamfered corners, offset signal rails and a narrow animated scan line.
|
||||||
|
invoke DrawBox,20,38,4,4,0008101Bh
|
||||||
|
invoke DrawBox,296,198,4,4,0008101Bh
|
||||||
|
invoke DrawBox,24,34,46,2,003EE7D8h
|
||||||
|
invoke DrawBox,250,205,46,2,00DC4B9Bh
|
||||||
|
invoke DrawBox,30,70,260,1,00284E62h
|
||||||
|
invoke DrawBox,30,180,260,1,00284E62h
|
||||||
|
mov eax,welcomeElapsed3D
|
||||||
|
shr eax,5
|
||||||
|
xor edx,edx
|
||||||
|
mov ecx,100
|
||||||
|
div ecx
|
||||||
|
add edx,76
|
||||||
|
invoke DrawBox,22,edx,1,2,0058FFF0h
|
||||||
|
invoke PresentationText3D,60,90,OFFSET welcomeHeader,00FFE29Ah,2,-1
|
||||||
|
invoke PresentationText3D,60,120,OFFSET welcomeTag,006C9EB0h,1,-1
|
||||||
|
invoke PresentationText3D,60,154,OFFSET welcomeBody,00CDE9E8h,1,welcomeChars3D
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jae welcome_cursor_done
|
||||||
|
test welcomeElapsed3D,100h
|
||||||
|
jnz welcome_cursor_done
|
||||||
|
mov cursorX,60
|
||||||
|
mov cursorY,154
|
||||||
|
mov esi,OFFSET welcomeBody
|
||||||
|
mov edi,welcomeChars3D
|
||||||
|
welcome_cursor_scan:
|
||||||
|
test edi,edi
|
||||||
|
jz welcome_cursor_draw
|
||||||
|
cmp BYTE PTR [esi],10
|
||||||
|
jne welcome_cursor_column
|
||||||
|
mov cursorX,60
|
||||||
|
add cursorY,11
|
||||||
|
jmp welcome_cursor_next
|
||||||
|
welcome_cursor_column:
|
||||||
|
add cursorX,8
|
||||||
|
welcome_cursor_next:
|
||||||
|
inc esi
|
||||||
|
dec edi
|
||||||
|
jmp welcome_cursor_scan
|
||||||
|
welcome_cursor_draw:
|
||||||
|
invoke PresentationText3D,cursorX,cursorY,OFFSET welcomeCursor3D,0058FFF0h,1,1
|
||||||
|
welcome_cursor_done:
|
||||||
|
; Blinking activity indicator; no random flicker and no gameplay RNG changes.
|
||||||
|
mov eax,welcomeElapsed3D
|
||||||
|
test eax,200h
|
||||||
|
jnz @F
|
||||||
|
invoke DrawBox,280,49,7,2,0058FFF0h
|
||||||
|
@@:
|
||||||
|
invoke DrawBoxBorder,212,184,80,14,00172A38h,003EE7D8h,1
|
||||||
|
invoke PresentationText3D,436,376,OFFSET welcomeButton,006EF4DEh,1,-1
|
||||||
|
mov eax,OFFSET welcomeTypeHint
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jb @F
|
||||||
|
mov eax,OFFSET welcomeDoneHint
|
||||||
|
@@:
|
||||||
|
invoke PresentationText3D,60,380,eax,008EAFBEh,1,-1
|
||||||
|
welcome_render_done:
|
||||||
|
ret
|
||||||
|
RenderWelcome3D ENDP
|
||||||
27
src_graphics/presentation_data.inc
Normal file
27
src_graphics/presentation_data.inc
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
; All timings and presentation state are native ASM; no extra runtime or assets.
|
||||||
|
STARTUP_STUDIO equ 0
|
||||||
|
STARTUP_AI equ 1
|
||||||
|
STARTUP_CODE equ 2
|
||||||
|
WELCOME_OPEN_MS equ 600
|
||||||
|
WELCOME_CHAR_MS equ 18
|
||||||
|
BeginWelcome3D PROTO
|
||||||
|
HandleWelcome3D PROTO
|
||||||
|
CloseWelcome3D PROTO
|
||||||
|
RenderWelcome3D PROTO
|
||||||
|
RenderWelcomeScene3D PROTO
|
||||||
|
PresentationText3D PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
|
||||||
|
RenderStartupNotice3D PROTO
|
||||||
|
AdvanceStartup3D PROTO
|
||||||
|
.data
|
||||||
|
startupPage3D dd STARTUP_STUDIO
|
||||||
|
startupDurations3D dd 7000,10000,11000
|
||||||
|
welcomeActive3D dd 0
|
||||||
|
welcomeElapsed3D dd 0
|
||||||
|
welcomeChars3D dd 0
|
||||||
|
welcomeCursor3D db '_',0
|
||||||
|
welcomeTextLength3D equ welcomeBodyEnd-welcomeBody-1
|
||||||
|
presCppLines dd OFFSET presCpp0,OFFSET presCpp1,OFFSET presCpp2,OFFSET presCpp3
|
||||||
|
dd OFFSET presCpp4,OFFSET presCpp5,OFFSET presCpp6
|
||||||
|
presAsmLines dd OFFSET presAsm0,OFFSET presAsm1,OFFSET presAsm2,OFFSET presAsm3
|
||||||
|
dd OFFSET presAsm4,OFFSET presAsm5,OFFSET presAsm6
|
||||||
|
.code
|
||||||
86
src_graphics/presentation_text.inc
Normal file
86
src_graphics/presentation_text.inc
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
; Generated by tools/generators/make_presentation_text.py. CP1251 bytes.
|
||||||
|
.data
|
||||||
|
presNext db 69,78,84,69,82,32,47,32,83,80,65,67,69,58,32,196,192,203,220,216,197,32,32,32,69,83,67,58,32,207,208,206
|
||||||
|
db 207,211,209,210,200,210,220,0
|
||||||
|
presNextEnd label byte
|
||||||
|
presAIHeader db 206,193,32,200,209,207,206,203,220,199,206,194,192,205,200,200,32,65,73,0
|
||||||
|
presAIHeaderEnd label byte
|
||||||
|
presAITag db 84,82,65,78,83,80,65,82,69,78,67,89,32,78,79,84,73,67,69,32,47,32,48,49,0
|
||||||
|
presAITagEnd label byte
|
||||||
|
presAIBody db 194,32,232,227,240,229,32,229,241,242,252,32,236,224,242,229,240,232,224,235,251,44,32,241,238,231,228,224,237,237,251,229
|
||||||
|
db 10,241,32,239,238,236,238,249,252,254,32,232,241,234,243,241,241,242,226,229,237,237,238,227,238,32,232,237,242,229,235,235
|
||||||
|
db 229,234,242,224,46,10,10,207,240,232,32,241,238,231,228,224,237,232,232,32,247,224,241,242,232,32,242,229,234,241,242,243
|
||||||
|
db 240,32,232,227,240,251,10,232,241,239,238,235,252,231,238,226,224,235,232,241,252,32,242,229,245,237,238,235,238,227,232,232
|
||||||
|
db 10,232,241,234,243,241,241,242,226,229,237,237,238,227,238,32,232,237,242,229,235,235,229,234,242,224,46,10,10,210,224,234
|
||||||
|
db 230,229,32,232,241,239,238,235,252,231,243,254,242,241,255,32,241,242,238,240,238,237,237,232,229,32,240,229,241,243,240,241
|
||||||
|
db 251,46,10,200,245,32,224,226,242,238,240,251,32,232,32,235,232,246,229,237,231,232,232,32,241,238,245,240,224,237,229,237
|
||||||
|
db 251,46,0
|
||||||
|
presAIBodyEnd label byte
|
||||||
|
presAIFooter db 209,206,199,196,192,205,206,32,209,32,65,73,46,32,209,206,193,208,192,205,206,32,194,208,211,215,205,211,46,0
|
||||||
|
presAIFooterEnd label byte
|
||||||
|
presCodeHeader db 192,32,194,219,32,199,205,192,203,200,63,0
|
||||||
|
presCodeHeaderEnd label byte
|
||||||
|
presCodeSub db 200,195,208,206,194,206,201,32,196,194,200,198,206,202,32,205,192,207,200,209,192,205,32,205,192,32,77,65,83,77,51,50
|
||||||
|
db 0
|
||||||
|
presCodeSubEnd label byte
|
||||||
|
presCodeLeft db 67,43,43,32,47,32,207,208,200,204,197,208,0
|
||||||
|
presCodeLeftEnd label byte
|
||||||
|
presCodeRight db 77,65,83,77,32,47,32,202,206,196,32,221,210,206,201,32,200,195,208,219,0
|
||||||
|
presCodeRightEnd label byte
|
||||||
|
presCodeCaption db 206,196,205,192,32,199,192,196,192,215,192,32,45,32,196,194,192,32,223,199,219,202,192,46,0
|
||||||
|
presCodeCaptionEnd label byte
|
||||||
|
presCodeNote db 208,229,237,228,229,240,44,32,243,239,240,224,226,235,229,237,232,229,32,232,32,232,227,240,251,32,45,32,120,56,54,32
|
||||||
|
db 65,83,77,46,10,67,43,43,32,241,235,229,226,224,32,239,238,234,224,231,224,237,32,242,238,235,252,234,238,32,228,235
|
||||||
|
db 255,32,241,240,224,226,237,229,237,232,255,46,0
|
||||||
|
presCodeNoteEnd label byte
|
||||||
|
presCpp0 db 47,47,32,67,108,101,97,114,32,116,104,101,32,102,114,97,109,101,98,117,102,102,101,114,0
|
||||||
|
presCpp0End label byte
|
||||||
|
presCpp1 db 118,111,105,100,32,99,108,101,97,114,70,114,97,109,101,40,41,32,123,0
|
||||||
|
presCpp1End label byte
|
||||||
|
presCpp2 db 32,32,102,111,114,32,40,105,110,116,32,105,32,61,32,48,59,0
|
||||||
|
presCpp2End label byte
|
||||||
|
presCpp3 db 32,32,32,32,32,32,32,105,32,60,32,54,52,48,32,42,32,52,56,48,59,32,43,43,105,41,32,123,0
|
||||||
|
presCpp3End label byte
|
||||||
|
presCpp4 db 32,32,32,32,115,99,114,101,101,110,66,117,102,102,101,114,91,105,93,32,61,32,48,120,48,53,48,56,48,57,59,0
|
||||||
|
presCpp4End label byte
|
||||||
|
presCpp5 db 32,32,125,0
|
||||||
|
presCpp5End label byte
|
||||||
|
presCpp6 db 125,0
|
||||||
|
presCpp6End label byte
|
||||||
|
presAsm0 db 59,32,115,116,97,114,116,117,112,95,115,101,113,117,101,110,99,101,46,105,110,99,0
|
||||||
|
presAsm0End label byte
|
||||||
|
presAsm1 db 108,101,97,32,101,100,105,44,32,115,99,114,101,101,110,66,117,102,102,101,114,0
|
||||||
|
presAsm1End label byte
|
||||||
|
presAsm2 db 109,111,118,32,101,97,120,44,32,48,48,48,53,48,56,48,57,104,0
|
||||||
|
presAsm2End label byte
|
||||||
|
presAsm3 db 109,111,118,32,101,99,120,44,32,83,67,82,69,69,78,95,83,73,90,69,0
|
||||||
|
presAsm3End label byte
|
||||||
|
presAsm4 db 114,101,112,32,115,116,111,115,100,0
|
||||||
|
presAsm4End label byte
|
||||||
|
presAsm5 db 59,32,54,52,48,32,42,32,52,56,48,32,112,105,120,101,108,115,0
|
||||||
|
presAsm5End label byte
|
||||||
|
presAsm6 db 59,32,78,97,116,105,118,101,32,120,56,54,32,47,32,87,105,110,51,50,0
|
||||||
|
presAsm6End label byte
|
||||||
|
welcomeHeader db 65,83,83,69,77,66,76,69,82,32,67,65,83,73,78,79,0
|
||||||
|
welcomeHeaderEnd label byte
|
||||||
|
welcomeTag db 76,79,67,65,76,32,83,69,83,83,73,79,78,32,47,32,83,89,83,84,69,77,32,66,82,73,69,70,73,78,71,0
|
||||||
|
welcomeTagEnd label byte
|
||||||
|
welcomeBody db 62,32,194,197,208,209,200,223,32,52,46,48,32,47,32,87,73,78,68,79,87,83,32,120,56,54,10,10,196,238,225,240
|
||||||
|
db 238,32,239,238,230,224,235,238,226,224,242,252,32,226,32,65,115,115,101,109,98,108,101,114,32,67,97,115,105,110,111,46
|
||||||
|
db 10,202,224,231,232,237,238,32,241,32,241,238,225,241,242,226,229,237,237,251,236,32,50,46,53,68,45,228,226,232,230,234
|
||||||
|
db 238,236,10,237,224,32,224,241,241,229,236,225,235,229,240,229,32,77,65,83,77,51,50,46,10,10,194,237,243,242,240,232
|
||||||
|
db 58,32,234,224,240,242,238,247,237,251,229,32,232,227,240,251,44,32,224,226,242,238,236,224,242,251,44,10,225,238,243,235
|
||||||
|
db 232,237,227,44,32,225,232,235,252,255,240,228,44,32,241,229,234,240,229,242,251,32,232,32,239,238,245,238,228,32,226,32
|
||||||
|
db 192,228,46,10,10,87,65,83,68,32,45,32,228,226,232,230,229,237,232,229,46,32,204,251,248,252,32,45,32,238,241,236
|
||||||
|
db 238,242,240,46,10,69,32,45,32,226,231,224,232,236,238,228,229,233,241,242,226,232,229,46,32,69,83,67,32,45,32,239
|
||||||
|
db 224,243,231,224,46,10,207,240,238,227,240,229,241,241,32,241,238,245,240,224,237,255,229,242,241,255,32,226,32,226,224,248
|
||||||
|
db 229,236,32,239,240,238,244,232,235,229,46,0
|
||||||
|
welcomeBodyEnd label byte
|
||||||
|
welcomeTypeHint db 69,78,84,69,82,58,32,207,206,202,192,199,192,210,220,32,210,197,202,209,210,32,214,197,203,200,202,206,204,0
|
||||||
|
welcomeTypeHintEnd label byte
|
||||||
|
welcomeDoneHint db 69,78,84,69,82,32,47,32,69,83,67,58,32,199,192,202,208,219,210,220,32,200,32,205,192,215,192,210,220,32,200,195
|
||||||
|
db 208,211,0
|
||||||
|
welcomeDoneHintEnd label byte
|
||||||
|
welcomeButton db 194,206,201,210,200,32,194,32,200,195,208,211,0
|
||||||
|
welcomeButtonEnd label byte
|
||||||
|
.code
|
||||||
|
|
@ -70,6 +70,8 @@ BeginStartup3D PROC
|
||||||
mov interactTargetId, 0
|
mov interactTargetId, 0
|
||||||
mov interactPromptPtr, 0
|
mov interactPromptPtr, 0
|
||||||
mov startupElapsed3D, 0
|
mov startupElapsed3D, 0
|
||||||
|
mov startupPage3D, STARTUP_STUDIO
|
||||||
|
mov welcomeActive3D, 0
|
||||||
mov startupVariant3D, 0
|
mov startupVariant3D, 0
|
||||||
mov animationClock3D, 0
|
mov animationClock3D, 0
|
||||||
mov rr3d_state, RR_READY
|
mov rr3d_state, RR_READY
|
||||||
|
|
@ -89,12 +91,26 @@ FinishStartup3D PROC
|
||||||
ret
|
ret
|
||||||
FinishStartup3D ENDP
|
FinishStartup3D ENDP
|
||||||
|
|
||||||
|
AdvanceStartup3D PROC
|
||||||
|
cmp startupPage3D,STARTUP_CODE
|
||||||
|
jae startup_advance_finish
|
||||||
|
inc startupPage3D
|
||||||
|
mov startupElapsed3D,0
|
||||||
|
call ClearKeys3D
|
||||||
|
ret
|
||||||
|
startup_advance_finish:
|
||||||
|
call FinishStartup3D
|
||||||
|
ret
|
||||||
|
AdvanceStartup3D ENDP
|
||||||
|
|
||||||
HandleStartupInput3D PROC
|
HandleStartupInput3D PROC
|
||||||
mov eax, deltaTime3D
|
mov eax, deltaTime3D
|
||||||
add startupElapsed3D, eax
|
add startupElapsed3D, eax
|
||||||
invoke Pressed3D, 71h
|
invoke Pressed3D, 71h
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz @F
|
jz @F
|
||||||
|
cmp startupPage3D,STARTUP_STUDIO
|
||||||
|
jne @F
|
||||||
xor startupVariant3D, 1
|
xor startupVariant3D, 1
|
||||||
mov startupElapsed3D, 0
|
mov startupElapsed3D, 0
|
||||||
@@:
|
@@:
|
||||||
|
|
@ -105,18 +121,22 @@ HandleStartupInput3D PROC
|
||||||
test eax, eax
|
test eax, eax
|
||||||
jz startup_input_done
|
jz startup_input_done
|
||||||
startup_enter:
|
startup_enter:
|
||||||
call FinishStartup3D
|
call AdvanceStartup3D
|
||||||
startup_input_done:
|
startup_input_done:
|
||||||
cmp engineMode, MODE_INTRO
|
cmp engineMode, MODE_INTRO
|
||||||
jne @F
|
jne @F
|
||||||
cmp startupElapsed3D, 7000
|
mov ecx,startupPage3D
|
||||||
|
mov eax,startupElapsed3D
|
||||||
|
cmp eax,startupDurations3D[ecx*4]
|
||||||
jb @F
|
jb @F
|
||||||
call FinishStartup3D
|
call AdvanceStartup3D
|
||||||
@@:
|
@@:
|
||||||
ret
|
ret
|
||||||
HandleStartupInput3D ENDP
|
HandleStartupInput3D ENDP
|
||||||
|
|
||||||
RenderStartup3D PROC
|
RenderStartup3D PROC
|
||||||
|
cmp startupPage3D,STARTUP_STUDIO
|
||||||
|
jne startup_notice
|
||||||
cmp startupVariant3D, 0
|
cmp startupVariant3D, 0
|
||||||
jne startup_studio_variant
|
jne startup_studio_variant
|
||||||
cmp startupSequence3D, 0
|
cmp startupSequence3D, 0
|
||||||
|
|
@ -128,6 +148,9 @@ startup_studio_variant:
|
||||||
call RenderStudioStartup3D
|
call RenderStudioStartup3D
|
||||||
call FadeStartupOut3D
|
call FadeStartupOut3D
|
||||||
ret
|
ret
|
||||||
|
startup_notice:
|
||||||
|
call RenderStartupNotice3D
|
||||||
|
ret
|
||||||
RenderStartup3D ENDP
|
RenderStartup3D ENDP
|
||||||
|
|
||||||
FadeStartupOut3D PROC
|
FadeStartupOut3D PROC
|
||||||
|
|
|
||||||
69
tools/generators/make_presentation_text.py
Normal file
69
tools/generators/make_presentation_text.py
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
"""Compile Russian presentation copy to CP1251 byte declarations for MASM."""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
TEXT = {
|
||||||
|
'presNext': 'ENTER / SPACE: ДАЛЬШЕ ESC: ПРОПУСТИТЬ',
|
||||||
|
'presAIHeader': 'ОБ ИСПОЛЬЗОВАНИИ AI',
|
||||||
|
'presAITag': 'TRANSPARENCY NOTICE / 01',
|
||||||
|
'presAIBody': 'В игре есть материалы, созданные\n'
|
||||||
|
'с помощью искусственного интеллекта.\n\n'
|
||||||
|
'При создании части текстур игры\n'
|
||||||
|
'использовались технологии\n'
|
||||||
|
'искусственного интеллекта.\n\n'
|
||||||
|
'Также используются сторонние ресурсы.\n'
|
||||||
|
'Их авторы и лицензии сохранены.',
|
||||||
|
'presAIFooter': 'СОЗДАНО С AI. СОБРАНО ВРУЧНУ.',
|
||||||
|
'presCodeHeader': 'А ВЫ ЗНАЛИ?',
|
||||||
|
'presCodeSub': 'ИГРОВОЙ ДВИЖОК НАПИСАН НА MASM32',
|
||||||
|
'presCodeLeft': 'C++ / ПРИМЕР',
|
||||||
|
'presCodeRight': 'MASM / КОД ЭТОЙ ИГРЫ',
|
||||||
|
'presCodeCaption': 'ОДНА ЗАДАЧА — ДВА ЯЗЫКА.',
|
||||||
|
'presCodeNote': 'Рендер, управление и игры — x86 ASM.\n'
|
||||||
|
'C++ слева показан только для сравнения.',
|
||||||
|
'presCpp0': '// Clear the framebuffer',
|
||||||
|
'presCpp1': 'void clearFrame() {',
|
||||||
|
'presCpp2': ' for (int i = 0;',
|
||||||
|
'presCpp3': ' i < 640 * 480; ++i) {',
|
||||||
|
'presCpp4': ' screenBuffer[i] = 0x050809;',
|
||||||
|
'presCpp5': ' }',
|
||||||
|
'presCpp6': '}',
|
||||||
|
'presAsm0': '; startup_sequence.inc',
|
||||||
|
'presAsm1': 'lea edi, screenBuffer',
|
||||||
|
'presAsm2': 'mov eax, 00050809h',
|
||||||
|
'presAsm3': 'mov ecx, SCREEN_SIZE',
|
||||||
|
'presAsm4': 'rep stosd',
|
||||||
|
'presAsm5': '; 640 * 480 pixels',
|
||||||
|
'presAsm6': '; Native x86 / Win32',
|
||||||
|
'welcomeHeader': 'ASSEMBLER CASINO',
|
||||||
|
'welcomeTag': 'LOCAL SESSION / SYSTEM BRIEFING',
|
||||||
|
'welcomeBody': '> ВЕРСИЯ 4.0 / WINDOWS x86\n\n'
|
||||||
|
'Добро пожаловать в Assembler Casino.\n'
|
||||||
|
'Казино с собственным 2.5D-движком\n'
|
||||||
|
'на ассемблере MASM32.\n\n'
|
||||||
|
'Внутри: карточные игры, автоматы,\n'
|
||||||
|
'боулинг, бильярд, секреты и поход в Ад.\n\n'
|
||||||
|
'WASD — движение. Мышь — осмотр.\n'
|
||||||
|
'E — взаимодействие. ESC — пауза.\n'
|
||||||
|
'Прогресс сохраняется в вашем профиле.',
|
||||||
|
'welcomeTypeHint': 'ENTER: ПОКАЗАТЬ ТЕКСТ ЦЕЛИКОМ',
|
||||||
|
'welcomeDoneHint': 'ENTER / ESC: ЗАКРЫТЬ И НАЧАТЬ ИГРУ',
|
||||||
|
'welcomeButton': 'ВОЙТИ В ИГРУ',
|
||||||
|
}
|
||||||
|
TEXT = {name:text.replace('\u2014','-') for name,text in TEXT.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
lines = ['; Generated by tools/generators/make_presentation_text.py. CP1251 bytes.', '.data']
|
||||||
|
for name, text in TEXT.items():
|
||||||
|
data = text.encode('cp1251') + b'\0'
|
||||||
|
for offset in range(0,len(data),32):
|
||||||
|
prefix = f'{name} db ' if offset == 0 else ' db '
|
||||||
|
lines.append(prefix + ','.join(map(str, data[offset:offset+32])))
|
||||||
|
lines.append(f'{name}End label byte')
|
||||||
|
lines.append('.code')
|
||||||
|
(ROOT/'src_graphics/presentation_text.inc').write_bytes(('\n'.join(lines)+'\n').encode('ascii'))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
@ -202,6 +202,14 @@ RunArrivalTest3D PROC uses ebx esi edi
|
||||||
mov startupElapsed3D, 6990
|
mov startupElapsed3D, 6990
|
||||||
mov deltaTime3D, 16
|
mov deltaTime3D, 16
|
||||||
call HandleStartupInput3D
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_AI
|
||||||
|
jne arrival_test_fail
|
||||||
|
mov startupElapsed3D,10000
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_CODE
|
||||||
|
jne arrival_test_fail
|
||||||
|
mov startupElapsed3D,11000
|
||||||
|
call HandleStartupInput3D
|
||||||
cmp engineMode, MODE_ARRIVAL
|
cmp engineMode, MODE_ARRIVAL
|
||||||
jne arrival_test_fail
|
jne arrival_test_fail
|
||||||
cmp cityPhase3D, CITY_BLACK
|
cmp cityPhase3D, CITY_BLACK
|
||||||
|
|
@ -595,6 +603,9 @@ arrival_admit_sequence:
|
||||||
call HandleArrival3D
|
call HandleArrival3D
|
||||||
cmp engineMode, MODE_WALK
|
cmp engineMode, MODE_WALK
|
||||||
jne arrival_test_fail
|
jne arrival_test_fail
|
||||||
|
cmp welcomeActive3D,1
|
||||||
|
jne arrival_test_fail
|
||||||
|
call CloseWelcome3D
|
||||||
cmp playerY, (27*FP_1+FP_HALF)
|
cmp playerY, (27*FP_1+FP_HALF)
|
||||||
jne arrival_test_fail
|
jne arrival_test_fail
|
||||||
invoke CanWalk3D, playerX, playerY
|
invoke CanWalk3D, playerX, playerY
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,14 @@ action_studio_snapshots:
|
||||||
mov keys3D[57h], 1
|
mov keys3D[57h], 1
|
||||||
mov pressedKeys3D[45h], 1
|
mov pressedKeys3D[45h], 1
|
||||||
call HandleStartupInput3D
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_AI
|
||||||
|
jne action_fail_15
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_CODE
|
||||||
|
jne action_fail_15
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
call HandleStartupInput3D
|
||||||
cmp engineMode, MODE_ARRIVAL
|
cmp engineMode, MODE_ARRIVAL
|
||||||
jne action_fail_15
|
jne action_fail_15
|
||||||
cmp keys3D[57h], 0
|
cmp keys3D[57h], 0
|
||||||
|
|
@ -256,6 +264,9 @@ action_studio_snapshots:
|
||||||
jz action_fail_15
|
jz action_fail_15
|
||||||
mov pressedKeys3D[20h], 1
|
mov pressedKeys3D[20h], 1
|
||||||
call HandleStartupInput3D
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_AI
|
||||||
|
jne action_fail_15
|
||||||
|
call FinishStartup3D
|
||||||
cmp engineMode, MODE_ARRIVAL
|
cmp engineMode, MODE_ARRIVAL
|
||||||
jne action_fail_15
|
jne action_fail_15
|
||||||
cmp rngSeed3D, 12345678h
|
cmp rngSeed3D, 12345678h
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,12 @@ def test_code_structure():
|
||||||
assert "call RenderJukeboxVolumeHUD" in casino_inc
|
assert "call RenderJukeboxVolumeHUD" in casino_inc
|
||||||
assert "jboxUserVolume dd" in data_inc
|
assert "jboxUserVolume dd" in data_inc
|
||||||
assert "setaudio jboxmusic volume to" in data_inc
|
assert "setaudio jboxmusic volume to" in data_inc
|
||||||
|
play_proc = code_inc.split("PlayJukeboxTrack3D PROC", 1)[1].split("PlayJukeboxTrack3D ENDP", 1)[0]
|
||||||
|
assert play_proc.index("call UpdateJukeboxAudio3D") < play_proc.index("OFFSET jboxPlayCmd"), "Set gain before playback"
|
||||||
|
arrival_inc = (ROOT / "src_graphics/arrival_scene.inc").read_bytes().decode("cp1251")
|
||||||
|
entry = arrival_inc.split("arrival_entry:", 1)[1].split("arrival_profile_input:", 1)[0]
|
||||||
|
assert entry.index("mov engineMode, MODE_WALK") < entry.index("mov jboxUserVolume, 5")
|
||||||
|
assert "invoke PlayJukeboxTrack3D, 0" in entry
|
||||||
|
|
||||||
assert "call LoadJackboxArt3D" in world_inc
|
assert "call LoadJackboxArt3D" in world_inc
|
||||||
assert "call FreeJackboxArt3D" in world_inc
|
assert "call FreeJackboxArt3D" in world_inc
|
||||||
|
|
|
||||||
81
tools/tests/check_presentation.py
Normal file
81
tools/tests/check_presentation.py
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
"""Compile and verify real MASM startup pages and the post-admission briefing."""
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from PIL import Image, ImageChops, ImageDraw
|
||||||
|
from check_artifacts import toolchain
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = ROOT/'build/scratch'
|
||||||
|
sys.path.insert(0,str(ROOT/'tools/generators'))
|
||||||
|
from make_presentation_text import TEXT
|
||||||
|
|
||||||
|
|
||||||
|
def snapshot_runtime():
|
||||||
|
return {p:hashlib.sha256(p.read_bytes()).digest()
|
||||||
|
for p in (ROOT/'runtime').rglob('*') if p.is_file()}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--window',action='store_true')
|
||||||
|
args = parser.parse_args()
|
||||||
|
OUT.mkdir(parents=True,exist_ok=True)
|
||||||
|
# Prevent silent clipping of the Russian copy or a missing font character.
|
||||||
|
for name,text in TEXT.items():
|
||||||
|
assert all(len(line)<=39 for line in text.splitlines()),name
|
||||||
|
assert b'\x97' not in text.encode('cp1251'),name
|
||||||
|
before = snapshot_runtime()
|
||||||
|
ml,link = toolchain()
|
||||||
|
sdk = Path('C:/Program Files (x86)/Windows Kits/10/Lib')
|
||||||
|
lib = next(p/'um/x86' for p in sorted(sdk.iterdir(),reverse=True)
|
||||||
|
if (p/'um/x86/kernel32.lib').exists())
|
||||||
|
commands = [[ml,'/c','/coff','/Cp','/nologo','/I.','/DPRESENTATION_TEST=1',
|
||||||
|
'/Fobuild/scratch/presentation-test.obj','poker.asm'],
|
||||||
|
[link,'/nologo','/SUBSYSTEM:CONSOLE','/LIBPATH:'+str(lib),
|
||||||
|
'/OUT:build/scratch/presentation-test.exe','build/scratch/presentation-test.obj',
|
||||||
|
'kernel32.lib','winmm.lib','user32.lib','ws2_32.lib','gdi32.lib']]
|
||||||
|
if args.window:
|
||||||
|
commands[0].insert(1,'/DPRESENTATION_WINDOW_TEST=1')
|
||||||
|
try:
|
||||||
|
for command in commands:
|
||||||
|
subprocess.run(list(map(str,command)),cwd=ROOT,check=True,timeout=120)
|
||||||
|
result = subprocess.run([str(OUT/'presentation-test.exe')],cwd=ROOT,timeout=120)
|
||||||
|
assert result.returncode == 0,f'Native presentation check failed: {result.returncode:#x}'
|
||||||
|
finally:
|
||||||
|
assert before == snapshot_runtime(),'Test changed player saves'
|
||||||
|
frames=[]
|
||||||
|
for index in range(12):
|
||||||
|
raw = (OUT/f'presentation-{index:02}.bgra').read_bytes()
|
||||||
|
assert len(raw)==640*480*4
|
||||||
|
image=Image.frombytes('RGBA',(640,480),raw,'raw','BGRA').convert('RGB')
|
||||||
|
image.save(OUT/f'presentation-{index:02}.png')
|
||||||
|
frames.append(image)
|
||||||
|
assert len({im.tobytes() for im in frames})==len(frames),'Frozen/repeated presentation'
|
||||||
|
for index in (1,2):
|
||||||
|
assert len(frames[index].getcolors(640*480))>5,'Missing native text'
|
||||||
|
# Opening starts at screen centre and expands horizontally, then vertically.
|
||||||
|
for index in (3,4,5,6,7):
|
||||||
|
image=frames[index]
|
||||||
|
assert image.getpixel((320,240)) in ((62,231,216),(8,16,27),(220,75,155)),index
|
||||||
|
assert ImageChops.difference(frames[9],frames[11]).getbbox(),'Typewriter did not advance'
|
||||||
|
sheet=Image.new('RGB',(3*640,4*504),(8,12,20))
|
||||||
|
draw=ImageDraw.Draw(sheet)
|
||||||
|
for index,image in enumerate(frames):
|
||||||
|
x,y=index%3*640,index//3*504
|
||||||
|
sheet.paste(image,(x,y))
|
||||||
|
draw.text((x+12,y+484),f'Native ASM / {index:02}',fill='white')
|
||||||
|
sheet.save(OUT/'presentation-contact.png')
|
||||||
|
if args.window:
|
||||||
|
image=Image.frombytes('RGBA',(640,480),(OUT/'presentation-window.bgra').read_bytes(),'raw','BGRA')
|
||||||
|
image.convert('RGB').save(OUT/'presentation-window.png')
|
||||||
|
print('PASS: ordered startup, automatic/key/skip transitions, guest admission, '
|
||||||
|
'centred deployment, typewriter, input cleanup, 50% entry music, '
|
||||||
|
'MCI playback/volume, no modal restart, manual track/stop, unchanged saves/RNG/bank; '
|
||||||
|
'12 native captures'+('; 150 Win32 frames' if args.window else ''))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
main()
|
||||||
368
tools/tests/presentation_test.inc
Normal file
368
tools/tests/presentation_test.inc
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
; Exercise the shipping ASM startup, admission, overlay and input procedures.
|
||||||
|
.data
|
||||||
|
presTestStage dd 1
|
||||||
|
presTestIo dd 0
|
||||||
|
presTestPath db 'build\scratch\presentation-00.bgra',0
|
||||||
|
presTestWindow db 'build\scratch\presentation-window.bgra',0
|
||||||
|
presTestTimes dd 0,100,200,300,450,600,1200,2400,10000
|
||||||
|
presTestX dd 0
|
||||||
|
presTestY dd 0
|
||||||
|
presTestAngle dd 0
|
||||||
|
presTestBank dd 0
|
||||||
|
presTestRng dd 0
|
||||||
|
presTestMusicMode db 'status jboxmusic mode',0
|
||||||
|
presTestMusicVolume db 'status jboxmusic volume',0
|
||||||
|
presTestMusicPosition db 'status jboxmusic position',0
|
||||||
|
presTestMusicSeek db 'seek jboxmusic to 5000',0
|
||||||
|
presTestMusicReply db 64 dup(0)
|
||||||
|
.code
|
||||||
|
PresTestMusicNumber PROC uses esi ebx command:DWORD
|
||||||
|
invoke mciSendStringA,command,OFFSET presTestMusicReply,64,0
|
||||||
|
test eax,eax
|
||||||
|
jnz pres_music_number_failed
|
||||||
|
xor eax,eax
|
||||||
|
lea esi,presTestMusicReply
|
||||||
|
pres_music_number_digit:
|
||||||
|
movzx ebx,BYTE PTR [esi]
|
||||||
|
test ebx,ebx
|
||||||
|
jz pres_music_number_done
|
||||||
|
sub ebx,'0'
|
||||||
|
cmp ebx,9
|
||||||
|
ja pres_music_number_failed
|
||||||
|
imul eax,10
|
||||||
|
add eax,ebx
|
||||||
|
inc esi
|
||||||
|
jmp pres_music_number_digit
|
||||||
|
pres_music_number_failed:
|
||||||
|
mov eax,-1
|
||||||
|
pres_music_number_done:
|
||||||
|
ret
|
||||||
|
PresTestMusicNumber ENDP
|
||||||
|
|
||||||
|
PresTestCapture PROC uses ebx path:DWORD
|
||||||
|
invoke CreateFileA,path,40000000h,0,0,2,80h,0
|
||||||
|
cmp eax,-1
|
||||||
|
je pres_capture_failed
|
||||||
|
mov ebx,eax
|
||||||
|
invoke WriteFile,ebx,OFFSET screenBuffer,SCREEN_SIZE*4,OFFSET presTestIo,0
|
||||||
|
push eax
|
||||||
|
invoke CloseHandle,ebx
|
||||||
|
pop eax
|
||||||
|
ret
|
||||||
|
pres_capture_failed:
|
||||||
|
xor eax,eax
|
||||||
|
ret
|
||||||
|
PresTestCapture ENDP
|
||||||
|
|
||||||
|
RunPresentationTest3D PROC uses esi edi ebx
|
||||||
|
call InitPaths3D
|
||||||
|
call InitHall3D
|
||||||
|
call LoadTextures3D
|
||||||
|
call LoadHallAssets3D
|
||||||
|
call InitializeCasinoSprites3D
|
||||||
|
mov rngSeed3D,12345678h
|
||||||
|
mov bankroll,12345
|
||||||
|
mov keys3D[57h],1
|
||||||
|
call BeginStartup3D
|
||||||
|
cmp startupPage3D,STARTUP_STUDIO
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp keys3D[57h],0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov startupElapsed3D,2500
|
||||||
|
call RenderStartup3D
|
||||||
|
invoke PresTestCapture,OFFSET presTestPath
|
||||||
|
mov presTestStage,2
|
||||||
|
; No early transition. At the boundary, studio -> AI (not arrival).
|
||||||
|
mov startupElapsed3D,6999
|
||||||
|
mov deltaTime3D,0
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_STUDIO
|
||||||
|
jne pres_test_failed
|
||||||
|
mov deltaTime3D,1
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_AI
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp startupElapsed3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp engineMode,MODE_INTRO
|
||||||
|
jne pres_test_failed
|
||||||
|
mov startupElapsed3D,1000
|
||||||
|
call RenderStartup3D
|
||||||
|
mov presTestPath[28],'1'
|
||||||
|
invoke PresTestCapture,OFFSET presTestPath
|
||||||
|
; Enter skips only this page, and held movement keys cannot leak through.
|
||||||
|
mov keys3D[57h],1
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
mov deltaTime3D,0
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_CODE
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp keys3D[57h],0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov startupElapsed3D,1500
|
||||||
|
call RenderStartup3D
|
||||||
|
mov presTestPath[28],'2'
|
||||||
|
invoke PresTestCapture,OFFSET presTestPath
|
||||||
|
mov presTestStage,3
|
||||||
|
mov startupElapsed3D,11000
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp engineMode,MODE_ARRIVAL
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp arrivalState3D,ARRIVAL_WALK
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp cityPhase3D,CITY_BLACK
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxIsPlaying,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp startupPixels3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp startupSequence3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
; Full automatic order, followed by a fresh-launch reset and Escape path.
|
||||||
|
call BeginStartup3D
|
||||||
|
mov deltaTime3D,7000
|
||||||
|
call HandleStartupInput3D
|
||||||
|
mov deltaTime3D,10000
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp startupPage3D,STARTUP_CODE
|
||||||
|
jne pres_test_failed
|
||||||
|
mov deltaTime3D,11000
|
||||||
|
call HandleStartupInput3D
|
||||||
|
cmp engineMode,MODE_ARRIVAL
|
||||||
|
jne pres_test_failed
|
||||||
|
call BeginStartup3D
|
||||||
|
cmp startupPage3D,STARTUP_STUDIO
|
||||||
|
jne pres_test_failed
|
||||||
|
call FinishStartup3D
|
||||||
|
cmp engineMode,MODE_ARRIVAL
|
||||||
|
jne pres_test_failed
|
||||||
|
mov presTestStage,4
|
||||||
|
; Guest profile -> admission -> hall triggers the modal only after entry.
|
||||||
|
mov arrivalState3D,ARRIVAL_PROFILE
|
||||||
|
mov arrivalSelected3D,0
|
||||||
|
mov deltaTime3D,0
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
call HandleArrival3D
|
||||||
|
cmp arrivalConfirmed3D,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxIsPlaying,0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov deltaTime3D,1200
|
||||||
|
call HandleArrival3D
|
||||||
|
cmp arrivalState3D,ARRIVAL_ENTER
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxIsPlaying,0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov deltaTime3D,1400
|
||||||
|
call HandleArrival3D
|
||||||
|
cmp engineMode,MODE_WALK
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeActive3D,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeElapsed3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov presTestStage,41
|
||||||
|
cmp jboxIsPlaying,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxCurrentTrack,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxUserVolume,5
|
||||||
|
jne pres_test_failed
|
||||||
|
mov presTestStage,42
|
||||||
|
invoke mciSendStringA,OFFSET presTestMusicMode,OFFSET presTestMusicReply,64,0
|
||||||
|
test eax,eax
|
||||||
|
jnz pres_test_failed
|
||||||
|
cmp DWORD PTR presTestMusicReply,79616C70h ; "play" in "playing"
|
||||||
|
jne pres_test_failed
|
||||||
|
mov presTestStage,43
|
||||||
|
invoke PresTestMusicNumber,OFFSET presTestMusicVolume
|
||||||
|
cmp eax,-1
|
||||||
|
je pres_test_failed
|
||||||
|
cmp eax,500
|
||||||
|
ja pres_test_failed
|
||||||
|
test eax,eax
|
||||||
|
jz pres_test_failed
|
||||||
|
; Windows MCI rounds through device gain; allow a few units out of 1000.
|
||||||
|
sub eax,jboxEffectiveVolume
|
||||||
|
jns @F
|
||||||
|
neg eax
|
||||||
|
@@:
|
||||||
|
cmp eax,4
|
||||||
|
ja pres_test_failed
|
||||||
|
mov eax,playerX
|
||||||
|
mov presTestX,eax
|
||||||
|
mov eax,playerY
|
||||||
|
mov presTestY,eax
|
||||||
|
mov eax,playerAngle
|
||||||
|
mov presTestAngle,eax
|
||||||
|
mov eax,bankroll
|
||||||
|
mov presTestBank,eax
|
||||||
|
mov eax,rngSeed3D
|
||||||
|
mov presTestRng,eax
|
||||||
|
mov presTestStage,5
|
||||||
|
xor esi,esi
|
||||||
|
pres_test_overlay_frames:
|
||||||
|
mov eax,presTestTimes[esi*4]
|
||||||
|
mov welcomeElapsed3D,eax
|
||||||
|
mov deltaTime3D,0
|
||||||
|
call HandleWelcome3D
|
||||||
|
call RenderWelcomeScene3D
|
||||||
|
mov eax,esi
|
||||||
|
add al,'3'
|
||||||
|
cmp al,'9'
|
||||||
|
jbe @F
|
||||||
|
sub al,10
|
||||||
|
mov presTestPath[27],'1'
|
||||||
|
@@:
|
||||||
|
mov presTestPath[28],al
|
||||||
|
invoke PresTestCapture,OFFSET presTestPath
|
||||||
|
test eax,eax
|
||||||
|
jz pres_test_failed
|
||||||
|
inc esi
|
||||||
|
cmp esi,9
|
||||||
|
jb pres_test_overlay_frames
|
||||||
|
mov eax,presTestX
|
||||||
|
cmp eax,playerX
|
||||||
|
jne pres_test_failed
|
||||||
|
mov eax,presTestY
|
||||||
|
cmp eax,playerY
|
||||||
|
jne pres_test_failed
|
||||||
|
mov eax,presTestAngle
|
||||||
|
cmp eax,playerAngle
|
||||||
|
jne pres_test_failed
|
||||||
|
mov eax,presTestRng
|
||||||
|
cmp eax,rngSeed3D
|
||||||
|
jne pres_test_failed
|
||||||
|
mov eax,presTestBank
|
||||||
|
cmp eax,bankroll
|
||||||
|
jne pres_test_failed
|
||||||
|
mov presTestStage,6
|
||||||
|
; Put playback past zero: closing/reopening the modal must not restart it.
|
||||||
|
invoke mciSendStringA,OFFSET presTestMusicSeek,0,0,0
|
||||||
|
test eax,eax
|
||||||
|
jnz pres_test_failed
|
||||||
|
invoke mciSendStringA,OFFSET jboxPlayCmd,0,0,0
|
||||||
|
test eax,eax
|
||||||
|
jnz pres_test_failed
|
||||||
|
mov pressedKeys3D[0BDh],1
|
||||||
|
call HandleJukeboxKeys3D
|
||||||
|
cmp jboxUserVolume,4
|
||||||
|
jne pres_test_failed
|
||||||
|
; Early input cannot skip the deployment; typing completion is persistent.
|
||||||
|
call BeginWelcome3D
|
||||||
|
mov deltaTime3D,100
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeActive3D,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeChars3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
call ClearKeys3D
|
||||||
|
mov deltaTime3D,700
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeChars3D,0
|
||||||
|
je pres_test_failed
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jae pres_test_failed
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
mov keys3D[57h],1
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeActive3D,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp keys3D[57h],0
|
||||||
|
jne pres_test_failed
|
||||||
|
mov deltaTime3D,1
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeChars3D,welcomeTextLength3D
|
||||||
|
jne pres_test_failed
|
||||||
|
mov pressedKeys3D[0Dh],1
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp pressedKeys3D[0Dh],0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxUserVolume,4
|
||||||
|
jne pres_test_failed
|
||||||
|
invoke PresTestMusicNumber,OFFSET presTestMusicPosition
|
||||||
|
cmp eax,-1
|
||||||
|
je pres_test_failed
|
||||||
|
cmp eax,5000
|
||||||
|
jb pres_test_failed
|
||||||
|
; Escape uses the same clean close; click stays inside the button.
|
||||||
|
call BeginWelcome3D
|
||||||
|
call CloseWelcome3D
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp paused3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
call BeginWelcome3D
|
||||||
|
mov welcomeElapsed3D,10000
|
||||||
|
mov mouseX3D,220
|
||||||
|
mov mouseY3D,190
|
||||||
|
mov mouseClick3D,1
|
||||||
|
call HandleWelcome3D
|
||||||
|
cmp welcomeActive3D,0
|
||||||
|
jne pres_test_failed
|
||||||
|
IFDEF PRESENTATION_WINDOW_TEST
|
||||||
|
mov presTestStage,7
|
||||||
|
call Create3DWindow
|
||||||
|
test eax,eax
|
||||||
|
jz pres_test_failed
|
||||||
|
cmp fullscreen3D,0
|
||||||
|
je @F
|
||||||
|
call ToggleFullscreen3D
|
||||||
|
@@:
|
||||||
|
invoke SetWindowPos,h3DWnd,0,80,80,800,640,14h
|
||||||
|
call BeginWelcome3D
|
||||||
|
invoke ShowWindow,h3DWnd,4
|
||||||
|
mov esi,150
|
||||||
|
pres_test_window_frame:
|
||||||
|
invoke PeekMessageA,OFFSET msg3D,0,0,0,PM_REMOVE
|
||||||
|
test eax,eax
|
||||||
|
jz pres_test_window_tick
|
||||||
|
invoke TranslateMessage,OFFSET msg3D
|
||||||
|
invoke DispatchMessageA,OFFSET msg3D
|
||||||
|
jmp pres_test_window_frame
|
||||||
|
pres_test_window_tick:
|
||||||
|
mov deltaTime3D,50
|
||||||
|
call HandleWelcome3D
|
||||||
|
call RenderWelcomeScene3D
|
||||||
|
call Present3D
|
||||||
|
invoke Sleep,17
|
||||||
|
dec esi
|
||||||
|
jnz pres_test_window_frame
|
||||||
|
invoke PresTestCapture,OFFSET presTestWindow
|
||||||
|
call CloseWelcome3D
|
||||||
|
invoke DestroyWindow,h3DWnd
|
||||||
|
ENDIF
|
||||||
|
mov presTestStage,8
|
||||||
|
; Manual track switching and Stop still work after automatic entry playback.
|
||||||
|
invoke PlayJukeboxTrack3D,1
|
||||||
|
cmp jboxIsPlaying,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxCurrentTrack,1
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxUserVolume,4
|
||||||
|
jne pres_test_failed
|
||||||
|
call StopJukeboxTrack3D
|
||||||
|
cmp jboxIsPlaying,0
|
||||||
|
jne pres_test_failed
|
||||||
|
cmp jboxCurrentTrack,-1
|
||||||
|
jne pres_test_failed
|
||||||
|
call FreeStartupAssets3D
|
||||||
|
call FreeArrivalAssets3D
|
||||||
|
xor eax,eax
|
||||||
|
ret
|
||||||
|
pres_test_failed:
|
||||||
|
call StopJukeboxTrack3D
|
||||||
|
mov eax,presTestStage
|
||||||
|
ret
|
||||||
|
RunPresentationTest3D ENDP
|
||||||
Loading…
Add table
Reference in a new issue