KAZIK/src_graphics/hall_scene.inc
Artvasil09 3ad5bf4c9d Develop assembly-only casino scenes and native games
Add native Durak, poker, blackjack, roulette, Buckshot and billiards scenes with animation assets and regression tests. Improve arrival, city, hall, profiles, shops, audio and exit handling; remove the portable C game core and refresh shipping executables.
2026-10-08 22:39:19 +03:00

1220 lines
32 KiB
PHP

; Room planes use independent ceiling/floor distances; the eye is not the room midpoint.
RenderCeilingAndFloor PROC uses ebx esi edi
local row:DWORD,distance:DWORD,sx:DWORD,sy:DWORD,wx:DWORD,wy:DWORD
local material:DWORD,shade:DWORD
mov row, 0
hall_plane_row:
mov eax, row
cmp eax, viewHorizon3D
jge hall_plane_floor
cmp outdoorRender3D, 0
jne hall_plane_next_row
mov ecx, viewHorizon3D
sub ecx, eax
mov eax, viewCeiling3D
sub eax, viewEye3D
mov material, 101
cmp hallLevel3D, 0
je @F
mov material, 93
@@:
jmp hall_plane_distance
hall_plane_floor:
sub eax, viewHorizon3D
inc eax
mov ecx, eax
mov eax, viewEye3D
mov ebx, floorTexture3D
mov material, ebx
hall_plane_distance:
imul eax, SCREEN_H
cdq
idiv ecx
mov distance, eax
shr eax, 14
neg eax
add eax, 256
cmp eax, 55
jge @F
mov eax, 55
@@:
mov shade, eax
cmp hallLevel3D, 0
je @F
mov eax, shade
imul eax, 7
shr eax, 3
mov shade, eax
@@:
mov eax, playerPlaneX
shl eax, 1
imul distance
shrd eax, edx, 16
cdq
mov ecx, SCREEN_W
idiv ecx
mov sx, eax
mov eax, playerPlaneY
shl eax, 1
imul distance
shrd eax, edx, 16
cdq
idiv ecx
mov sy, eax
mov eax, playerDirX
sub eax, playerPlaneX
imul distance
shrd eax, edx, 16
add eax, playerX
mov wx, eax
mov eax, playerDirY
sub eax, playerPlaneY
imul distance
shrd eax, edx, 16
add eax, playerY
mov wy, eax
mov eax, row
imul eax, SCREEN_W*4
lea edi, screenBuffer[eax]
mov esi, SCREEN_W
hall_plane_pixel:
mov ebx, material
cmp outdoorRender3D, 0
je hall_plane_sample
mov eax, wy
cmp eax, 13*FP_1
jb hall_plane_crossroad
cmp eax, 16*FP_1
jb hall_plane_sample
hall_plane_crossroad:
mov eax, wx
cmp eax, 29*FP_1
jl hall_plane_sidewalk
cmp eax, 32*FP_1
jl hall_plane_sample
hall_plane_sidewalk:
mov ebx, 72
hall_plane_sample:
cmp outdoorRender3D, 0
jne hall_plane_low_sample
mov eax, row
cmp eax, viewHorizon3D
jl hall_plane_choose_hd
cmp hallLevel3D, 0
jne hall_plane_choose_hd
cmp wy, 23*FP_1
jl hall_plane_choose_hd
cmp wx, 12*FP_1
jl hall_plane_wood
cmp wx, 23*FP_1
jl hall_plane_choose_hd
hall_plane_wood:
mov ebx, 85
hall_plane_choose_hd:
cmp distance, 6*FP_1
ja hall_plane_low_sample
mov ecx, hallRoomHD3D.pixels
cmp ebx, 80
jb hall_plane_low_sample
cmp ebx, 103
ja hall_plane_low_sample
cmp ebx, 92
jb hall_plane_old_hd
mov ecx, hallArchitectureHD3D.pixels
sub ebx, 12
hall_plane_old_hd:
test ecx, ecx
jz hall_plane_hd_fallback
sub ebx, 80
shl ebx, 18
add ecx, ebx
mov eax, wy
shr eax, 8
and eax, 255
shl eax, 8
mov edx, wx
shr edx, 8
and edx, 255
add eax, edx
mov eax, [ecx+eax*4]
jmp hall_plane_shade
hall_plane_hd_fallback:
mov ebx, material
hall_plane_low_sample:
shl ebx, 16
mov eax, wy
shr eax, 9
and eax, 127
shl eax, 7
mov edx, wx
shr edx, 9
and edx, 127
add eax, edx
lea ebx, texturesBuffer[ebx]
mov eax, [ebx+eax*4]
hall_plane_shade:
cmp outdoorRender3D, 0
je hall_plane_ambient
invoke ShadeCityGround3D, eax, wx, wy, shade
jmp hall_plane_store
hall_plane_ambient:
mov ebx, eax
and eax, 0000FF00h
imul eax, shade
shr eax, 8
and eax, 0000FF00h
mov ecx, ebx
and ecx, 0FFh
imul ecx, shade
shr ecx, 8
or eax, ecx
shr ebx, 16
and ebx, 0FFh
imul ebx, shade
shr ebx, 8
shl ebx, 16
or eax, ebx
hall_plane_store:
stosd
mov eax, sx
add wx, eax
mov eax, sy
add wy, eax
dec esi
jnz hall_plane_pixel
hall_plane_next_row:
inc row
cmp row, SCREEN_H
jb hall_plane_row
ret
RenderCeilingAndFloor ENDP
RenderSprites PROC uses ebx esi edi
cmp hallLevel3D, 0
jne hall_sprites_done
xor esi, esi
hall_sprite_loop:
cmp esi, 14
je hall_sprite_next
imul ebx, esi, SIZEOF SpriteObject
mov eax, casinoSprites[ebx].posX
mov hallSpriteTemp3D.posX, eax
mov eax, casinoSprites[ebx].posY
mov hallSpriteTemp3D.posY, eax
mov eax, hallSpriteWidths3D[esi*4]
mov hallSpriteTemp3D.worldW, eax
mov eax, hallSpriteHeights3D[esi*4]
mov hallSpriteTemp3D.worldH, eax
mov hallSpriteTemp3D.groundZ, 0
cmp esi, 3
jae @F
mov hallSpriteTemp3D.groundZ, FP_1/8
@@:
mov ecx, casinoSprites[ebx].animSpeed
imul ecx, 40
test ecx, ecx
jnz @F
mov ecx, 40
@@:
mov eax, animationClock3D
cmp esi,3
jae @F
mov edx,casinoSprites[ebx].curFrame
imul edx,ecx
add eax,edx
@@:
xor edx, edx
div ecx
mov ecx, casinoSprites[ebx].frameCount
test ecx, ecx
jnz @F
mov ecx, 1
@@:
xor edx, edx
div ecx
add edx, casinoSprites[ebx].baseTexId
shl edx, 16
add edx, OFFSET texturesBuffer
mov hallLegacyPack3D.pixels, edx
mov hallSpriteTemp3D.frame, 0
mov hallSpriteTemp3D.asset, OFFSET hallLegacyPack3D
invoke DrawCityObject3D, OFFSET hallSpriteTemp3D, 0
hall_sprite_next:
inc esi
cmp esi, NUM_SPRITES
jb hall_sprite_loop
hall_sprites_done:
ret
RenderSprites ENDP
InitHall3D PROC uses esi edi
lea esi, hallLayout3D
lea edi, casinoMap
mov ecx, 256
rep movsd
mov hallLevel3D, 0
mov worldMap3D, OFFSET casinoMap
mov viewEye3D, FP_1*17/20
mov viewCeiling3D, FP_1*5/2
mov floorTexture3D, 100
mov casinoSprites[14*SIZEOF SpriteObject].interactId, 0
mov patronClock3D, 0
ret
InitHall3D ENDP
LoadHallAssets3D PROC
invoke LoadAnimPack3D, OFFSET hallBartender3D, OFFSET hallBartenderPath3D
invoke LoadAnimPack3D, OFFSET hallProps3D, OFFSET hallPropsPath3D
invoke LoadAnimPack3D, OFFSET hallDrink3D, OFFSET hallDrinkPath3D
invoke LoadAnimPack3D, OFFSET hallCityDetail3D, OFFSET hallCityDetailPath3D
invoke LoadAnimPack3D, OFFSET hallRoomMaterials3D, OFFSET hallRoomMaterialsPath3D
invoke LoadAnimPack3D, OFFSET hallPatrons3D, OFFSET hallPatronsPath3D
invoke LoadAnimPack3D, OFFSET hallStreetLife3D, OFFSET hallStreetLifePath3D
invoke LoadAnimPack3D, OFFSET hallRoomHD3D, OFFSET hallRoomHDPath3D
invoke LoadAnimPack3D, OFFSET hallArchitecture3D, OFFSET hallArchitecturePath3D
invoke LoadAnimPack3D, OFFSET hallArchitectureHD3D, OFFSET hallArchitectureHDPath3D
invoke LoadAnimPack3D, OFFSET hallDecorPack3D, OFFSET hallDecorPath3D
cmp hallArchitecture3D.pixels, 0
je @F
push esi
push edi
mov esi, hallArchitecture3D.pixels
mov edi, OFFSET texturesBuffer+(92*128*128*4)
mov ecx, 12*128*128
rep movsd
pop edi
pop esi
@@:
cmp hallRoomMaterials3D.pixels, 0
je @F
push esi
push edi
mov esi, hallRoomMaterials3D.pixels
mov edi, OFFSET texturesBuffer+(80*128*128*4)
mov ecx, 12*128*128
rep movsd
pop edi
pop esi
@@:
invoke LoadAnimPack3D, OFFSET materialsPack3D, OFFSET materialsPath3D
cmp materialsPack3D.pixels, 0
je hall_load_sign
push ebx
push esi
push edi
xor ebx, ebx
hall_copy_material:
mov esi, materialsPack3D.pixels
mov eax, ebx
shl eax, 16
add esi, eax
mov eax, hallMaterialSlots3D[ebx*4]
shl eax, 16
lea edi, texturesBuffer[eax]
mov ecx, 128*128
rep movsd
inc ebx
cmp ebx, 4
jb hall_copy_material
pop edi
pop esi
pop ebx
hall_load_sign:
ret
LoadHallAssets3D ENDP
FreeHallAssets3D PROC
invoke FreeAnimPack3D, OFFSET hallBartender3D
invoke FreeAnimPack3D, OFFSET hallProps3D
invoke FreeAnimPack3D, OFFSET hallDrink3D
invoke FreeAnimPack3D, OFFSET hallCityDetail3D
invoke FreeAnimPack3D, OFFSET hallRoomMaterials3D
invoke FreeAnimPack3D, OFFSET hallPatrons3D
invoke FreeAnimPack3D, OFFSET hallStreetLife3D
invoke FreeAnimPack3D, OFFSET hallRoomHD3D
invoke FreeAnimPack3D, OFFSET hallArchitecture3D
invoke FreeAnimPack3D, OFFSET hallArchitectureHD3D
invoke FreeAnimPack3D, OFFSET hallDecorPack3D
ret
FreeHallAssets3D ENDP
; EAX=pixels, ECX=width, EDX=height; legacy materials keep their 128px fallback.
ResolveWorldSurface3D PROC uses esi material:DWORD
mov eax, material
cmp eax,110
jne @F
mov eax,OFFSET cityBenchMetal3D
mov ecx,32
mov edx,32
ret
@@:
cmp eax, 104
jae surface_decor
cmp eax, 92
jae surface_architecture
cmp eax, 80
jae surface_room
cmp eax, 57
jb surface_legacy
cmp eax, 72
ja surface_legacy
mov esi, OFFSET hallCityDetail3D
sub eax, 57
jmp surface_pack
surface_room:
mov esi, OFFSET hallRoomHD3D
sub eax, 80
jmp surface_pack
surface_architecture:
mov esi, OFFSET hallArchitectureHD3D
sub eax, 92
jmp surface_pack
surface_decor:
cmp eax, 109
ja surface_missing
mov esi, OFFSET hallDecorPack3D
sub eax, 104
surface_pack:
cmp [esi].AnimPack3D.pixels, 0
je surface_legacy
cmp eax, [esi].AnimPack3D.frames
jae surface_missing
mov ecx, [esi].AnimPack3D.imageWidth
mov edx, [esi].AnimPack3D.height
imul eax, ecx
imul eax, edx
shl eax, 2
add eax, [esi].AnimPack3D.pixels
ret
surface_legacy:
mov eax, material
cmp eax, 104
jae surface_missing
shl eax, 16
add eax, OFFSET texturesBuffer
mov ecx, 128
mov edx, 128
ret
surface_missing:
xor eax, eax
mov ecx, 128
mov edx, 128
ret
ResolveWorldSurface3D ENDP
RenderHall3D PROC uses ebx esi
cmp hallLevel3D, 0
jne hall_render_bunker
; Fixed bar counter/stage are world geometry, with height and occlusion.
invoke DrawCityBoxSides3D, 3*FP_1,9*FP_1,23*FP_1,24*FP_1,0,FP_1*13/20,86
invoke DrawCityHorizontal3D, 3*FP_1,9*FP_1,23*FP_1,24*FP_1,FP_1*13/20,85
; Three physical panels preserve detail instead of stretching one over the whole bar.
invoke DrawCityVertical3D,1,24*FP_1,3*FP_1,5*FP_1,0,FP_1*13/20,84
invoke DrawCityVertical3D,1,24*FP_1,5*FP_1,7*FP_1,0,FP_1*13/20,84
invoke DrawCityVertical3D,1,24*FP_1,7*FP_1,9*FP_1,0,FP_1*13/20,84
invoke DrawCityBoxSides3D,3*FP_1,9*FP_1,21*FP_1,22*FP_1,0,FP_1*19/10,86
invoke DrawCityVertical3D,1,22*FP_1,3*FP_1,5*FP_1,FP_1*3/5,FP_1*19/10,87
invoke DrawCityVertical3D,1,22*FP_1,5*FP_1,7*FP_1,FP_1*3/5,FP_1*19/10,87
invoke DrawCityVertical3D,1,22*FP_1,7*FP_1,9*FP_1,FP_1*3/5,FP_1*19/10,87
invoke DrawCityBoxSides3D, 10*FP_1,22*FP_1,2*FP_1,5*FP_1,0,FP_1/8,2
invoke DrawCityHorizontal3D, 10*FP_1,22*FP_1,2*FP_1,5*FP_1,FP_1/8,2
; Cabaret has a solid stage, side wings, stairs and lighting truss.
invoke DrawCityVertical3D,0,10*FP_1,2*FP_1,5*FP_1,FP_1/8,FP_1*23/10,2
invoke DrawCityVertical3D,0,22*FP_1,2*FP_1,5*FP_1,FP_1/8,FP_1*23/10,2
invoke DrawCityVertical3D,1,2*FP_1,10*FP_1,22*FP_1,FP_1/8,FP_1*23/10,2
invoke DrawCityHorizontal3D,14*FP_1,18*FP_1,5*FP_1,FP_1*11/2,FP_1/12,85
invoke DrawCityHorizontal3D,14*FP_1,18*FP_1,FP_1*11/2,6*FP_1,FP_1/24,85
invoke DrawCityBoxSides3D,10*FP_1,22*FP_1,5*FP_1,FP_1*51/10,FP_1*11/5,FP_1*23/10,86
; Low room boundaries frame dining and billiards without closing their entrances.
invoke DrawCityBoxSides3D,FP_1*119/10,FP_1*121/10,24*FP_1,FP_1*51/2,0,FP_1*13/20,102
invoke DrawCityHorizontal3D,FP_1*119/10,FP_1*121/10,24*FP_1,FP_1*51/2,FP_1*13/20,85
invoke DrawCityBoxSides3D,FP_1*119/10,FP_1*121/10,FP_1*55/2,30*FP_1,0,FP_1*13/20,102
invoke DrawCityBoxSides3D,23*FP_1,FP_1*116/5,23*FP_1,24*FP_1,0,FP_1*13/20,102
invoke DrawCityBoxSides3D,23*FP_1,FP_1*116/5,26*FP_1,29*FP_1,0,FP_1*13/20,102
invoke DrawCityVertical3D,1,6*FP_1,14*FP_1,18*FP_1,FP_1*17/10,FP_1*12/5,109
invoke DrawCityBoxSides3D,1*FP_1,9*FP_1,FP_1,FP_1*6/5,FP_1*11/5,FP_1*5/2,103
invoke DrawCityBoxSides3D,23*FP_1,31*FP_1,FP_1,FP_1*6/5,FP_1*11/5,FP_1*5/2,103
mov eax, animationClock3D
xor edx, edx
mov ecx, 220
div ecx
and eax, 1
cmp engineMode, MODE_BAR
jne hall_bartender_pose
cmp barPhase3D, 1
jne hall_bartender_pose
mov eax, barTime3D
xor edx, edx
mov ecx, 375
div ecx
cmp eax, 7
jbe hall_bartender_pose
mov eax, 7
jmp hall_bartender_selected
hall_bartender_pose:
cmp engineMode, MODE_BAR
jne hall_bartender_store
cmp barPhase3D, 1
je hall_bartender_selected
cmp barPhase3D, 2
jne hall_bartender_store
mov eax,7
hall_bartender_selected:
mov ecx, barSelection3D
shl ecx, 3
add eax, ecx
hall_bartender_store:
mov hallObjects3D[4*SIZEOF CityProp3D].frame, eax
xor esi, esi
hall_render_props:
; The former whole-stage billboard is replaced with world surfaces above.
cmp esi, 15
je hall_render_next_prop
imul eax, esi, SIZEOF CityProp3D
add eax, OFFSET hallObjects3D
invoke DrawCityObject3D, eax, 0
hall_render_next_prop:
inc esi
cmp esi, HALL_PROP_COUNT
jb hall_render_props
xor esi, esi
hall_render_lights:
imul eax, esi, SIZEOF CityProp3D
add eax, OFFSET hallLights3D
invoke DrawCityObject3D,eax,0
inc esi
cmp esi, HALL_LIGHT_COUNT
jb hall_render_lights
call RenderPatrons3D
ret
hall_render_bunker:
mov esi, 0
hall_stair_step:
mov eax, esi
imul eax, FP_1/2
add eax, 24*FP_1
lea ebx, [eax+FP_1/2]
lea ecx, [esi+1]
imul ecx, FP_1/8
invoke DrawCityHorizontal3D,15*FP_1,18*FP_1,eax,ebx,ecx,88
mov eax, esi
imul eax, FP_1/2
add eax, 24*FP_1
mov ecx, esi
imul ecx, FP_1/8
lea edx, [ecx+FP_1/8]
invoke DrawCityVertical3D,1,eax,15*FP_1,18*FP_1,ecx,edx,92
inc esi
cmp esi, 8
jb hall_stair_step
invoke DrawCityBoxSides3D, 14*FP_1,20*FP_1,14*FP_1,15*FP_1,0,FP_1/2,96
invoke DrawCityHorizontal3D, 14*FP_1,20*FP_1,14*FP_1,15*FP_1,FP_1/2,97
invoke DrawCityVertical3D,1,11*FP_1+FP_1/10,14*FP_1,16*FP_1,FP_1/4,FP_1*8/5,95
invoke DrawCityVertical3D,1,11*FP_1+FP_1/10,17*FP_1,19*FP_1+FP_HALF,FP_1/4,FP_1*8/5,95
invoke DrawCityVertical3D,0,19*FP_1+FP_1*9/10,17*FP_1,20*FP_1,0,FP_1*3/2,99
; A narrow, stepped vault is real geometry, not a square workshop ceiling.
invoke DrawCityHorizontal3D,14*FP_1,15*FP_1,11*FP_1,24*FP_1,FP_1*9/5,93
invoke DrawCityVertical3D,0,15*FP_1,11*FP_1,24*FP_1,FP_1*9/5,FP_1*11/5,93
invoke DrawCityHorizontal3D,15*FP_1,16*FP_1,11*FP_1,24*FP_1,FP_1*11/5,93
invoke DrawCityVertical3D,0,16*FP_1,11*FP_1,24*FP_1,FP_1*11/5,FP_1*5/2,93
invoke DrawCityHorizontal3D,18*FP_1,19*FP_1,11*FP_1,24*FP_1,FP_1*11/5,93
invoke DrawCityVertical3D,0,18*FP_1,11*FP_1,24*FP_1,FP_1*11/5,FP_1*5/2,93
invoke DrawCityHorizontal3D,19*FP_1,20*FP_1,11*FP_1,24*FP_1,FP_1*9/5,93
invoke DrawCityVertical3D,0,19*FP_1,11*FP_1,24*FP_1,FP_1*9/5,FP_1*11/5,93
mov eax, animationClock3D
xor edx, edx
mov ecx, 240
div ecx
and eax, 7
mov bunkerMerchant3D.frame, eax
invoke DrawCityObject3D, OFFSET bunkerMerchant3D, 0
invoke DrawCityObject3D, OFFSET bunkerDisplay3D, 0
invoke DrawCityObject3D, OFFSET bunkerDesk3D, 0
invoke DrawCityObject3D, OFFSET bunkerDoor3D, 0
ret
RenderHall3D ENDP
; Extra rooms use the same distance and facing checks as the existing tables.
HallTarget3D PROC uses ebx wx:DWORD,wy:DWORD,id:DWORD,prompt:DWORD
mov eax, wx
sub eax, playerX
sar eax, 8
mov ebx, eax
imul eax, eax
mov ecx, eax
mov eax, wy
sub eax, playerY
sar eax, 8
mov edx, eax
imul eax, eax
add ecx, eax
cmp ecx, 262144
jae hall_target_done
mov eax, playerDirX
sar eax, 8
imul eax, ebx
mov ebx, playerDirY
sar ebx, 8
imul ebx, edx
add eax, ebx
cmp eax, 18000
jl hall_target_done
mov eax, id
mov interactTargetId, eax
mov eax, prompt
mov interactPromptPtr, eax
hall_target_done:
ret
HallTarget3D ENDP
CheckHallInteractions3D PROC
cmp hallLevel3D, 0
jne hall_check_bunker
cmp playerX, 3*FP_1
jl hall_check_other
cmp playerX, 9*FP_1
jg hall_check_other
cmp playerY, 24*FP_1+9830
jl hall_check_other
; A point on the serving edge remains in front even when standing close.
invoke HallTarget3D, playerX,23*FP_1+FP_HALF,INTERACT_BAR,OFFSET hallBarPrompt3D
hall_check_other:
invoke HallTarget3D, 28*FP_1+FP_HALF,10*FP_1+FP_HALF,INTERACT_BASEMENT,OFFSET hallBunkerPrompt3D
invoke HallTarget3D, 27*FP_1,25*FP_1,INTERACT_BILLIARDS,OFFSET hallPoolPrompt3D
ret
hall_check_bunker:
mov interactTargetId, 0
mov interactPromptPtr, 0
invoke HallTarget3D, 16*FP_1,14*FP_1+FP_HALF,INTERACT_SHOP,OFFSET promptShop
invoke HallTarget3D, 16*FP_1,27*FP_1,INTERACT_UPSTAIRS,OFFSET hallUpPrompt3D
ret
CheckHallInteractions3D ENDP
TriggerHallInteraction3D PROC
cmp interactTargetId, INTERACT_BAR
jne hall_trigger_stairs
call LoadHallAssets3D
mov engineMode, MODE_BAR
mov barPhase3D, 0
mov barTime3D, 0
call ClearKeys3D
mov eax, 1
ret
hall_trigger_stairs:
cmp interactTargetId, INTERACT_BASEMENT
je hall_begin_stairs
cmp interactTargetId, INTERACT_UPSTAIRS
jne hall_trigger_none
hall_begin_stairs:
cmp hallLevel3D, 0
jne @F
mov eax, playerX
mov stairsReturnX3D, eax
mov eax, playerY
mov stairsReturnY3D, eax
mov eax, playerAngle
mov stairsReturnAngle3D, eax
@@:
mov engineMode, MODE_STAIRS
mov stairsTime3D, 0
call ClearKeys3D
mov eax, 1
ret
hall_trigger_none:
cmp interactTargetId, INTERACT_BILLIARDS
jne @F
call InitPool3D
mov engineMode, MODE_POOL
call ClearKeys3D
mov eax, 1
ret
@@:
xor eax, eax
ret
TriggerHallInteraction3D ENDP
HandleStairs3D PROC
mov eax, deltaTime3D
add stairsTime3D, eax
cmp stairsTime3D, 1600
jb stairs_handle_done
xor hallLevel3D, 1
cmp hallLevel3D, 0
je stairs_back_to_hall
mov worldMap3D, OFFSET bunkerMap3D
mov floorTexture3D, 94
mov viewCeiling3D, FP_1*5/2
mov playerX, 16*FP_1+FP_HALF
mov playerY, 23*FP_1+FP_HALF
mov playerAngle, 384
jmp stairs_complete
stairs_back_to_hall:
mov worldMap3D, OFFSET casinoMap
mov floorTexture3D, 100
mov viewCeiling3D, FP_1*5/2
mov eax, stairsReturnX3D
mov playerX, eax
mov eax, stairsReturnY3D
mov playerY, eax
mov eax, stairsReturnAngle3D
mov playerAngle, eax
stairs_complete:
mov viewEye3D, FP_1*17/20
mov engineMode, MODE_WALK
call ClearKeys3D
stairs_handle_done:
ret
HandleStairs3D ENDP
RenderStairs3D PROC uses ebx esi
local oldX:DWORD,oldY:DWORD,oldAngle:DWORD,oldMap:DWORD,oldEye:DWORD,oldCeiling:DWORD,oldLevel:DWORD,oldFloor:DWORD
mov eax, playerX
mov oldX, eax
mov eax, playerY
mov oldY, eax
mov eax, playerAngle
mov oldAngle, eax
mov eax, worldMap3D
mov oldMap, eax
mov eax, viewEye3D
mov oldEye, eax
mov eax, viewCeiling3D
mov oldCeiling, eax
mov eax, hallLevel3D
mov oldLevel, eax
mov eax, floorTexture3D
mov oldFloor, eax
mov hallLevel3D, 1
mov worldMap3D, OFFSET bunkerMap3D
mov floorTexture3D, 94
mov viewCeiling3D, FP_1*5/2
mov playerX, 16*FP_1+FP_HALF
mov playerAngle, 384
mov eax, stairsTime3D
cmp eax, 1600
jbe @F
mov eax, 1600
@@:
cmp oldLevel, 0
je @F
neg eax
add eax, 1600
@@:
imul eax, 4*FP_1
xor edx, edx
mov ecx, 1600
div ecx
mov ebx, 27*FP_1+FP_HALF
sub ebx, eax
mov playerY, ebx
shr eax, 2
neg eax
add eax, FP_1*37/20
mov viewEye3D, eax
call UpdateCamera3D
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
call RenderHall3D
mov eax, oldX
mov playerX, eax
mov eax, oldY
mov playerY, eax
mov eax, oldAngle
mov playerAngle, eax
mov eax, oldMap
mov worldMap3D, eax
mov eax, oldEye
mov viewEye3D, eax
mov eax, oldCeiling
mov viewCeiling3D, eax
mov eax, oldLevel
mov hallLevel3D, eax
mov eax, oldFloor
mov floorTexture3D, eax
call UpdateCamera3D
ret
RenderStairs3D ENDP
BuyBarDrink3D PROC drink:DWORD
cmp barPhase3D, 0
jne bar_buy_done
mov ecx, drink
cmp ecx, 2
ja bar_buy_done
mov eax, barPrice3D[ecx*4]
cmp bankroll, eax
jb bar_buy_poor
sub bankroll, eax
mov barSelection3D, ecx
mov barPhase3D, 1
mov barTime3D, 0
call SaveProgress3D
ret
bar_buy_poor:
invoke CopyString3D, OFFSET barPoor3D, OFFSET flashMessage
mov flashTimer, 150
bar_buy_done:
ret
BuyBarDrink3D ENDP
HandleBar3D PROC uses ebx
cmp barPhase3D, 0
jne bar_animate
mov ebx, 31h
bar_select_key:
invoke Pressed3D, ebx
test eax, eax
jz @F
mov eax, ebx
sub eax, 31h
invoke BuyBarDrink3D, eax
ret
@@:
inc ebx
cmp ebx, 33h
jbe bar_select_key
cmp mouseClick3D, 0
je bar_handle_done
cmp mouseX3D, 170
jb bar_handle_done
cmp mouseY3D, 98
jb bar_handle_done
cmp mouseY3D, 155
jae bar_handle_done
mov eax, mouseY3D
sub eax, 98
xor edx, edx
mov ecx, 19
div ecx
invoke BuyBarDrink3D, eax
ret
bar_animate:
mov eax, deltaTime3D
add barTime3D, eax
cmp barPhase3D, 1
jne bar_after_drink
cmp barTime3D, 3000
jb bar_handle_done
mov barPhase3D, 2
mov barTime3D, 0
ret
bar_after_drink:
cmp barTime3D, 2400
jb bar_handle_done
mov ecx, barSelection3D
mov eax, barStrength3D[ecx*4]
test eax, eax
jnz @F
mov barIntoxication3D, 0
@@:
add barIntoxication3D, eax
cmp barIntoxication3D, 60000
jbe @F
mov barIntoxication3D, 60000
@@:
mov barPhase3D, 0
mov barTime3D, 0
bar_handle_done:
ret
HandleBar3D ENDP
RenderBar3D PROC uses ebx
local oldX:DWORD,oldY:DWORD,oldAngle:DWORD,oldHorizon:DWORD,oldEye:DWORD,oldMode:DWORD
mov eax, playerX
mov oldX, eax
mov eax, playerY
mov oldY, eax
mov eax, playerAngle
mov oldAngle, eax
mov eax, viewHorizon3D
mov oldHorizon, eax
mov eax, viewEye3D
mov oldEye, eax
mov eax, engineMode
mov oldMode, eax
mov engineMode, MODE_BAR
mov playerX, 6*FP_1
mov playerY, 25*FP_1+FP_1/3
mov playerAngle, 384
mov viewHorizon3D, HALF_H
mov viewEye3D, FP_1*17/20
call UpdateCamera3D
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
call RenderHall3D
cmp barPhase3D, 0
jne bar_active_scene
invoke DrawBoxBorder, 170,83,146,86,0017201Bh,00836D42h,1
invoke DrawString8x8, 174,99,OFFSET barDrinks3D,00E4D9BDh
invoke DrawString8x8, 174,118,OFFSET barDrinks23D,00E4D9BDh
invoke DrawString8x8, 174,137,OFFSET barDrinks33D,00BCD7D0h
jmp bar_draw_title
bar_active_scene:
mov ebx, OFFSET barMixText3D
cmp barPhase3D, 2
jne @F
mov ebx, OFFSET barDrinkText3D
@@:
invoke DrawBox,170,83,146,24,0017201Bh
invoke DrawString8x8,176,91,ebx,00E7CA88h
bar_draw_title:
invoke DrawBox,0,0,320,28,0014191Dh
invoke DrawString8x8, 18,15,OFFSET barName3D,00E7CA88h
cmp barPhase3D, 2
jne bar_render_done
mov eax, barTime3D
xor edx, edx
mov ecx, 343
div ecx
cmp eax, 6
jbe @F
mov eax, 6
@@:
mov ecx, barSelection3D
imul ecx, 7
add eax, ecx
invoke DrawAnimSprite3D, OFFSET hallDrink3D,eax,272,170,360,360
bar_render_done:
invoke DrawNumber,240,15,bankroll,00E5D6B0h
mov eax, oldX
mov playerX, eax
mov eax, oldY
mov playerY, eax
mov eax, oldAngle
mov playerAngle, eax
mov eax, oldHorizon
mov viewHorizon3D, eax
mov eax, oldEye
mov viewEye3D, eax
mov eax, oldMode
mov engineMode, eax
call UpdateCamera3D
ret
RenderBar3D ENDP
RenderCityGuards3D PROC uses ebx
mov eax, cityClock3D
xor edx, edx
mov ecx, 180
div ecx
and eax, 7
mov cityGuardLeft3D.frame, eax
cmp arrivalState3D, ARRIVAL_WALK
je city_world_guard_right
mov cityGuardLeft3D.frame, 15
cmp arrivalState3D, ARRIVAL_STOP
jne city_world_guard_invite
mov eax, arrivalTime3D
xor edx, edx
mov ecx, 90
div ecx
cmp eax, 7
jbe @F
mov eax, 7
@@:
add eax, 8
mov cityGuardLeft3D.frame, eax
jmp city_world_guard_right
city_world_guard_invite:
cmp arrivalState3D, ARRIVAL_ADMIT
jb city_world_guard_right
mov eax, arrivalTime3D
xor edx, edx
mov ecx, 120
div ecx
add eax, 16
cmp eax, 22
jbe @F
mov eax, 22
@@:
mov cityGuardLeft3D.frame, eax
city_world_guard_right:
mov eax, cityClock3D
add eax, 590
xor edx, edx
mov ecx, 220
div ecx
and eax, 7
cmp arrivalState3D, ARRIVAL_PROFILE
jne @F
add eax, 24
@@:
mov cityGuardRight3D.frame, eax
invoke DrawCityObject3D, OFFSET cityGuardLeft3D,0
invoke DrawCityObject3D, OFFSET cityGuardRight3D,0
ret
RenderCityGuards3D ENDP
CanWalkHall3D PROC px:DWORD,py:DWORD
cmp hallLevel3D, 0
jne hall_collision_bunker
; Stage and wings are solid: the audience stays in the cabaret's front aisle.
cmp px, 10*FP_1-9830
jl hall_collision_stage_clear
cmp px, 22*FP_1+9830
jg hall_collision_stage_clear
cmp py, 2*FP_1-9830
jl hall_collision_stage_clear
cmp py, 5*FP_1+9830
jle hall_collision_blocked
hall_collision_stage_clear:
cmp px, FP_1*47/4
jl hall_collision_cabinets
cmp px, FP_1*49/4
jg hall_collision_pool_divider
cmp py, 24*FP_1-9830
jl hall_collision_cabinets
cmp py, FP_1*51/2+9830
jle hall_collision_blocked
cmp py, FP_1*55/2-9830
jl hall_collision_cabinets
cmp py, 30*FP_1+9830
jle hall_collision_blocked
hall_collision_pool_divider:
cmp px, 23*FP_1-9830
jl hall_collision_cabinets
cmp px, FP_1*116/5+9830
jg hall_collision_cabinets
cmp py, 23*FP_1-9830
jl hall_collision_cabinets
cmp py, 24*FP_1+9830
jle hall_collision_blocked
cmp py, 26*FP_1-9830
jl hall_collision_cabinets
cmp py, 29*FP_1+9830
jle hall_collision_blocked
hall_collision_cabinets:
; The work aisle is staff-only; player interaction is from the serving side.
cmp px, 3*FP_1-9830
jl hall_collision_counter
cmp px, 9*FP_1+9830
jg hall_collision_counter
cmp py, 21*FP_1-9830
jl hall_collision_counter
cmp py, 24*FP_1+9830
jle hall_collision_blocked
hall_collision_counter:
cmp px, 3*FP_1-9830
jl hall_collision_dining
cmp px, 9*FP_1+9830
jg hall_collision_pool
cmp py, 23*FP_1-9830
jl hall_collision_clear
cmp py, 24*FP_1+9830
jg hall_collision_dining
xor eax, eax
ret
hall_collision_pool:
cmp px, 26*FP_1-9830
jl hall_collision_dining
cmp px, 28*FP_1+9830
jg hall_collision_dining
cmp py, 24*FP_1-9830
jl hall_collision_clear
cmp py, 26*FP_1+9830
jg hall_collision_dining
xor eax, eax
ret
hall_collision_bunker:
cmp px, 14*FP_1-9830
jl hall_collision_clear
cmp px, 20*FP_1+9830
jg hall_collision_clear
cmp py, 14*FP_1-9830
jl hall_collision_clear
cmp py, 15*FP_1+9830
jg hall_collision_clear
hall_collision_blocked:
xor eax, eax
ret
hall_collision_clear:
mov eax, 1
ret
hall_collision_dining:
cmp py, 26*FP_1+FP_1/3
jl hall_collision_clear
cmp py, 29*FP_1+FP_HALF
jg hall_collision_clear
cmp px, 2*FP_1
jl hall_collision_clear
cmp px, 5*FP_1
jle hall_collision_blocked
cmp px, 8*FP_1
jl hall_collision_clear
cmp px, 11*FP_1
jle hall_collision_blocked
jmp hall_collision_clear
CanWalkHall3D ENDP
RenderCityFacade3D PROC uses ebx esi
; The original entrance artwork carries CASINO itself, mapped once across the doorway.
invoke DrawCityBoxSides3D,21*FP_1,24*FP_1,8*FP_1,8*FP_1+FP_1/5,0,FP_1*9/5,57
invoke DrawCityVertical3D,1,8*FP_1+FP_1/5,21*FP_1,24*FP_1,0,FP_1*9/5,58
invoke DrawCityBoxSides3D,FP_1*104/5,FP_1*106/5,8*FP_1,8*FP_1+FP_1*2/5,0,2*FP_1,103
invoke DrawCityBoxSides3D,FP_1*119/5,FP_1*121/5,8*FP_1,8*FP_1+FP_1*2/5,0,2*FP_1,103
invoke DrawCityBoxSides3D,FP_1*104/5,FP_1*121/5,8*FP_1,8*FP_1+FP_HALF,FP_1*9/5,2*FP_1,86
invoke DrawCityHorizontal3D,FP_1*104/5,FP_1*121/5,8*FP_1,8*FP_1+FP_HALF,2*FP_1,85
invoke DrawCityVertical3D,1,8*FP_1+FP_1*41/100,FP_1*101/5,FP_1*104/5,FP_1,FP_1*8/5,105
invoke DrawCityVertical3D,1,8*FP_1+FP_1*41/100,FP_1*121/5,FP_1*124/5,FP_1,FP_1*8/5,105
; Recessed street windows, projecting bays and ledges are fixed world surfaces.
mov esi, 11
hall_city_pilaster:
cmp esi, 20
je hall_city_next_pilaster
cmp esi, 24
je hall_city_next_pilaster
mov ebx, esi
shl ebx, 16
lea eax, [ebx+FP_1/5]
invoke DrawCityBoxSides3D, ebx,eax,12*FP_1,12*FP_1+FP_1/6,0,5*FP_1,57
lea eax, [ebx+FP_1/5]
invoke DrawCityBoxSides3D, ebx,eax,17*FP_1-FP_1/6,17*FP_1,0,5*FP_1,57
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityBoxSides3D,eax,edx,FP_1*237/20,12*FP_1,FP_1/20,FP_1*13/10,57
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityVertical3D,1,12*FP_1+FP_1/25,eax,edx,FP_1/20,FP_1*13/10,62
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityBoxSides3D,eax,edx,12*FP_1,12*FP_1+FP_1/5,2*FP_1,FP_1*18/5,57
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityVertical3D,1,12*FP_1+FP_1/5,eax,edx,2*FP_1,FP_1*18/5,106
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityBoxSides3D,eax,edx,17*FP_1-FP_1/4,17*FP_1,2*FP_1,FP_1*18/5,57
lea eax, [ebx+FP_1/5]
lea edx, [ebx+FP_1*7/5]
invoke DrawCityVertical3D,1,17*FP_1-FP_1/4,eax,edx,2*FP_1,FP_1*18/5,106
hall_city_next_pilaster:
add esi, 4
cmp esi, 29
jb hall_city_pilaster
ret
RenderCityFacade3D ENDP
UpdateHall3D PROC
call UpdatePatrons3D
mov viewHorizon3D, HALF_H
mov viewEye3D, FP_1*17/20
cmp hallLevel3D, 0
je @F
mov eax, playerY
sub eax, 24*FP_1
jle @F
shr eax, 2
cmp eax, FP_1
jbe hall_step_eye
mov eax, FP_1
hall_step_eye:
add viewEye3D, eax
@@:
cmp barIntoxication3D, 0
je hall_update_done
mov eax, deltaTime3D
imul eax, 2
sub barIntoxication3D, eax
jnc @F
mov barIntoxication3D, 0
@@:
mov eax, animationClock3D
shr eax, 3
and eax, 511
mov eax, tableSin[eax*4]
imul barIntoxication3D
shrd eax, edx, 16
sar eax, 14
add viewHorizon3D, eax
hall_update_done:
ret
UpdateHall3D ENDP
; Absolute route phase avoids accumulated movement drift and keeps walking FPS-independent.
UpdatePatrons3D PROC uses ebx esi edi
local wx:DWORD,wy:DWORD,phase:DWORD
cmp hallLevel3D, 0
jne patron_update_done
mov eax, deltaTime3D
add eax, patronClock3D
xor edx, edx
mov ecx, 20000
div ecx
mov patronClock3D, edx
xor esi, esi
patron_update_loop:
mov eax, esi
imul eax, 10000
add eax, patronClock3D
xor edx, edx
mov ecx, 20000
div ecx
mov eax, edx
xor edx, edx
mov ecx, 5000
div ecx
mov phase, eax
mov eax, edx
imul eax, 4*FP_1
xor edx, edx
div ecx
mov wx, 18*FP_1
mov wy, 18*FP_1
cmp phase, 0
jne patron_route_south
add wx, eax
jmp patron_route_check
patron_route_south:
cmp phase, 1
jne patron_route_west
mov wx, 22*FP_1
shr eax, 1
add wy, eax
jmp patron_route_check
patron_route_west:
mov wy, 20*FP_1
cmp phase, 2
jne patron_route_north
mov wx, 22*FP_1
sub wx, eax
jmp patron_route_check
patron_route_north:
shr eax, 1
sub wy, eax
patron_route_check:
invoke CanWalk3D,wx,wy
test eax, eax
jz patron_update_next
imul ebx, esi, SIZEOF CityProp3D
mov eax, wx
mov hallGuests3D[ebx].posX, eax
mov eax, wy
mov hallGuests3D[ebx].posY, eax
mov eax, patronClock3D
xor edx, edx
mov ecx, 220
div ecx
and eax, 3
lea eax, [eax+esi*4]
mov hallGuests3D[ebx].frame, eax
patron_update_next:
inc esi
cmp esi, 2
jb patron_update_loop
patron_update_done:
ret
UpdatePatrons3D ENDP
RenderPatrons3D PROC uses esi
xor esi, esi
patron_render_loop:
imul eax, esi, SIZEOF CityProp3D
add eax, OFFSET hallGuests3D
invoke DrawCityObject3D,eax,0
inc esi
cmp esi, HALL_PATRON_COUNT
jb patron_render_loop
ret
RenderPatrons3D ENDP