KAZIK/src_graphics/buckshot.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

1403 lines
32 KiB
PHP

.code
FreeBuckshotAssets3D PROC uses esi
xor esi, esi
bs_free_pack:
invoke FreeAnimPack3D, bs3d_packs[esi*4]
inc esi
cmp esi, BS_ASSET_COUNT
jb bs_free_pack
ret
FreeBuckshotAssets3D ENDP
LoadBuckshotAssets3D PROC uses ebx esi
xor esi, esi
bs_load_pack:
invoke LoadAnimPack3D, bs3d_packs[esi*4], bs3d_paths[esi*4]
test eax, eax
jz bs_pack_failed
mov ebx, bs3d_packs[esi*4]
mov eax, [ebx].AnimPack3D.frames
cmp eax, bs3d_frameCounts[esi*4]
jne bs_pack_failed
mov eax, [ebx].AnimPack3D.imageWidth
cmp eax, bs3d_frameWidths[esi*4]
jne bs_pack_failed
mov eax, [ebx].AnimPack3D.height
cmp eax, bs3d_frameHeights[esi*4]
jne bs_pack_failed
inc esi
cmp esi, BS_ASSET_COUNT
jb bs_load_pack
mov eax, 1
ret
bs_pack_failed:
call FreeBuckshotAssets3D
xor eax, eax
ret
LoadBuckshotAssets3D ENDP
InitBuckshot3D PROC
call LoadBuckshotAssets3D
test eax, eax
jz bs_init_error
mov bs3d_state, BS_READY
mov bs3d_hpPlayer, 4
mov bs3d_hpDealer, 4
mov bs3d_shellCount, 0
mov bs3d_shellIndex, 0
mov bs3d_liveCount, 0
mov bs3d_blankCount, 0
mov bs3d_timer, 0
mov bs3d_clock, 0
mov bs3d_error, 0
mov bs3d_message, 0
mov bs3d_payout, 0
mov bs3d_result, 0
mov bs3d_pitch, 0
mov eax, 1
ret
bs_init_error:
mov bs3d_state, BS_ERROR
xor eax, eax
ret
InitBuckshot3D ENDP
BuckshotReload3D PROC uses ebx esi
invoke RandomRange3D, 5
add eax, 4
mov bs3d_shellCount, eax
mov bs3d_shellIndex, 0
mov bs3d_liveCount, 0
mov bs3d_blankCount, 0
mov bs3d_known, -1
mov bs3d_known[4], -1
xor esi, esi
bs_reload_shell:
invoke RandomRange3D, 2
mov bs3d_shells[esi*4], eax
test eax, eax
jz bs_reload_blank
inc bs3d_liveCount
jmp bs_reload_next
bs_reload_blank:
inc bs3d_blankCount
bs_reload_next:
inc esi
cmp esi, bs3d_shellCount
jb bs_reload_shell
cmp bs3d_liveCount, 0
jne @F
mov bs3d_shells, 1
inc bs3d_liveCount
dec bs3d_blankCount
@@:
cmp bs3d_blankCount, 0
jne @F
mov bs3d_shells[4], 0
inc bs3d_blankCount
dec bs3d_liveCount
@@:
; The loading motion loops once per actual cartridge, then racks the pump.
mov eax, bs3d_shellCount
imul eax, 330
add eax, 920
mov bs3d_loadDuration, eax
mov eax, bs3d_turn
mov bs3d_loadActor, eax
inc eax
mov bs3d_afterAnim, eax
mov bs3d_timer, 0
mov bs3d_state, BS_LOAD
invoke PlayCasinoSound3D, OFFSET bs3d_pumpSound, 0, 20003h
ret
BuckshotReload3D ENDP
; Animation queues a shot; the cartridge and health change exactly once at the trigger frame.
BuckshotShoot3D PROC target:DWORD
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_shoot_done
cmp target, 1
ja bs_shoot_done
mov eax, target
mov bs3d_target, eax
mov eax, bs3d_turn
mov bs3d_shooter, eax
mov bs3d_effectDone, 0
mov bs3d_timer, 0
mov bs3d_state, BS_SHOT
bs_shoot_done:
ret
BuckshotShoot3D ENDP
CommitBuckshotShot3D PROC uses ebx esi edi
cmp bs3d_effectDone, 0
jne bs_commit_done
mov bs3d_effectDone, 1
mov esi, bs3d_shooter
mov edi, esi
mov ebx, bs3d_shellIndex
cmp ebx, bs3d_shellCount
jae bs_commit_done
mov eax, bs3d_shells[ebx*4]
mov bs3d_lastShot, eax
inc bs3d_shellIndex
test eax, eax
jz bs_commit_blank
dec bs3d_liveCount
mov ecx, bs3d_damage[esi*4]
cmp bs3d_target, 0
jne bs_commit_dealer_hit
sub bs3d_hpPlayer, ecx
cmp bs3d_hpPlayer, 0
jg bs_commit_live_turn
mov bs3d_hpPlayer, 0
mov bs3d_afterAnim, BS_LOSE
jmp bs_commit_live_sound
bs_commit_dealer_hit:
sub bs3d_hpDealer, ecx
cmp bs3d_hpDealer, 0
jg bs_commit_live_turn
mov bs3d_hpDealer, 0
mov bs3d_afterAnim, BS_WIN
jmp bs_commit_live_sound
bs_commit_live_turn:
xor esi, 1
mov bs3d_turn, esi
inc esi
mov bs3d_afterAnim, esi
bs_commit_live_sound:
mov bs3d_message, OFFSET bs3d_textShot
invoke PlayCasinoSound3D, OFFSET rrFireSound3D, 0, 20003h
jmp bs_commit_cleanup
bs_commit_blank:
dec bs3d_blankCount
; Only a blank directed at the shooter's own side keeps the current turn.
mov eax, bs3d_target
cmp eax, esi
je @F
xor esi, 1
@@:
mov bs3d_turn, esi
inc esi
mov bs3d_afterAnim, esi
mov bs3d_message, OFFSET bs3d_textDry
invoke PlayCasinoSound3D, OFFSET rrDrySound3D, 0, 20003h
bs_commit_cleanup:
mov bs3d_damage[edi*4], 1
mov bs3d_known, -1
mov bs3d_known[4], -1
mov bs3d_messageTime, 1800
bs_commit_done:
ret
CommitBuckshotShot3D ENDP
FinishBuckshotAction3D PROC uses ebx
cmp bs3d_state, BS_SHOT
jne bs_finish_done
mov eax, bs3d_afterAnim
cmp eax, BS_WIN
je bs_finish_win
cmp eax, BS_LOSE
je bs_finish_lose
mov ebx, bs3d_turn
cmp bs3d_skip[ebx*4], 0
je @F
dec bs3d_skip[ebx*4]
xor ebx, 1
mov bs3d_turn, ebx
@@:
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_finish_reload
lea eax, [ebx+1]
mov bs3d_state, eax
mov bs3d_timer, 0
ret
bs_finish_reload:
call BuckshotReload3D
ret
bs_finish_win:
mov bs3d_state, BS_DEATH
mov bs3d_result, BS_WIN
mov bs3d_victim, 1
mov bs3d_timer, 800
mov eax, bs3d_bet
imul eax, 3
mov bs3d_payout, eax
add bankroll, eax
cmp bankroll, 1000000000
jbe @F
mov bankroll, 1000000000
@@:
call SaveProgress3D
ret
bs_finish_lose:
mov bs3d_state, BS_DEATH
mov bs3d_result, BS_LOSE
mov bs3d_victim, 0
mov bs3d_timer, 800
call SaveProgress3D
bs_finish_done:
ret
FinishBuckshotAction3D ENDP
UseBuckshotItem3D PROC uses ebx esi item:DWORD
mov eax, bs3d_state
cmp eax, BS_PLAYER
je @F
cmp eax, BS_DEALER
jne bs_item_invalid
@@:
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_item_invalid
cmp item, 3
ja bs_item_invalid
mov esi, bs3d_turn
mov ebx, esi
shl ebx, 2
add ebx, item
cmp bs3d_items[ebx*4], 0
je bs_item_invalid
cmp item, 1
jne @F
cmp bs3d_damage[esi*4], 2
je bs_item_invalid
@@:
cmp item, 3
jne @F
mov eax, esi
xor eax, 1
cmp bs3d_skip[eax*4], 0
jne bs_item_invalid
@@:
dec bs3d_items[ebx*4]
mov eax, item
mov bs3d_item, eax
mov bs3d_timer, 0
mov bs3d_effectDone, 0
lea eax, [esi+1]
mov bs3d_afterAnim, eax
mov bs3d_state, BS_ITEM
mov eax, 1
ret
bs_item_invalid:
cmp bs3d_turn, 0
jne @F
mov bs3d_message, OFFSET bs3d_textItemEmpty
mov bs3d_messageTime, 1500
@@:
xor eax, eax
ret
UseBuckshotItem3D ENDP
CommitBuckshotItem3D PROC uses ebx esi
cmp bs3d_effectDone, 0
jne bs_item_commit_done
mov bs3d_effectDone, 1
mov esi, bs3d_turn
mov eax, bs3d_item
test eax, eax
jz bs_item_glass
cmp eax, 1
je bs_item_saw
cmp eax, 2
je bs_item_beer
mov eax, esi
xor eax, 1
mov bs3d_skip[eax*4], 1
mov bs3d_message, OFFSET bs3d_textCuffs
jmp bs_item_committed
bs_item_glass:
mov ebx, bs3d_shellIndex
mov eax, bs3d_shells[ebx*4]
mov bs3d_known[esi*4], eax
mov bs3d_message, OFFSET bs3d_textKnownBlank
test eax, eax
jz bs_item_committed
mov bs3d_message, OFFSET bs3d_textKnownLive
jmp bs_item_committed
bs_item_saw:
mov bs3d_damage[esi*4], 2
mov bs3d_message, OFFSET bs3d_textSaw
jmp bs_item_committed
bs_item_beer:
mov ebx, bs3d_shellIndex
mov eax, bs3d_shells[ebx*4]
mov bs3d_lastShot, eax
inc bs3d_shellIndex
test eax, eax
jz @F
dec bs3d_liveCount
jmp bs_item_beer_counts
@@:
dec bs3d_blankCount
bs_item_beer_counts:
mov bs3d_known, -1
mov bs3d_known[4], -1
mov bs3d_message, OFFSET bs3d_textBeer
bs_item_committed:
mov bs3d_messageTime, 1800
invoke PlayCasinoSound3D, OFFSET bs3d_pumpSound, 0, 20003h
bs_item_commit_done:
ret
CommitBuckshotItem3D ENDP
; The dealer reasons from the revealed shell or remaining counts, never from hidden order.
ChooseBuckshotDealer3D PROC
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_dealer_reload
cmp bs3d_known[4], -1
jne bs_dealer_saw
cmp bs3d_items[16], 0
je bs_dealer_saw
invoke UseBuckshotItem3D, 0
ret
bs_dealer_saw:
cmp bs3d_known[4], 1
jne bs_dealer_beer
cmp bs3d_items[20], 0
je bs_dealer_cuffs
cmp bs3d_damage[4], 1
jne bs_dealer_cuffs
invoke UseBuckshotItem3D, 1
ret
bs_dealer_beer:
cmp bs3d_known[4], 0
jne bs_dealer_cuffs
cmp bs3d_items[24], 0
je bs_dealer_cuffs
invoke UseBuckshotItem3D, 2
ret
bs_dealer_cuffs:
cmp bs3d_skip, 0
jne bs_dealer_target
cmp bs3d_items[28], 0
je bs_dealer_target
invoke UseBuckshotItem3D, 3
ret
bs_dealer_target:
cmp bs3d_known[4], 0
je bs_dealer_self
cmp bs3d_known[4], 1
je bs_dealer_player
cmp bs3d_liveCount, 0
je bs_dealer_self
mov eax, bs3d_blankCount
cmp eax, bs3d_liveCount
jbe bs_dealer_player
invoke RandomRange3D, 100
cmp eax, 60
jae bs_dealer_player
bs_dealer_self:
invoke BuckshotShoot3D, 1
ret
bs_dealer_player:
invoke BuckshotShoot3D, 0
ret
bs_dealer_reload:
call BuckshotReload3D
ret
ChooseBuckshotDealer3D ENDP
BuckshotMouse3D PROC uses ebx
cmp mouseClick3D, 0
je bs_mouse_done
mov mouseClick3D, 0
mov eax, mouseX3D
shl eax, 1
mov ebx, mouseY3D
shl ebx, 1
cmp bs3d_state, BS_READY
je bs_mouse_start
cmp bs3d_state, BS_WIN
je bs_mouse_start
cmp bs3d_state, BS_LOSE
je bs_mouse_start
cmp bs3d_state, BS_PLAYER
jne bs_mouse_done
cmp ebx, 396
jb bs_mouse_done
cmp ebx, 443
jae bs_mouse_shoot
sub eax, 160
js bs_mouse_done
xor edx, edx
mov ecx, 112
div ecx
cmp eax, 3
ja bs_mouse_done
add eax, 33h
mov pressedKeys3D[eax], 1
ret
bs_mouse_shoot:
cmp ebx, 476
jae bs_mouse_done
cmp eax, 32
jb bs_mouse_done
cmp eax, 132
jb bs_mouse_self
cmp eax, 150
jb bs_mouse_done
cmp eax, 270
jae bs_mouse_done
mov pressedKeys3D[32h], 1
ret
bs_mouse_self:
mov pressedKeys3D[31h], 1
ret
bs_mouse_start:
cmp ebx, 442
jb bs_mouse_amount
cmp ebx, 476
jae bs_mouse_done
cmp eax, 246
jb bs_mouse_done
cmp eax, 382
jae bs_mouse_done
mov pressedKeys3D[20h], 1
ret
bs_mouse_amount:
cmp bs3d_state, BS_READY
jne bs_mouse_done
cmp ebx, 442
jae bs_mouse_done
cmp ebx, 408
jb bs_mouse_done
cmp eax, 30
jb bs_mouse_done
cmp eax, 60
jb bs_mouse_down
cmp eax, 112
jb bs_mouse_done
cmp eax, 144
jae bs_mouse_done
mov pressedKeys3D[26h], 1
ret
bs_mouse_down:
mov pressedKeys3D[28h], 1
bs_mouse_done:
ret
BuckshotMouse3D ENDP
HandleBuckshot3D PROC uses ebx esi
call BuckshotMouse3D
mov eax, deltaTime3D
add bs3d_clock, eax
cmp bs3d_messageTime, eax
ja @F
mov bs3d_messageTime, 0
jmp bs_update_state
@@:
sub bs3d_messageTime, eax
bs_update_state:
mov eax, bs3d_state
cmp eax, BS_READY
je bs_input_ready
cmp eax, BS_PLAYER
je bs_input_player
cmp eax, BS_DEALER
je bs_input_dealer
cmp eax, BS_LOAD
je bs_input_loading
cmp eax, BS_SHOT
je bs_input_shot
cmp eax, BS_ITEM
je bs_input_item
cmp eax, BS_DEATH
je bs_input_death
cmp eax, BS_RECOVERY
je bs_input_recovery
cmp eax, BS_ERROR
je bs_input_done
invoke Pressed3D, 20h
test eax, eax
jz bs_input_done
call InitBuckshot3D
test eax, eax
jz bs_input_done
jmp bs_input_start
bs_input_ready:
invoke Pressed3D, 26h
test eax, eax
jz @F
add bs3d_bet, 50
cmp bs3d_bet, 5000
jbe bs_input_done
mov bs3d_bet, 5000
ret
@@:
invoke Pressed3D, 28h
test eax, eax
jz @F
cmp bs3d_bet, 50
jbe bs_input_done
sub bs3d_bet, 50
ret
@@:
invoke Pressed3D, 20h
test eax, eax
jz bs_input_done
bs_input_start:
mov eax, bs3d_bet
cmp eax, 0
je bs_input_no_cash
cmp eax, bankroll
ja bs_input_no_cash
sub bankroll, eax
mov bs3d_hpPlayer, 4
mov bs3d_hpDealer, 4
mov bs3d_turn, 0
mov bs3d_damage, 1
mov bs3d_damage[4], 1
mov bs3d_skip, 0
mov bs3d_skip[4], 0
mov bs3d_error, 0
mov bs3d_messageTime, 0
mov bs3d_payout, 0
xor esi, esi
bs_give_item:
mov bs3d_items[esi*4], 1
inc esi
cmp esi, 8
jb bs_give_item
call BuckshotReload3D
call SaveProgress3D
ret
bs_input_no_cash:
mov bs3d_error, 1
ret
bs_input_player:
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_input_reload
mov bs3d_turn, 0
invoke Pressed3D, 31h
test eax, eax
jz @F
invoke BuckshotShoot3D, 0
ret
@@:
invoke Pressed3D, 32h
test eax, eax
jz @F
invoke BuckshotShoot3D, 1
ret
@@:
xor esi, esi
bs_item_key:
lea ebx, [esi+33h]
invoke Pressed3D, ebx
test eax, eax
jz @F
invoke UseBuckshotItem3D, esi
ret
@@:
inc esi
cmp esi, 4
jb bs_item_key
ret
bs_input_dealer:
mov eax, deltaTime3D
add bs3d_timer, eax
cmp bs3d_timer, 850
jb bs_input_done
mov bs3d_turn, 1
call ChooseBuckshotDealer3D
ret
bs_input_reload:
call BuckshotReload3D
ret
bs_input_loading:
mov eax, deltaTime3D
add bs3d_timer, eax
mov eax, bs3d_timer
cmp eax, bs3d_loadDuration
jb bs_input_done
mov eax, bs3d_afterAnim
mov bs3d_state, eax
mov bs3d_timer, 0
call ClearKeys3D
ret
bs_input_shot:
mov eax, deltaTime3D
add bs3d_timer, eax
cmp bs3d_timer, 450
jb bs_input_done
call CommitBuckshotShot3D
cmp bs3d_timer, 1250
jb bs_input_done
call FinishBuckshotAction3D
call ClearKeys3D
ret
bs_input_item:
mov eax, deltaTime3D
add bs3d_timer, eax
cmp bs3d_timer, 430
jb bs_input_done
call CommitBuckshotItem3D
cmp bs3d_timer, 1000
jb bs_input_done
mov eax, bs3d_shellIndex
cmp eax, bs3d_shellCount
jae bs_input_reload
mov eax, bs3d_afterAnim
mov bs3d_state, eax
mov bs3d_timer, 0
call ClearKeys3D
ret
bs_input_death:
mov eax, deltaTime3D
add bs3d_timer, eax
cmp bs3d_timer, 1800
jb bs_input_done
mov bs3d_timer, 0
mov bs3d_state, BS_RECOVERY
invoke PlayCasinoSound3D, OFFSET bs3d_pumpSound, 0, 20003h
ret
bs_input_recovery:
mov eax, deltaTime3D
add bs3d_timer, eax
cmp bs3d_timer, 3600
jb bs_input_done
mov eax, bs3d_result
mov bs3d_state, eax
mov bs3d_hpPlayer, 4
mov bs3d_hpDealer, 4
mov bs3d_timer, 0
cmp eax, BS_WIN
jne @F
invoke PlayCasinoSound3D, OFFSET soundRoundWin, 0, 20003h
jmp bs_recovery_done
@@:
invoke PlayCasinoSound3D, OFFSET soundRoundLose, 0, 20003h
bs_recovery_done:
call ClearKeys3D
bs_input_done:
ret
HandleBuckshot3D ENDP
; This scene's HUD uses physical 640x480 coordinates, unlike the legacy doubled primitives.
DrawBuckshotPanel3D PROC uses ebx x:DWORD,y:DWORD,w:DWORD,h:DWORD,ink:DWORD
mov eax, x
sar eax, 1
mov edx, y
sar edx, 1
mov ecx, w
shr ecx, 1
mov ebx, h
shr ebx, 1
invoke DrawBox, eax, edx, ecx, ebx, ink
ret
DrawBuckshotPanel3D ENDP
DrawBuckshotText3D PROC uses ebx esi edi x:DWORD,y:DWORD,source:DWORD,ink:DWORD
local px:DWORD,rowPx:DWORD,glyphBits:DWORD
mov esi, source
test esi, esi
jz bs_text_done
mov eax, x
mov px, eax
bs_text_char:
movzx eax, byte ptr [esi]
test eax, eax
jz bs_text_done
lea edi, font8x8[eax*8]
xor ebx, ebx
bs_text_row:
movzx eax, byte ptr [edi+ebx]
mov glyphBits, eax
mov edx, y
add edx, ebx
cmp edx, 480
jae bs_text_next_row
imul edx, 640
mov rowPx, edx
xor ecx, ecx
bs_text_pixel:
mov eax, px
add eax, ecx
cmp eax, 640
jae bs_text_skip
test glyphBits, 80h
jz bs_text_skip
add eax, rowPx
mov edx, ink
mov screenBuffer[eax*4], edx
bs_text_skip:
shl glyphBits, 1
inc ecx
cmp ecx, 8
jb bs_text_pixel
bs_text_next_row:
inc ebx
cmp ebx, 8
jb bs_text_row
add px, 8
inc esi
jmp bs_text_char
bs_text_done:
ret
DrawBuckshotText3D ENDP
DrawBuckshotNumber3D PROC x:DWORD,y:DWORD,value:DWORD,ink:DWORD
invoke FormatNumber, value, OFFSET hudNumBuffer
invoke DrawBuckshotText3D, x, y, OFFSET hudNumBuffer, ink
ret
DrawBuckshotNumber3D ENDP
; Keep each pose anchored; move the whole silhouette smoothly as hands rise and settle.
DrawBuckshotHand3D PROC pack:DWORD,frame:DWORD,x:DWORD,y:DWORD,w:DWORD,h:DWORD
invoke DrawAnimSprite3D, pack, frame, x, y, w, h
ret
DrawBuckshotHand3D ENDP
ResolveBuckshotPose3D PROC uses ebx
mov eax, bs3d_timer
cmp bs3d_state, BS_LOAD
jne bs_resolve_shot
cmp eax, 220
jb bs_pose_first
sub eax, 220
mov ecx, bs3d_shellCount
imul ecx, 330
cmp eax, ecx
jae bs_pose_pump
xor edx, edx
mov ecx, 330
div ecx
and eax, 1
imul ebx, eax, 3
mov eax, edx
xor edx, edx
mov ecx, 110
div ecx
inc eax
add eax, ebx
ret
bs_pose_pump:
sub eax, ecx
xor edx, edx
cmp eax, 100
jb bs_pose_settle
sub eax, 100
mov ecx, 150
div ecx
cmp eax, 3
jbe @F
mov eax, 3
@@:
add eax, 8
ret
bs_pose_settle:
mov eax, 7
ret
bs_pose_first:
xor eax, eax
ret
bs_resolve_shot:
cmp eax, 140
jb bs_pose_first
cmp eax, 300
jb bs_pose_aim
cmp eax, 450
jb bs_pose_steady
cmp eax, 535
jb bs_pose_flash
cmp eax, 700
jb bs_pose_smoke
cmp eax, 890
jb bs_pose_rack
cmp eax, 1080
jb bs_pose_return
mov eax, 7
ret
bs_pose_aim:
mov eax, 1
ret
bs_pose_steady:
mov eax, 2
ret
bs_pose_flash:
cmp bs3d_lastShot, 0
je bs_pose_steady
mov eax, 3
ret
bs_pose_smoke:
cmp bs3d_lastShot, 0
je bs_pose_steady
mov eax, 4
ret
bs_pose_rack:
mov eax, 5
ret
bs_pose_return:
mov eax, 6
ret
ResolveBuckshotPose3D ENDP
RenderBuckshot3D PROC uses ebx esi edi
local handY:DWORD,pose:DWORD,actor:DWORD
mov animOpacity3D, 255
cmp bs3d_room.pixels, 0
je bs_render_error
mov eax, bs3d_turn
cmp bs3d_state, BS_SHOT
jne @F
mov eax, bs3d_shooter
@@:
mov actor, eax
mov bs3d_pitch, 0
cmp bs3d_state, BS_SHOT
jne bs_pitch_death
cmp actor, 0
jne bs_pitch_done
cmp bs3d_target, 0
jne bs_pitch_done
mov eax, bs3d_timer
cmp eax, 300
jb bs_pitch_rise
mov bs3d_pitch, 120
cmp eax, 900
jb bs_pitch_done
cmp bs3d_hpPlayer, 0
je bs_pitch_done
mov ecx, 1250
sub ecx, eax
jle bs_pitch_clear
imul eax, ecx, 120
xor edx, edx
mov ecx, 350
div ecx
mov bs3d_pitch, eax
jmp bs_pitch_done
bs_pitch_clear:
mov bs3d_pitch, 0
jmp bs_pitch_done
bs_pitch_rise:
imul eax, 120
xor edx, edx
mov ecx, 300
div ecx
mov bs3d_pitch, eax
jmp bs_pitch_done
bs_pitch_death:
cmp bs3d_state, BS_DEATH
je bs_pitch_dead_player
cmp bs3d_state, BS_RECOVERY
jne bs_pitch_done
bs_pitch_dead_player:
cmp bs3d_victim, 0
jne bs_pitch_done
mov bs3d_pitch, 120
bs_pitch_done:
cmp bs3d_pitch, 0
jne bs_render_pitched_room
mov esi, bs3d_room.pixels
lea edi, screenBuffer
mov ecx, SCREEN_SIZE
rep movsd
jmp bs_render_room_done
bs_render_pitched_room:
mov eax, bs3d_pitch
neg eax
mov ecx, bs3d_pitch
add ecx, 480
invoke DrawAnimSprite3D, OFFSET bs3d_room, 0, 0, eax, 640, ecx
bs_render_room_done:
mov bs3d_dealerFrame, 0
mov eax, bs3d_clock
xor edx, edx
mov ecx, 3100
div ecx
cmp edx, 150
jae @F
mov bs3d_dealerFrame, 1
@@:
cmp bs3d_state, BS_DEALER
jne @F
mov bs3d_dealerFrame, 2
@@:
cmp bs3d_state, BS_LOAD
jne @F
mov bs3d_dealerFrame, 4
@@:
cmp bs3d_state, BS_SHOT
jne @F
mov bs3d_dealerFrame, 6
cmp actor, 1
je @F
mov bs3d_dealerFrame, 0
cmp bs3d_timer, 450
jb @F
cmp bs3d_target, 1
jne @F
cmp bs3d_lastShot, 0
je @F
mov bs3d_dealerFrame, 12
@@:
cmp bs3d_state, BS_ITEM
jne @F
cmp bs3d_turn, 1
jne @F
mov bs3d_dealerFrame, 7
@@:
cmp bs3d_state, BS_WIN
jne @F
mov bs3d_dealerFrame, 14
@@:
cmp bs3d_state, BS_LOSE
jne @F
mov bs3d_dealerFrame, 11
@@:
cmp bs3d_state, BS_DEATH
jne bs_dealer_death_shot
cmp bs3d_victim, 1
jne bs_dealer_normal
mov eax, bs3d_timer
jmp bs_dealer_death_pose
bs_dealer_death_shot:
cmp bs3d_state, BS_SHOT
jne bs_dealer_medical
cmp bs3d_hpDealer, 0
jne bs_dealer_normal
mov eax, bs3d_timer
sub eax, 450
js bs_dealer_normal
jmp bs_dealer_death_pose
bs_dealer_medical:
cmp bs3d_state, BS_RECOVERY
jne bs_dealer_normal
cmp bs3d_victim, 1
jne bs_dealer_normal
cmp bs3d_timer, 2250
jae bs_dealer_normal
mov eax, 1100
bs_dealer_death_pose:
xor edx, edx
mov ecx, 100
div ecx
cmp eax, 11
jbe @F
mov eax, 11
@@:
invoke DrawAnimSprite3D, OFFSET bs3d_death, eax, 192, 2, 256, 224
jmp bs_render_rail
bs_dealer_normal:
cmp bs3d_state, BS_LOAD
jne bs_dealer_forward_pose
cmp bs3d_loadActor, 1
jne bs_dealer_gesture
mov eax, bs3d_timer
cmp eax, 220
jb bs_dealer_reach
sub eax, 220
mov ecx, bs3d_shellCount
imul ecx, 330
cmp eax, ecx
jae bs_dealer_pump_pose
xor edx, edx
mov ecx, 330
div ecx
mov eax, edx
xor edx, edx
mov ecx, 110
div ecx
add eax, 2
jmp bs_dealer_action_draw
bs_dealer_pump_pose:
sub eax, ecx
cmp eax, 100
jb bs_dealer_grip
cmp eax, 400
jb bs_dealer_pull
mov eax, 7
jmp bs_dealer_action_draw
bs_dealer_grip:
mov eax, 5
jmp bs_dealer_action_draw
bs_dealer_pull:
mov eax, 6
jmp bs_dealer_action_draw
bs_dealer_reach:
xor eax, eax
jmp bs_dealer_action_draw
bs_dealer_forward_pose:
cmp bs3d_state, BS_SHOT
jne bs_dealer_gesture
cmp actor, 1
jne bs_dealer_gesture
cmp bs3d_target, 0
jne bs_dealer_gesture
call ResolveBuckshotPose3D
add eax, 8
bs_dealer_action_draw:
invoke DrawAnimSprite3D, OFFSET bs3d_dealerActions, eax, 192, 2, 256, 224
jmp bs_render_rail
bs_dealer_gesture:
mov eax, 2
sub eax, bs3d_pitch
invoke DrawAnimSprite3D, OFFSET bs3d_dealer, bs3d_dealerFrame, 192, eax, 256, 224
bs_render_rail:
; Dealer's torso stops at the far leather rail; hands can overlap its upper edge.
cmp bs3d_pitch, 0
jne bs_render_after_rail
mov esi, bs3d_room.pixels
add esi, 640*222*4
lea edi, screenBuffer[640*222*4]
mov ecx, 640*8
rep movsd
bs_render_after_rail:
cmp bs3d_state, BS_DEATH
je bs_render_death
cmp bs3d_state, BS_RECOVERY
je bs_render_recovery
cmp bs3d_state, BS_LOAD
je bs_render_load
cmp bs3d_state, BS_SHOT
je bs_render_shot
cmp bs3d_state, BS_ITEM
je bs_render_item
jmp bs_render_idle_gun
bs_render_load:
call ResolveBuckshotPose3D
mov pose, eax
cmp bs3d_loadActor, 1
je bs_render_dealer_load
mov handY, 140
mov eax, bs3d_timer
cmp eax, 220
jae @F
mov ecx, 220
sub ecx, eax
imul ecx, 60
mov eax, ecx
xor edx, edx
mov ecx, 220
div ecx
add handY, eax
@@:
invoke DrawBuckshotHand3D, OFFSET bs3d_loading, pose, 166, handY, 320, 280
jmp bs_render_hud
bs_render_dealer_load:
jmp bs_render_hud
bs_render_shot:
call ResolveBuckshotPose3D
mov pose, eax
cmp actor, 1
je bs_render_dealer_shot
mov eax, bs3d_target
test eax, eax
jz bs_render_self_shot
mov handY, 140
mov eax, bs3d_timer
cmp eax, 140
jae @F
mov ecx, 140
sub ecx, eax
imul eax, ecx, 60
xor edx, edx
mov ecx, 140
div ecx
add handY, eax
@@:
invoke DrawBuckshotHand3D, OFFSET bs3d_shots, pose, 158, handY, 320, 280
jmp bs_render_hit_overlay
bs_render_self_shot:
mov handY, 120
mov eax, bs3d_timer
cmp eax, 300
jae @F
mov ecx, 300
sub ecx, eax
imul eax, ecx, 80
xor edx, edx
mov ecx, 300
div ecx
add handY, eax
@@:
mov eax, bs3d_timer
xor edx, edx
mov ecx, 150
div ecx
cmp eax, 7
jbe @F
mov eax, 7
@@:
cmp bs3d_timer, 450
jb @F
cmp bs3d_timer, 900
jae @F
mov eax, 5
@@:
invoke DrawBuckshotHand3D, OFFSET bs3d_self, eax, 156, handY, 328, 287
cmp bs3d_effectDone, 0
je bs_render_hit_overlay
cmp bs3d_lastShot, 0
je bs_render_hit_overlay
cmp bs3d_timer, 900
jae bs_render_hit_overlay
mov eax, bs3d_timer
sub eax, 450
cmp eax, 120
jae bs_self_smoke
xor edx, edx
mov ecx, 30
div ecx
jmp bs_self_flash_draw
bs_self_smoke:
sub eax, 120
xor edx, edx
mov ecx, 90
div ecx
add eax, 4
cmp eax, 7
jbe bs_self_flash_draw
mov eax, 7
bs_self_flash_draw:
; The atlas origin is its center, aligned with the bore rather than the weapon bounds.
mov edx, handY
add edx, 44
invoke DrawAnimSprite3D, OFFSET bs3d_selfFlash, eax, 251, edx, 128, 128
jmp bs_render_hit_overlay
bs_render_dealer_shot:
; The dealer action atlas already owns the raised weapon, including its first pose.
cmp bs3d_target, 1
je bs_render_dealer_self
jmp bs_render_hit_overlay
bs_render_dealer_self:
invoke DrawAnimSprite3D, OFFSET bs3d_props, 1, 206, 78, 176, 94
jmp bs_render_hit_overlay
bs_render_hit_overlay:
cmp bs3d_effectDone, 0
je bs_render_hud
cmp bs3d_lastShot, 0
je bs_render_hud
cmp bs3d_target, 0
jne bs_render_hud
mov eax, bs3d_timer
sub eax, 450
xor edx, edx
mov ecx, 180
div ecx
cmp eax, 7
jbe @F
mov eax, 7
@@:
invoke DrawAnimSprite3D, OFFSET bs3d_blood, eax, 0, 0, 640, 480
ret
bs_render_death:
cmp bs3d_victim, 1
je bs_draw_done
; First-person death keeps the player's body off camera.
lea edi, screenBuffer
mov ecx, SCREEN_SIZE
bs_dim_death:
mov eax, [edi]
shr eax, 2
and eax, 003F3F3Fh
mov [edi], eax
add edi, 4
loop bs_dim_death
mov eax, bs3d_timer
xor edx, edx
mov ecx, 250
div ecx
cmp eax, 7
jbe @F
mov eax, 7
@@:
invoke DrawAnimSprite3D, OFFSET bs3d_blood, eax, 0, 0, 640, 480
ret
bs_render_recovery:
; Both perspectives use all sixteen poses, once, in chronological order.
mov eax, bs3d_timer
imul eax,16
xor edx, edx
mov ecx,3600
div ecx
cmp eax,15
jbe @F
mov eax,15
@@:
cmp bs3d_victim, 0
jne @F
add eax,16
@@:
invoke DrawAnimSprite3D, OFFSET bs3d_medical, eax, 0, 0, 640, 480
ret
bs_render_item:
mov eax, bs3d_item
shl eax, 1
cmp bs3d_timer, 430
jb @F
inc eax
@@:
mov pose, eax
cmp bs3d_turn, 1
je bs_render_dealer_item
invoke DrawBuckshotHand3D, OFFSET bs3d_itemHands, pose, 180, 168, 256, 256
jmp bs_render_hud
bs_render_dealer_item:
mov eax, bs3d_item
add eax, 4
invoke DrawAnimSprite3D, OFFSET bs3d_props, eax, 244, 161, 86, 86
jmp bs_render_hud
bs_render_idle_gun:
invoke DrawAnimSprite3D, OFFSET bs3d_props, 0, 190, 226, 260, 168
bs_render_hud:
invoke DrawBuckshotPanel3D, 0, 0, 640, 32, 00111116h
invoke DrawBuckshotText3D, 14, 12, OFFSET bs3d_textTitle, 00E9C47Ah
invoke DrawBuckshotText3D, 488, 12, OFFSET bs3d_textBank, 00BCBCBCh
invoke DrawBuckshotNumber3D, 540, 12, bankroll, 00F3E4BAh
invoke DrawBuckshotPanel3D, 10, 42, 110, 28, 00151C20h
invoke DrawBuckshotPanel3D, 520, 42, 110, 28, 00151C20h
invoke DrawBuckshotText3D, 16, 48, OFFSET bs3d_textPlayer, 00E2E2E2h
invoke DrawBuckshotText3D, 526, 48, OFFSET bs3d_textDealer, 00E2E2E2h
xor esi, esi
bs_draw_health:
imul ebx, esi, 16
add ebx, 18
mov ecx, 003B3232h
cmp esi, bs3d_hpPlayer
jae @F
mov ecx, 00BD4F46h
@@:
invoke DrawBuckshotPanel3D, ebx, 60, 12, 6, ecx
add ebx, 510
mov ecx, 003B3232h
cmp esi, bs3d_hpDealer
jae @F
mov ecx, 00BD4F46h
@@:
invoke DrawBuckshotPanel3D, ebx, 60, 12, 6, ecx
inc esi
cmp esi, 4
jb bs_draw_health
invoke DrawBuckshotPanel3D, 0, 386, 640, 94, 00111617h
invoke DrawBuckshotPanel3D, 0, 386, 640, 2, 008A794Bh
invoke DrawBuckshotText3D, 16, 396, OFFSET bs3d_textShells, 00C7B88Fh
mov eax, bs3d_shellCount
sub eax, bs3d_shellIndex
invoke DrawBuckshotNumber3D, 78, 396, eax, 00FFFFFFh
invoke DrawBuckshotText3D, 14, 412, OFFSET bs3d_textLive, 00DF6656h
invoke DrawBuckshotNumber3D, 52, 412, bs3d_liveCount, 00DF6656h
invoke DrawBuckshotText3D, 76, 412, OFFSET bs3d_textBlank, 007DBBCCh
invoke DrawBuckshotNumber3D, 120, 412, bs3d_blankCount, 007DBBCCh
xor esi, esi
bs_draw_inventory:
imul ebx, esi, 112
add ebx, 160
invoke DrawBuckshotPanel3D, ebx, 396, 104, 44, 0020292Ch
lea eax, [esi+4]
lea edx, [ebx+4]
invoke DrawAnimSprite3D, OFFSET bs3d_props, eax, edx, 399, 34, 34
lea eax, [ebx+40]
invoke DrawBuckshotText3D, eax, 404, bs3d_textItems[esi*4], 00CFCAACh
lea eax, [ebx+44]
invoke DrawBuckshotNumber3D, eax, 420, bs3d_items[esi*4], 00EEEEEEh
inc esi
cmp esi, 4
jb bs_draw_inventory
cmp bs3d_state, BS_READY
je bs_draw_ready
cmp bs3d_state, BS_WIN
je bs_draw_win
cmp bs3d_state, BS_LOSE
je bs_draw_lose
cmp bs3d_state, BS_PLAYER
je bs_draw_player
cmp bs3d_state, BS_LOAD
je bs_draw_loading
cmp bs3d_state, BS_ITEM
je bs_draw_using
cmp bs3d_state, BS_DEATH
je bs_draw_death
cmp bs3d_state, BS_RECOVERY
je bs_draw_recovery
mov ebx, OFFSET bs3d_textWait
cmp bs3d_state, BS_SHOT
jne bs_draw_message
cmp bs3d_effectDone, 0
je bs_draw_message
mov ebx, bs3d_message
jmp bs_draw_message
bs_draw_loading:
mov ebx, OFFSET bs3d_textLoad
jmp bs_draw_message
bs_draw_using:
mov ebx, OFFSET bs3d_textItem
jmp bs_draw_message
bs_draw_death:
mov ebx, OFFSET bs3d_textDeath
jmp bs_draw_message
bs_draw_recovery:
mov ebx, OFFSET bs3d_textMedical
bs_draw_message:
invoke DrawBuckshotText3D, 24, 455, ebx, 00E1C67Bh
invoke DrawBuckshotText3D, 530, 455, OFFSET bs3d_textPause, 00AFAFAFh
jmp bs_draw_notice
bs_draw_ready:
invoke DrawBuckshotPanel3D, 30, 416, 28, 22, 00404A46h
invoke DrawBuckshotText3D, 40, 423, OFFSET bs3d_minus, 00FFFFFFh
invoke DrawBuckshotPanel3D, 112, 416, 28, 22, 00404A46h
invoke DrawBuckshotText3D, 122, 423, OFFSET bs3d_plus, 00FFFFFFh
invoke DrawBuckshotText3D, 22, 451, OFFSET bs3d_textBet, 00C7B88Fh
invoke DrawBuckshotNumber3D, 64, 451, bs3d_bet, 00FFFFFFh
invoke DrawBuckshotPanel3D, 246, 446, 136, 24, 00363C30h
invoke DrawBuckshotText3D, 270, 454, OFFSET bs3d_textReady, 00E1C67Bh
invoke DrawBuckshotText3D, 548, 454, OFFSET bs3d_textExit, 00AFAFAFh
cmp bs3d_error, 0
je bs_draw_done
invoke DrawBuckshotPanel3D, 232, 348, 176, 22, 00291919h
invoke DrawBuckshotText3D, 260, 355, OFFSET bs3d_textEmpty, 00DD7768h
jmp bs_draw_done
bs_draw_player:
invoke DrawBuckshotPanel3D, 30, 446, 102, 24, 00383E33h
invoke DrawBuckshotPanel3D, 150, 446, 122, 24, 00462E2Eh
invoke DrawBuckshotText3D, 48, 455, OFFSET bs3d_textChoose, 00E9DDC4h
invoke DrawBuckshotText3D, 176, 455, OFFSET bs3d_textOpponent, 00E9DDC4h
invoke DrawBuckshotText3D, 530, 455, OFFSET bs3d_textPause, 00AFAFAFh
jmp bs_draw_notice
bs_draw_win:
invoke DrawBuckshotText3D, 20, 455, OFFSET bs3d_textWin, 007FE395h
invoke DrawBuckshotNumber3D, 96, 455, bs3d_payout, 007FE395h
jmp bs_draw_result
bs_draw_lose:
invoke DrawBuckshotText3D, 20, 455, OFFSET bs3d_textLose, 00E1766Ah
bs_draw_result:
invoke DrawBuckshotPanel3D, 246, 446, 136, 24, 00363C30h
invoke DrawBuckshotText3D, 266, 455, OFFSET bs3d_textResult, 00E1C67Bh
invoke DrawBuckshotText3D, 548, 455, OFFSET bs3d_textExit, 00AFAFAFh
jmp bs_draw_done
bs_draw_notice:
cmp bs3d_turn, 0
jne bs_draw_done
cmp bs3d_known, -1
je @F
mov eax, OFFSET bs3d_textKnownBlank
cmp bs3d_known, 0
je bs_draw_known
mov eax, OFFSET bs3d_textKnownLive
bs_draw_known:
; Drawing primitives may overwrite EAX; preserve the selected string address.
mov ebx, eax
invoke DrawBuckshotPanel3D, 8, 350, 120, 22, 001B2325h
invoke DrawBuckshotText3D, 14, 357, ebx, 00E9C47Ah
@@:
cmp bs3d_messageTime, 0
je bs_draw_done
cmp bs3d_message, 0
je bs_draw_done
invoke DrawBuckshotPanel3D, 170, 354, 280, 22, 001B2325h
invoke DrawBuckshotText3D, 180, 361, bs3d_message, 00E1C67Bh
bs_draw_done:
ret
bs_render_error:
invoke DrawBuckshotPanel3D, 0, 0, 640, 480, 00111719h
invoke DrawBuckshotText3D, 184, 230, OFFSET bs3d_textAssets, 00E1C67Bh
invoke DrawBuckshotText3D, 276, 254, OFFSET bs3d_textExit, 00C7B88Fh
ret
RenderBuckshot3D ENDP