KAZIK/src_graphics/jackbox.inc

885 lines
21 KiB
PHP

; ==============================================================================
; JACKBOX / JUKEBOX IMPLEMENTATION - MASM32 / CP1251
; ==============================================================================
.code
LoadJackboxArt3D PROC
invoke LoadAnimPack3D, OFFSET jackboxWorldArt3D, OFFSET jackboxWorldPath3D
invoke ValidateCityPack3D, OFFSET jackboxWorldArt3D, 256, 512, 3
invoke LoadAnimPack3D, OFFSET jackboxScreenArt3D, OFFSET jackboxScreenPath3D
invoke ValidateCityPack3D, OFFSET jackboxScreenArt3D, 640, 480, 1
ret
LoadJackboxArt3D ENDP
FreeJackboxArt3D PROC
invoke FreeAnimPack3D, OFFSET jackboxWorldArt3D
invoke FreeAnimPack3D, OFFSET jackboxScreenArt3D
ret
FreeJackboxArt3D ENDP
ResolveJackboxSurface3D PROC material:DWORD
cmp jackboxWorldArt3D.pixels, 0
je jackbox_surface_missing
mov eax, material
cmp eax, MATERIAL_JACKBOX_FRONT
je jackbox_surface_front
cmp eax, MATERIAL_JACKBOX_SIDE
je jackbox_surface_side
cmp eax, MATERIAL_JACKBOX_BACK
jne jackbox_surface_missing
; Frame 2: rear panel (offset 256*512*4*2 = 1048576)
mov eax, jackboxWorldArt3D.pixels
add eax, 1048576
mov ecx, 256
mov edx, 512
ret
jackbox_surface_side:
; Frame 1: side profile (offset 256*512*4 = 524288)
mov eax, jackboxWorldArt3D.pixels
add eax, 524288
mov ecx, 256
mov edx, 512
ret
jackbox_surface_front:
; Frame 0: front face
mov eax, jackboxWorldArt3D.pixels
mov ecx, 256
mov edx, 512
ret
jackbox_surface_missing:
xor eax, eax
ret
ResolveJackboxSurface3D ENDP
DrawJackboxCabinet3D PROC uses ebx esi edi wx:DWORD, wy:DWORD
local x0:DWORD, x1:DWORD, y0:DWORD, y1:DWORD
; Solid rectangular cabinet against East wall beside billiards:
; Depth along X: 0.55m (x0 = 30.40m, x1 = 30.95m against wall at 31.0m)
; Width along Y: 0.85m (y0 = 23.075m, y1 = 23.925m, centered at Y = 23.5m)
; Leaves painting 116 at Y = [25.0 .. 26.5] completely visible and unblocked!
; Height Z: 1.85m
mov x0, FP_1*304/10
mov x1, FP_1*3095/100
mov y0, FP_1*235/10 - FP_1*425/1000
mov y1, FP_1*235/10 + FP_1*425/1000
; 1. Back Face (against East wall: X = x1)
invoke DrawCityVertical3D, 0, x1, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_BACK
; 2. North Side (Y = y0) - Authentic wooden terminal cabinet panel with brass trim
invoke DrawCityVertical3D, 1, y0, x0, x1, 0, FP_1*37/20, MATERIAL_JACKBOX_SIDE
; 3. South Side (Y = y1) - Authentic wooden terminal cabinet panel with brass trim
invoke DrawCityVertical3D, 1, y1, x0, x1, 0, FP_1*37/20, MATERIAL_JACKBOX_SIDE
; 4. Front Face (facing West towards billiards: X = x0)
invoke DrawCityVertical3D, 0, x0, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_FRONT
; 5. Top Lid (horizontal cap at z = 1.85m)
invoke DrawCityHorizontal3D, x0, x1, y0, y1, FP_1*37/20, 110
ret
DrawJackboxCabinet3D ENDP
RenderJackboxCabinet3D PROC
invoke DrawJackboxCabinet3D, JACKBOX_X, JACKBOX_Y
ret
RenderJackboxCabinet3D ENDP
JackboxCanWalk3D PROC px:DWORD, py:DWORD
mov eax, px
cmp eax, FP_1*303/10
jb jackbox_walk_clear
cmp eax, 31*FP_1+9830
ja jackbox_walk_clear
mov eax, py
sub eax, FP_1*235/10
test eax, eax
jns @F
neg eax
@@:
cmp eax, FP_1*55/100
ja jackbox_walk_clear
xor eax, eax
ret
jackbox_walk_clear:
mov eax, 1
ret
JackboxCanWalk3D ENDP
PlayJukeboxTrack3D PROC uses ebx trackIndex:DWORD
invoke mciSendStringA, OFFSET jboxStopCmd, 0, 0, 0
invoke mciSendStringA, OFFSET jboxCloseCmd, 0, 0, 0
mov jboxIsPlaying, 0
mov ebx, trackIndex
cmp ebx, 2
jae jbox_play_stop_selected
cmp ebx, JACKBOX_TRACK_COUNT
jae jbox_play_stop_selected
mov eax, jboxOpenCommands[ebx*4]
test eax, eax
jz jbox_play_stop_selected
invoke mciSendStringA, eax, 0, 0, 0
invoke mciSendStringA, OFFSET jboxPlayCmd, 0, 0, 0
mov jboxCurrentTrack, ebx
mov jboxIsPlaying, 1
mov jboxEffectiveVolume, -1
call UpdateJukeboxAudio3D
ret
jbox_play_stop_selected:
mov jboxCurrentTrack, -1
call UpdateJukeboxAudio3D
ret
PlayJukeboxTrack3D ENDP
StopJukeboxTrack3D PROC
invoke mciSendStringA, OFFSET jboxStopCmd, 0, 0, 0
invoke mciSendStringA, OFFSET jboxCloseCmd, 0, 0, 0
mov jboxIsPlaying, 0
mov jboxCurrentTrack, -1
call UpdateJukeboxAudio3D
ret
StopJukeboxTrack3D ENDP
BeginJackbox3D PROC
mov engineMode, MODE_JACKBOX
call ClearKeys3D
mov mouseClick3D, 0
ret
BeginJackbox3D ENDP
HandleJackbox3D PROC uses ebx esi
; 1. Mouse interactions
cmp mouseClick3D, 0
je jbox_keys
; Exit via Top-Right LCD slot: x in [232..284], y in [12..26]
cmp mouseY3D, 12
jb @F
cmp mouseY3D, 26
ja @F
cmp mouseX3D, 232
jb @F
cmp mouseX3D, 284
jbe jbox_exit
@@:
; Exit via Bottom Red CANCEL button: x in [224..256], y in [195..225]
cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 224
jb @F
cmp mouseX3D, 256
jbe jbox_exit
@@:
; Bottom Green START button: x in [154..188], y in [195..225] -> Play selected
cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 154
jb @F
cmp mouseX3D, 188
jbe jbox_play_selected
@@:
; Bottom Orange SELECT button: x in [190..222], y in [195..225] -> Next track & play
cmp mouseY3D, 195
jb @F
cmp mouseY3D, 225
ja @F
cmp mouseX3D, 190
jb @F
cmp mouseX3D, 222
ja @F
inc jboxSelectedTrack
cmp jboxSelectedTrack, JACKBOX_TRACK_COUNT
jb jbox_play_selected
mov jboxSelectedTrack, 0
jmp jbox_play_selected
@@:
; Bottom Left Arrow: x in [256..274], y in [204..224] -> Prev track
cmp mouseY3D, 204
jb @F
cmp mouseY3D, 224
ja @F
cmp mouseX3D, 256
jb @F
cmp mouseX3D, 274
ja @F
dec jboxSelectedTrack
jns jbox_play_selected
mov jboxSelectedTrack, JACKBOX_TRACK_COUNT - 1
jmp jbox_play_selected
@@:
; Bottom Right Arrow: x in [276..294], y in [204..224] -> Next track
cmp mouseY3D, 204
jb @F
cmp mouseY3D, 224
ja @F
cmp mouseX3D, 276
jb @F
cmp mouseX3D, 294
ja @F
inc jboxSelectedTrack
cmp jboxSelectedTrack, JACKBOX_TRACK_COUNT
jb jbox_play_selected
mov jboxSelectedTrack, 0
jmp jbox_play_selected
@@:
; Track list click: x in [46..274], y in [66..108], step = 14
cmp mouseY3D, 66
jb jbox_keys
cmp mouseY3D, 108
ja jbox_keys
cmp mouseX3D, 46
jb jbox_keys
cmp mouseX3D, 274
ja jbox_keys
mov eax, mouseY3D
sub eax, 66
xor edx, edx
mov ebx, 14
div ebx
cmp eax, JACKBOX_TRACK_COUNT
jae jbox_keys
mov jboxSelectedTrack, eax
invoke PlayJukeboxTrack3D, eax
jmp jbox_handled
jbox_keys:
; Exit keys: ESC (1Bh) or 'E' (45h)
invoke Pressed3D, 1Bh
test eax, eax
jnz jbox_exit
invoke Pressed3D, 45h
test eax, eax
jnz jbox_exit
; Navigation: UP (26h) / DOWN (28h)
invoke Pressed3D, 26h
test eax, eax
jz @F
dec jboxSelectedTrack
jns jbox_handled
mov jboxSelectedTrack, JACKBOX_TRACK_COUNT - 1
jmp jbox_handled
@@:
invoke Pressed3D, 28h
test eax, eax
jz @F
inc jboxSelectedTrack
cmp jboxSelectedTrack, JACKBOX_TRACK_COUNT
jb jbox_handled
mov jboxSelectedTrack, 0
jmp jbox_handled
@@:
; Play selection: ENTER (0Dh) or SPACE (20h)
invoke Pressed3D, 0Dh
test eax, eax
jnz jbox_play_selected
invoke Pressed3D, 20h
test eax, eax
jnz jbox_play_selected
; Stop key: 'S' (53h)
invoke Pressed3D, 53h
test eax, eax
jz @F
call StopJukeboxTrack3D
jmp jbox_handled
@@:
; Random key: 'R' (52h)
invoke Pressed3D, 52h
test eax, eax
jz @F
invoke RandomRange3D, 2
mov jboxSelectedTrack, eax
invoke PlayJukeboxTrack3D, eax
jmp jbox_handled
@@:
; Direct digit keys '1'..'2'
mov ebx, 31h ; '1'
jbox_digit_loop:
invoke Pressed3D, ebx
test eax, eax
jz jbox_digit_next
mov eax, ebx
sub eax, 31h
mov jboxSelectedTrack, eax
invoke PlayJukeboxTrack3D, eax
jmp jbox_handled
jbox_digit_next:
inc ebx
cmp ebx, 32h ; '2'
jbe jbox_digit_loop
; '0' key for mute/stop
invoke Pressed3D, 30h
test eax, eax
jz jbox_handled
mov jboxSelectedTrack, 2
invoke PlayJukeboxTrack3D, 2
jmp jbox_handled
jbox_play_selected:
invoke PlayJukeboxTrack3D, jboxSelectedTrack
jmp jbox_handled
jbox_exit:
mov engineMode, MODE_WALK
call ClearKeys3D
jbox_handled:
mov mouseClick3D, 0
ret
HandleJackbox3D ENDP
RenderJackbox3D PROC uses ebx esi edi
local rowY:DWORD, color:DWORD
; 1. Draw base background
invoke DrawBox, 0, 0, 320, 240, 000B1815h
; 2. Overlay screen artwork (640x480 physical buffer)
cmp jackboxScreenArt3D.pixels, 0
je @F
invoke DrawAnimSprite3D, OFFSET jackboxScreenArt3D, 0, 0, 0, 640, 480
@@:
; 3. Top Digital LCD Slots
; Left slot: status text
cmp jboxIsPlaying, 1
jne jbox_top_lcd_stopped
cmp jboxCurrentTrack, -1
je jbox_top_lcd_stopped
cmp jboxCurrentTrack, 2
jae jbox_top_lcd_stopped
invoke DrawString8x8, 42, 17, OFFSET jboxLcdPlay, 0050FF90h
jmp jbox_top_lcd_exit
jbox_top_lcd_stopped:
invoke DrawString8x8, 45, 17, OFFSET jboxLcdStop, 008CB8A5h
jbox_top_lcd_exit:
; Right slot: exit button text
invoke DrawString8x8, 241, 17, OFFSET jboxLcdExit, 00F2A648h
; 4. CRT Monitor Header: Now Playing Status
cmp jboxIsPlaying, 1
jne jbox_render_stopped
cmp jboxCurrentTrack, -1
je jbox_render_stopped
cmp jboxCurrentTrack, 2
jae jbox_render_stopped
invoke DrawString8x8, 48, 52, OFFSET jboxHdrNow, 0050FF90h
mov eax, jboxCurrentTrack
mov edx, jboxTrackNames[eax*4]
invoke DrawString8x8, 108, 52, edx, 00F0E6C3h
jmp jbox_render_divider
jbox_render_stopped:
invoke DrawString8x8, 48, 52, OFFSET jboxHdrStop, 008CB8A5h
jbox_render_divider:
invoke DrawBox, 46, 62, 228, 1, 001C3828h
; 5. Track Selection List (3 rows, step Y = 14, from Y = 70)
mov rowY, 70
xor esi, esi
jbox_render_row:
mov color, 008CB8A5h ; Default CRT phosphor pale cyan
cmp esi, jboxSelectedTrack
jne @F
; Selected row: highlight box, golden cursor, bright white text
invoke DrawBox, 46, rowY, 228, 10, 00143526h
invoke DrawString8x8, 48, rowY, OFFSET jboxCursor, 00FFD700h
mov color, 00FFFFFFh
@@:
mov edx, jboxTrackNames[esi*4]
invoke DrawString8x8, 58, rowY, edx, color
; Mark playing track with [>] tag
cmp esi, jboxCurrentTrack
jne jbox_row_next
cmp jboxIsPlaying, 1
jne jbox_row_next
invoke DrawString8x8, 238, rowY, OFFSET jboxTagPlay, 0050FF90h
jbox_row_next:
add rowY, 14
inc esi
cmp esi, JACKBOX_TRACK_COUNT
jb jbox_render_row
; 6. Footer Controls Help (strictly inside CRT)
invoke DrawBox, 46, 166, 228, 1, 001C3828h
invoke DrawString8x8, 56, 170, OFFSET jboxFooterHelp, 0070AA90h
ret
RenderJackbox3D ENDP
; ==============================================================================
; 3D SOUND PROPAGATION & MULTI-FLOOR ATTENUATION
; ==============================================================================
CalculateJukeboxFalloff PROC uses ebx esi edi
local dxDist:DWORD, dyDist:DWORD, distSq:DWORD, distVal:DWORD
local factor:DWORD
; If music is not playing, factor = 0
cmp jboxIsPlaying, 1
jne falloff_silent
cmp jboxCurrentTrack, -1
je falloff_silent
cmp jboxCurrentTrack, 2
jae falloff_silent
; Check if on stairs (MODE_STAIRS)
cmp engineMode, MODE_STAIRS
je falloff_stairs
; Check floor level
mov eax, hallLevel3D
cmp eax, 0
je falloff_ground
cmp eax, 1
je falloff_bunker
cmp eax, 2
je falloff_upper
cmp eax, 3
je falloff_fortune
jmp falloff_silent
falloff_ground:
; Level 0 (Ground Hall) - standard quadratic 2D distance falloff from Jackbox
; Jackbox: JACKBOX_X = 30.6m, JACKBOX_Y = 23.5m
mov eax, playerX
sub eax, JACKBOX_X
test eax, eax
jns @F
neg eax
@@:
shr eax, 16 ; integer meters
mov dxDist, eax
mov eax, playerY
sub eax, JACKBOX_Y
test eax, eax
jns @F
neg eax
@@:
shr eax, 16 ; integer meters
mov dyDist, eax
; distSq = dx*dx + dy*dy
mov eax, dxDist
imul eax, eax
mov ebx, dyDist
imul ebx, ebx
add eax, ebx
mov distSq, eax
; distVal = sqrt(distSq)
fild distSq
fsqrt
fistp distVal
; Acoustic curve:
; dist <= 2m -> factor = 1000
; dist >= 35m -> factor = 0
; in between: rem = 35 - dist; factor = 1000 * rem * rem / 1089
mov eax, distVal
cmp eax, 2
jbe falloff_full
cmp eax, 35
jae falloff_silent
mov ecx, 35
sub ecx, eax ; ecx = 35 - distVal (in 1..32)
imul eax, ecx, 1000
imul eax, ecx ; eax = 1000 * rem * rem
xor edx, edx
mov ebx, 1089 ; 33 * 33
div ebx
mov factor, eax
jmp falloff_done
falloff_full:
mov factor, 1000
jmp falloff_done
falloff_upper:
; Level 2 (Upper Lounge) - sound travels up the open stairs (stairwell at X=16, Y=21 on upper map)
; Base attenuation through floor + distance from stairwell opening
mov eax, playerX
sub eax, 16*FP_1
test eax, eax
jns @F
neg eax
@@:
shr eax, 16
mov dxDist, eax
mov eax, playerY
sub eax, 21*FP_1
test eax, eax
jns @F
neg eax
@@:
shr eax, 16
mov dyDist, eax
mov eax, dxDist
imul eax, eax
mov ebx, dyDist
imul ebx, ebx
add eax, ebx
mov distSq, eax
fild distSq
fsqrt
fistp distVal
; At stair opening: factor = 420 (muffled from below)
; Drops by 18 per meter, min 90
mov eax, distVal
imul eax, 18
mov ecx, 420
sub ecx, eax
cmp ecx, 90
jge @F
mov ecx, 90
@@:
mov factor, ecx
jmp falloff_done
falloff_bunker:
; Level 1 (Bunker) - underground, heavily muffled concrete absorption (~160)
mov factor, 160
jmp falloff_done
falloff_fortune:
; Level 3 (Fortune Room) - secret room on opposite side of casino (~90)
mov factor, 90
jmp falloff_done
falloff_stairs:
; On stairs between floors
mov eax, stairRoute3D
cmp eax, 2
je falloff_stairs_upper
cmp eax, 1
je falloff_stairs_bunker
mov factor, 150
jmp falloff_done
falloff_stairs_upper:
; Route 2 (Upper stairs)
; playerX goes from ~3 (bottom, beside jukebox) to ~16 (top, upper floor)
; At bottom: 850. At top: 420.
mov eax, playerX
shr eax, 16 ; integer X (3..16)
cmp eax, 3
jge @F
mov eax, 3
@@:
cmp eax, 16
jle @F
mov eax, 16
@@:
; Interpolate: factor = 850 - (eax - 3) * (850 - 420) / 13
sub eax, 3
imul eax, 430
xor edx, edx
mov ebx, 13
div ebx
mov ecx, 850
sub ecx, eax
mov factor, ecx
jmp falloff_done
falloff_stairs_bunker:
; Route 1 (Basement stairs)
; Smooth blend between 350 (top) and 160 (bottom)
mov factor, 250
jmp falloff_done
falloff_silent:
mov factor, 0
falloff_done:
mov eax, factor
ret
CalculateJukeboxFalloff ENDP
UpdateJukeboxAudio3D PROC uses ebx esi edi
local falloff:DWORD, targetVol:DWORD
; Check if music is playing
cmp jboxIsPlaying, 1
jne jbox_audio_mute
; If user volume is 0 -> mute
mov eax, jboxUserVolume
test eax, eax
jz jbox_audio_mute
; Calculate 3D attenuation factor (0..1000)
call CalculateJukeboxFalloff
mov falloff, eax
test eax, eax
jz jbox_audio_mute
; targetVol = (jboxUserVolume * 100) * falloff / 1000
; jboxUserVolume is 0..10 (0..1000 base)
mov eax, jboxUserVolume
imul eax, 100
imul eax, falloff
xor edx, edx
mov ebx, 1000
div ebx
mov targetVol, eax
jmp jbox_apply_vol
jbox_audio_mute:
mov targetVol, 0
jbox_apply_vol:
; If targetVol matches last applied volume, skip redundant MCI call
mov eax, targetVol
cmp eax, jboxEffectiveVolume
je jbox_audio_done
mov jboxEffectiveVolume, eax
; Format: "setaudio jboxmusic volume to <targetVol>"
; Copy prefix to jboxVolCmdBuf
lea esi, jboxVolCmdPrefix
lea edi, jboxVolCmdBuf
jbox_vol_copy:
lodsb
stosb
test al, al
jnz jbox_vol_copy
dec edi ; point at null terminator
; Append decimal number targetVol
invoke FormatNumber, targetVol, edi
; Send to MCI
invoke mciSendStringA, OFFSET jboxVolCmdBuf, 0, 0, 0
jbox_audio_done:
ret
UpdateJukeboxAudio3D ENDP
; ==============================================================================
; VOLUME CONTROL KEYS & POP-UP SLIDING HUD BAR
; ==============================================================================
HandleJukeboxKeys3D PROC
; '+' key: VK_OEM_PLUS (0BBh) or VK_ADD (6Bh - numpad +)
invoke Pressed3D, 0BBh
test eax, eax
jnz jbox_do_plus
invoke Pressed3D, 6Bh
test eax, eax
jz jbox_check_minus
jbox_do_plus:
cmp jboxUserVolume, 10
jae @F
inc jboxUserVolume
@@:
mov jboxHudTimer, 90 ; Show HUD for ~1.5s
call UpdateJukeboxAudio3D
ret
jbox_check_minus:
; '-' key: VK_OEM_MINUS (0BDh) or VK_SUBTRACT (6Dh - numpad -)
invoke Pressed3D, 0BDh
test eax, eax
jnz jbox_do_minus
invoke Pressed3D, 6Dh
test eax, eax
jz jbox_keys_done
jbox_do_minus:
cmp jboxUserVolume, 0
jbe @F
dec jboxUserVolume
@@:
mov jboxHudTimer, 90 ; Show HUD for ~1.5s
call UpdateJukeboxAudio3D
jbox_keys_done:
ret
HandleJukeboxKeys3D ENDP
RenderJukeboxVolumeHUD PROC uses ebx esi edi
local winX:DWORD, winY:DWORD, barX:DWORD, barY:DWORD, barW:DWORD, barH:DWORD
local numBuf[16]:BYTE
; 1. Update Timer and Animation Position
cmp jboxHudTimer, 0
je hud_sliding_down
; Active: decrement timer
dec jboxHudTimer
; Slide UP towards target Y = 206
cmp jboxHudY, 206
jbe hud_at_target
sub jboxHudY, 4
cmp jboxHudY, 206
jae hud_at_target
mov jboxHudY, 206
hud_at_target:
jmp hud_draw
hud_sliding_down:
; Timer expired: slide DOWN towards 240 (offscreen)
cmp jboxHudY, 240
jae hud_hidden
add jboxHudY, 3
cmp jboxHudY, 240
jbe hud_draw
mov jboxHudY, 240
hud_hidden:
ret
hud_draw:
mov eax, jboxHudY
mov winY, eax
mov winX, 72 ; Centered in 320: width 176
; 2. Background and Frame
; Outer dark shadow (178 x 30)
mov eax, winX
dec eax
mov ecx, winY
dec ecx
invoke DrawBox, eax, ecx, 178, 30, 0008100Ch
; Outer bezel (176 x 28)
invoke DrawBox, winX, winY, 176, 28, 001C2E24h
; Inner panel body (174 x 26)
mov eax, winX
inc eax
mov ecx, winY
inc ecx
invoke DrawBox, eax, ecx, 174, 26, 00101A14h
; Brass top trim accent (174 x 1)
mov eax, winX
inc eax
mov ecx, winY
inc ecx
invoke DrawBox, eax, ecx, 174, 1, 008A6B34h
; 3. Title text: "MUZ. AVTOMAT: " + percentage
mov eax, winX
add eax, 10
mov ecx, winY
add ecx, 4
invoke DrawString8x8, eax, ecx, OFFSET jboxHudTitle, 0050FF90h
; Draw percentage or "VYKL"
mov eax, winX
add eax, 126
mov ecx, winY
add ecx, 4
cmp jboxUserVolume, 0
jne hud_draw_pct_num
invoke DrawString8x8, eax, ecx, OFFSET jboxHudMute, 008CB8A5h
jmp hud_draw_trough
hud_draw_pct_num:
push eax
push ecx
mov edx, jboxUserVolume
imul edx, 10
lea edi, numBuf
invoke FormatNumber, edx, edi
hud_find_term:
cmp byte ptr [edi], 0
je hud_append_pct
inc edi
jmp hud_find_term
hud_append_pct:
mov byte ptr [edi], '%'
mov byte ptr [edi+1], 0
pop ecx
pop eax
lea edx, numBuf
invoke DrawString8x8, eax, ecx, edx, 00F0E6C3h
hud_draw_trough:
; Progress trough at barX = winX + 24, barY = winY + 15, barW = 128, barH = 7
mov eax, winX
add eax, 24
mov barX, eax
mov ecx, winY
add ecx, 15
mov barY, ecx
mov barW, 128
mov barH, 7
; Trough border
mov eax, barX
dec eax
mov ecx, barY
dec ecx
invoke DrawBox, eax, ecx, 130, 9, 00223828h
invoke DrawBox, barX, barY, 128, 7, 000C1610h
; Draw 10 blocks: i = 0..9
xor esi, esi
hud_blocks_loop:
mov eax, barX
add eax, 4
mov edx, esi
imul edx, 12
add eax, edx ; blockX = barX + 4 + i*12
mov ecx, barY
inc ecx ; blockY = barY + 1
cmp esi, jboxUserVolume
jae hud_block_empty
; Filled block color gradient
cmp esi, 7
jb hud_col_green
cmp esi, 9
jb hud_col_gold
mov edx, 00465AFFh ; Red/orange accent for 100%
jmp hud_draw_block_rect
hud_col_green:
mov edx, 0050FF90h ; Phosphor green
jmp hud_draw_block_rect
hud_col_gold:
mov edx, 00FFD700h ; Golden amber
jmp hud_draw_block_rect
hud_block_empty:
mov edx, 0018261Eh ; Dim background
hud_draw_block_rect:
invoke DrawBox, eax, ecx, 10, 5, edx
inc esi
cmp esi, 10
jb hud_blocks_loop
; Draw '-' and '+' labels
mov eax, winX
add eax, 8
mov ecx, winY
add ecx, 15
invoke DrawString8x8, eax, ecx, OFFSET jboxHudMinus, 008CB8A5h
mov eax, winX
add eax, 158
mov ecx, winY
add ecx, 15
invoke DrawString8x8, eax, ecx, OFFSET jboxHudPlus, 008CB8A5h
ret
RenderJukeboxVolumeHUD ENDP