fix(jackbox): realign UI strictly within CRT monitor sprite and clear wall painting

This commit is contained in:
Игорь Федосеев 2026-10-25 17:07:05 +03:00
parent 6bf2a2885c
commit 7c262a15ad
11 changed files with 434 additions and 315 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 38 KiB

BIN
poker.exe

Binary file not shown.

BIN
poker.obj

Binary file not shown.

View file

@ -56,12 +56,13 @@ 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 = 24.575m, y1 = 25.425m, centered at Y = 25.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, 25*FP_1 - FP_1*425/1000
mov y1, 25*FP_1 + FP_1*425/1000
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
@ -88,7 +89,7 @@ JackboxCanWalk3D PROC px:DWORD, py:DWORD
cmp eax, 31*FP_1+9830
ja jackbox_walk_clear
mov eax, py
sub eax, 25*FP_1
sub eax, FP_1*235/10
test eax, eax
jns @F
neg eax
@ -144,27 +145,93 @@ HandleJackbox3D PROC uses ebx esi
cmp mouseClick3D, 0
je jbox_keys
; Check Exit button in top right: x in [228..312], y in [8..26]
cmp mouseY3D, 8
; 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, 228
jae jbox_exit
cmp mouseX3D, 232
jb @F
cmp mouseX3D, 284
jbe jbox_exit
@@:
; Check track row click: y in [54..186]
cmp mouseY3D, 54
; 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
@@:
; Check track row click inside CRT screen: x in [46..274], y in [65..165]
cmp mouseY3D, 65
jb jbox_keys
cmp mouseY3D, 186
cmp mouseY3D, 165
ja jbox_keys
cmp mouseX3D, 16
cmp mouseX3D, 46
jb jbox_keys
cmp mouseX3D, 304
cmp mouseX3D, 274
ja jbox_keys
mov eax, mouseY3D
sub eax, 54
sub eax, 65
xor edx, edx
mov ebx, 13
mov ebx, 10
div ebx
cmp eax, JACKBOX_TRACK_COUNT
jae jbox_keys
@ -223,7 +290,7 @@ jbox_keys:
invoke PlayJukeboxTrack3D, eax
jmp jbox_handled
@@:
; Direct digit keys '1'..'9', '0'
; Direct digit keys '1'..'9'
mov ebx, 31h ; '1'
jbox_digit_loop:
invoke Pressed3D, ebx
@ -266,17 +333,28 @@ RenderJackbox3D PROC uses ebx esi edi
; 1. Draw base background
invoke DrawBox, 0, 0, 320, 240, 000B1815h
; 2. Overlay screen artwork if available
; 2. Overlay screen artwork (640x480 physical buffer)
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
; 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, 9
jae jbox_top_lcd_stopped
invoke DrawString8x8, 42, 17, OFFSET jboxLcdPlay, 0050FF90h ; Green "ÈÃÐÀÅÒ"
jmp jbox_top_lcd_exit
jbox_top_lcd_stopped:
invoke DrawString8x8, 45, 17, OFFSET jboxLcdStop, 008CB8A5h ; Dim green "ÑÒÎÏ"
jbox_top_lcd_exit:
; Right slot: exit button text
invoke DrawString8x8, 241, 17, OFFSET jboxLcdExit, 00F2A648h ; Amber "ÂÛÕÎÄ"
; 4. Now Playing Status Banner
; 4. CRT Monitor Header: Now Playing Status
cmp jboxIsPlaying, 1
jne jbox_render_stopped
cmp jboxCurrentTrack, -1
@ -284,48 +362,50 @@ RenderJackbox3D PROC uses ebx esi edi
cmp jboxCurrentTrack, 9
jae jbox_render_stopped
invoke DrawString8x8, 20, 34, OFFSET jboxStatusPlaying, 008CD8AFh
invoke DrawString8x8, 48, 52, OFFSET jboxHdrNow, 0050FF90h ; Green "ÑÅÉ×ÀÑ:"
mov eax, jboxCurrentTrack
mov edx, jboxTrackNames[eax*4]
invoke DrawString8x8, 140, 34, edx, 00F0E6C3h
invoke DrawString8x8, 108, 52, edx, 00F0E6C3h
jmp jbox_render_divider
jbox_render_stopped:
invoke DrawString8x8, 20, 34, OFFSET jboxStatusStopped, 0090B19Fh
invoke DrawString8x8, 48, 52, OFFSET jboxHdrStop, 008CB8A5h ; Dim green "ÑÒÀÒÓÑ: ÎÑÒÀÍÎÂËÅÍ"
jbox_render_divider:
invoke DrawBox, 20, 47, 280, 1, 00495B4Ah
invoke DrawBox, 46, 62, 228, 1, 001C3828h
; 5. Track Selection List (10 rows, step Y = 13)
mov rowY, 55
; 5. Track Selection List (10 rows, step Y = 10, from Y = 66)
mov rowY, 66
xor esi, esi
jbox_render_row:
mov color, 0090B19Fh ; Default muted
mov color, 008CB8A5h ; Default CRT phosphor pale cyan
cmp esi, jboxSelectedTrack
jne @F
mov color, 00F2E6C6h ; Bright cream for selection
invoke DrawString8x8, 14, rowY, OFFSET jboxCursor, 00E7C479h
; Selected row: highlight box, golden cursor, bright white text
invoke DrawBox, 46, rowY, 228, 9, 00143526h
invoke DrawString8x8, 48, rowY, OFFSET jboxCursor, 00FFD700h
mov color, 00FFFFFFh
@@:
mov edx, jboxTrackNames[esi*4]
invoke DrawString8x8, 28, rowY, edx, color
invoke DrawString8x8, 58, rowY, edx, color
; Mark playing track
; Mark playing track with [>] tag
cmp esi, jboxCurrentTrack
jne jbox_row_next
cmp jboxIsPlaying, 1
jne jbox_row_next
invoke DrawString8x8, 252, rowY, OFFSET jboxPlayingTag, 008CD8AFh
invoke DrawString8x8, 238, rowY, OFFSET jboxTagPlay, 0050FF90h
jbox_row_next:
add rowY, 13
add rowY, 10
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
; 6. Footer Controls Help (strictly inside CRT)
invoke DrawBox, 46, 166, 228, 1, 001C3828h
invoke DrawString8x8, 56, 170, OFFSET jboxFooterHelp, 0070AA90h
ret
RenderJackbox3D ENDP

View file

@ -6,7 +6,7 @@ MODE_JACKBOX equ 28
INTERACT_JACKBOX equ 48
JACKBOX_X equ FP_1*306/10
JACKBOX_Y equ 25*FP_1
JACKBOX_Y equ FP_1*235/10
JACKBOX_TRACK_COUNT equ 10
MATERIAL_JACKBOX_FRONT equ 161
@ -30,7 +30,8 @@ jackboxScreenArt3D AnimPack3D <>
jackboxWorldPath3D db "assets\animations\hall\jackbox-v1.bin",0
jackboxScreenPath3D db "assets\animations\hall\jackbox-ui-v1.bin",0
jackboxPrompt3D db "E: ÄÆÓÊÁÎÊÑ",0
; Prompt: "E: Âêëþ÷èòü àâòîìàò"
jackboxPrompt3D db 69,58,32,194,234,235,254,247,232,242,252,32,224,226,242,238,236,224,242,0
jboxCurrentTrack dd -1
jboxSelectedTrack dd 0
@ -54,26 +55,31 @@ jboxOpenCommands dd OFFSET jboxOpen0, OFFSET jboxOpen1, OFFSET jboxOpen2, OFFSET
dd OFFSET jboxOpen4, OFFSET jboxOpen5, OFFSET jboxOpen6, OFFSET jboxOpen7
dd OFFSET jboxOpen8, 0
jboxName0 db "1. Keygen Church - Tenebre Rosso Sangue",0
jboxName1 db "2. Keygen Church - Hareklavit",0
jboxName2 db "3. Keygen Church - Ladikerfos",0
jboxName3 db "4. Keygen Church - Tilaskarot",0
jboxName4 db "5. Mick Gordon - BFG Division (DOOM)",0
jboxName5 db "6. Mick Gordon - Rip & Tear (DOOM)",0
jboxName6 db "7. Mick Gordon - The Only Thing They Fear",0
jboxName7 db "8. Hakari Dance (Jackpot Theme)",0
jboxName8 db "9. Team Fortress 2 - Victory Theme",0
jboxName9 db "0. [ ÂÛÊËÞ×ÈÒÜ ÌÓÇÛÊÓ / ÒÈØÈÍÀ ]",0
jboxName0 db "1. Keygen - Tenebre",0
jboxName1 db "2. Keygen - Hareklavit",0
jboxName2 db "3. Keygen - Ladikerfos",0
jboxName3 db "4. Keygen - Tilaskarot",0
jboxName4 db "5. Mick Gordon - BFG",0
jboxName5 db "6. Mick Gordon - Rip",0
jboxName6 db "7. Mick Gordon - Doom",0
jboxName7 db "8. Hakari Dance (Ost)",0
jboxName8 db "9. TF2 - Victory",0
; "0. [Âûêëþ÷èòü çâóê]"
jboxName9 db 48,46,32,91,194,251,234,235,254,247,232,242,252,32,231,226,243,234,93,0
jboxTrackNames dd OFFSET jboxName0, OFFSET jboxName1, OFFSET jboxName2, OFFSET jboxName3
dd OFFSET jboxName4, OFFSET jboxName5, OFFSET jboxName6, OFFSET jboxName7
dd OFFSET jboxName8, OFFSET jboxName9
jboxTitle db "ÌÓÇÛÊÀËÜÍÛÉ ÀÂÒÎÌÀÒ",0
jboxClose db "ÂÛÕÎÄ [ESC]",0
jboxStatusPlaying db "ÑÅÉ×ÀÑ ÈÃÐÀÅÒ:",0
jboxStatusStopped db "ÌÓÇÛÊÀ ÂÛÊËÞ×ÅÍÀ",0
jboxCursor db "> ",0
jboxPlayingTag db " [ÈÃÐÀÅÒ]",0
jboxHelp1 db "ÑÒÐÅËÊÈ / 0-9: Âûáîð ENTER: Âêëþ÷èòü",0
jboxHelp2 db "S: Ñòîï R: Ñëó÷àéíûé ESC:  çàë",0
; Top Digital LCD Display Slots
jboxLcdPlay db 200,195,208,192,197,210,0 ; "ÈÃÐÀÅÒ"
jboxLcdStop db 209,210,206,207,0 ; "ÑÒÎÏ"
jboxLcdExit db 194,219,213,206,196,0 ; "ÂÛÕÎÄ"
; CRT Monitor Screen Text
jboxHdrNow db 209,197,201,215,192,209,58,0 ; "ÑÅÉ×ÀÑ:"
jboxHdrStop db 209,210,192,210,211,209,58,32,206,209,210,192,205,206,194,203,197,205,0 ; "ÑÒÀÒÓÑ: ÎÑÒÀÍÎÂËÅÍ"
jboxCursor db ">",0
jboxTagPlay db "[>]",0
; "ENTER:Ïóñê S:Ñòîï R:Ìèêñ"
jboxFooterHelp db 69,78,84,69,82,58,207,243,241,234,32,32,83,58,209,242,238,239,32,32,82,58,204,232,234,241,0

View file

@ -64,7 +64,7 @@ def test_code_structure():
assert "MODE_JACKBOX equ 28" in data_inc
assert "INTERACT_JACKBOX equ 48" in data_inc
assert "JACKBOX_X equ FP_1*306/10" in data_inc
assert "JACKBOX_Y equ 25*FP_1" in data_inc
assert "JACKBOX_Y equ FP_1*235/10" in data_inc
assert "MATERIAL_JACKBOX_BACK equ 163" in data_inc
# Check procs

View file

@ -251,14 +251,47 @@ def render_scene(cam_x, cam_y, cam_angle, out_path):
draw_pool_side(0, int(26.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1))
draw_pool_side(0, int(28.0*FP_1), int(24.0*FP_1), int(26.0*FP_1), 0, int(0.85*FP_1))
# 2. Solid Rectangular Jukebox Cabinet (at East wall, next to billiards table!)
# 2. Wall Art / Painting 116 on East Wall: X = 30.98m, Y in [25.0m .. 26.5m], Z in [1.0m .. 2.0m]
def draw_painting(axis, coord, lo, hi, z0, z1, slot):
for col in range(SCREEN_W):
ray_dir = cityRayX[col] if axis == 0 else cityRayY[col]
if abs(ray_dir) < 256:
continue
orig = playerX if axis == 0 else playerY
num = (coord - orig)
depth = (num << 16) // ray_dir
if depth <= 4096 or depth >= zBuffer[col]:
continue
along = playerY + ((depth * cityRayY[col]) >> 16) if axis == 0 else playerX + ((depth * cityRayX[col]) >> 16)
if along < lo or along >= hi:
continue
top = (HALL_STANDING_EYE - z1) * SCREEN_H // depth + HALF_H
bottom = (HALL_STANDING_EYE - z0) * SCREEN_H // depth + HALF_H
span = bottom - top
if span <= 0:
continue
r_start = max(0, top)
r_end = min(SCREEN_H, bottom)
span_along = hi - lo
tx = int((along - lo) * 128 / span_along) % 128
shade = max(40, min(255, 255 - (depth >> 12)))
for row in range(r_start, r_end):
ty = int((row - top) * 128 / span) % 128
r, g, b, a = get_tex_pixel(slot, tx, ty)
if depth < depthBuffer[row * SCREEN_W + col]:
depthBuffer[row * SCREEN_W + col] = depth
screen_pixels[row * SCREEN_W + col] = ((r * shade) >> 8, (g * shade) >> 8, (b * shade) >> 8)
draw_painting(0, int(30.98 * FP_1), int(25.0 * FP_1), int(26.5 * FP_1), FP_1, 2 * FP_1, 116)
# 3. Solid Rectangular Jukebox Cabinet (at East wall, Y = 23.5m, clearing Painting 116!)
# Depth: X in [30.40m .. 30.95m] (back against East wall at 31.0m)
# Width: Y in [24.575m .. 25.425m] (centered at Y = 25.0m)
# Width: Y in [23.075m .. 23.925m] (centered at Y = 23.5m)
# Height: Z in [0 .. 1.85m]
x0 = int(30.40 * FP_1)
x1 = int(30.95 * FP_1)
y0 = int(24.575 * FP_1)
y1 = int(25.425 * FP_1)
y0 = int(23.075 * FP_1)
y1 = int(23.925 * FP_1)
zHigh = int(1.85 * FP_1)
# Back Face (against wall: X = x1) - Frame 2
@ -277,11 +310,11 @@ def render_scene(cam_x, cam_y, cam_angle, out_path):
if __name__ == '__main__':
# 1. Front View: Standing near billiards at (26.0, 25.0) looking East (angle=0) past table at Jukebox
render_scene(26.0, 25.0, 0, DOCS_DIR / 'jukebox_3d_front.png')
render_scene(26.0, 24.5, 0, DOCS_DIR / 'jukebox_3d_front.png')
# 2. Angle View: Standing at (27.5, 22.5) looking South-East (angle=480) at pool table and Jukebox
render_scene(27.5, 22.5, 480, DOCS_DIR / 'jukebox_3d_angle.png')
render_scene(27.5, 21.0, 128, DOCS_DIR / 'jukebox_3d_angle.png')
# 3. Close-up View: Standing at (29.2, 25.0) looking East (angle=0) right at Jukebox
render_scene(29.2, 25.0, 0, DOCS_DIR / 'jukebox_3d_close.png')
render_scene(29.2, 23.5, 0, DOCS_DIR / 'jukebox_3d_close.png')
# 4. Side View: Standing at (30.0, 27.5) looking North (angle=384) at South side of Jukebox
render_scene(30.0, 27.5, 384, DOCS_DIR / 'jukebox_3d_side.png')
render_scene(30.6, 25.5, 768, DOCS_DIR / 'jukebox_3d_side.png')
print('All Jukebox 3D preview frames rendered to docs/previews_minigames/!')