; 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 BowlingTravel3D call UpdateBowling3D cmp hallLevel3D,HALL_BOWLING je interior_travel_done 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_BOWLING jne @F call BowlingEye3D ret @@: 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 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] xor edx,edx mov ecx,6 div ecx invoke ConfigureCharacter3D,OFFSET upperGuest3D,eax,CAST_SEAT_TALK,animationClock3D,0,0 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