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:
@@ -140,6 +140,7 @@ static void run_jump(void)
|
||||
}
|
||||
|
||||
static void safe_step(void); /* fwd */
|
||||
static void draw_sword(void); /* fwd: нужен в control_standing */
|
||||
|
||||
static void forward_pressed(void)
|
||||
{
|
||||
@@ -233,7 +234,32 @@ static void control_standing(void)
|
||||
if (control_shift2 == CONTROL_HELD && control_shift == CONTROL_HELD &&
|
||||
get_item_action())
|
||||
return;
|
||||
/* Kid charid_0, без меча: остаётся нижняя часть control_standing. */
|
||||
/* Ветку «charid != kid && вниз+вперёд -> draw_sword» не портируем: у нас
|
||||
* соперник до control_standing не доходит, его перехватывает
|
||||
* control_guard_inactive в самом диспетчере (порядок как в seg005). */
|
||||
|
||||
/* seg005:352 — Кид с мечом ВИДИТ активного стража: достаёт клинок сам.
|
||||
* Без этого игрок стоит с мечом в ножнах, пока его рубят. */
|
||||
if (pop_have_sword) {
|
||||
if (offguard != 0 && control_shift >= CONTROL_RELEASED) {
|
||||
/* Меч убран намеренно (down в бою) — не доставать, пока не
|
||||
* отпустят Shift; в оригинале это переход на loc_6213. */
|
||||
} else if (can_guard_see_kid >= 2) {
|
||||
int16_t d = pop_char_opp_dist();
|
||||
if (d >= -10 && d < 90) {
|
||||
holding_sword = 1;
|
||||
/* (word)d < (word)-6 — беззнаковое: истинно для ВСЕГО, кроме
|
||||
* −6..−1. То есть «страж вплотную за спиной» -> отступить,
|
||||
* иначе достать меч. */
|
||||
if (d >= -6 && d < 0) { back_pressed(); return; }
|
||||
draw_sword();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
offguard = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (control_shift == CONTROL_HELD) {
|
||||
if (control_backward == CONTROL_HELD) back_pressed();
|
||||
else if (control_up == CONTROL_HELD) up_pressed();
|
||||
@@ -333,9 +359,11 @@ static void draw_sword(void)
|
||||
{
|
||||
uint8_t seq_id = SEQ_55_DRAW_SWORD;
|
||||
control_forward = control_shift2 = release_arrows();
|
||||
if (Char.charid != CHARID_0_KID && Char.charid != CHARID_1_SHADOW)
|
||||
seq_id = SEQ_90_EN_GARDE;
|
||||
/* TODO: у Кида здесь play_sound(19) + offguard = 0 — звука пока нет. */
|
||||
if (Char.charid == CHARID_0_KID) {
|
||||
offguard = 0; /* TODO: play_sound(19) — звука пока нет */
|
||||
} else if (Char.charid != CHARID_1_SHADOW) {
|
||||
seq_id = SEQ_90_EN_GARDE; /* соперник встаёт сразу в стойку */
|
||||
}
|
||||
Char.sword = SWORD_2_DRAWN;
|
||||
seqtbl_offset_char(seq_id);
|
||||
}
|
||||
@@ -455,8 +483,9 @@ static void swordfight(void)
|
||||
control_down = CONTROL_IGNORE;
|
||||
Char.sword = SWORD_0_SHEATHED;
|
||||
if (Char.charid == CHARID_0_KID) {
|
||||
/* TODO: offguard/holding_sword — вместе с боёвкой Кида. */
|
||||
guard_refrac = 9;
|
||||
offguard = 1; /* убрал намеренно — сразу не доставать */
|
||||
guard_refrac = 9; /* и страж на это время придержан */
|
||||
holding_sword = 0;
|
||||
seq_id = SEQ_93_PUT_SWORD_AWAY_FAST;
|
||||
} else if (Char.charid == CHARID_1_SHADOW) {
|
||||
seq_id = SEQ_92_PUT_SWORD_AWAY;
|
||||
@@ -505,6 +534,16 @@ static void control_with_sword(void)
|
||||
void pop_control(void)
|
||||
{
|
||||
uint8_t f = Char.frame;
|
||||
/* seg005 control(), самая первая ветка: персонаж УМИРАЕТ (alive >= 0).
|
||||
* Из любой стойки он валится в seq_71_dying; остальное управление в
|
||||
* этом состоянии не обрабатывается. Через это же место проходит чит K
|
||||
* (pop_guard_kill ставит Guard.alive = 0). */
|
||||
if (Char.alive >= 0) {
|
||||
if (f == FRAME_15_STAND || f == FRAME_166_STAND_INACTIVE ||
|
||||
f == FRAME_158_STAND_WITH_SWORD || f == FRAME_171_STAND_WITH_SWORD)
|
||||
seqtbl_offset_char(SEQ_71_DYING);
|
||||
return;
|
||||
}
|
||||
/* seg005 control(): в отскоке (bumped) и в свободном падении управление
|
||||
* НЕ обрабатывается вовсе — только гасятся стрелки. Без этого игрок
|
||||
* прерывает присед после удара (medland/плита по голове) нажатием ↑, и
|
||||
|
||||
Reference in New Issue
Block a user