PoP roomtest: HP-учёт, индикаторы HP, чит бессмертия; фикс кэша кадра
Боёвка (порт seg002/seg006): - check_sword_hurting / check_hurting / check_sword_hurt / hurt_by_sword / take_hp через дельты; do_delta_hp сводит их раз в кадр; - парирование (justblocked), refractimer после ранения стража; - смерть по seq_71_dying — через неё же теперь работает чит K: страж действительно погибает, а не замирает на месте; - парные окна Char/Opp: loadkid_and_opp / savekid_and_opp / saveshad_and_opp. Индикаторы HP (порт draw_kid_hp / draw_guard_hp): Кид слева, страж справа. Перерисовка ТОЛЬКО при изменении числа и тогда на ОБЕИХ страницах дабл-буфера (счётчик hp_todo, иначе на второй странице осталось бы старое значение и мерцало через кадр); pop_hp_invalidate при входе в комнату, где фон перерисован целиком. Чит I — бессмертие Кида (нашего изобретения, в оригинале его нет). Перекрывает и путь «безоружного закалывают насмерть»: тот идёт мимо HP, и без этого чит бесполезен ровно там, где нужен. ДВА НАЙДЕННЫХ БАГА: 1. Полосу HP блитил row-major примитивом, а атласы Кида и стража хранятся COLUMN-major (ради бесплатного флипа) — марки выходили транспонированными. Теперь колоночный блит, стрелки как в оригинале. 2. Кэш кадра для ОТРИСОВКИ заполняли pop_savekid/pop_saveshad. Любое окно Char БЕЗ play_seq — а это оба окна боёвки — записывало Киду кадр, который принадлежал СТРАЖУ, и kid_draw искал этот image в атласе Кида, рисуя произвольную позу. Владельцем кэша стал load_frame: он один знает, чей кадр загружен (по Char.charid). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,27 @@ uint8_t pop_sword_draw(const pop_char_t *ch, const kframe *fr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Блит спрайта chtab_2 (атласы Kid) по ЕГО id, левым верхним углом в (x,y).
|
||||
* Нужен полосе HP: она рисует id 216/217 из тех же атласов, что и кадры
|
||||
* Кида, а держать вторую копию раскладки в pop_gdraw ни к чему. */
|
||||
void pop_kid_img_blit(uint8_t image, int x, int y)
|
||||
{
|
||||
uint8_t pg = (uint8_t)(image >> 3); /* раскладка атласов: 8 спрайтов/стр. */
|
||||
uint8_t idx = (uint8_t)(image & 7);
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
if (pg >= kid_npages) return;
|
||||
img = (const uint8_t *)atlas_image(&kidp[pg], idx);
|
||||
gfx_w0_map(kidp[pg].page);
|
||||
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
|
||||
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
||||
/* Атласы Кида хранятся COLUMN-MAJOR (transpose_cols в pop_pack_kid —
|
||||
* ради бесплатного горизонтального флипа), поэтому блит обязан быть
|
||||
* колоночным. Row-major gfx_blit_noclip выдал бы марку транспонированной. */
|
||||
if (w && h) gfx_blit_cols_part_noclip(x, y, img, 0, 0, 0);
|
||||
gfx_w0_unmap();
|
||||
}
|
||||
|
||||
int pop_kid_load(uint8_t npages)
|
||||
{
|
||||
static const char *const names[KID_MAXPAGES] = {
|
||||
@@ -184,13 +205,16 @@ pop_char_t Char;
|
||||
pop_char_t Opp;
|
||||
|
||||
void pop_loadkid(void) { Char = Kid; }
|
||||
void pop_savekid(void) { Kid = Char; kid_frame = cur_frame; }
|
||||
void pop_savekid(void) { Kid = Char; }
|
||||
/* Выгрузка БЕЗ кадра: control() кадр не трогает, а cur_frame в этот
|
||||
* момент принадлежит тому, кто последним крутил play_seq. */
|
||||
void pop_savekid_state(void) { Kid = Char; }
|
||||
void pop_loadshad(void) { Char = Guard; }
|
||||
void pop_saveshad(void) { Guard = Char; pop_gframe = cur_frame; }
|
||||
void pop_saveshad(void) { Guard = Char; }
|
||||
void pop_loadshad_and_opp(void) { Char = Guard; Opp = Kid; }
|
||||
void pop_saveshad_and_opp(void) { Guard = Char; Kid = Opp; }
|
||||
void pop_loadkid_and_opp(void) { Char = Kid; Opp = Guard; }
|
||||
void pop_savekid_and_opp(void) { Kid = Char; Guard = Opp; }
|
||||
|
||||
/* char_opp_dist (seg006:2135): >0 — соперник ПЕРЕД Char, <0 — за спиной.
|
||||
* +13 при встречных направлениях: у стоящих лицом друг к другу «ноль»
|
||||
@@ -282,6 +306,15 @@ static void load_frame(void)
|
||||
cur_frame.dy = (int8_t)f[2];
|
||||
cur_frame.flags = f[3];
|
||||
cur_frame.sword = f[4];
|
||||
/* Кэш кадра для ОТРИСОВКИ раскладываем ЗДЕСЬ, по charid активного
|
||||
* персонажа, а не в save*-функциях. Раньше кэш писали pop_savekid/
|
||||
* pop_saveshad, и любое окно Char БЕЗ play_seq (окна боёвки
|
||||
* check_sword_hurting / check_sword_hurt) записывало Киду кадр, который
|
||||
* на самом деле принадлежал СТРАЖУ: kid_draw брал его image из атласа
|
||||
* Кида и рисовал произвольную позу. Теперь владелец один — тот, для
|
||||
* кого кадр реально загружен. */
|
||||
if (Char.charid == CHARID_0_KID) kid_frame = cur_frame;
|
||||
else pop_gframe = cur_frame;
|
||||
}
|
||||
|
||||
static uint8_t char_dx_forward(int8_t dx)
|
||||
|
||||
Reference in New Issue
Block a user