Фиксированный логический кадр по лучу + режимы FASTEST/FAST/NORMAL

Период стал max(n, ceil(W)) вместо ceil(W)+2: три gfx_wait_vsync после
работы отсчитывались от её КОНЦА, поэтому бюджет кадра был один растр.
Теперь ждём от якоря начала кадра, и при n=3 бюджет 1 290 240 тактов.

Счёт кадров — программный, по биту 5 порта 0xFE (положение луча), а не по
кадровым прерываниям: те теряются в DI-окнах акселератора фазозависимо
(замер: 0..2,8 %, на полной перерисовке три подряд).  Условие точности
одно — зазор между выборками меньше 64 512 тактов; точки выборки
расставлены по замеру, а не на глаз.

Режимы (pop_pace.h), клавиша P по кругу, дефолт FASTEST.  Условие боя
взято у оригинала буквально (SDLPoP seg003.c:363): Kid.sword ==
SWORD_2_DRAWN, а не «идёт бой».

Проверено в MAME на 11/15: счётчик без недосчёта на 270 кадров, период
ровно 3 растра на 302 логических кадрах (ни длиннее 3,1, ни короче 2,9),
NORMAL даёт ровно 4, с вынутым мечом — ровно 5.
This commit is contained in:
2026-08-19 23:06:27 +03:00
parent 61b8d80275
commit a6e39070af
11 changed files with 310 additions and 9 deletions
+8
View File
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <unistd.h>
#include "pop_bg.h"
#include "pop_pace.h" /* pop_beam_sample — счёт кадров по лучу */
#include "_pop_bg.h" /* контракт с горячей половиной (pop_bg.c, банк 2) */
#include "pop_tile.h" /* общие листья слоя фона (резидент): блит, тайлы, таблица */
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
@@ -625,6 +626,7 @@ void pop_loose_shake_draw(int row, int col) __banked
* 42/71/72 = 26x15-16. Задача HEAL-WIDTH. */
pop_heal_off(x, 63 * row + 46, 58, 24);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
draw_tile(row, col); /* loose: лево+низ (анимир.) */
if (col + 1 < 10)
draw_tile(row, col + 1); /* сосед: правая грань loose (анимир.) + его пол */
@@ -662,6 +664,7 @@ void pop_chomp_anim_draw(int row, int col) __banked
uint8_t pose = pop_chomp_pose(cm);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
pop_cd_batch_begin(); /* одна пометка на все куски */
pop_env_b(CHOMP_FRAM_BOT[pose], x, dmy);
if (cm & 0x80) /* кого-то перемололо */
@@ -691,6 +694,7 @@ void pop_spike_redraw(int row, int col) __banked
* (63*row+34 .. +74); ширина 64 = обе ячейки. */
pop_heal_off(x, 63 * row + 34, 64, 40);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
draw_tile(row, col);
if (col + 1 < 10)
draw_tile(row, col + 1);
@@ -714,6 +718,7 @@ void pop_chomp_redraw(int row, int col) __banked
* Было 64 «на всю высоту тайла» — четыре лишние строки. */
pop_heal_off(x, 63 * row + 3, 32, 60);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
draw_tile(row, col);
gfx_set_bank(GFX_BANK_NORMAL);
}
@@ -866,6 +871,7 @@ void pop_ceil_shake_draw(int col) __banked
* heal'а, — он её и стирает. */
pop_cd_touch(x, POP_YOFF, 64, CEIL_BAND_H);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
pop_t_clip_top = POP_YOFF;
pop_t_win_set(x, POP_YOFF, 64, CEIL_BAND_H); /* восстанавливаем ровно полосу */
draw_tile(-1, col);
@@ -975,6 +981,7 @@ void pop_potion_draw(int row, int col, uint8_t modif) __banked
}
pop_heal_off(x - 1, yb - 10, 8, 12);
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
pop_pot_b(POT_MASK_ID, x, yb); /* маска (под пузырьком) */
pop_pot_b(bubb, x, yb); /* кадр пузырька */
gfx_set_bank(GFX_BANK_NORMAL);
@@ -1788,6 +1795,7 @@ static void mob_render(mob_t *m, uint8_t pg)
* left(41) на obj_y-3, bottom(43) на obj_y, right(42) на obj_x+4 (=col+1,
* заходит в тайл СПРАВА) на obj_y-1. */
gfx_set_bank(GFX_BANK_SPRITE);
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
/* КЛИПА ОБЪЕКТА ЗДЕСЬ НЕТ. У оригинала он есть — add_mob_to_objtable
* (seg007:1161) ставит куску clip.right = 40, — но единицы этого поля я
* НЕ выяснил: буквальные 40 экранных пикселей срезают правый задний угол