; ============================================================================== ; 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 ; Footprint: width 0.75m, depth 0.55m, height 1.85m mov eax, wx sub eax, FP_1*15/40 mov x0, eax add eax, FP_1*15/20 mov x1, eax mov eax, wy sub eax, FP_1*11/40 mov y0, eax add eax, FP_1*11/20 mov y1, eax ; Rear: North face (Y = y0) invoke DrawCityVertical3D, 1, y0, x0, x1, 0, FP_1*37/20, MATERIAL_JACKBOX_BACK ; Sides: West face (X = x0) and East face (X = x1) invoke DrawCityVertical3D, 0, x0, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_SIDE invoke DrawCityVertical3D, 0, x1, y0, y1, 0, FP_1*37/20, MATERIAL_JACKBOX_SIDE ; Front: South face (Y = y1) invoke DrawCityVertical3D, 1, y1, x0, x1, 0, FP_1*37/20, MATERIAL_JACKBOX_FRONT ret DrawJackboxCabinet3D ENDP RenderJackboxCabinet3D PROC invoke DrawJackboxCabinet3D, JACKBOX_X, JACKBOX_Y ret RenderJackboxCabinet3D ENDP JackboxCanWalk3D PROC px:DWORD, py:DWORD mov eax, py sub eax, JACKBOX_Y test eax, eax jns @F neg eax @@: cmp eax, FP_1*11/20 ja jackbox_walk_clear mov eax, px sub eax, JACKBOX_X test eax, eax jns @F neg eax @@: cmp eax, FP_1*15/20 jbe jackbox_walk_blocked jackbox_walk_clear: mov eax, 1 ret jackbox_walk_blocked: xor eax, eax 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, 9 jae jbox_play_done cmp ebx, JACKBOX_TRACK_COUNT jae jbox_play_done mov eax, jboxOpenCommands[ebx*4] test eax, eax jz jbox_play_done invoke mciSendStringA, eax, 0, 0, 0 invoke mciSendStringA, OFFSET jboxPlayCmd, 0, 0, 0 mov jboxCurrentTrack, ebx mov jboxIsPlaying, 1 jbox_play_done: 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 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 ; Check Exit button in top right: x in [228..312], y in [8..26] cmp mouseY3D, 8 jb @F cmp mouseY3D, 26 ja @F cmp mouseX3D, 228 jae jbox_exit @@: ; Check track row click: y in [54..186] cmp mouseY3D, 54 jb jbox_keys cmp mouseY3D, 186 ja jbox_keys cmp mouseX3D, 16 jb jbox_keys cmp mouseX3D, 304 ja jbox_keys mov eax, mouseY3D sub eax, 54 xor edx, edx mov ebx, 13 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, 9 mov jboxSelectedTrack, eax invoke PlayJukeboxTrack3D, eax jmp jbox_handled @@: ; Direct digit keys '1'..'9', '0' 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, 39h ; '9' jbe jbox_digit_loop ; '0' key for mute/stop invoke Pressed3D, 30h test eax, eax jz jbox_handled mov jboxSelectedTrack, 9 invoke PlayJukeboxTrack3D, 9 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 if available cmp jackboxScreenArt3D.pixels, 0 je @F invoke DrawAnimSprite3D, OFFSET jackboxScreenArt3D, 0, 0, 0, 640, 480 @@: ; 3. Title & Exit Button invoke DrawString8x8, 52, 12, OFFSET jboxTitle, 00E7C479h invoke DrawBoxBorder, 228, 8, 84, 16, 001A2522h, 00C8AD75h, 1 invoke DrawString8x8, 234, 12, OFFSET jboxClose, 00F2E6C6h ; 4. Now Playing Status Banner cmp jboxIsPlaying, 1 jne jbox_render_stopped cmp jboxCurrentTrack, -1 je jbox_render_stopped cmp jboxCurrentTrack, 9 jae jbox_render_stopped invoke DrawString8x8, 20, 34, OFFSET jboxStatusPlaying, 008CD8AFh mov eax, jboxCurrentTrack mov edx, jboxTrackNames[eax*4] invoke DrawString8x8, 140, 34, edx, 00F0E6C3h jmp jbox_render_divider jbox_render_stopped: invoke DrawString8x8, 20, 34, OFFSET jboxStatusStopped, 0090B19Fh jbox_render_divider: invoke DrawBox, 20, 47, 280, 1, 00495B4Ah ; 5. Track Selection List (10 rows, step Y = 13) mov rowY, 55 xor esi, esi jbox_render_row: mov color, 0090B19Fh ; Default muted cmp esi, jboxSelectedTrack jne @F mov color, 00F2E6C6h ; Bright cream for selection invoke DrawString8x8, 14, rowY, OFFSET jboxCursor, 00E7C479h @@: mov edx, jboxTrackNames[esi*4] invoke DrawString8x8, 28, rowY, edx, color ; Mark playing track cmp esi, jboxCurrentTrack jne jbox_row_next cmp jboxIsPlaying, 1 jne jbox_row_next invoke DrawString8x8, 252, rowY, OFFSET jboxPlayingTag, 008CD8AFh jbox_row_next: add rowY, 13 inc esi cmp esi, JACKBOX_TRACK_COUNT jb jbox_render_row ; 6. Footer Controls Help invoke DrawBox, 20, 192, 280, 1, 00314538h invoke DrawString8x8, 20, 200, OFFSET jboxHelp1, 00C1A982h invoke DrawString8x8, 20, 214, OFFSET jboxHelp2, 0090B19Fh ret RenderJackbox3D ENDP