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

986 lines
26 KiB
PHP

; Connected stairwells use the normal player movement and body collision routines.
; Only room-local coordinates are translated at a landing, never by a timer.
ResolveUpperMaterial3D PROC material:DWORD
cmp material,131
jne @F
mov eax,basementDoorArt3D.pixels
test eax,eax
jz upper_material_missing
add eax,17*256*512*4
mov ecx,256
mov edx,512
ret
@@:
cmp material,129
jne @F
mov eax,upperPortal3D.frame
imul eax,256*512*4
cmp upperPortalArt3D.pixels,0
je upper_material_missing
add eax,upperPortalArt3D.pixels
mov ecx,256
mov edx,512
ret
@@:
cmp material,130
jne @F
mov eax,OFFSET upperGlowPixels3D
mov ecx,32
mov edx,32
ret
@@:
cmp material,128
jne upper_material_not_door
cmp basementDoorArt3D.pixels,0
je upper_material_missing
imul eax,basementWheelTime3D,16
xor edx,edx
mov ecx,700
div ecx
cmp eax,16
jbe @F
mov eax,16
@@:
imul eax,256*512*4
add eax,basementDoorArt3D.pixels
mov ecx,256
mov edx,512
ret
upper_material_not_door:
cmp material,126
jne @F
mov eax,OFFSET upperFeltPixels3D
mov ecx,32
mov edx,32
ret
@@:
cmp material,127
jne @F
mov eax,OFFSET upperKeyPixels3D
mov ecx,32
mov edx,32
ret
@@:
mov eax,upperMaterialArt3D.pixels
test eax,eax
jz upper_material_missing
mov ecx,material
sub ecx,122
cmp ecx,3
ja upper_material_missing
shl ecx,18
add eax,ecx
mov ecx,256
mov edx,256
ret
upper_material_missing:
xor eax,eax
ret
ResolveUpperMaterial3D ENDP
InitUpperSurfaces3D PROC uses esi
xor esi,esi
upper_surface_pixel:
; Small native material swatches, not a replacement external renderer.
mov eax,esi
imul eax,1103515245
xor eax,5A63h
and eax,7
add eax,0FF1B5039h
mov upperFeltPixels3D[esi*4],eax
and eax,7
add eax,0FF311114h
mov upperGlowPixels3D[esi*4],eax
mov eax,esi
and eax,31
and eax,3
cmp eax,3
je upper_key_dark
cmp esi,16*32
jae upper_key_white
test eax,eax
jz upper_key_dark
upper_key_white:
mov eax,0FFECE3C8h
jmp upper_key_store
upper_key_dark:
mov eax,0FF16191Bh
upper_key_store:
mov upperKeyPixels3D[esi*4],eax
inc esi
cmp esi,1024
jb upper_surface_pixel
ret
InitUpperSurfaces3D ENDP
DrawUpperGameTable3D PROC uses ebx esi edi centreX:DWORD,centreY:DWORD
local x0:DWORD,x1:DWORD,y0:DWORD,y1:DWORD,legX:DWORD,legY:DWORD
mov eax,centreX
sub eax,FP_1
mov x0,eax
add eax,2*FP_1
mov x1,eax
mov eax,centreY
sub eax,FP_1/2
mov y0,eax
add eax,FP_1
mov y1,eax
invoke DrawCityBoxSides3D,x0,x1,y0,y1,FP_1/2,FP_1*13/20,85
invoke DrawCityHorizontal3D,x0,x1,y0,y1,FP_1*13/20,85
mov eax,x0
add eax,FP_1/10
mov ebx,x1
sub ebx,FP_1/10
mov ecx,y0
add ecx,FP_1/10
mov edx,y1
sub edx,FP_1/10
invoke DrawCityHorizontal3D,eax,ebx,ecx,edx,FP_1*33/50,126
xor esi,esi
upper_table_leg:
mov eax,x0
add eax,FP_1/8
test esi,1
jz @F
mov eax,x1
sub eax,FP_1/4
@@:
mov legX,eax
mov eax,y0
add eax,FP_1/8
test esi,2
jz @F
mov eax,y1
sub eax,FP_1/4
@@:
mov legY,eax
mov ebx,legX
add ebx,FP_1/8
add eax,FP_1/8
invoke DrawCityBoxSides3D,legX,ebx,legY,eax,0,FP_1/2,85
inc esi
cmp esi,4
jb upper_table_leg
ret
DrawUpperGameTable3D ENDP
BeginWalkableStairs3D PROC route:DWORD,fromFarEnd:DWORD
mov eax,route
mov stairRoute3D,eax
mov engineMode,MODE_STAIRS
mov interactTargetId,0
mov interactPromptPtr,0
cmp route,1
jne interior_begin_upper
mov worldMap3D,OFFSET basementStairMap3D
mov floorTexture3D,94
sub playerX,25*FP_1
add playerY,FP_1*21/2
cmp fromFarEnd,0
je interior_begin_finish
add playerX,12*FP_1
sub playerY,32*FP_1
jmp interior_begin_finish
interior_begin_upper:
mov worldMap3D,OFFSET upperStairMap3D
mov floorTexture3D,85
sub playerX,27*FP_1
cmp fromFarEnd,0
je interior_begin_finish
add playerX,39*FP_1
interior_begin_finish:
call UpdateStairHeight3D
ret
BeginWalkableStairs3D ENDP
UpdateInteriorTravel3D PROC
call UpdateRoof3D
cmp hallLevel3D,HALL_ROOF
je interior_travel_done
call UpdateUpperEffects3D
call UpdateBasementDoor3D
call UpdateFortunePassage3D
interior_travel_check:
cmp engineMode,MODE_STAIRS
je interior_travel_stairs
cmp engineMode,MODE_WALK
jne interior_travel_done
cmp hallLevel3D,1
je interior_travel_bunker
cmp hallLevel3D,2
je interior_travel_upper
cmp hallLevel3D,3
je interior_travel_fortune_room
cmp fortunePassageTime3D,1400
jne interior_travel_east
cmp playerX,FP_1*14/10
ja interior_travel_east
cmp playerY,FP_1*92/10
jb interior_travel_east
cmp playerY,FP_1*108/10
ja interior_travel_east
add playerX,28*FP_1
mov stairRoute3D,3
mov engineMode,MODE_STAIRS
mov worldMap3D,OFFSET fortuneStairMap3D
mov floorTexture3D,134
call UpdateStairHeight3D
ret
interior_travel_east:
cmp playerY,20*FP_1
jb interior_travel_door
cmp playerY,22*FP_1
ja interior_travel_done
cmp playerX,FP_1*303/10
jb interior_travel_done
invoke BeginWalkableStairs3D,2,0
ret
interior_travel_door:
cmp basementDoorOpen3D,FP_1*9/10
jb interior_travel_done
cmp playerX,29*FP_1
jb interior_travel_done
cmp playerY,FP_1*99/10
jb interior_travel_done
cmp playerY,FP_1*111/10
ja interior_travel_done
invoke BeginWalkableStairs3D,1,0
ret
interior_travel_bunker:
cmp playerY,FP_1*277/10
jb interior_travel_done
; Bunker landing (16.5,27.7) continues to the stairwell (16.5,14.7).
sub playerY,13*FP_1
mov stairRoute3D,1
mov engineMode,MODE_STAIRS
mov worldMap3D,OFFSET basementStairMap3D
mov floorTexture3D,94
call UpdateStairHeight3D
ret
interior_travel_upper:
call TryWalkUpperPortal3D
cmp engineMode,MODE_WALK
jne interior_travel_done
cmp playerY,20*FP_1
jb interior_travel_done
cmp playerY,22*FP_1
ja interior_travel_done
cmp playerX,FP_1*32/10
ja interior_travel_done
; Upper west landing and the far east end of its stairwell share an axis.
add playerX,12*FP_1
mov stairRoute3D,2
mov engineMode,MODE_STAIRS
mov worldMap3D,OFFSET upperStairMap3D
mov floorTexture3D,85
call UpdateStairHeight3D
ret
interior_travel_fortune_room:
cmp playerX,FP_1*175/10
jb interior_travel_done
cmp playerY,10*FP_1
jb interior_travel_done
cmp playerY,12*FP_1
jae interior_travel_done
mov stairRoute3D,3
sub playerY,FP_1
mov engineMode,MODE_STAIRS
mov worldMap3D,OFFSET fortuneStairMap3D
mov floorTexture3D,134
call UpdateStairHeight3D
ret
interior_travel_stairs:
cmp stairRoute3D,3
je interior_fortune_thresholds
cmp stairRoute3D,1
jne interior_upper_thresholds
cmp playerX,FP_1*31/10
jbe interior_exit_basement_top
cmp playerY,FP_1*143/10
ja interior_travel_done
mov hallLevel3D,1
mov worldMap3D,OFFSET bunkerMap3D
add playerY,13*FP_1
mov floorTexture3D,94
jmp interior_finish
interior_exit_basement_top:
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
add playerX,25*FP_1
sub playerY,FP_1*21/2
mov floorTexture3D,100
jmp interior_finish
interior_upper_thresholds:
cmp playerX,FP_1*31/10
jbe interior_exit_upper_bottom
cmp playerX,16*FP_1
jb interior_travel_done
mov hallLevel3D,2
mov worldMap3D,OFFSET upperLoungeMap3D
sub playerX,12*FP_1
mov floorTexture3D,124
jmp interior_finish
interior_exit_upper_bottom:
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
add playerX,27*FP_1
mov floorTexture3D,100
jmp interior_finish
interior_fortune_thresholds:
cmp playerX,FP_1*2955/100
jae interior_fortune_top
cmp playerX,FP_1*172/10
ja interior_travel_done
mov hallLevel3D,3
add playerY,FP_1
mov worldMap3D,OFFSET fortuneRoomMap3D
mov floorTexture3D,134
jmp interior_finish
interior_fortune_top:
mov hallLevel3D,0
mov worldMap3D,OFFSET casinoMap
sub playerX,28*FP_1
mov floorTexture3D,100
interior_finish:
mov engineMode,MODE_WALK
mov interactTargetId,0
mov interactPromptPtr,0
call UpdateInteriorEye3D
interior_travel_done:
ret
UpdateInteriorTravel3D ENDP
UpdateStairHeight3D PROC
cmp engineMode,MODE_STAIRS
jne interior_height_done
mov viewHorizon3D,HALF_H
mov viewCeiling3D,FP_1*11/2
cmp stairRoute3D,3
jne @F
mov viewCeiling3D,4*FP_1
mov eax,playerX
sub eax,19*FP_1
jle interior_height_zero
cmp eax,8*FP_1
jle interior_height_fortune
mov eax,8*FP_1
interior_height_fortune:
imul eax,3
cdq
mov ecx,16
idiv ecx
jmp interior_height_store
@@:
cmp stairRoute3D,1
jne interior_height_upper
mov viewCeiling3D,4*FP_1
mov eax,13*FP_1
sub eax,playerX
jle interior_height_zero
cmp eax,8*FP_1
jle @F
mov eax,8*FP_1
@@:
imul eax,3
cdq
mov ecx,16
idiv ecx
jmp interior_height_store
interior_height_upper:
mov eax,playerX
sub eax,5*FP_1
jle interior_height_zero
cmp eax,8*FP_1
jle @F
mov eax,8*FP_1
@@:
imul eax,13
cdq
mov ecx,40
idiv ecx
jmp interior_height_store
interior_height_zero:
xor eax,eax
interior_height_store:
add eax,HALL_STANDING_EYE
mov viewEye3D,eax
interior_height_done:
ret
UpdateStairHeight3D ENDP
UpdateInteriorEye3D PROC
cmp engineMode,MODE_STAIRS
je UpdateStairHeight3D
cmp engineMode,MODE_WALK
jne interior_eye_done
cmp hallLevel3D,HALL_ROOF
jne @F
call UpdateRoofEye3D
ret
@@:
mov viewHorizon3D,HALF_H
mov viewEye3D,HALL_STANDING_EYE
mov viewCeiling3D,FP_1*5/2
interior_eye_done:
ret
UpdateInteriorEye3D ENDP
InteriorDoorCanWalk3D PROC px:DWORD,py:DWORD
cmp px,29*FP_1-FP_1/6
jb interior_check_steel
cmp py,FP_1*1955/100
jb interior_check_steel
cmp py,20*FP_1+FP_1/6
jbe interior_portal_blocked
cmp py,22*FP_1-FP_1/6
jb interior_check_steel
cmp py,FP_1*2245/100
jbe interior_portal_blocked
interior_check_steel:
cmp py,9*FP_1
jb interior_door_clear
cmp py,12*FP_1
jae interior_door_clear
cmp px,FP_1*2875/100
jb interior_door_clear
cmp py,FP_1*96/10
jb interior_portal_blocked
cmp py,FP_1*114/10
ja interior_portal_blocked
cmp basementDoorOpen3D,FP_1*9/10
jae interior_door_clear
interior_portal_blocked:
xor eax,eax
ret
interior_door_clear:
mov eax,1
ret
InteriorDoorCanWalk3D ENDP
RenderHallPortals3D PROC uses ebx
; Same east alcove, with a deeper reveal and a stationary iron frame.
invoke DrawCityBoxSides3D,FP_1*284/10,29*FP_1,9*FP_1,FP_1*975/100,0,FP_1*11/5,102
invoke DrawCityBoxSides3D,FP_1*284/10,29*FP_1,FP_1*1125/100,12*FP_1,0,FP_1*11/5,102
invoke DrawCityBoxSides3D,FP_1*284/10,29*FP_1,FP_1*975/100,FP_1*1125/100,FP_1*19/10,FP_1*11/5,102
invoke DrawCityVertical3D,0,FP_1*2838/100,9*FP_1,12*FP_1,-FP_1/10,FP_1*21/10,131
; East stair entrance: projecting jambs, a low first tread and overhead lintel.
invoke DrawCityBoxSides3D,29*FP_1,31*FP_1,FP_1*197/10,20*FP_1,0,FP_1*5/2,102
invoke DrawCityBoxSides3D,29*FP_1,31*FP_1,22*FP_1,FP_1*223/10,0,FP_1*5/2,102
invoke DrawCityHorizontal3D,30*FP_1,31*FP_1,20*FP_1,22*FP_1,FP_1/8,85
invoke DrawCityVertical3D,0,30*FP_1,20*FP_1,22*FP_1,0,FP_1/8,102
ret
RenderHallPortals3D ENDP
RenderWalkableStairs3D PROC uses ebx esi edi
local treadStart:DWORD,treadEnd:DWORD,z0:DWORD,z1:DWORD
cmp stairRoute3D,3
jne @F
call RenderFortuneStairs3D
ret
@@:
cmp stairRoute3D,1
jne interior_render_upper_steps
; East-facing descent, then a level northward turn into the old bunker.
xor esi,esi
interior_concrete_step:
mov eax,esi
imul eax,FP_1/3
add eax,5*FP_1
mov treadStart,eax
add eax,FP_1/3
mov treadEnd,eax
imul eax,esi,FP_1/16
neg eax
add eax,FP_1*3/2
mov z0,eax
sub eax,FP_1/16
mov z1,eax
invoke DrawCityHorizontal3D,treadStart,treadEnd,20*FP_1,23*FP_1,z1,94
invoke DrawCityVertical3D,0,treadStart,20*FP_1,23*FP_1,z1,z0,92
inc esi
cmp esi,24
jb interior_concrete_step
invoke DrawCityHorizontal3D,2*FP_1,5*FP_1,20*FP_1,23*FP_1,FP_1*3/2,94
invoke DrawCityHorizontal3D,13*FP_1,18*FP_1,20*FP_1,23*FP_1,0,94
ret
interior_render_upper_steps:
xor esi,esi
interior_wood_step:
imul eax,esi,FP_1*2/5
add eax,5*FP_1
mov treadStart,eax
add eax,FP_1*2/5
mov treadEnd,eax
imul eax,esi,FP_1*13/100
mov z0,eax
add eax,FP_1*13/100
mov z1,eax
invoke DrawCityHorizontal3D,treadStart,treadEnd,20*FP_1,22*FP_1,z1,85
invoke DrawCityVertical3D,0,treadStart,20*FP_1,22*FP_1,z0,z1,102
mov eax,z1
add eax,FP_1*3/4
mov ebx,eax
add eax,FP_1/20
mov edi,eax
invoke DrawCityVertical3D,1,FP_1*201/10,treadStart,treadEnd,ebx,edi,110
invoke DrawCityVertical3D,1,FP_1*219/10,treadStart,treadEnd,ebx,edi,110
; Posts follow the slope instead of a billboard painted on the wall.
test esi,3
jnz @F
mov eax,z1
add eax,FP_1*3/4
mov ebx,eax
invoke DrawCityVertical3D,0,treadStart,FP_1*201/10,FP_1*202/10,z1,ebx,110
invoke DrawCityVertical3D,0,treadStart,FP_1*218/10,FP_1*219/10,z1,ebx,110
@@:
inc esi
cmp esi,20
jb interior_wood_step
invoke DrawCityHorizontal3D,13*FP_1,18*FP_1,20*FP_1,22*FP_1,FP_1*13/5,85
invoke DrawCityVertical3D,1,20*FP_1,2*FP_1,18*FP_1,0,FP_1*11/2,102
invoke DrawCityVertical3D,1,22*FP_1,2*FP_1,18*FP_1,0,FP_1*11/2,102
ret
RenderWalkableStairs3D ENDP
UpperCanWalk3D PROC px:DWORD,py:DWORD
; The same station centres drive art, interaction and collision.
cmp px,10*FP_1-FP_1/5
jb upper_walk_tables
cmp px,15*FP_1+FP_1/5
ja upper_walk_tables
cmp py,13*FP_1-FP_1/5
jb upper_walk_tables
cmp py,15*FP_1+FP_1/5
jbe upper_walk_block
upper_walk_tables:
xor ecx,ecx
upper_walk_station:
mov eax,px
sub eax,upperStationX3D[ecx*4]
test eax,eax
jns @F
neg eax
@@:
cmp eax,FP_1*11/10
ja upper_walk_next
mov eax,py
sub eax,upperStationY3D[ecx*4]
test eax,eax
jns @F
neg eax
@@:
cmp eax,FP_1*7/10
jbe upper_walk_block
upper_walk_next:
inc ecx
cmp ecx,2
jb upper_walk_station
xor ecx,ecx
upper_walk_guest:
mov eax,px
sub eax,upperGuestX3D[ecx*4]
test eax,eax
jns @F
neg eax
@@:
cmp eax,FP_1*2/5
ja upper_walk_guest_next
mov eax,py
sub eax,upperGuestY3D[ecx*4]
test eax,eax
jns @F
neg eax
@@:
cmp eax,FP_1*2/5
jbe upper_walk_block
upper_walk_guest_next:
inc ecx
cmp ecx,3
jb upper_walk_guest
cmp upperPortalReady3D,1
je upper_walk_clear
cmp py,24*FP_1
jb upper_walk_clear
cmp px,FP_1*95/10
jb upper_walk_clear
cmp px,FP_1*115/10
jbe upper_walk_block
upper_walk_clear:
mov eax,1
ret
upper_walk_block:
xor eax,eax
ret
UpperCanWalk3D ENDP
CheckUpperInteractions3D PROC
mov interactTargetId,0
mov interactPromptPtr,0
invoke HallTarget3D,3*FP_1,21*FP_1,0,OFFSET upperExitPrompt3D
invoke HallTarget3D,upperStationX3D[0],upperStationY3D[0],INTERACT_BUCKSHOT,OFFSET promptBuckshot
invoke HallTarget3D,upperStationX3D[4],upperStationY3D[4],INTERACT_RUSSIAN_ROULETTE,OFFSET promptRussianRoulette
test upperLeverMask3D,1
jnz upper_check_left_release
invoke HallTarget3D,FP_1*91/10,FP_1*226/10,INTERACT_UPPER_LEFT,OFFSET upperLeftPrompt3D
jmp upper_check_right
upper_check_left_release:
invoke HallTarget3D,FP_1*91/10,FP_1*226/10,INTERACT_UPPER_LEFT,OFFSET upperLeftRelease3D
upper_check_right:
test upperLeverMask3D,2
jnz upper_check_right_release
invoke HallTarget3D,FP_1*119/10,FP_1*226/10,INTERACT_UPPER_RIGHT,OFFSET upperRightPrompt3D
jmp upper_check_portal
upper_check_right_release:
invoke HallTarget3D,FP_1*119/10,FP_1*226/10,INTERACT_UPPER_RIGHT,OFFSET upperRightRelease3D
upper_check_portal:
cmp upperPortalReady3D,1
jne upper_check_bar
invoke HallTarget3D,FP_1*105/10,FP_1*237/10,INTERACT_HELL_TOWER,OFFSET upperPortalPrompt3D
upper_check_bar:
cmp playerX,10*FP_1
jb @F
cmp playerX,15*FP_1
ja @F
cmp playerY,15*FP_1
jb @F
invoke HallTarget3D,playerX,15*FP_1,INTERACT_BAR,OFFSET hallBarPrompt3D
@@:
ret
CheckUpperInteractions3D ENDP
RenderUpperLounge3D PROC uses ebx esi
; Small midnight lounge: dark panels, brass ribs, a marble-topped straight bar.
invoke DrawCityBoxSides3D,10*FP_1,15*FP_1,14*FP_1,15*FP_1,0,FP_1*13/20,102
invoke DrawCityHorizontal3D,10*FP_1,15*FP_1,14*FP_1,15*FP_1,FP_1*13/20,123
invoke DrawCityVertical3D,1,13*FP_1+FP_1/20,10*FP_1,15*FP_1,FP_1/2,2*FP_1,87
invoke DrawCityBoxSides3D,10*FP_1,15*FP_1,13*FP_1,FP_1*132/10,0,FP_1/2,102
invoke DrawCityBoxSides3D,10*FP_1,15*FP_1,13*FP_1,FP_1*132/10,2*FP_1,FP_1*21/10,102
invoke DrawCityVertical3D,1,FP_1*152/10,10*FP_1,15*FP_1,FP_1/8,FP_1*16/100,110
mov upperBarTender3D.asset,OFFSET upperBarArt3D
mov upperBarTender3D.worldW,FP_1*4/5
mov upperBarTender3D.worldH,FP_1*7/5
mov upperBarTender3D.groundZ,0
mov upperBarTender3D.frame,0
mov upperBarTender3D.posX,FP_1*25/2
mov upperBarTender3D.posY,FP_1*27/2
cmp engineMode,MODE_BAR
jne upper_draw_bartender
mov upperBarTender3D.posX,FP_1*115/10
mov upperBarTender3D.asset,OFFSET hallBartender3D
mov upperBarTender3D.worldW,FP_1
mov upperBarTender3D.worldH,FP_1
mov upperBarTender3D.groundZ,FP_1*9/20
mov eax,barSelection3D
shl eax,3
mov upperBarTender3D.frame,eax
mov eax,barTime3D
xor edx,edx
mov ecx,375
div ecx
cmp eax,7
jbe @F
mov eax,7
@@:
add upperBarTender3D.frame,eax
upper_draw_bartender:
invoke DrawCityObject3D,OFFSET upperBarTender3D,0
xor esi,esi
upper_draw_table:
mov ebx,upperStationX3D[esi*4]
mov upperTable3D.posX,ebx
mov eax,upperStationY3D[esi*4]
mov upperTable3D.posY,eax
mov upperTable3D.worldW,2*FP_1
mov upperTable3D.worldH,FP_1*6/5
mov upperTable3D.asset,OFFSET upperGamesArt3D
mov upperTable3D.frame,esi
invoke DrawCityObject3D,OFFSET upperTable3D,0
mov upperDealer3D.posX,ebx
mov eax,upperStationY3D[esi*4]
sub eax,FP_1*3/4
mov upperDealer3D.posY,eax
mov upperDealer3D.frame,esi
invoke DrawCityObject3D,OFFSET upperDealer3D,0
inc esi
cmp esi,2
jb upper_draw_table
mov upperPortal3D.frame,0
cmp upperPortalReady3D,1
jne upper_draw_portal
mov eax,animationClock3D
xor edx,edx
mov ecx,80
div ecx
xor edx,edx
mov ecx,12
div ecx
inc edx
mov upperPortal3D.frame,edx
upper_draw_portal:
invoke DrawCityVertical3D,1,FP_1*249/10,9*FP_1,12*FP_1,0,FP_1*5/2,122
invoke DrawCityBoxSides3D,FP_1*89/10,FP_1*915/100,FP_1*243/10,25*FP_1,0,FP_1*5/2,122
invoke DrawCityBoxSides3D,FP_1*1185/100,FP_1*121/10,FP_1*243/10,25*FP_1,0,FP_1*5/2,122
invoke DrawCityBoxSides3D,9*FP_1,12*FP_1,FP_1*243/10,25*FP_1,FP_1*24/10,FP_1*5/2,122
invoke DrawCityVertical3D,1,FP_1*247/10,FP_1*925/100,FP_1*1175/100,0,FP_1*245/100,129
mov eax,animationClock3D
shr eax,7
and eax,3
mov upperBrazier3D.frame,eax
mov upperBrazier3D.posX,FP_1*84/10
invoke DrawCityObject3D,OFFSET upperBrazier3D,0
mov upperBrazier3D.posX,FP_1*126/10
invoke DrawCityObject3D,OFFSET upperBrazier3D,0
invoke DrawCityVertical3D,1,FP_1*242/10,FP_1*92/10,FP_1*924/100,FP_1*16/10,FP_1*25/10,110
invoke DrawCityVertical3D,1,FP_1*242/10,FP_1*1176/100,FP_1*118/10,FP_1*16/10,FP_1*25/10,110
mov upperLever3D.posX,FP_1*91/10
mov eax,upperLeverTime3D
xor edx,edx
mov ecx,120
div ecx
mov upperLever3D.frame,eax
invoke DrawCityObject3D,OFFSET upperLever3D,0
mov upperLever3D.posX,FP_1*119/10
mov eax,upperLeverTime3D[4]
xor edx,edx
mov ecx,120
div ecx
mov upperLever3D.frame,eax
invoke DrawCityObject3D,OFFSET upperLever3D,0
mov upperGuest3D.asset,OFFSET npcGuestArt3D
xor esi,esi
upper_draw_guest:
mov eax,upperGuestX3D[esi*4]
mov upperGuest3D.posX,eax
mov eax,upperGuestY3D[esi*4]
mov upperGuest3D.posY,eax
mov eax,upperGuestFrame3D[esi*4]
mov upperGuest3D.frame,eax
invoke DrawCityObject3D,OFFSET upperGuest3D,0
inc esi
cmp esi,3
jb upper_draw_guest
mov upperChair3D.posX,FP_1*56/10
mov upperChair3D.posY,FP_1*225/10
mov upperChair3D.worldW,FP_1*3/5
mov upperChair3D.worldH,FP_1*7/10
mov upperChair3D.asset,OFFSET hallLampFurniture3D
invoke DrawCityObject3D,OFFSET upperChair3D,0
mov upperChair3D.posX,FP_1*143/10
mov upperChair3D.posY,FP_1*221/10
invoke DrawCityObject3D,OFFSET upperChair3D,0
mov upperChair3D.asset,OFFSET hallChairFurniture3D
mov upperChair3D.worldW,FP_1*3/4
mov upperChair3D.worldH,FP_1
mov upperChair3D.posX,15*FP_1
mov upperChair3D.posY,FP_1*227/10
invoke DrawCityObject3D,OFFSET upperChair3D,0
invoke DrawCityObject3D,OFFSET upperSofa3D,0
cmp engineMode,MODE_BAR
je upper_bar_stools_done
xor esi,esi
upper_bar_stools:
imul eax,esi,FP_1*14/10
add eax,FP_1*109/10
mov upperStool3D.posX,eax
invoke DrawCityObject3D,OFFSET upperStool3D,0
inc esi
cmp esi,3
jb upper_bar_stools
upper_bar_stools_done:
invoke DrawHallLantern3D,3*FP_1+FP_1/50,15*FP_1,1
invoke DrawHallLantern3D,3*FP_1+FP_1/50,18*FP_1,1
invoke DrawHallLantern3D,16*FP_1-FP_1/50,17*FP_1,-1
invoke DrawHallLantern3D,16*FP_1-FP_1/50,22*FP_1,-1
invoke DrawCityVertical3D,0,16*FP_1-FP_1/40,14*FP_1,16*FP_1,FP_1,2*FP_1,115
invoke DrawCityVertical3D,0,3*FP_1+FP_1/40,15*FP_1,17*FP_1,FP_1,2*FP_1,115
invoke DrawCityHorizontal3D,3*FP_1,5*FP_1,20*FP_1,22*FP_1,0,85
call ApplyUpperPortalGlow3D
ret
RenderUpperLounge3D ENDP
TryUpperInteraction3D PROC
cmp hallLevel3D,2
jne upper_interaction_none
cmp interactTargetId,INTERACT_UPPER_LEFT
jne @F
xor upperLeverMask3D,1
jmp upper_interaction_lever
@@:
cmp interactTargetId,INTERACT_UPPER_RIGHT
jne @F
xor upperLeverMask3D,2
jmp upper_interaction_lever
@@:
cmp interactTargetId,INTERACT_HELL_TOWER
jne upper_interaction_none
cmp upperPortalReady3D,1
jne upper_interaction_locked
mov upperPortalEntered3D,1
call InitHellTower3D
jmp upper_interaction_handled
upper_interaction_lever:
; Do not wait for the next animation tick to disable both entry paths.
mov upperPortalReady3D,0
jmp upper_interaction_handled
upper_interaction_locked:
invoke CopyString3D,OFFSET upperPortalLocked3D,OFFSET flashMessage
mov flashTimer,120
upper_interaction_handled:
call ClearKeys3D
mov eax,1
ret
upper_interaction_none:
xor eax,eax
ret
TryUpperInteraction3D ENDP
TryWalkUpperPortal3D PROC
cmp playerY,FP_1*235/10
jae @F
mov upperPortalEntered3D,0
@@:
cmp upperPortalReady3D,1
jne upper_portal_walk_done
cmp upperPortalEntered3D,0
jne upper_portal_walk_done
cmp playerX,10*FP_1
jb upper_portal_walk_done
cmp playerX,11*FP_1
ja upper_portal_walk_done
cmp playerY,FP_1*2425/100
jb upper_portal_walk_done
mov upperPortalEntered3D,1
call InitHellTower3D
call ClearKeys3D
upper_portal_walk_done:
ret
TryWalkUpperPortal3D ENDP
UpdateUpperEffects3D PROC uses ebx esi
mov eax,animationClock3D
cmp eax,upperEffectClock3D
je upper_effects_done
mov upperEffectClock3D,eax
xor esi,esi
mov ebx,1
upper_effect_lever:
mov eax,deltaTime3D
cmp eax,100
jbe @F
mov eax,100
@@:
test upperLeverMask3D,ebx
jz upper_effect_release
add eax,upperLeverTime3D[esi*4]
cmp eax,600
jbe @F
mov eax,600
@@:
jmp upper_effect_store
upper_effect_release:
mov ecx,upperLeverTime3D[esi*4]
sub ecx,eax
jae @F
xor ecx,ecx
@@:
mov eax,ecx
upper_effect_store:
mov upperLeverTime3D[esi*4],eax
upper_effect_next:
shl ebx,1
inc esi
cmp esi,2
jb upper_effect_lever
mov upperPortalReady3D,0
cmp upperLeverMask3D,3
jne upper_effects_done
cmp upperLeverTime3D,600
jne upper_effects_done
cmp upperLeverTime3D[4],600
jne upper_effects_done
mov upperPortalReady3D,1
upper_effects_done:
ret
UpdateUpperEffects3D ENDP
ApplyUpperPortalGlow3D PROC uses ebx esi edi
local row:DWORD,column:DWORD,depth:DWORD,wx:DWORD,amount:DWORD,pixel:DWORD,pulse:DWORD
mov eax,animationClock3D
shr eax,7
and eax,3
add eax,10
cmp upperPortalReady3D,1
jne @F
add eax,8
@@:
mov pulse,eax
mov eax,viewHorizon3D
add eax,2
mov row,eax
upper_glow_row:
mov ecx,row
sub ecx,viewHorizon3D
mov eax,viewEye3D
imul eax,SCREEN_H
cdq
idiv ecx
mov depth,eax
mov eax,row
imul eax,SCREEN_W*4
mov edi,eax
mov column,0
upper_glow_pixel:
mov ebx,column
mov eax,depth
cmp eax,cityDepthBuffer3D[edi]
ja upper_glow_next
imul cityRayX3D[ebx*4]
shrd eax,edx,16
add eax,playerX
sub eax,FP_1*105/10
test eax,eax
jns @F
neg eax
@@:
mov wx,eax
mov eax,depth
imul cityRayY3D[ebx*4]
shrd eax,edx,16
add eax,playerY
sub eax,FP_1*243/10
test eax,eax
jns @F
neg eax
@@:
add eax,wx
cmp eax,3*FP_1
jae upper_glow_next
neg eax
add eax,3*FP_1
imul pulse
shrd eax,edx,16
mov amount,eax
mov eax,screenBuffer[edi]
mov pixel,eax
shr eax,16
and eax,255
add eax,amount
cmp eax,255
jbe @F
mov eax,255
@@:
shl eax,16
mov ebx,pixel
and ebx,0000FFFFh
or eax,ebx
mov screenBuffer[edi],eax
upper_glow_next:
add edi,4
inc column
cmp column,SCREEN_W
jb upper_glow_pixel
inc row
cmp row,SCREEN_H
jb upper_glow_row
ret
ApplyUpperPortalGlow3D ENDP