LoadFortuneArt3D PROC invoke LoadAnimPack3D,OFFSET fortuneArt3D,OFFSET fortuneArtPath3D invoke ValidateCityPack3D,OFFSET fortuneArt3D,256,256,24 invoke LoadAnimPack3D,OFFSET fortuneMaterialArt3D,OFFSET fortuneMaterialPath3D invoke ValidateCityPack3D,OFFSET fortuneMaterialArt3D,256,256,4 ret LoadFortuneArt3D ENDP FreeFortuneArt3D PROC invoke FreeAnimPack3D,OFFSET fortuneArt3D invoke FreeAnimPack3D,OFFSET fortuneMaterialArt3D ret FreeFortuneArt3D ENDP ResolveFortuneMaterial3D PROC material:DWORD mov eax,material sub eax,132 cmp eax,3 ja fortune_material_sprite cmp fortuneMaterialArt3D.pixels,0 je fortune_material_missing shl eax,18 add eax,fortuneMaterialArt3D.pixels mov ecx,256 mov edx,256 ret fortune_material_sprite: sub eax,4 cmp eax,23 ja fortune_material_missing cmp fortuneArt3D.pixels,0 je fortune_material_missing shl eax,18 add eax,fortuneArt3D.pixels mov ecx,256 mov edx,256 ret fortune_material_missing: xor eax,eax ret ResolveFortuneMaterial3D ENDP UpdateFortunePassage3D PROC mov eax,animationClock3D cmp eax,fortunePassageClock3D je fortune_update_done mov fortunePassageClock3D,eax mov eax,deltaTime3D cmp eax,100 jbe @F mov eax,100 @@: cmp fortunePassageTarget3D,0 je fortune_update_close add eax,fortunePassageTime3D cmp eax,1400 jbe fortune_update_store mov eax,1400 jmp fortune_update_store fortune_update_close: ; A pending close waits for the visitor to leave the entire secret branch. cmp hallLevel3D,3 je fortune_update_done cmp engineMode,MODE_STAIRS jne fortune_update_hall_guard cmp stairRoute3D,3 jne fortune_update_subtract jmp fortune_update_done fortune_update_hall_guard: cmp hallLevel3D,0 jne fortune_update_subtract cmp playerX,2*FP_1 ja fortune_update_subtract cmp playerY,FP_1*85/10 jb fortune_update_subtract cmp playerY,FP_1*115/10 jbe fortune_update_done fortune_update_subtract: mov edx,fortunePassageTime3D sub edx,eax jae @F xor edx,edx @@: mov eax,edx fortune_update_store: mov fortunePassageTime3D,eax fortune_update_done: ret UpdateFortunePassage3D ENDP FortuneEntranceCanWalk3D PROC px:DWORD,py:DWORD cmp px,FP_1*17/10 ja fortune_entrance_clear cmp py,9*FP_1 jb fortune_entrance_clear cmp py,11*FP_1 ja fortune_entrance_clear cmp fortunePassageTime3D,1400 jb fortune_entrance_block cmp py,FP_1*92/10 jb fortune_entrance_block cmp py,FP_1*108/10 ja fortune_entrance_block fortune_entrance_clear: mov eax,1 ret fortune_entrance_block: xor eax,eax ret FortuneEntranceCanWalk3D ENDP TryFortuneInteraction3D PROC cmp interactTargetId,INTERACT_SECRET_LAMP jne fortune_try_seer cmp hallLevel3D,0 jne fortune_interaction_none xor fortunePassageTarget3D,1 call ClearKeys3D mov eax,1 ret fortune_try_seer: cmp interactTargetId,INTERACT_FORTUNE jne fortune_interaction_none cmp hallLevel3D,3 jne fortune_interaction_none call BeginUnavailable3D mov eax,1 ret fortune_interaction_none: xor eax,eax ret TryFortuneInteraction3D ENDP CheckFortuneInteractions3D PROC cmp hallLevel3D,3 je fortune_check_room cmp fortunePassageTime3D,1400 jne @F invoke HallTarget3D,FP_1*13/10,10*FP_1,0,OFFSET fortuneStairHint3D @@: cmp fortunePassageTarget3D,0 jne fortune_check_release invoke HallTarget3D,FP_1*14/10,FP_1*87/10,INTERACT_SECRET_LAMP,OFFSET fortuneLampPull3D ret fortune_check_release: invoke HallTarget3D,FP_1*14/10,FP_1*87/10,INTERACT_SECRET_LAMP,OFFSET fortuneLampReturn3D ret fortune_check_room: mov interactTargetId,0 mov interactPromptPtr,0 invoke HallTarget3D,FP_1*173/10,11*FP_1,0,OFFSET fortuneExitHint3D invoke HallTarget3D,FP_1*141/10,11*FP_1,INTERACT_FORTUNE,OFFSET fortuneTalk3D fortune_check_done: ret CheckFortuneInteractions3D ENDP RenderFortuneEntrance3D PROC uses ebx esi local panelLo:DWORD,panelHi:DWORD,bodyLow:DWORD,bodyHigh:DWORD ; The real wall remains behind this aperture; the portal compositor clips it. invoke DrawCityBoxSides3D,FP_1*128/100,FP_1*138/100,FP_1*88/10,9*FP_1,0,FP_1*5/2,102 invoke DrawCityBoxSides3D,FP_1*128/100,FP_1*138/100,11*FP_1,FP_1*112/10,0,FP_1*5/2,102 invoke DrawCityBoxSides3D,FP_1*128/100,FP_1*138/100,9*FP_1,11*FP_1,FP_1*23/10,FP_1*5/2,102 mov eax,fortunePassageTime3D sub eax,280 jns @F xor eax,eax @@: imul eax,2*FP_1 xor edx,edx mov ecx,1120 div ecx add eax,9*FP_1 mov panelLo,eax add eax,2*FP_1 mov panelHi,eax invoke DrawCityVertical3D,0,FP_1*135/100,panelLo,panelHi,0,FP_1*23/10,1 ; A rigid brass arm stays fixed while the lantern itself is pulled down. mov eax,fortunePassageTime3D cmp eax,280 jbe @F mov eax,280 @@: imul eax,FP_1/5 xor edx,edx mov ecx,280 div ecx mov ebx,FP_1*14/10 sub ebx,eax mov bodyLow,ebx add ebx,FP_1/2 mov bodyHigh,ebx invoke DrawCityBoxSides3D,FP_1*131/100,FP_1*155/100,FP_1*857/100,FP_1*883/100,bodyLow,bodyHigh,120 invoke DrawCityHorizontal3D,FP_1*131/100,FP_1*155/100,FP_1*857/100,FP_1*883/100,bodyHigh,110 invoke DrawCityHorizontal3D,FP_1*131/100,FP_1*155/100,FP_1*857/100,FP_1*883/100,bodyLow,110 invoke DrawCityBoxSides3D,FP_1*102/100,FP_1*143/100,FP_1*866/100,FP_1*874/100,FP_1*194/100,2*FP_1,110 invoke DrawCityBoxSides3D,FP_1*140/100,FP_1*146/100,FP_1*866/100,FP_1*874/100,bodyHigh,2*FP_1,110 ret RenderFortuneEntrance3D ENDP DrawFortuneFixedProp3D PROC uses esi prop:DWORD,axis:DWORD local coordinate:DWORD,lo:DWORD,hi:DWORD,zTop:DWORD,material:DWORD mov esi,prop mov eax,[esi].CityProp3D.posX mov ecx,[esi].CityProp3D.posY cmp axis,0 je @F xchg eax,ecx @@: mov coordinate,eax mov eax,[esi].CityProp3D.worldW sar eax,1 mov edx,ecx sub edx,eax mov lo,edx add ecx,eax mov hi,ecx mov eax,[esi].CityProp3D.groundZ add eax,[esi].CityProp3D.worldH mov zTop,eax mov eax,[esi].CityProp3D.frame add eax,136 mov material,eax invoke DrawCityVertical3D,axis,coordinate,lo,hi,[esi].CityProp3D.groundZ,zTop,material ret DrawFortuneFixedProp3D ENDP RenderFortuneFurnishings3D PROC uses ebx ; Layered cloth, a worn rug and irregular floor clutter make a working den. invoke DrawCityHorizontal3D,FP_1*135/10,FP_1*176/10,FP_1*97/10,FP_1*124/10,FP_1/100,135 ; Furniture fronts have fixed wall axes and solid depth, never billboards. invoke DrawCityBoxSides3D,FP_1*134/10,FP_1*148/10,FP_1*902/100,FP_1*931/100,0,FP_1*21/10,132 invoke DrawCityHorizontal3D,FP_1*134/10,FP_1*148/10,FP_1*902/100,FP_1*931/100,FP_1*21/10,134 invoke DrawCityBoxSides3D,FP_1*154/10,FP_1*176/10,FP_1*1266/100,FP_1*129/10,FP_1*2/10,FP_1*6/10,135 invoke DrawCityBoxSides3D,FP_1*1771/100,FP_1*1798/100,FP_1*1225/100,FP_1*1285/100,0,FP_1*19/10,132 invoke DrawCityBoxSides3D,FP_1*14,FP_1*152/10,FP_1*1271/100,FP_1*129/10,0,FP_1*6/10,132 ; Both poses keep the face hidden; the hands and mantle change instead. mov eax,animationClock3D xor edx,edx mov ecx,6000 div ecx xor eax,eax cmp edx,4800 jb @F inc eax @@: mov fortuneSeer3D.frame,eax invoke DrawFortuneFixedProp3D,OFFSET fortuneTapestry3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneShelf3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneBench3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneMirror3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneCandleA3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneCandleB3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneScrolls3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneHerbs3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneHerbsB3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneHerbsC3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneHanging3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneHanging3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortunePotions3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneBooks3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneChest3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneBookPileA3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneBookPileB3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneCauldron3D,0 invoke DrawFortuneFixedProp3D,OFFSET fortuneTray3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneFloorCandlesA3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneFloorCandlesB3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneNorthLamp3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneSouthLamp3D,1 invoke DrawFortuneFixedProp3D,OFFSET fortuneSeer3D,0 ret RenderFortuneFurnishings3D ENDP FortuneLightAt3D PROC uses ebx esi edi wx:DWORD,wy:DWORD,wz:DWORD local best:DWORD mov best,0 xor esi,esi fortune_light_source: mov eax,wx sub eax,fortuneLights3D[esi] imul eax,eax mov ebx,eax mov eax,wy sub eax,fortuneLights3D[esi+4] imul eax,eax add ebx,eax mov eax,wz sub eax,fortuneLights3D[esi+8] imul eax,eax add eax,ebx cmp eax,900 jae fortune_light_source_next neg eax add eax,900 imul eax,fortuneLights3D[esi+12] xor edx,edx mov ecx,900 div ecx cmp eax,best jbe fortune_light_source_next mov best,eax fortune_light_source_next: add esi,16 cmp esi,FORTUNE_LIGHT_COUNT*16 jb fortune_light_source mov eax,best ret FortuneLightAt3D ENDP ApplyFortuneLighting3D PROC uses ebx esi edi local row:DWORD,column:DWORD,planeDepth:DWORD,depth:DWORD local wx:DWORD,wy:DWORD,wz:DWORD,light:DWORD local gainR:DWORD,gainG:DWORD,gainB:DWORD,subRow:DWORD,subColumn:DWORD mov row,0 fortune_light_row: mov eax,row cmp eax,viewHorizon3D jge fortune_light_floor mov ecx,viewHorizon3D sub ecx,eax mov eax,viewCeiling3D sub eax,viewEye3D jmp fortune_light_plane fortune_light_floor: sub eax,viewHorizon3D inc eax mov ecx,eax mov eax,viewEye3D fortune_light_plane: imul eax,SCREEN_H cdq idiv ecx mov planeDepth,eax mov column,0 fortune_light_column: imul edi,row,SCREEN_W add edi,column mov eax,cityDepthBuffer3D[edi*4] cmp eax,planeDepth jle @F mov eax,planeDepth @@: ; Limit the reconstructed sample at the horizon before squaring distances. cmp eax,16*FP_1 jle @F mov eax,16*FP_1 @@: mov depth,eax mov ebx,column imul cityRayX3D[ebx*4] shrd eax,edx,16 add eax,playerX sar eax,12 mov wx,eax mov eax,depth imul cityRayY3D[ebx*4] shrd eax,edx,16 add eax,playerY sar eax,12 mov wy,eax mov eax,viewHorizon3D sub eax,row imul eax,depth cdq mov ecx,SCREEN_H idiv ecx add eax,viewEye3D sar eax,12 mov wz,eax invoke FortuneLightAt3D,wx,wy,wz mov light,eax mov ebx,eax xor edx,edx mov ecx,3 div ecx add eax,48 mov gainR,eax imul eax,ebx,3 shr eax,2 add eax,64 mov gainG,eax add ebx,82 mov gainB,ebx mov subRow,0 fortune_light_block_row: mov subColumn,0 fortune_light_pixel: imul esi,subRow,SCREEN_W add esi,subColumn add esi,edi mov ebx,screenBuffer[esi*4] ; Preserve the small blue-white flame cores only beside an actual light. cmp light,100 jb fortune_light_shade cmp bl,210 jb fortune_light_shade cmp bh,180 jae fortune_light_pixel_next fortune_light_shade: movzx eax,bl imul eax,gainB shr eax,8 mov ecx,eax movzx eax,bh imul eax,gainG shr eax,8 shl eax,8 or ecx,eax mov eax,ebx shr eax,16 and eax,255 imul eax,gainR shr eax,8 shl eax,16 or eax,ecx mov screenBuffer[esi*4],eax fortune_light_pixel_next: inc subColumn cmp subColumn,2 jb fortune_light_pixel inc subRow cmp subRow,2 jb fortune_light_block_row add column,2 cmp column,SCREEN_W jb fortune_light_column add row,2 cmp row,SCREEN_H jb fortune_light_row ret ApplyFortuneLighting3D ENDP RenderFortuneRoom3D PROC call RenderFortuneFurnishings3D call ApplyFortuneLighting3D ret RenderFortuneRoom3D ENDP FortuneCanWalk3D PROC px:DWORD,py:DWORD cmp px,FP_1*1485/100 ja fortune_walk_north cmp py,FP_1*98/10 jb fortune_walk_north cmp py,FP_1*118/10 jbe fortune_walk_block fortune_walk_north: cmp py,FP_1*1005/100 ja @F cmp px,FP_1*146/10 jb @F cmp px,FP_1*1565/100 jbe fortune_walk_block @@: cmp py,FP_1*965/100 ja fortune_walk_south cmp px,15*FP_1 jb fortune_walk_block cmp px,FP_1*155/10 jb fortune_walk_south cmp px,FP_1*171/10 jbe fortune_walk_block fortune_walk_south: cmp px,FP_1*172/10 jb @F cmp py,FP_1*122/10 jae fortune_walk_block @@: cmp py,FP_1*1175/100 jb fortune_walk_clear cmp px,FP_1*146/10 jb fortune_walk_block cmp px,15*FP_1 jb @F cmp px,FP_1*158/10 jbe fortune_walk_block @@: cmp py,FP_1*121/10 jae fortune_walk_block fortune_walk_clear: mov eax,1 ret fortune_walk_block: xor eax,eax ret FortuneCanWalk3D ENDP RenderFortuneStairs3D PROC uses ebx esi local x0:DWORD,x1:DWORD,z0:DWORD,z1:DWORD ; A west-facing descent: the player controls every step, with level landings. xor esi,esi fortune_stair_step: imul eax,esi,FP_1/3 add eax,19*FP_1 mov x0,eax add eax,FP_1/3 mov x1,eax imul eax,esi,FP_1/16 mov z0,eax add eax,FP_1/16 mov z1,eax invoke DrawCityHorizontal3D,x0,x1,9*FP_1,11*FP_1,z0,134 invoke DrawCityVertical3D,0,x1,9*FP_1,11*FP_1,z0,z1,132 inc esi cmp esi,24 jb fortune_stair_step invoke DrawCityHorizontal3D,27*FP_1,31*FP_1,9*FP_1,11*FP_1,FP_1*3/2,134 invoke DrawCityHorizontal3D,16*FP_1,19*FP_1,9*FP_1,11*FP_1,0,134 ret RenderFortuneStairs3D ENDP RenderFortuneViews3D PROC cmp engineMode,MODE_STAIRS je fortune_views_stairs cmp hallLevel3D,3 je fortune_views_room cmp hallLevel3D,0 jne fortune_views_done cmp fortunePassageTime3D,280 jbe fortune_views_done cmp playerX,FP_1*14/10 jbe fortune_views_done invoke DrawInteriorView3D,0,FP_1*138/100,9*FP_1,11*FP_1,0,FP_1*23/10,28*FP_1,0,FP_1*3/2,OFFSET fortuneStairMap3D,MODE_STAIRS,0,134,3 ret fortune_views_room: cmp playerX,FP_1*175/10 jae fortune_views_done invoke DrawInteriorView3D,0,FP_1*174/10,10*FP_1,12*FP_1,0,FP_1*5/2,0,-FP_1,0,OFFSET fortuneStairMap3D,MODE_STAIRS,3,134,3 ret fortune_views_stairs: cmp playerX,FP_1*2955/100 jae @F invoke DrawInteriorView3D,0,FP_1*295/10,9*FP_1,11*FP_1,FP_1*3/2,4*FP_1,-28*FP_1,0,-FP_1*3/2,OFFSET casinoMap,MODE_WALK,0,100,0 @@: cmp playerX,FP_1*172/10 jbe fortune_views_done invoke DrawInteriorView3D,0,FP_1*173/10,9*FP_1,11*FP_1,0,FP_1*5/2,0,FP_1,0,OFFSET fortuneRoomMap3D,MODE_WALK,3,134,0 fortune_views_done: ret RenderFortuneViews3D ENDP