Таблица рекордов: оба показа оригинала, ввод имени, переходы полосами

pop_hof.c был написан, но никуда не вызывался: после финала автомат уходил
мимо него в title, а на титрах экран получался чёрным. Теперь это хвост
end_sequence и шаг show_title между credits и attract-demo, как в оригинале.

Два корня пустого экрана:

- story.pal — 256 записей, и запись 0x3F (цвет глифов шрифта) в ней чёрная:
  текст рисовался, но был не виден. Генератор кладёт туда золотой 0xB7;
- полосовой переход копирует страницу акселератором, а тот читает ОЗУ-копию,
  куда прозрачный блит текста не пишет. Строки рисуются после перехода,
  прямо в видимую страницу.

Попутно:

- s5 в архиве PV — фон таблицы (рамка story + логотип на y=24, HOF_POP);
- отдельный индекс палитры под фон текстовой рамки: финал красит его в
  #800000, титры оставляют #100060 (load_title_images(bgcolor)). Прежний
  ремап в индекс 9 подменить было нельзя — им нарисована сама титульная
  картинка;
- второй набор глифов в font.atl цветом 0x3E: у SDLPoP шрифт маска и
  show_hof_text рисует текст дважды разным цветом, у нас цвет запечён в
  пиксели. Каталог SPA1 держит счётчик в байте, поэтому набор обрезан по '_';
- общий pop_screen_present_ltr(): им теперь пользуются story-переход интро,
  титры, таблица и титульная картинка финала. Заодно вернулся пропущенный
  шаг show_title — экран с логотипом и Jordan Mechner между «свадьбой» и
  титрами (BUGS_CLOSED#cutscene-ltr).

Формат POP.HOF — 6 записей, имя до 15 символов, версия 2. Проверено в MAME
на сборке LEVEL=14: HAIL → титульная картинка → таблица с полосой ввода и
временем справа → ввод имени → титульная картинка; на следующем запуске
таблица показывается между credits и demo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 16:41:41 +03:00
parent faec9a7d3a
commit a3c5c600da
52 changed files with 740 additions and 275 deletions
+34 -11
View File
@@ -27,6 +27,18 @@ OUT_H = ROOT / "applications" / "PoP" / "roomtest" / "pop_font.h"
FIRST, LAST = 32, 126
FONT_COLOR = 0x3F
# ВТОРОЙ ЦВЕТ КРУПНОГО ШРИФТА. У SDLPoP шрифт — маска, и цвет задаётся
# параметром рисования (show_hof_text рисует текст дважды: тень цветом 0 со
# сдвигом (1,1) и сам текст цветом 0xB7). У нас цвет запечён в пиксели
# глифа, поэтому второй цвет — это второй набор глифов. Он нужен таблице
# рекордов: чёрная тень строк и тёмное имя на золотой полосе ввода.
# Набор крупный, потому что draw_text() рисует hc_font (seg009:1594).
FONT_DARK_COLOR = 0x3E
# Каталог SPA1 хранит число картинок одним байтом, а три полных набора по
# 95 глифов — это 285. Тёмному набору полный ASCII и не нужен: им пишется
# только таблица рекордов (имена A..Z, время вида 59:43 и курсор ввода
# '_'), поэтому он обрезан по '_'. 190 + 64 = 254 картинки — потолок.
DARK_FIRST, DARK_LAST = 32, 95
ATL_MAGIC = b"SPA1"
ATL_DIR_OFF = 0x68
SNAPSHOT_OFF = 0x3C00
@@ -97,31 +109,32 @@ def parse_glyphs(vals: list[int]) -> tuple[dict, list[dict]]:
return font, glyphs
def glyph_pixels(glyph: dict) -> bytes:
"""1 бит/пиксель SDLPoP -> 8bpp getimage: 1 = FONT_COLOR."""
def glyph_pixels(glyph: dict, color: int) -> bytes:
"""1 бит/пиксель SDLPoP -> 8bpp getimage: 1 = color."""
out = bytearray()
for row in glyph["rows"]:
for x in range(glyph["w"]):
byte = row[x // 8]
on = byte & (1 << (7 - (x & 7)))
out.append(FONT_COLOR if on else 0xFF)
out.append(color if on else 0xFF)
return bytes(out)
def pack_atlas(fonts: list[tuple[dict, list[dict]]]) -> int:
def pack_atlas(fonts: list[tuple[dict, list[dict], int]]) -> int:
entries = []
for font, glyphs in fonts:
assert font["first"] <= FIRST <= LAST <= font["last"]
entries.extend(glyphs[FIRST - font["first"]:LAST - font["first"] + 1])
for font, glyphs, color, first, last in fonts:
assert font["first"] <= first <= last <= font["last"]
entries.extend((glyph, color) for glyph in
glyphs[first - font["first"]:last - font["first"] + 1])
assert len(entries) <= 255
data_off = ATL_DIR_OFF + len(entries) * 8
out = bytearray(data_off)
out[0:4] = ATL_MAGIC
out[4] = len(entries)
for index, glyph in enumerate(entries):
for index, (glyph, color) in enumerate(entries):
offset = len(out)
pixels = glyph_pixels(glyph)
pixels = glyph_pixels(glyph, color)
out += glyph["w"].to_bytes(2, "little")
out += glyph["h"].to_bytes(2, "little")
out += pixels
@@ -152,6 +165,7 @@ def emit_header(small: dict, big: dict, atlas_size: int) -> None:
#include <stdint.h>
#define POP_FONT_COLOR 0x{FONT_COLOR:02X}
#define POP_FONT_DARK_COLOR 0x{FONT_DARK_COLOR:02X}
#define POP_FONT_FIRST {FIRST}
#define POP_FONT_LAST {LAST}
#define POP_FONT_SMALL_BASE 0
@@ -160,6 +174,11 @@ def emit_header(small: dict, big: dict, atlas_size: int) -> None:
#define POP_FONT_BIG_BASE {small_n}
#define POP_FONT_BIG_ASCENT {big['ascent']}
#define POP_FONT_BIG_SPACE {big['space_chars']}
/* Тот же КРУПНЫЙ шрифт цветом POP_FONT_DARK_COLOR: тень и текст на светлом.
* Набор обрезан по '_' — им пишется только таблица рекордов. */
#define POP_FONT_DARK_BASE {2 * small_n}
#define POP_FONT_DARK_FIRST {DARK_FIRST}
#define POP_FONT_DARK_LAST {DARK_LAST}
#define POP_FONT_SNAPSHOT_OFF 0x{SNAPSHOT_OFF:04X}
#define POP_FONT_ATLAS_SIZE {atlas_size}
@@ -175,9 +194,13 @@ def main() -> None:
print(f"{name}: chars={font['first']}..{font['last']} ascent={font['ascent']} "
f"space={font['space_chars']}")
parsed.append((font, glyphs))
atlas_size = pack_atlas(parsed)
sets = [(parsed[0][0], parsed[0][1], FONT_COLOR, FIRST, LAST),
(parsed[1][0], parsed[1][1], FONT_COLOR, FIRST, LAST),
(parsed[1][0], parsed[1][1], FONT_DARK_COLOR, DARK_FIRST, DARK_LAST)]
atlas_size = pack_atlas(sets)
emit_header(parsed[0][0], parsed[1][0], atlas_size)
print(f"{OUT_ATL}: 2 x {LAST - FIRST + 1} glyphs, {atlas_size} Б; "
print(f"{OUT_ATL}: 2 x {LAST - FIRST + 1} + {DARK_LAST - DARK_FIRST + 1} glyphs, "
f"{atlas_size} Б; "
f"snapshot from 0x{SNAPSHOT_OFF:04X}")