.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 invoke TriggerCharmBulletProtection test eax, eax jz @F mov bs3d_hpPlayer, 1 jmp 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 @@: invoke NpcRecordRound3D,7,1 call SaveProgress3D ret bs_finish_lose: mov bs3d_state, BS_DEATH mov bs3d_result, BS_LOSE mov bs3d_victim, 0 mov bs3d_timer, 800 invoke NpcRecordRound3D,7,0 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 cmp tournamentMode, 1 jne bs_regular_restart invoke Pressed3D, 20h test eax, eax jnz bs_tourney_report invoke Pressed3D, 0Dh test eax, eax jnz bs_tourney_report ret bs_tourney_report: cmp bs3d_state, BS_WIN jne bs_tourney_loss invoke TowerReportRoundOutcome, 1 ret bs_tourney_loss: invoke TowerReportRoundOutcome, 2 ret bs_regular_restart: 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, 70, 412, bs3d_liveCount, 00DF6656h invoke DrawBuckshotText3D, 14, 430, OFFSET bs3d_textBlank, 007DBBCCh invoke DrawBuckshotNumber3D, 86, 430, 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, 92, 451, bs3d_bet, 00FFFFFFh invoke DrawBuckshotPanel3D, 246, 446, 136, 24, 00363C30h invoke DrawBuckshotText3D, 258, 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, 120, 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, 254, 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