KAZIK/tools/tests/hall_expansion_test.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

1182 lines
35 KiB
PHP

RoofTestCrashFilter PROTO :DWORD
.data
expansionStage dd 1
expansionOcclusionPixel dd 0
expansionGaitX dd 0
expansionGaitY dd 0
expansionGaitPhase dd 0
expansionDoorState dd 0
expansionBmpHeader db 42h,4Dh
dd 1228854
dw 0,0
dd 54,40,640,-480
dw 1,32
dd 0,1228800,0,0,0,0
expansionDoor db "build\hall-expansion\basement-door.bmp",0
expansionDoorWheel db "build\hall-expansion\door-wheel-turn.bmp",0
expansionDoorSwing db "build\hall-expansion\door-swing-half.bmp",0
expansionDoorClosing db "build\hall-expansion\door-closing.bmp",0
expansionDoorLocking db "build\hall-expansion\door-locking.bmp",0
expansionDoorShut db "build\hall-expansion\door-closed-again.bmp",0
expansionDoorBack db "build\hall-expansion\door-from-stairs.bmp",0
expansionFarUpper db "build\hall-expansion\upper-return-far.bmp",0
expansionFarEntry db "build\hall-expansion\upper-entry-far.bmp",0
expansionFarBasement db "build\hall-expansion\basement-return-far.bmp",0
expansionGait0 db "build\hall-expansion\gait-0.bmp",0
expansionGait1 db "build\hall-expansion\gait-1.bmp",0
expansionGait2 db "build\hall-expansion\gait-2.bmp",0
expansionGait3 db "build\hall-expansion\gait-3.bmp",0
expansionGait4 db "build\hall-expansion\gait-4.bmp",0
expansionGait5 db "build\hall-expansion\gait-5.bmp",0
expansionGait6 db "build\hall-expansion\gait-6.bmp",0
expansionGait7 db "build\hall-expansion\gait-7.bmp",0
expansionGaitPaths dd OFFSET expansionGait0,OFFSET expansionGait1,OFFSET expansionGait2,OFFSET expansionGait3
dd OFFSET expansionGait4,OFFSET expansionGait5,OFFSET expansionGait6,OFFSET expansionGait7
expansionStairs db "build\hall-expansion\upper-stairs.bmp",0
expansionStairsMid db "build\hall-expansion\upper-stairs-mid.bmp",0
expansionUpper db "build\hall-expansion\upper-lounge.bmp",0
expansionUpperBar db "build\hall-expansion\upper-bar.bmp",0
expansionJazz db "build\hall-expansion\cabaret-jazz.bmp",0
expansionJazz1 db "build\hall-expansion\cabaret-jazz-1.bmp",0
expansionJazz2 db "build\hall-expansion\cabaret-jazz-2.bmp",0
expansionJazz3 db "build\hall-expansion\cabaret-jazz-3.bmp",0
expansionChorus db "build\hall-expansion\cabaret-chorus.bmp",0
expansionCast db "build\hall-expansion\guest-cast.bmp",0
expansionUpEntry db "build\hall-expansion\upper-entrance-open.bmp",0
expansionUpReturn db "build\hall-expansion\upper-stair-return.bmp",0
expansionUpLanding db "build\hall-expansion\upper-landing-open.bmp",0
expansionUpExit db "build\hall-expansion\upper-exit-open.bmp",0
expansionDownClosed db "build\hall-expansion\old-basement-closed.bmp",0
expansionDownReturn db "build\hall-expansion\basement-stair-return.bmp",0
expansionDownLanding db "build\hall-expansion\basement-landing-open.bmp",0
expansionBunkerReturn db "build\hall-expansion\bunker-return-open.bmp",0
expansionPortalClosed db "build\hall-expansion\portal-closed.bmp",0
expansionBuckshotTable db "build\hall-expansion\upper-buckshot-table.bmp",0
expansionRussianTable db "build\hall-expansion\upper-russian-table.bmp",0
expansionBarWorld db "build\hall-expansion\upper-bar-world.bmp",0
expansionSeating db "build\hall-expansion\upper-seating.bmp",0
expansionLeverMid db "build\hall-expansion\lever-mid-pull.bmp",0
expansionPortalOff db "build\hall-expansion\portal-disabled.bmp",0
expansionLeverRelease db "build\hall-expansion\lever-mid-release.bmp",0
expansionPortal0 db "build\hall-expansion\portal-00.bmp",0
expansionPortal1 db "build\hall-expansion\portal-01.bmp",0
expansionPortal2 db "build\hall-expansion\portal-02.bmp",0
expansionPortal3 db "build\hall-expansion\portal-03.bmp",0
expansionPortal4 db "build\hall-expansion\portal-04.bmp",0
expansionPortal5 db "build\hall-expansion\portal-05.bmp",0
expansionPortal6 db "build\hall-expansion\portal-06.bmp",0
expansionPortal7 db "build\hall-expansion\portal-07.bmp",0
expansionPortal8 db "build\hall-expansion\portal-08.bmp",0
expansionPortal9 db "build\hall-expansion\portal-09.bmp",0
expansionPortal10 db "build\hall-expansion\portal-10.bmp",0
expansionPortal11 db "build\hall-expansion\portal-11.bmp",0
expansionPortalPaths dd OFFSET expansionPortal0,OFFSET expansionPortal1,OFFSET expansionPortal2,OFFSET expansionPortal3,OFFSET expansionPortal4,OFFSET expansionPortal5
dd OFFSET expansionPortal6,OFFSET expansionPortal7,OFFSET expansionPortal8,OFFSET expansionPortal9,OFFSET expansionPortal10,OFFSET expansionPortal11
.data?
expansionSinglePixels dd SCREEN_SIZE dup(?)
.code
ExpansionSnapshot PROC uses ebx path:DWORD
local count:DWORD
invoke CreateFileA,path,40000000h,0,0,2,80h,0
cmp eax,-1
je expansion_snapshot_fail
mov ebx,eax
invoke WriteFile,ebx,OFFSET expansionBmpHeader,54,ADDR count,0
invoke WriteFile,ebx,OFFSET screenBuffer,1228800,ADDR count,0
invoke CloseHandle,ebx
ret
expansion_snapshot_fail:
invoke ExitProcess,99
ret
ExpansionSnapshot ENDP
ExpansionFrame PROC
call UpdateCamera3D
cmp hallLevel3D,HALL_ROOF
je expansion_world_ready
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
call RenderSprites
expansion_world_ready:
call RenderHall3D
ret
ExpansionFrame ENDP
ExpansionWalkFrame PROC
add animationClock3D,16
call UpdateInteriorTravel3D
call HandlePlayerInput
call UpdateInteriorTravel3D
call UpdateInteriorEye3D
ret
ExpansionWalkFrame ENDP
ExpansionPortalSnapshot PROC path:DWORD
call UpdateInteriorEye3D
call ExpansionFrame
cmp portalPixelsWritten3D,1000
jae @F
invoke ExitProcess,expansionStage
@@:
invoke ExpansionSnapshot,path
ret
ExpansionPortalSnapshot ENDP
ExpansionDoorTicks PROC uses esi count:DWORD
mov esi,count
expansion_door_tick:
add animationClock3D,16
call UpdateBasementDoor3D
dec esi
jnz expansion_door_tick
ret
ExpansionDoorTicks ENDP
ExpansionTestStart PROC
invoke SetUnhandledExceptionFilter,OFFSET RoofTestCrashFilter
call InitPaths3D
call LoadTextures3D
call InitializeCasinoSprites3D
call InitHall3D
call LoadHallAssets3D
cmp npcGuestArt3D.pixels,0
je expansion_fail
cmp npcWalkArt3D.frames,48
jne expansion_fail
cmp npcWalkLeftArt3D.frames,48
jne expansion_fail
cmp basementDoorArt3D.frames,18
jne expansion_fail
cmp cabaretArt3D.pixels,0
je expansion_fail
cmp cabaretPianoArt3D.pixels,0
je expansion_fail
cmp cabaretGuitarArt3D.pixels,0
je expansion_fail
cmp upperPortalArt3D.frames,13
jne expansion_fail
cmp upperLeverArt3D.frames,6
jne expansion_fail
cmp upperBrazierArt3D.frames,4
jne expansion_fail
cmp scrStation3D.posX,29*FP_1
jne expansion_fail
cmp scrStation3D.posY,FP_1*15/2
jne expansion_fail
cmp upperFeltPixels3D[0],0FF1B5039h
jb expansion_fail
cmp upperKeyPixels3D[0],80000000h
jb expansion_fail
mov deltaTime3D,16
mov engineMode,MODE_WALK
mov hallLevel3D,0
mov expansionStage,2
invoke CanWalk3D,FP_1*289/10,FP_1*105/10
test eax,eax
jnz expansion_fail
mov playerX,27*FP_1
mov playerY,FP_1*105/10
mov playerAngle,0
add animationClock3D,16
call UpdateInteriorTravel3D
cmp engineMode,MODE_WALK
jne expansion_fail
cmp basementDoorTarget3D,FP_1
jne expansion_fail
cmp basementDoorOpen3D,0
jne expansion_fail
xor esi,esi
expansion_open_door:
add animationClock3D,16
call UpdateInteriorTravel3D
inc esi
cmp esi,20
jb expansion_open_door
cmp basementWheelTime3D,0
je expansion_fail
cmp basementDoorOpen3D,0
jne expansion_fail
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoorWheel
mov esi,50
expansion_door_swing:
add animationClock3D,16
call UpdateInteriorTravel3D
dec esi
jnz expansion_door_swing
cmp basementWheelTime3D,700
jne expansion_fail
cmp basementDoorOpen3D,0
je expansion_fail
cmp basementDoorOpen3D,FP_1
jae expansion_fail
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoorSwing
mov esi,50
expansion_finish_door:
add animationClock3D,16
call UpdateInteriorTravel3D
dec esi
jnz expansion_finish_door
cmp basementDoorOpen3D,FP_1
jne expansion_fail
invoke CanWalk3D,FP_1*289/10,FP_1*105/10
cmp eax,1
jne expansion_fail
mov playerX,27*FP_1
mov playerY,FP_1*105/10
mov playerAngle,0
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoor
mov expansionStage,3
mov keys3D[57h],1
xor esi,esi
expansion_down:
cmp engineMode,MODE_STAIRS
jne @F
cmp playerX,FP_1*165/10
jb @F
mov playerAngle,384
@@:
call ExpansionWalkFrame
cmp engineMode,MODE_WALK
jne @F
cmp hallLevel3D,1
je expansion_at_bunker
@@:
inc esi
cmp esi,800
jb expansion_down
jmp expansion_fail
expansion_at_bunker:
mov keys3D[57h],0
cmp playerAngle,384
jne expansion_fail
cmp worldMap3D,OFFSET bunkerMap3D
jne expansion_fail
mov expansionStage,4
mov playerAngle,128
mov keys3D[57h],1
xor esi,esi
expansion_up_basement:
cmp engineMode,MODE_STAIRS
jne @F
cmp playerY,21*FP_1
jb @F
mov playerAngle,256
@@:
call ExpansionWalkFrame
cmp engineMode,MODE_WALK
jne @F
cmp hallLevel3D,0
je expansion_back_hall
@@:
inc esi
cmp esi,800
jb expansion_up_basement
jmp expansion_fail
expansion_back_hall:
mov keys3D[57h],0
cmp playerX,28*FP_1-FP_1/10
jb expansion_fail
cmp playerX,FP_1*282/10
ja expansion_fail
mov expansionStage,5
mov playerX,FP_1*294/10
mov playerY,21*FP_1
mov playerAngle,0
mov keys3D[57h],1
xor esi,esi
expansion_upper_walk:
call ExpansionWalkFrame
cmp engineMode,MODE_WALK
jne @F
cmp hallLevel3D,2
je expansion_at_upper
@@:
inc esi
cmp esi,1100
jb expansion_upper_walk
jmp expansion_fail
expansion_at_upper:
mov keys3D[57h],0
cmp worldMap3D,OFFSET upperLoungeMap3D
jne expansion_fail
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionUpper
mov expansionStage,6
mov playerX,7*FP_1
mov playerY,FP_1*187/10
mov playerAngle,384
call UpdateCamera3D
call CheckInteractions
cmp interactTargetId,INTERACT_BUCKSHOT
jne expansion_fail
mov playerX,12*FP_1
mov playerY,FP_1*197/10
call CheckInteractions
cmp interactTargetId,INTERACT_RUSSIAN_ROULETTE
jne expansion_fail
mov playerX,9*FP_1
mov playerY,FP_1*221/10
mov playerX,FP_1*91/10
mov playerAngle,128
call UpdateCamera3D
call CheckInteractions
cmp interactTargetId,INTERACT_UPPER_LEFT
jne expansion_fail
mov playerX,13*FP_1
mov playerY,FP_1*163/10
mov playerAngle,384
call UpdateCamera3D
call CheckInteractions
cmp interactTargetId,INTERACT_BAR
jne expansion_fail
call TriggerHallInteraction3D
cmp engineMode,MODE_BAR
jne expansion_fail
call RenderBar3D
cmp playerX,13*FP_1
jne expansion_fail
cmp hallLevel3D,2
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionUpperBar
mov expansionStage,7
mov engineMode,MODE_WALK
mov playerX,4*FP_1
mov playerY,21*FP_1
mov playerAngle,256
mov keys3D[57h],1
xor esi,esi
expansion_descend_upper:
call ExpansionWalkFrame
cmp engineMode,MODE_WALK
jne @F
cmp hallLevel3D,0
je expansion_upper_returned
@@:
inc esi
cmp esi,1100
jb expansion_descend_upper
jmp expansion_fail
expansion_upper_returned:
mov keys3D[57h],0
; No key held: neither position nor floor changes even after a long wait.
mov engineMode,MODE_STAIRS
mov stairRoute3D,2
mov worldMap3D,OFFSET upperStairMap3D
mov floorTexture3D,85
mov playerX,7*FP_1
mov playerY,21*FP_1
mov playerAngle,0
mov deltaTime3D,5000
call HandleStairs3D
cmp playerX,7*FP_1
jne expansion_fail
cmp engineMode,MODE_STAIRS
jne expansion_fail
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionStairs
mov playerX,11*FP_1
call UpdateStairHeight3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionStairsMid
mov expansionStage,8
mov deltaTime3D,16
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
mov floorTexture3D,100
mov playerX,16*FP_1
mov playerY,FP_1*67/10
mov playerAngle,384
mov cabaretTime3D,30000
call UpdateCabaret3D
call BeginCabaret3D
mov animationClock3D,0
call RenderCabaret3D
invoke ExpansionSnapshot,OFFSET expansionJazz
mov animationClock3D,200
call RenderCabaret3D
cmp cabaretPiano3D.frame,1
jne expansion_fail
cmp cabaretGuitar3D.frame,1
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionJazz1
mov animationClock3D,400
call RenderCabaret3D
invoke ExpansionSnapshot,OFFSET expansionJazz2
mov animationClock3D,600
call RenderCabaret3D
cmp cabaretPiano3D.frame,3
jne expansion_fail
cmp cabaretGuitar3D.frame,3
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionJazz3
mov cabaretTime3D,0
call UpdateCabaret3D
call RenderCabaret3D
invoke ExpansionSnapshot,OFFSET expansionChorus
mov pressedKeys3D[45h],1
call HandleCabaret3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov bankroll,100
call BeginCabaret3D
mov mouseClick3D,1
mov mouseX3D,40
mov mouseY3D,220
call HandleCabaret3D
cmp bankroll,0
jne expansion_fail
mov mouseClick3D,1
call HandleCabaret3D
cmp bankroll,0
jne expansion_fail
mov mouseClick3D,1
mov mouseX3D,280
call HandleCabaret3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov expansionStage,9
; Each visitor maps to their own frame block, not the first man's idle pose.
mov playerX,16*FP_1
mov playerY,20*FP_1
mov playerAngle,384
xor esi,esi
expansion_cast_positions:
imul ebx,esi,SIZEOF NpcMindEntity
imul eax,esi,FP_1
add eax,FP_1*27/2
mov casinoNpcs3D[ebx].posX,eax
mov casinoNpcs3D[ebx].posY,16*FP_1
imul ebx,esi,SIZEOF NpcLife3D
mov npcLife3D[ebx].identity,esi
mov npcLife3D[ebx].state,NPC_STAND
inc esi
cmp esi,6
jb expansion_cast_positions
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionCast
mov hallLevel3D,2
mov worldMap3D,OFFSET upperLoungeMap3D
mov floorTexture3D,124
mov playerX,7*FP_1
mov playerY,FP_1*194/10
mov playerAngle,384
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionBuckshotTable
mov playerX,12*FP_1
mov playerY,FP_1*204/10
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionRussianTable
mov playerX,FP_1*125/10
mov playerY,FP_1*168/10
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionBarWorld
mov playerX,FP_1*56/10
mov playerY,FP_1*205/10
mov playerAngle,128
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionSeating
mov expansionStage,20
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
mov floorTexture3D,100
mov playerX,FP_1*285/10
mov playerY,21*FP_1
mov playerAngle,0
invoke ExpansionPortalSnapshot,OFFSET expansionUpEntry
invoke DrawCityVertical3D,0,29*FP_1,FP_1*208/10,FP_1*212/10,0,FP_1*22/10,122
mov eax,screenBuffer[(240*SCREEN_W+320)*4]
mov expansionOcclusionPixel,eax
call RenderInteriorViews3D
mov eax,screenBuffer[(240*SCREEN_W+320)*4]
cmp eax,expansionOcclusionPixel
jne expansion_fail
mov expansionStage,21
mov engineMode,MODE_STAIRS
mov stairRoute3D,2
mov worldMap3D,OFFSET upperStairMap3D
mov floorTexture3D,85
mov playerX,FP_1*48/10
mov playerAngle,256
invoke ExpansionPortalSnapshot,OFFSET expansionUpReturn
mov expansionStage,22
mov playerX,15*FP_1
mov playerAngle,0
invoke ExpansionPortalSnapshot,OFFSET expansionUpLanding
mov expansionStage,23
mov engineMode,MODE_WALK
mov hallLevel3D,2
mov worldMap3D,OFFSET upperLoungeMap3D
mov floorTexture3D,124
mov playerX,FP_1*45/10
mov playerAngle,256
invoke ExpansionPortalSnapshot,OFFSET expansionUpExit
mov expansionStage,24
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
mov floorTexture3D,100
mov playerX,FP_1*267/10
mov playerY,FP_1*105/10
mov playerAngle,0
mov basementDoorOpen3D,0
call UpdateInteriorEye3D
call ExpansionFrame
cmp portalPixelsWritten3D,0
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionDownClosed
mov basementDoorOpen3D,FP_1
invoke ExpansionPortalSnapshot,OFFSET expansionDoor
mov expansionStage,25
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
mov floorTexture3D,94
mov playerX,FP_1*45/10
mov playerY,21*FP_1
mov playerAngle,256
invoke ExpansionPortalSnapshot,OFFSET expansionDownReturn
mov expansionStage,26
mov playerX,FP_1*165/10
mov playerY,FP_1*155/10
mov playerAngle,384
invoke ExpansionPortalSnapshot,OFFSET expansionDownLanding
mov expansionStage,27
mov engineMode,MODE_WALK
mov hallLevel3D,1
mov worldMap3D,OFFSET bunkerMap3D
mov playerY,FP_1*265/10
mov playerAngle,128
invoke ExpansionPortalSnapshot,OFFSET expansionBunkerReturn
mov expansionStage,28
; These viewpoints used to lose their continuation at the eight-metre cutoff.
mov engineMode,MODE_STAIRS
mov stairRoute3D,2
mov worldMap3D,OFFSET upperStairMap3D
mov floorTexture3D,85
mov playerX,12*FP_1
mov playerY,21*FP_1
mov playerAngle,256
call UpdateInteriorEye3D
call ExpansionFrame
cmp portalPixelsWritten3D,100
jb expansion_fail
invoke ExpansionSnapshot,OFFSET expansionFarUpper
mov engineMode,MODE_WALK
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
mov floorTexture3D,100
mov playerX,21*FP_1
mov playerAngle,0
call UpdateInteriorEye3D
call ExpansionFrame
cmp portalPixelsWritten3D,100
jb expansion_fail
invoke ExpansionSnapshot,OFFSET expansionFarEntry
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
mov floorTexture3D,94
mov playerX,12*FP_1
mov playerAngle,256
call UpdateInteriorEye3D
call ExpansionFrame
cmp portalPixelsWritten3D,100
jb expansion_fail
invoke ExpansionSnapshot,OFFSET expansionFarBasement
mov engineMode,MODE_WALK
mov hallLevel3D,2
mov worldMap3D,OFFSET upperLoungeMap3D
mov floorTexture3D,124
mov playerX,FP_1*105/10
mov playerY,FP_1*193/10
mov playerAngle,128
mov upperLeverMask3D,0
mov upperPortalReady3D,0
mov upperLeverTime3D,0
mov upperLeverTime3D[4],0
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionPortalClosed
mov interactTargetId,INTERACT_UPPER_LEFT
call TriggerHallInteraction3D
mov esi,40
expansion_first_lever:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_first_lever
cmp upperLeverTime3D,600
jne expansion_fail
cmp upperLeverTime3D[4],0
jne expansion_fail
cmp upperPortalReady3D,0
jne expansion_fail
mov playerY,FP_1*244/10
call TryWalkUpperPortal3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov playerY,FP_1*193/10
mov interactTargetId,INTERACT_UPPER_RIGHT
call TriggerHallInteraction3D
mov esi,20
expansion_second_lever_half:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_second_lever_half
cmp upperPortalReady3D,0
jne expansion_fail
call ExpansionFrame
cmp upperLever3D.frame,2
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionLeverMid
mov esi,20
expansion_second_lever_end:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_second_lever_end
cmp upperPortalReady3D,1
jne expansion_fail
xor esi,esi
expansion_portal_motion:
imul eax,esi,80
mov animationClock3D,eax
call ExpansionFrame
mov eax,esi
inc eax
cmp upperPortal3D.frame,eax
jne expansion_fail
invoke ExpansionSnapshot,expansionPortalPaths[esi*4]
inc esi
cmp esi,12
jb expansion_portal_motion
mov expansionStage,29
mov playerX,FP_1*91/10
mov playerY,FP_1*214/10
mov playerAngle,128
call UpdateCamera3D
call CheckUpperInteractions3D
cmp interactTargetId,INTERACT_UPPER_LEFT
jne expansion_fail
cmp interactPromptPtr,OFFSET upperLeftRelease3D
jne expansion_fail
call TriggerHallInteraction3D
cmp upperLeverMask3D,2
jne expansion_fail
cmp upperPortalReady3D,0
jne expansion_fail
mov playerX,FP_1*105/10
mov playerY,FP_1*244/10
call TryWalkUpperPortal3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov interactTargetId,INTERACT_HELL_TOWER
call TriggerHallInteraction3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov playerY,FP_1*193/10
call ExpansionFrame
cmp upperPortal3D.frame,0
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionPortalOff
mov esi,20
expansion_release_half:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_release_half
cmp upperLeverTime3D,280
jne expansion_fail
cmp upperLeverTime3D[4],600
jne expansion_fail
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionLeverRelease
; Reverse the handle halfway through release, without snapping to an endpoint.
mov interactTargetId,INTERACT_UPPER_LEFT
call TriggerHallInteraction3D
cmp upperLeverTime3D,280
jne expansion_fail
cmp upperPortalReady3D,0
jne expansion_fail
mov esi,20
expansion_reenable_half:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_reenable_half
cmp upperPortalReady3D,1
jne expansion_fail
; The right handle is also available after activation, and disables immediately.
mov playerX,FP_1*119/10
mov playerY,FP_1*214/10
call CheckUpperInteractions3D
cmp interactTargetId,INTERACT_UPPER_RIGHT
jne expansion_fail
cmp interactPromptPtr,OFFSET upperRightRelease3D
jne expansion_fail
call TriggerHallInteraction3D
cmp upperLeverMask3D,1
jne expansion_fail
cmp upperPortalReady3D,0
jne expansion_fail
mov esi,40
expansion_release_right:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_release_right
cmp upperLeverTime3D[4],0
jne expansion_fail
cmp upperLeverTime3D,600
jne expansion_fail
mov interactTargetId,INTERACT_UPPER_LEFT
call TriggerHallInteraction3D
mov esi,40
expansion_release_both:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_release_both
cmp upperLeverMask3D,0
jne expansion_fail
cmp upperLeverTime3D,0
jne expansion_fail
cmp upperLeverTime3D[4],0
jne expansion_fail
cmp upperPortalReady3D,0
jne expansion_fail
call CheckUpperInteractions3D
cmp interactTargetId,INTERACT_UPPER_RIGHT
jne expansion_fail
cmp interactPromptPtr,OFFSET upperRightPrompt3D
jne expansion_fail
mov interactTargetId,INTERACT_UPPER_LEFT
call TriggerHallInteraction3D
mov interactTargetId,INTERACT_UPPER_RIGHT
call TriggerHallInteraction3D
mov esi,40
expansion_reopen_both:
add animationClock3D,16
call UpdateUpperEffects3D
dec esi
jnz expansion_reopen_both
cmp upperPortalReady3D,1
jne expansion_fail
mov playerX,FP_1*105/10
mov playerY,FP_1*244/10
call TryWalkUpperPortal3D
cmp engineMode,MODE_HELL_TOWER
jne expansion_fail
call TowerExitToHall
call TryWalkUpperPortal3D
cmp engineMode,MODE_WALK
jne expansion_fail
mov expansionStage,30
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
mov floorTexture3D,100
mov playerX,FP_1*285/10
mov playerY,21*FP_1
mov playerAngle,0
call UpdateInteriorEye3D
call ExpansionFrame
cld
lea esi,screenBuffer
lea edi,expansionSinglePixels
mov ecx,SCREEN_SIZE
rep movsd
invoke CreateEventA,0,0,0,0
mov hRaycastStartEvent,eax
invoke CreateEventA,0,0,0,0
mov hRaycastDoneEvent,eax
mov bRaycastQuit,0
invoke CreateThread,0,65536,OFFSET RaycastWorkerProc,0,0,OFFSET raycastThreadId
mov hRaycastThread,eax
test eax,eax
jz expansion_fail
call ExpansionFrame
lea esi,screenBuffer
lea edi,expansionSinglePixels
mov ecx,SCREEN_SIZE
repe cmpsd
jne expansion_fail
mov bRaycastQuit,1
invoke SetEvent,hRaycastStartEvent
invoke WaitForSingleObject,hRaycastThread,2000
test eax,eax
jnz expansion_fail
invoke CloseHandle,hRaycastThread
invoke CloseHandle,hRaycastStartEvent
invoke CloseHandle,hRaycastDoneEvent
mov hRaycastThread,0
mov hRaycastStartEvent,0
mov hRaycastDoneEvent,0
mov expansionStage,31
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
; Equal walked distance at two update rates must select the same gait phase.
call InitNpcLife3D
invoke NpcPlanPath3D,0,5
test eax,eax
jz expansion_fail
mov npcLife3D.state,NPC_WALK
mov esi,10
expansion_gait_rate16:
invoke NpcMove3D,0,16
dec esi
jnz expansion_gait_rate16
mov eax,casinoNpcs3D.posX
mov expansionGaitX,eax
mov eax,casinoNpcs3D.posY
mov expansionGaitY,eax
mov eax,npcWalkDistance3D
mov expansionGaitPhase,eax
call InitNpcLife3D
invoke NpcPlanPath3D,0,5
test eax,eax
jz expansion_fail
mov npcLife3D.state,NPC_WALK
mov esi,5
expansion_gait_rate32:
invoke NpcMove3D,0,32
dec esi
jnz expansion_gait_rate32
mov eax,casinoNpcs3D.posX
cmp eax,expansionGaitX
jne expansion_fail
mov playerX,eax
mov eax,casinoNpcs3D.posY
cmp eax,expansionGaitY
jne expansion_fail
mov playerY,eax
mov eax,npcWalkDistance3D
cmp eax,expansionGaitPhase
jne expansion_fail
invoke NpcMove3D,0,16
mov eax,npcWalkDistance3D
cmp eax,expansionGaitPhase
jne expansion_fail
cmp npcLife3D.state,NPC_STAND
jne expansion_fail
mov playerX,FP_1*285/10
mov playerY,21*FP_1
call InitNpcLife3D
; A blocked move must not tick the gait. A successful one consumes distance.
mov npcLife3D.state,NPC_WALK
mov npcLife3D.pathCount,0
invoke NpcMove3D,0,16
cmp npcWalkDistance3D,0
jne expansion_fail
invoke NpcPlanPath3D,0,5
test eax,eax
jz expansion_fail
mov npcLife3D.state,NPC_WALK
invoke NpcMove3D,0,16
cmp npcWalkDistance3D,0
je expansion_fail
mov eax,npcWalkDistance3D
mov expansionOcclusionPixel,eax
invoke NpcMove3D,0,0
mov eax,npcWalkDistance3D
cmp eax,expansionOcclusionPixel
jne expansion_fail
; Native renders of each gait phase, not just hashes of offline source art.
mov esi,1
expansion_gait_hide:
imul ebx,esi,SIZEOF NpcLife3D
mov npcLife3D[ebx].state,NPC_AWAY
inc esi
cmp esi,NPC_LIFE_COUNT
jb expansion_gait_hide
mov npcLife3D.state,NPC_WALK
mov npcLife3D.identity,0
mov casinoNpcs3D.posX,FP_1*165/10
mov casinoNpcs3D.posY,FP_1*175/10
mov npcWalkVelocityX3D,FP_1
mov npcWalkVelocityY3D,0
mov playerX,FP_1*165/10
mov playerY,FP_1*195/10
mov playerAngle,384
call UpdateInteriorEye3D
xor esi,esi
expansion_gait_frame:
imul eax,esi,FP_1*3/32
mov npcWalkDistance3D,eax
call UpdateCamera3D
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
call RenderNpcLife3D
mov eax,npcSprite3D.frame
cmp eax,esi
jne expansion_fail
invoke ExpansionSnapshot,expansionGaitPaths[esi*4]
inc esi
cmp esi,8
jb expansion_gait_frame
mov npcWalkVelocityX3D,-FP_1
call PrepareCityDepth3D
call RenderNpcLife3D
cmp npcSprite3D.asset,OFFSET npcWalkLeftArt3D
jne expansion_fail
mov expansionStage,32
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
mov floorTexture3D,94
mov playerX,FP_1*46/10
mov playerY,21*FP_1
mov playerAngle,256
mov basementDoorTarget3D,0
mov basementDoorOpen3D,0
mov basementWheelTime3D,0
invoke CanWalk3D,FP_1*39/10,FP_1*227/10
test eax,eax
jnz expansion_fail
mov keys3D[57h],1
mov esi,10
expansion_return_closed:
call ExpansionWalkFrame
dec esi
jnz expansion_return_closed
cmp engineMode,MODE_STAIRS
jne expansion_fail
cmp playerX,FP_1*405/100
jb expansion_fail
cmp basementDoorTarget3D,FP_1
jne expansion_fail
cmp basementDoorOpen3D,0
jne expansion_fail
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoorBack
mov esi,150
expansion_return_auto_open:
call ExpansionWalkFrame
cmp engineMode,MODE_WALK
je expansion_return_opened
dec esi
jnz expansion_return_auto_open
jmp expansion_fail
expansion_return_opened:
mov keys3D[57h],0
cmp hallLevel3D,0
jne expansion_fail
cmp basementWheelTime3D,700
jne expansion_fail
cmp basementDoorOpen3D,FP_1*9/10
jb expansion_fail
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
invoke CanWalk3D,FP_1*39/10,FP_1*227/10
test eax,eax
jnz expansion_fail
invoke CanWalk3D,FP_1*39/10,21*FP_1
cmp eax,1
jne expansion_fail
mov engineMode,MODE_WALK
mov worldMap3D,OFFSET casinoMap
mov expansionStage,33
mov playerX,FP_1*305/10
mov playerY,FP_1*305/10
call InitNpcLife3D
mov deltaTime3D,50
mov esi,2400
expansion_long_gait:
call UpdateNpcLife3D
xor edi,edi
expansion_gait_bounds:
cmp npcWalkDistance3D[edi*4],FP_1*3/4
jae expansion_fail
imul ebx,edi,SIZEOF NpcMindEntity
invoke CanWalk3D,casinoNpcs3D[ebx].posX,casinoNpcs3D[ebx].posY
cmp eax,1
jne expansion_fail
inc edi
cmp edi,NPC_LIFE_COUNT
jb expansion_gait_bounds
dec esi
jnz expansion_long_gait
cmp npcLifeClock3D,120000
jne expansion_fail
mov expansionStage,34
mov deltaTime3D,16
mov floorTexture3D,100
mov playerX,FP_1*288/10
mov playerY,FP_1*105/10
mov playerAngle,0
mov basementDoorTarget3D,FP_1
mov basementDoorOpen3D,FP_1
mov basementWheelTime3D,700
mov basementDoorHold3D,0
invoke ExpansionDoorTicks,200
cmp basementDoorOpen3D,FP_1
jne expansion_fail
cmp basementDoorHold3D,1200
jne expansion_fail
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
mov playerX,FP_1*43/10
mov playerY,21*FP_1
invoke ExpansionDoorTicks,200
cmp basementDoorOpen3D,FP_1
jne expansion_fail
cmp basementWheelTime3D,700
jne expansion_fail
mov engineMode,MODE_WALK
mov worldMap3D,OFFSET casinoMap
mov playerX,25*FP_1
mov playerY,FP_1*105/10
add animationClock3D,16
call UpdateBasementDoor3D
cmp basementDoorHold3D,1184
jne expansion_fail
call UpdateBasementDoor3D
cmp basementDoorHold3D,1184
jne expansion_fail
invoke ExpansionDoorTicks,74
cmp basementDoorHold3D,0
jne expansion_fail
cmp basementDoorOpen3D,FP_1
jne expansion_fail
invoke ExpansionDoorTicks,20
cmp basementDoorOpen3D,0
je expansion_fail
cmp basementDoorOpen3D,FP_1
jae expansion_fail
cmp basementWheelTime3D,700
jne expansion_fail
mov eax,basementDoorOpen3D
mov expansionDoorState,eax
mov playerX,27*FP_1
call UpdateInteriorEye3D
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoorClosing
; Returning during the swing reverses smoothly and keeps the wheel unlocked.
invoke ExpansionDoorTicks,1
mov eax,basementDoorOpen3D
cmp eax,expansionDoorState
jbe expansion_fail
cmp eax,FP_1
jae expansion_fail
cmp basementWheelTime3D,700
jne expansion_fail
invoke ExpansionDoorTicks,75
cmp basementDoorOpen3D,FP_1
jne expansion_fail
mov playerX,25*FP_1
invoke ExpansionDoorTicks,75
mov esi,70
expansion_wait_closed_leaf:
invoke ExpansionDoorTicks,1
cmp basementDoorOpen3D,0
je expansion_leaf_shut
cmp basementWheelTime3D,700
jne expansion_fail
dec esi
jnz expansion_wait_closed_leaf
jmp expansion_fail
expansion_leaf_shut:
cmp basementWheelTime3D,600
jbe expansion_fail
invoke ExpansionDoorTicks,20
cmp basementDoorOpen3D,0
jne expansion_fail
cmp basementWheelTime3D,0
je expansion_fail
cmp basementWheelTime3D,700
jae expansion_fail
mov eax,basementWheelTime3D
mov expansionDoorState,eax
mov playerX,27*FP_1
call ExpansionFrame
invoke ExpansionSnapshot,OFFSET expansionDoorLocking
; Returning during locking unlocks from that pose before moving the leaf.
invoke ExpansionDoorTicks,1
cmp basementDoorOpen3D,0
jne expansion_fail
mov eax,basementWheelTime3D
cmp eax,expansionDoorState
jbe expansion_fail
invoke ExpansionDoorTicks,100
cmp basementDoorOpen3D,FP_1
jne expansion_fail
mov playerX,25*FP_1
invoke ExpansionDoorTicks,200
cmp basementDoorTarget3D,0
jne expansion_fail
cmp basementDoorOpen3D,0
jne expansion_fail
cmp basementWheelTime3D,0
jne expansion_fail
invoke CanWalk3D,FP_1*289/10,FP_1*105/10
test eax,eax
jnz expansion_fail
mov playerX,27*FP_1
call ExpansionFrame
cmp portalPixelsWritten3D,0
jne expansion_fail
invoke ExpansionSnapshot,OFFSET expansionDoorShut
mov engineMode,MODE_STAIRS
mov stairRoute3D,1
mov worldMap3D,OFFSET basementStairMap3D
mov playerX,FP_1*43/10
mov playerY,21*FP_1
invoke ExpansionDoorTicks,120
cmp basementDoorOpen3D,FP_1
jne expansion_fail
mov playerX,8*FP_1
invoke ExpansionDoorTicks,200
cmp basementDoorOpen3D,0
jne expansion_fail
cmp basementWheelTime3D,0
jne expansion_fail
invoke CanWalk3D,FP_1*39/10,21*FP_1
test eax,eax
jnz expansion_fail
mov playerX,FP_1*43/10
invoke ExpansionDoorTicks,120
cmp basementDoorOpen3D,FP_1
jne expansion_fail
; Optional E also works outside the automatic opening radius, then expires.
mov engineMode,MODE_WALK
mov worldMap3D,OFFSET casinoMap
mov playerX,25*FP_1
mov playerY,FP_1*105/10
mov basementDoorOpen3D,0
mov basementWheelTime3D,0
mov basementDoorHold3D,0
mov interactTargetId,INTERACT_BASEMENT
call TriggerHallInteraction3D
invoke ExpansionDoorTicks,110
cmp basementDoorOpen3D,FP_1
jne expansion_fail
invoke ExpansionDoorTicks,200
cmp basementDoorOpen3D,0
jne expansion_fail
cmp basementWheelTime3D,0
jne expansion_fail
call FortuneNativeTests
call BarCameraNativeTests
call FortuneDialogNativeTests
call ExpansionDartsTests
call RoofNativeTests
invoke ExitProcess,0
expansion_fail:
invoke ExitProcess,expansionStage
ret
ExpansionTestStart ENDP
include tools/tests/fortune_room_test.inc
include tools/tests/bar_camera_test.inc
include tools/tests/fortune_dialog_test.inc
include tools/tests/darts_hall_test.inc
include tools/tests/rooftop_test.inc