Sequence studio, texture AI disclosure and MASM code comparison before arrival. Show a typed hall briefing after admission. Start the jukebox at 50% user volume on hall entry. Apply positional gain before playback to avoid a full-volume startup burst.
892 lines
21 KiB
PHP
892 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
|
|
test eax, eax
|
|
jnz jbox_play_stop_selected
|
|
mov jboxCurrentTrack, ebx
|
|
mov jboxIsPlaying, 1
|
|
mov jboxEffectiveVolume, -1
|
|
; Apply volume before play: never start a newly opened device at full gain.
|
|
call UpdateJukeboxAudio3D
|
|
invoke mciSendStringA, OFFSET jboxPlayCmd, 0, 0, 0
|
|
test eax, eax
|
|
jz jbox_play_done
|
|
call StopJukeboxTrack3D
|
|
jbox_play_done:
|
|
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
|