KAZIK/src_graphics/backrooms.inc

1068 lines
23 KiB
PHP

; Native Backrooms: connected DFS maze, rooms/loops, BFS farthest exit.
LoadBackroomsAssets3D PROC uses esi edi
invoke LoadAnimPack3D,OFFSET brMaterials3D,OFFSET brMaterialPath3D
test eax,eax
jz br_assets_done
cmp brMaterials3D.imageWidth,128
jne br_assets_invalid
cmp brMaterials3D.height,128
jne br_assets_invalid
cmp brMaterials3D.frames,5
jne br_assets_invalid
mov esi,brMaterials3D.pixels
mov edi,OFFSET texturesBuffer+BR_WALL*65536
mov ecx,5*128*128
rep movsd
mov eax,1
ret
br_assets_invalid:
invoke FreeAnimPack3D,OFFSET brMaterials3D
xor eax,eax
br_assets_done:
ret
LoadBackroomsAssets3D ENDP
GenerateBackrooms3D PROC uses ebx esi edi
local top:DWORD,count:DWORD,current:DWORD,next:DWORD,tail:DWORD,head:DWORD
lea edi,brMap3D
mov eax,0B4B4B4B4h
mov ecx,256
rep stosd
mov brMap3D[33],0
mov brStack3D,33
mov top,1
br_dfs:
mov eax,top
test eax,eax
jz br_rooms
dec eax
mov ebx,brStack3D[eax*4]
mov current,ebx
mov count,0
xor esi,esi
br_neighbors:
mov edx,ebx
and edx,31
cmp esi,0
jne @F
cmp ebx,65
jb br_neighbor_next
@@:
cmp esi,1
jne @F
cmp edx,29
jae br_neighbor_next
@@:
cmp esi,2
jne @F
cmp ebx,29*32
jae br_neighbor_next
@@:
cmp esi,3
jne @F
cmp edx,3
jb br_neighbor_next
@@:
mov eax,ebx
add eax,brSteps3D[esi*4]
cmp brMap3D[eax],0
je br_neighbor_next
mov ecx,count
mov brCandidates3D[ecx*4],eax
inc count
br_neighbor_next:
inc esi
cmp esi,4
jb br_neighbors
cmp count,0
je br_backtrack
invoke RandomRange3D,count
mov eax,brCandidates3D[eax*4]
mov brMap3D[eax],0
mov edx,eax
add edx,current
shr edx,1
mov brMap3D[edx],0
mov ecx,top
mov brStack3D[ecx*4],eax
inc top
jmp br_dfs
br_backtrack:
dec top
jmp br_dfs
br_rooms:
; Open a small landing room so the recovered camera never faces a wall.
mov brMap3D[33],0
mov brMap3D[34],0
mov brMap3D[35],0
mov brMap3D[65],0
mov brMap3D[66],0
mov brMap3D[67],0
mov brMap3D[97],0
mov brMap3D[98],0
mov brMap3D[99],0
; Every 3x3 room includes an odd lattice node: cannot be disconnected.
mov esi,12
br_room:
invoke RandomRange3D,13
shl eax,1
inc eax
mov ebx,eax
invoke RandomRange3D,13
shl eax,1
inc eax
shl eax,5
add ebx,eax
mov edi,3
br_room_row:
mov brMap3D[ebx],0
mov brMap3D[ebx+1],0
mov brMap3D[ebx+2],0
add ebx,32
dec edi
jnz br_room_row
dec esi
jnz br_room
; Open connecting walls only; never carve outside the sealed border.
mov esi,55
br_loop:
invoke RandomRange3D,29
inc eax
mov ebx,eax
invoke RandomRange3D,29
inc eax
shl eax,5
add ebx,eax
cmp brMap3D[ebx-1],0
jne br_loop_vertical
cmp brMap3D[ebx+1],0
je br_loop_open
br_loop_vertical:
cmp brMap3D[ebx-32],0
jne br_loop_next
cmp brMap3D[ebx+32],0
jne br_loop_next
br_loop_open:
mov brMap3D[ebx],0
br_loop_next:
dec esi
jnz br_loop
lea edi,brDistance3D
mov eax,-1
mov ecx,1024
rep stosd
mov brDistance3D[33*4],0
mov brStack3D,33
mov head,0
mov tail,1
mov brExitCell3D,33
br_bfs:
mov eax,head
cmp eax,tail
jae br_place_games
mov ebx,brStack3D[eax*4]
inc head
mov eax,brDistance3D[ebx*4]
mov ecx,brExitCell3D
cmp eax,brDistance3D[ecx*4]
jbe @F
mov brExitCell3D,ebx
@@:
xor esi,esi
br_bfs_neighbor:
mov eax,brSteps3D[esi*4]
sar eax,1
add eax,ebx
cmp brMap3D[eax],0
jne br_bfs_next
cmp brDistance3D[eax*4],-1
jne br_bfs_next
mov edx,brDistance3D[ebx*4]
inc edx
mov brDistance3D[eax*4],edx
mov ecx,tail
mov brStack3D[ecx*4],eax
inc tail
br_bfs_next:
inc esi
cmp esi,4
jb br_bfs_neighbor
jmp br_bfs
br_place_games:
; Sample distinct reachable cells at evenly spaced BFS distances.
xor esi,esi
br_place_game:
mov eax,tail
imul eax,esi
xor edx,edx
mov ecx,7
div ecx
add eax,8
mov ebx,brStack3D[eax*4]
cmp ebx,brExitCell3D
jne @F
mov ebx,brStack3D[eax*4+4]
@@:
mov brGameCells3D[esi*4],ebx
inc esi
cmp esi,6
jb br_place_game
ret
GenerateBackrooms3D ENDP
BackroomsEntry3D PROC
cmp brActive3D,0
jne br_entry_reset
cmp engineMode,MODE_WALK
jne br_entry_reset
cmp hallLevel3D,0
jne br_entry_reset
cmp paused3D,0
jne br_entry_reset
cmp playerX,16*FP_1
jb br_entry_reset
cmp playerX,17*FP_1
jae br_entry_reset
cmp playerY,30*FP_1-15000
jb br_entry_reset
cmp playerY,30*FP_1
jae br_entry_reset
cmp playerAngle,104
jb br_entry_reset
cmp playerAngle,152
ja br_entry_reset
cmp keys3D[53h],0
jne br_entry_reset
cmp keys3D[28h],0
jne br_entry_reset
cmp keys3D[41h],0
jne br_entry_reset
cmp keys3D[44h],0
jne br_entry_reset
cmp keys3D[57h],0
jne br_entry_hold
cmp keys3D[26h],0
je br_entry_reset
br_entry_hold:
mov eax,playerAngle
cmp brEntryHold3D,0
je @F
cmp eax,brEntryAngle3D
jne br_entry_reset
@@:
mov brEntryAngle3D,eax
mov eax,deltaTime3D
add brEntryHold3D,eax
cmp brEntryHold3D,2000
jb br_entry_done
call BeginBackrooms3D
ret
br_entry_reset:
mov brEntryHold3D,0
br_entry_done:
ret
BackroomsEntry3D ENDP
BeginBackrooms3D PROC
call LoadBackroomsAssets3D
test eax,eax
jz br_begin_done
call GenerateBackrooms3D
mov brActive3D,1
mov brEntryHold3D,0
mov brCutscene3D,1
mov brClock3D,0
mov brDialogue3D,0
mov paused3D,0
; First 900ms still show the casino while camera clips through the wall.
mov viewEye3D,HALL_STANDING_EYE
mov viewCeiling3D,FP_1*5/2
mov interactTargetId,0
call ClearKeys3D
br_begin_done:
ret
BeginBackrooms3D ENDP
LeaveBackrooms3D PROC reward:DWORD
cmp brActive3D,0
je br_leave_done
cmp reward,0
je @F
cmp brOwned3D,1
je @F
mov brOwned3D,1
mov brEnabled3D,1
@@:
invoke CopyString3D,OFFSET brAward3D,OFFSET flashMessage
mov flashTimer,200
@@:
mov brActive3D,0
mov brCutscene3D,0
mov brEntryHold3D,0
mov worldMap3D,OFFSET casinoMap
mov hallLevel3D,0
mov playerX,16*FP_1+FP_HALF
mov playerY,27*FP_1+FP_HALF
mov playerAngle,384
mov viewEye3D,HALL_STANDING_EYE
mov viewCeiling3D,FP_1*5/2
mov floorTexture3D,100
mov engineMode,MODE_WALK
mov paused3D,0
call ClearKeys3D
call SaveProgress3D
br_leave_done:
ret
LeaveBackrooms3D ENDP
HandleBackrooms3D PROC uses ebx esi edi
mov eax,deltaTime3D
add brClock3D,eax
cmp brCutscene3D,0
je br_walk
cmp brClock3D,900
jae br_fall_world
mov eax,deltaTime3D
imul eax,30
add playerY,eax
ret
br_fall_world:
cmp hallLevel3D,HALL_BACKROOMS
je @F
mov hallLevel3D,HALL_BACKROOMS
mov worldMap3D,OFFSET brMap3D
mov playerX,FP_1+FP_HALF
mov playerY,FP_1+FP_HALF
mov playerAngle,64
mov floorTexture3D,BR_FLOOR
@@:
cmp brClock3D,6500
jae br_stand
; Camera fall, impact, then low-to-standing recovery; no video player.
mov eax,brClock3D
cmp eax,2200
jae br_impact
imul eax,36
mov edx,FP_1*3/2
sub edx,eax
cmp edx,FP_1/8
jge @F
mov edx,FP_1/8
@@:
mov viewEye3D,edx
mov eax,brClock3D
shr eax,5
and eax,511
mov playerAngle,eax
ret
br_impact:
cmp eax,3100
jae br_rise
mov viewEye3D,FP_1/8
mov playerAngle,64
ret
br_rise:
sub eax,3100
imul eax,HALL_STANDING_EYE-FP_1/8
xor edx,edx
mov ecx,3400
div ecx
add eax,FP_1/8
mov viewEye3D,eax
ret
br_stand:
mov brCutscene3D,0
mov viewEye3D,HALL_STANDING_EYE
call ClearKeys3D
br_walk:
mov eax,deltaTime3D
add brDialogue3D,eax
call HandlePlayerInput
mov interactTargetId,0
mov interactPromptPtr,0
mov brTarget3D,-1
xor esi,esi
br_target_scan:
cmp esi,6
jb @F
mov ebx,brExitCell3D
jmp br_target_cell
@@:
mov ebx,brGameCells3D[esi*4]
br_target_cell:
mov eax,ebx
and eax,31
shl eax,16
add eax,FP_HALF
sub eax,playerX
sar eax,8
imul eax,eax
mov edi,eax
mov eax,ebx
shr eax,5
shl eax,16
add eax,FP_HALF
sub eax,playerY
sar eax,8
imul eax,eax
add eax,edi
cmp eax,FP_1*3/4
ja br_target_next
mov brTarget3D,esi
cmp esi,6
je @F
mov eax,brGamePrompts3D[esi*4]
mov interactPromptPtr,eax
jmp br_targets_done
@@:
mov interactPromptPtr,OFFSET brExitPrompt3D
jmp br_targets_done
br_target_next:
inc esi
cmp esi,7
jb br_target_scan
br_targets_done:
invoke Pressed3D,56h
test eax,eax
jz @F
xor brVhs3D,1
@@:
invoke Pressed3D,45h
test eax,eax
jz br_handle_done
mov esi,brTarget3D
cmp esi,6
ja br_handle_done
jne br_launch
invoke LeaveBackrooms3D,1
ret
br_launch:
; Reuse normal station dispatch; suppress all hall-specific interactions.
mov eax,brGames3D[esi*4]
mov interactTargetId,eax
call Trigger3DInteraction
call ClearKeys3D
br_handle_done:
ret
HandleBackrooms3D ENDP
RenderBackroomsDialogue3D PROC uses ebx esi edi
local x:DWORD,y:DWORD,age:DWORD,offsetY:DWORD
cmp brDialogue3D,9500
jae br_dialogue_done
invoke DrawBoxBorder,4,179,312,57,00191711h,009C9464h,1
mov x,12
mov y,189
xor esi,esi
br_letter:
movzx ebx,brText3D[esi]
test ebx,ebx
jz br_dialogue_done
; Wrap whole words, not arbitrary characters.
cmp ebx,32
jne br_letter_position
mov edi,esi
xor ecx,ecx
br_word_length:
inc edi
mov al,brText3D[edi]
test al,al
jz br_word_end
cmp al,32
je br_word_end
inc ecx
jmp br_word_length
br_word_end:
inc ecx
shl ecx,3
add ecx,x
cmp ecx,300
jbe br_letter_position
mov x,12
add y,14
jmp br_letter_next
br_letter_position:
mov eax,esi
imul eax,35
mov ecx,brDialogue3D
sub ecx,eax
js br_letter_advance
cmp ecx,6400
jae br_letter_advance
mov age,ecx
mov offsetY,0
cmp ecx,420
jae br_letter_out
mov eax,420
sub eax,ecx
imul eax,18
xor edx,edx
mov ecx,420
div ecx
mov offsetY,eax
jmp br_letter_draw
br_letter_out:
cmp ecx,5900
jb br_letter_draw
sub ecx,5900
imul ecx,18
mov eax,ecx
xor edx,edx
mov ecx,500
div ecx
neg eax
mov offsetY,eax
br_letter_draw:
mov eax,age
shr eax,3
mov ecx,esi
shl ecx,4
add eax,ecx
and eax,511
mov eax,tableSin[eax*4]
sar eax,15
add eax,y
add eax,offsetY
mov brGlyph3D,bl
invoke DrawString8x8,x,eax,OFFSET brGlyph3D,00EBE4B5h
br_letter_advance:
add x,8
br_letter_next:
inc esi
jmp br_letter
br_dialogue_done:
ret
RenderBackroomsDialogue3D ENDP
RenderBackrooms3D PROC uses ebx esi edi
local exitX:DWORD,exitY:DWORD
call UpdateCamera3D
call RenderCeilingAndFloor
call RenderWalls
call PrepareCityDepth3D
cmp hallLevel3D,HALL_BACKROOMS
je @F
call RenderSprites
call RenderHall3D
jmp br_camera_hud
@@:
xor esi,esi
br_render_station:
mov ebx,brGameCells3D[esi*4]
mov eax,ebx
and eax,31
shl eax,16
add eax,FP_HALF
mov brProp3D.posX,eax
mov eax,ebx
shr eax,5
shl eax,16
add eax,FP_HALF
mov brProp3D.posY,eax
mov eax,brGamePacks3D[esi*4]
mov brProp3D.asset,eax
mov eax,brGameFrames3D[esi*4]
mov brProp3D.frame,eax
invoke DrawCityObject3D,OFFSET brProp3D,0
inc esi
cmp esi,6
jb br_render_station
; Upright door on a neighboring solid wall; collision map stays unchanged.
mov ebx,brExitCell3D
mov eax,ebx
and eax,31
shl eax,16
mov exitX,eax
mov eax,ebx
shr eax,5
shl eax,16
mov exitY,eax
cmp brMap3D[ebx-32],0
je br_exit_south
add exitY,512
jmp br_exit_y_door
br_exit_south:
cmp brMap3D[ebx+32],0
je br_exit_west
add exitY,FP_1-512
br_exit_y_door:
mov eax,exitX
add eax,FP_1
invoke DrawCityVertical3D,1,exitY,exitX,eax,0,FP_1*21/10,BR_EXIT
jmp br_exit_drawn
br_exit_west:
cmp brMap3D[ebx-1],0
je br_exit_east
add exitX,512
jmp br_exit_x_door
br_exit_east:
add exitX,FP_1-512
br_exit_x_door:
mov eax,exitY
add eax,FP_1
invoke DrawCityVertical3D,0,exitX,exitY,eax,0,FP_1*21/10,BR_EXIT
br_exit_drawn:
cmp brVhs3D,0
je br_camera_hud
; Deterministic screen noise, independent of gameplay RNG.
lea edi,screenBuffer
mov ecx,SCREEN_SIZE
mov ebx,brClock3D
br_vhs_pixel:
imul ebx,1664525
add ebx,1013904223
mov eax,[edi]
; Reserve two low bits per channel: adding 0..3 cannot carry into RGB.
and eax,00FCFCFCh
mov edx,ebx
shr edx,30
imul edx,00010101h
add eax,edx
stosd
dec ecx
jnz br_vhs_pixel
mov esi,2
br_scanline:
imul eax,esi,SCREEN_W*4
lea edi,screenBuffer[eax]
mov ecx,SCREEN_W
br_scan_pixel:
mov eax,[edi]
and eax,00FCFCFCh
mov edx,eax
shr edx,2
sub eax,edx
stosd
loop br_scan_pixel
add esi,6
cmp esi,SCREEN_H
jb br_scanline
br_camera_hud:
mov eax,brClock3D
xor edx,edx
mov ecx,1000
div ecx
xor esi,esi
mov esi,6
br_time_pair:
xor edx,edx
mov ecx,60
div ecx
push eax
mov eax,edx
xor edx,edx
mov ecx,10
div ecx
add al,'0'
add dl,'0'
mov brTime3D[esi],al
mov brTime3D[esi+1],dl
pop eax
sub esi,3
jns br_time_pair
invoke DrawString8x8,224,12,OFFSET brTime3D,00EEEEDDh
invoke DrawString8x8,25,12,OFFSET brRec3D,00EEEEDDh
test brClock3D,512
jnz @F
invoke DrawBox,12,13,7,7,00EE3030h
@@:
invoke DrawString8x8,8,29,OFFSET brHelp3D,00C8C8A0h
cmp brCutscene3D,0
je br_hud_walk
cmp brClock3D,2200
jb br_render_done
cmp brClock3D,2800
jae br_render_done
invoke DrawBox,0,0,SCREEN_W,SCREEN_H,00080704h
ret
br_hud_walk:
cmp interactPromptPtr,0
je @F
invoke DrawString8x8,112,158,interactPromptPtr,00F1F1B5h
@@:
call RenderBackroomsDialogue3D
br_render_done:
ret
RenderBackrooms3D ENDP
; -1 = disabled; 0 = unlucky; 1 = lucky. Caller latches once per round.
BackroomsLuck3D PROC
cmp brOwned3D,1
jne br_luck_off
cmp brEnabled3D,1
jne br_luck_off
cmp brActive3D,0
jne br_luck_off
cmp tournamentMode,0
jne br_luck_off
cmp obsActive3D,0
jne br_luck_off
invoke RandomRange3D,100
cmp eax,90
setb al
movzx eax,al
ret
br_luck_off:
mov eax,-1
ret
BackroomsLuck3D ENDP
; Select a physically possible roulette result by actual net return.
BackroomsWheelLuck3D PROC uses ebx esi edi original:DWORD
local desired:DWORD,total:DWORD,count:DWORD
call BackroomsLuck3D
cmp eax,-1
je br_wheel_original
mov desired,eax
mov count,0
xor edi,edi
br_wheel_result:
mov total,0
xor esi,esi
br_wheel_bet:
invoke WheelBetMultiplier3D,esi,edi
imul eax,wheelBets3D[esi*4]
add total,eax
inc esi
cmp esi,49
jb br_wheel_bet
mov eax,total
cmp eax,wheelStake3D
seta al
movzx eax,al
cmp eax,desired
jne br_wheel_next
inc count
invoke RandomRange3D,count
test eax,eax
jnz br_wheel_next
mov original,edi
br_wheel_next:
inc edi
cmp edi,37
jb br_wheel_result
br_wheel_original:
mov eax,original
ret
BackroomsWheelLuck3D ENDP
; Permute a real deck by swapping cards, preserving all 52 unique identities.
BackroomsDeck3D PROC uses ebx esi edi deck:DWORD,targets:DWORD,count:DWORD
mov edi,deck
mov esi,targets
xor ebx,ebx
br_deck_position:
cmp ebx,count
jae br_deck_done
mov eax,[esi+ebx*4]
cmp eax,52
jae br_deck_next
xor ecx,ecx
br_deck_find:
cmp ecx,52
jae br_deck_next
cmp [edi+ecx*4],eax
je br_deck_swap
inc ecx
jmp br_deck_find
br_deck_swap:
mov edx,[edi+ebx*4]
mov [edi+ecx*4],edx
mov [edi+ebx*4],eax
br_deck_next:
inc ebx
jmp br_deck_position
br_deck_done:
ret
BackroomsDeck3D ENDP
BackroomsBlackjackDeck3D PROC uses ebx esi edi
call BackroomsLuck3D
cmp eax,-1
je br_bj_done
mov ebx,eax
lea edi,brDeckTargets3D
mov eax,-1
mov ecx,16
rep stosd
; Two aces + picture cards remain distinct. Party seats keep their cards.
mov ecx,cbBotCount3D
add ecx,2
cmp ebx,1
jne br_bj_unlucky
mov brDeckTargets3D,12
mov brDeckTargets3D[ecx*4],11
dec ecx
mov brDeckTargets3D[ecx*4],8
inc ecx
add ecx,ecx
dec ecx
mov brDeckTargets3D[ecx*4],7
jmp br_bj_apply
br_bj_unlucky:
mov brDeckTargets3D,8
mov brDeckTargets3D[ecx*4],7
dec ecx
mov brDeckTargets3D[ecx*4],12
inc ecx
add ecx,ecx
dec ecx
mov brDeckTargets3D[ecx*4],11
br_bj_apply:
invoke BackroomsDeck3D,OFFSET cbDeck3D,OFFSET brDeckTargets3D,10
br_bj_done:
ret
BackroomsBlackjackDeck3D ENDP
BackroomsPokerDeck3D PROC uses ebx edi
call BackroomsLuck3D
cmp eax,-1
je br_pk_done
mov ebx,eax
lea edi,brDeckTargets3D
mov eax,-1
mov ecx,16
rep stosd
; Fixed board creates a real royal flush for the lucky seat, no duplicate cards.
; Flop deck 5,6,7; turn 9; river 11. Burns remain shuffled.
mov brDeckTargets3D[5*4],8
mov brDeckTargets3D[6*4],9
mov brDeckTargets3D[7*4],10
mov brDeckTargets3D[9*4],13
mov brDeckTargets3D[11*4],27
mov ecx,pkButton3D
xor ecx,1
xor ebx,1
xor ecx,ebx
mov brDeckTargets3D[ecx*4],11
mov brDeckTargets3D[ecx*4+8],12
xor ecx,1
mov brDeckTargets3D[ecx*4],16
mov brDeckTargets3D[ecx*4+8],30
invoke BackroomsDeck3D,OFFSET pkDeck3D,OFFSET brDeckTargets3D,12
br_pk_done:
ret
BackroomsPokerDeck3D ENDP
BackroomsDurakDeck3D PROC uses ebx esi edi
call BackroomsLuck3D
cmp eax,-1
je br_dk_done
mov ebx,eax
; Favor six initial trump cards, preserving the compacted 36-card deck.
; A poor move can still lose: no settlement or rule is overridden.
mov ecx,0
br_dk_pair:
mov eax,ecx
add eax,7
cmp ebx,1
jne @F
add eax,26
@@:
mov edx,ecx
shl edx,1
xor esi,esi
br_dk_find:
cmp esi,36
jae br_dk_next
cmp dkDeck3D[esi*4],eax
je br_dk_swap
inc esi
jmp br_dk_find
br_dk_swap:
mov edi,dkDeck3D[edx*4]
mov dkDeck3D[esi*4],edi
mov dkDeck3D[edx*4],eax
br_dk_next:
inc ecx
cmp ecx,6
jb br_dk_pair
; Exposed trump must match the favored side, without introducing duplicates.
mov eax,43
cmp ebx,1
jne @F
mov eax,30
@@:
xor esi,esi
br_dk_trump_find:
cmp dkDeck3D[esi*4],eax
je br_dk_trump_swap
inc esi
cmp esi,36
jb br_dk_trump_find
jmp br_dk_done
br_dk_trump_swap:
mov edx,dkDeck3D[35*4]
mov dkDeck3D[esi*4],edx
mov dkDeck3D[35*4],eax
br_dk_done:
ret
BackroomsDurakDeck3D ENDP
; Reorder only at loading time, before shell knowledge or previews exist.
; This biases real cartridges, never changes a cartridge after it is revealed.
BackroomsBuckshotLuck3D PROC uses ebx esi edi
call BackroomsLuck3D
cmp eax,-1
je br_bs_done
mov brBuckshotLuck3D,eax
xor eax,bs3d_turn
mov ebx,eax
xor esi,esi
br_bs_shell:
; Only permute cartridges already loaded; preserve advertised counts.
xor eax,eax
cmp ebx,1
jne br_bs_blanks_first
cmp esi,bs3d_liveCount
setb al
jmp br_bs_store
br_bs_blanks_first:
cmp esi,bs3d_blankCount
setae al
br_bs_store:
mov bs3d_shells[esi*4],eax
inc esi
cmp esi,bs3d_shellCount
jb br_bs_shell
br_bs_done:
ret
BackroomsBuckshotLuck3D ENDP
BackroomsRussianLuck3D PROC
; Cylinder is arranged before LOAD/SPIN; shot animation consumes it unchanged.
call BackroomsLuck3D
cmp eax,-1
je br_rr_done
mov brRussianLuck3D,eax
mov rr3d_turn,eax
call BackroomsRussianCylinder3D
br_rr_done:
ret
BackroomsRussianLuck3D ENDP
; Search legal cylinders before loading animation, not at the trigger frame.
; Keep selected bullet count. Lucky cylinders eliminate guests, never player;
; subsequent reloads retain the single round's luck roll.
BackroomsRussianCylinder3D PROC uses ebx esi edi
local candidate:DWORD,alive:DWORD,actor:DWORD,step:DWORD
cmp brRussianLuck3D,-1
je br_cylinder_done
cmp brRussianLuck3D,0
jne br_cylinder_search
mov eax,1
mov ecx,rr3d_bullets
shl eax,cl
dec eax
mov rr3d_mask,eax
mov rr3d_turn,0
mov rr3d_chamber,0
ret
br_cylinder_search:
mov candidate,1
br_cylinder_candidate:
mov eax,candidate
xor ecx,ecx
br_cylinder_popcount:
shr eax,1
adc ecx,0
test eax,eax
jnz br_cylinder_popcount
cmp ecx,rr3d_bullets
jne br_cylinder_next
mov eax,rrPartyAlive3D
mov alive,eax
mov eax,rr3d_turn
mov actor,eax
mov step,0
br_cylinder_simulate:
mov eax,candidate
mov ecx,step
bt eax,ecx
jnc br_cylinder_advance
mov ecx,actor
test ecx,ecx
jz br_cylinder_next
btr alive,ecx
cmp alive,1
je br_cylinder_found
br_cylinder_advance:
inc actor
mov eax,actor
cmp eax,rrPartySize3D
jb @F
mov actor,0
xor eax,eax
@@:
bt alive,eax
jnc br_cylinder_advance
inc step
cmp step,6
jb br_cylinder_simulate
br_cylinder_found:
mov eax,candidate
mov rr3d_mask,eax
mov rr3d_chamber,0
ret
br_cylinder_next:
inc candidate
cmp candidate,64
jb br_cylinder_candidate
br_cylinder_done:
ret
BackroomsRussianCylinder3D ENDP
HandleBackroomsInventory3D PROC
cmp brOwned3D,0
jne @F
mov brInventoryOpen3D,0
xor eax,eax
ret
@@:
invoke Pressed3D,52h
test eax,eax
jz @F
xor brInventoryOpen3D,1
mov eax,1
ret
@@:
cmp brInventoryOpen3D,0
je br_inventory_unhandled
invoke Pressed3D,09h
test eax,eax
jz @F
mov brInventoryOpen3D,0
@@:
invoke Pressed3D,45h
test eax,eax
jz @F
xor brEnabled3D,1
call SaveProgress3D
@@:
mov eax,1
ret
br_inventory_unhandled:
xor eax,eax
ret
HandleBackroomsInventory3D ENDP
RenderBackroomsInventory3D PROC uses esi
invoke DrawBox,0,0,320,240,0015191Bh
invoke DrawBoxBorder,8,8,304,224,001D2425h,00D8BC6Ah,1
invoke DrawString8x8,24,24,OFFSET brInventory3D,00EED5A0h
invoke DrawString8x8,24,52,OFFSET brInventoryRules1,00FFFFFFh
invoke DrawString8x8,24,72,OFFSET brInventoryRules2,00FFFFFFh
invoke DrawString8x8,24,100,OFFSET brInventoryRules3,00DDCDAAh
invoke DrawString8x8,24,120,OFFSET brInventoryRules4,00DDCDAAh
invoke DrawString8x8,24,140,OFFSET brInventoryRules5,00DDCDAAh
invoke DrawString8x8,24,160,OFFSET brInventoryRules6,00DDCDAAh
invoke DrawString8x8,24,188,OFFSET brInventoryHelp3D,00D8BC6Ah
mov esi,OFFSET brDisabledText3D
cmp brEnabled3D,0
je @F
mov esi,OFFSET brEnabledText3D
@@:
invoke DrawString8x8,264,188,esi,00FFFFFFh
invoke DrawString8x8,24,212,OFFSET brInventoryReturn3D,0099AAA5h
ret
RenderBackroomsInventory3D ENDP