KAZIK/src_graphics/hall_scene.inc
Artvasil09 51c6512675 feat: implement secret fortune teller room, lived-in den v3, and bar camera stabilization
- Secret Fortune Teller Room: arcade lantern toggle, sliding timber panel, dedicated staircase and compact cellar chamber

- Lived-in den pass v3: cloth hangings, draped workbench, props/clutter, centered entrance, and custom light sources

- Bar camera stabilization: remove alcohol horizon sway while retaining drink animations

- Synchronize binaries and update launcher hash to EADBA9C8C9BD5B7E3CC4CE486ED647C1CE9383D1DCB6EBC94FE755EA1F4BF927
2026-10-20 17:29:52 +03:00

1394 lines
41 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,2
jne @F
mov material,125
@@:
cmp hallLevel3D, 1
jne @F
mov material, 93
@@:
cmp hallLevel3D,3
je hall_plane_fortune_ceiling
cmp engineMode,MODE_STAIRS
jne hall_plane_distance
cmp stairRoute3D,3
jne hall_plane_distance
hall_plane_fortune_ceiling:
mov material,133
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:
cmp ecx, 240
jbe @F
mov ecx, 240
@@:
cmp ecx, 1
jae @F
mov ecx, 1
@@:
push eax
mov edx, [tableInvDelta3D + ecx*4]
imul edx
shrd eax, edx, 16
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
@@:
pop eax
mov edx, [tableStepRatio3D + ecx*4]
imul edx
shrd eax, edx, 16
mov ebx, eax
mov eax, playerPlaneX
imul ebx
shrd eax, edx, 16
mov sx, eax
mov eax, playerPlaneY
imul ebx
shrd eax, edx, 16
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 ebx,132
jb hall_plane_other_hd
cmp ebx,135
ja hall_plane_other_hd
mov ecx,fortuneMaterialArt3D.pixels
test ecx,ecx
jz hall_plane_fortune_fallback
sub ebx,132
shl ebx,18
add ecx,ebx
jmp hall_plane_hd_coordinates
hall_plane_fortune_fallback:
mov ebx,94
mov material,ebx
hall_plane_other_hd:
cmp ebx,122
jb hall_plane_existing_hd
cmp ebx,125
ja hall_plane_existing_hd
mov ecx,upperMaterialArt3D.pixels
test ecx,ecx
jz hall_plane_upper_fallback
sub ebx,122
shl ebx,18
add ecx,ebx
jmp hall_plane_hd_coordinates
hall_plane_upper_fallback:
mov ebx,85
mov material,ebx
hall_plane_existing_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
hall_plane_hd_coordinates:
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 engineMode,MODE_STAIRS
je hall_sprites_done
cmp hallLevel3D, 0
jne hall_sprites_done
xor esi, esi
hall_sprite_loop:
cmp esi,3
jb hall_sprite_next
cmp esi,17
je hall_sprite_next
cmp esi,19
je hall_sprite_next
cmp esi,21
je hall_sprite_next
cmp esi, 14
je hall_sprite_next
cmp esi, 15
je hall_sprite_next
cmp esi, 16
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
mov eax, hallStationPacks3D[esi*4]
test eax, eax
jz hall_sprite_draw
; Missing dedicated art hides the station, never shows a contaminated atlas cell.
cmp [eax].AnimPack3D.pixels, 0
je hall_sprite_next
mov hallSpriteTemp3D.asset, eax
cmp eax, OFFSET hallSlotFurniture3D
jne hall_sprite_draw
mov eax, animationClock3D
xor edx, edx
mov ecx, 320
div ecx
add eax, esi
xor edx, edx
mov ecx, 3
div ecx
mov hallSpriteTemp3D.frame, edx
hall_sprite_draw:
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 fortunePassageTarget3D,0
mov fortunePassageTime3D,0
mov fortunePassageClock3D,-1
mov worldMap3D, OFFSET casinoMap
mov viewEye3D, HALL_STANDING_EYE
mov viewCeiling3D, FP_1*5/2
mov floorTexture3D, 100
mov casinoSprites[14*SIZEOF SpriteObject].interactId, 0
mov patronClock3D, 0
; Precalculate floor & ceiling distance / step LUTs (no division at runtime)
mov ecx, 1
init_plane_lut:
cmp ecx, 241
jge init_plane_done
mov eax, SCREEN_H * FP_1
xor edx, edx
div ecx
mov [tableInvDelta3D + ecx*4], eax
mov eax, 98304
xor edx, edx
div ecx
mov [tableStepRatio3D + ecx*4], eax
inc ecx
jmp init_plane_lut
init_plane_done:
call InitCasinoNpcMind
call PositionTerminalStations3D
mov scrStation3D.posX,29*FP_1
mov scrStation3D.posY,FP_1*15/2
call InitNpcLife3D
call BuildHallLighting3D
ret
InitHall3D ENDP
LoadHallAssets3D PROC
call InitUpperSurfaces3D
call LoadFortuneArt3D
invoke LoadAnimPack3D, OFFSET upperMaterialArt3D, OFFSET upperMaterialPath3D
invoke ValidateCityPack3D, OFFSET upperMaterialArt3D,256,256,4
invoke LoadAnimPack3D,OFFSET upperGamesArt3D,OFFSET upperGamesPath3D
invoke ValidateCityPack3D,OFFSET upperGamesArt3D,320,224,2
invoke LoadAnimPack3D,OFFSET upperPortalArt3D,OFFSET upperPortalPath3D
invoke ValidateCityPack3D,OFFSET upperPortalArt3D,256,512,13
invoke LoadAnimPack3D,OFFSET upperLeverArt3D,OFFSET upperLeverPath3D
invoke ValidateCityPack3D,OFFSET upperLeverArt3D,128,224,6
invoke LoadAnimPack3D,OFFSET upperBarArt3D,OFFSET upperBarPath3D
invoke ValidateCityPack3D,OFFSET upperBarArt3D,160,256,2
invoke LoadAnimPack3D,OFFSET upperBrazierArt3D,OFFSET upperBrazierPath3D
invoke ValidateCityPack3D,OFFSET upperBrazierArt3D,128,256,4
invoke LoadAnimPack3D, OFFSET cabaretArt3D, OFFSET cabaretPath3D
invoke ValidateCityPack3D, OFFSET cabaretArt3D,160,256,12
invoke LoadAnimPack3D, OFFSET cabaretPianoArt3D, OFFSET cabaretPianoPath3D
invoke ValidateCityPack3D, OFFSET cabaretPianoArt3D,384,256,4
invoke LoadAnimPack3D, OFFSET cabaretGuitarArt3D, OFFSET cabaretGuitarPath3D
invoke ValidateCityPack3D, OFFSET cabaretGuitarArt3D,160,256,4
invoke LoadAnimPack3D, OFFSET npcGuestArt3D, OFFSET npcGuestPath3D
invoke ValidateCityPack3D, OFFSET npcGuestArt3D,128,224,36
invoke LoadAnimPack3D, OFFSET npcWalkArt3D, OFFSET npcWalkPath3D
invoke ValidateCityPack3D, OFFSET npcWalkArt3D,128,224,48
invoke LoadAnimPack3D, OFFSET npcWalkLeftArt3D, OFFSET npcWalkLeftPath3D
invoke ValidateCityPack3D, OFFSET npcWalkLeftArt3D,128,224,48
invoke LoadAnimPack3D, OFFSET basementDoorArt3D, OFFSET basementDoorPath3D
invoke ValidateCityPack3D, OFFSET basementDoorArt3D,256,512,18
call LoadWorldDressing3D
call LoadScratchArt3D
invoke LoadAnimPack3D, OFFSET hallCardFurniture3D, OFFSET hallCardFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallWheelFurniture3D, OFFSET hallWheelFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallBackFurniture3D, OFFSET hallBackFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallSkillFurniture3D, OFFSET hallSkillFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallChairFurniture3D, OFFSET hallChairFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallLampFurniture3D, OFFSET hallLampFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallRopeFurniture3D, OFFSET hallRopeFurniturePath3D
invoke LoadAnimPack3D, OFFSET hallSlotFurniture3D, OFFSET hallSlotFurniturePath3D
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
call FreeFortuneArt3D
invoke FreeAnimPack3D, OFFSET upperMaterialArt3D
invoke FreeAnimPack3D,OFFSET upperGamesArt3D
invoke FreeAnimPack3D,OFFSET upperPortalArt3D
invoke FreeAnimPack3D,OFFSET upperLeverArt3D
invoke FreeAnimPack3D,OFFSET upperBarArt3D
invoke FreeAnimPack3D,OFFSET upperBrazierArt3D
invoke FreeAnimPack3D, OFFSET cabaretArt3D
invoke FreeAnimPack3D, OFFSET cabaretPianoArt3D
invoke FreeAnimPack3D, OFFSET cabaretGuitarArt3D
invoke FreeAnimPack3D, OFFSET npcGuestArt3D
invoke FreeAnimPack3D, OFFSET npcWalkArt3D
invoke FreeAnimPack3D, OFFSET npcWalkLeftArt3D
invoke FreeAnimPack3D, OFFSET basementDoorArt3D
call FreeWorldDressing3D
call FreeNativeWheelArt3D
call FreeNativeCoinArt3D
invoke FreeAnimPack3D, OFFSET hallCardFurniture3D
invoke FreeAnimPack3D, OFFSET hallWheelFurniture3D
invoke FreeAnimPack3D, OFFSET hallBackFurniture3D
invoke FreeAnimPack3D, OFFSET hallSkillFurniture3D
invoke FreeAnimPack3D, OFFSET hallChairFurniture3D
invoke FreeAnimPack3D, OFFSET hallLampFurniture3D
invoke FreeAnimPack3D, OFFSET hallRopeFurniture3D
invoke FreeAnimPack3D, OFFSET hallSlotFurniture3D
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 engineMode,MODE_STAIRS
je fortune_hall_stairs
cmp hallLevel3D,3
jne @F
call RenderFortuneRoom3D
call RenderInteriorViews3D
ret
@@:
fortune_hall_stairs:
cmp engineMode,MODE_STAIRS
jne @F
call RenderWalkableStairs3D
call RenderInteriorViews3D
call RenderStairDoor3D
ret
@@:
cmp hallLevel3D,2
jne @F
call RenderUpperLounge3D
call RenderInteriorViews3D
ret
@@:
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
cmp esi,6
je hall_render_next_prop
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
xor esi, esi
hall_render_lounge:
imul eax, esi, SIZEOF CityProp3D
add eax, OFFSET hallLoungeDecor3D
invoke DrawCityObject3D,eax,0
inc esi
cmp esi, HALL_DECOR_COUNT
jb hall_render_lounge
call RenderPatrons3D
call RenderCabaretActors3D
invoke DrawCityObject3D,OFFSET scrStation3D,0
call RenderHallDressing3D
call RenderHallPortals3D
call RenderFortuneEntrance3D
call ApplyHallLighting3D
call RenderInteriorViews3D
call DrawBasementLeaf3D
ret
hall_render_bunker:
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
call RenderInteriorViews3D
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,3
jne @F
call CheckFortuneInteractions3D
ret
@@:
cmp hallLevel3D,2
jne @F
call CheckUpperInteractions3D
ret
@@:
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,16*FP_1,FP_1*73/10,INTERACT_CABARET_SEAT,OFFSET cabaretSeat3D
invoke HallTarget3D,scrStation3D.posX,scrStation3D.posY,INTERACT_SCRATCH,OFFSET scratchHall3D
invoke HallTarget3D,FP_1*285/10,FP_1*105/10,INTERACT_BASEMENT,OFFSET hallBunkerPrompt3D
invoke HallTarget3D, 27*FP_1,25*FP_1,INTERACT_BILLIARDS,OFFSET hallPoolPrompt3D
invoke HallTarget3D,FP_1*305/10,21*FP_1,0,OFFSET upperStairPrompt3D
call CheckNpcInteractions3D
call CheckFortuneInteractions3D
ret
hall_check_bunker:
mov interactTargetId, 0
mov interactPromptPtr, 0
invoke HallTarget3D, 16*FP_1,14*FP_1+FP_HALF,INTERACT_SHOP,OFFSET promptShop
ret
CheckHallInteractions3D ENDP
TriggerHallInteraction3D PROC
call TryFortuneInteraction3D
test eax,eax
jnz hall_trigger_handled
call TryUpperInteraction3D
test eax,eax
jnz hall_trigger_handled
cmp interactTargetId,INTERACT_CABARET_SEAT
jne @F
call BeginCabaret3D
mov eax,1
ret
@@:
cmp interactTargetId,INTERACT_SCRATCH
jne @F
call BeginScratch3D
mov eax,1
ret
@@:
cmp interactTargetId,INTERACT_NPC
jne @F
call OpenNpcDialog3D
ret
@@:
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
jne hall_trigger_none
; The button opens the steel leaf. Walking across its threshold is separate.
mov basementDoorTarget3D,FP_1
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
hall_trigger_handled:
ret
TriggerHallInteraction3D ENDP
HandleStairs3D PROC
call UpdateStairHeight3D
call HandlePlayerInput
call UpdateInteriorTravel3D
call UpdateStairHeight3D
ret
HandleStairs3D ENDP
RenderStairs3D PROC uses ebx esi
call UpdateCamera3D
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
call RenderHall3D
call RenderHUD
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 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
cmp hallLevel3D,2
jne @F
mov playerX,FP_1*25/2
mov playerY,16*FP_1+FP_1/3
@@:
mov viewHorizon3D, HALF_H
mov viewEye3D, HALL_STANDING_EYE
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
mov eax,OFFSET barName3D
cmp hallLevel3D,2
jne @F
mov eax,OFFSET upperBarName3D
@@:
invoke DrawString8x8, 18,15,eax,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 uses esi ebx px:DWORD,py:DWORD
cmp engineMode,MODE_STAIRS
je fortune_collision_stairs
cmp hallLevel3D,3
jne fortune_collision_stairs
invoke FortuneCanWalk3D,px,py
ret
fortune_collision_stairs:
cmp engineMode,MODE_STAIRS
jne @F
invoke StairDoorCanWalk3D,px,py
ret
@@:
cmp hallLevel3D,2
jne @F
invoke UpperCanWalk3D,px,py
ret
@@:
cmp hallLevel3D, 0
jne hall_collision_bunker
invoke FortuneEntranceCanWalk3D,px,py
test eax,eax
jz hall_collision_blocked
invoke ScratchCanWalk3D,px,py
test eax,eax
jz hall_collision_blocked
invoke InteriorDoorCanWalk3D,px,py
test eax,eax
jz hall_collision_blocked
invoke TerminalCanWalk3D,px,py
test eax,eax
jz hall_collision_blocked
xor esi, esi
hall_collision_decor:
imul ebx, esi, SIZEOF CityProp3D
mov eax, px
sub eax, hallLoungeDecor3D[ebx].posX
test eax, eax
jns @F
neg eax
@@:
mov ecx, hallLoungeDecor3D[ebx].worldW
shr ecx, 1
add ecx, 9830
cmp eax, ecx
ja hall_collision_next_decor
mov eax, py
sub eax, hallLoungeDecor3D[ebx].posY
test eax, eax
jns @F
neg eax
@@:
cmp eax, FP_1*2/5
jbe hall_collision_blocked
hall_collision_next_decor:
inc esi
cmp esi, HALL_DECOR_COUNT
jb hall_collision_decor
; 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 UpdateCabaret3D
call UpdateInteriorTravel3D
call UpdatePatrons3D
call UpdateInteriorEye3D
ret
UpdateHall3D ENDP
; Absolute route phase avoids accumulated movement drift and keeps walking FPS-independent.
UpdatePatrons3D PROC uses ebx esi edi
call UpdateNpcLife3D
ret
IF 0
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:
call UpdateCasinoNpcMind
ret
ENDIF
UpdatePatrons3D ENDP
RenderPatrons3D PROC uses esi
call RenderNpcLife3D
mov esi,8
patron_render_loop:
imul eax, esi, SIZEOF CityProp3D
add eax, OFFSET hallGuests3D
invoke DrawCityObject3D,eax,0
inc esi
cmp esi,12
jb patron_render_loop
ret
RenderPatrons3D ENDP
include src_graphics\world_dressing.inc
include src_graphics\terminal.inc
include src_graphics\hall_expansion.inc
include src_graphics\steel_door.inc
include src_graphics\interior_portals.inc
include src_graphics\fortune_room.inc
include src_graphics\cabaret.inc
include src_graphics\hall_lighting.inc