Приёмка ур. 2–3: сквозь стену, клин в шве, бар под плитой, глухой страж
Четыре разбора с прогонов пользователя; три бага закрыты, четвёртый (BUG-SPIKE-1, пики) заведён с замером и гипотезой. BUG-JUMPWALL-1 (Critical) — недолетевший прыжок проходил СКВОЗЬ стену. check_collisions держал флаги перекрытия ОДНОГО ряда, а оригинал (seg004:0004) — трёх, и move_coll_to_prev (seg004:00DF) берёт «прошлые» флаги из нужного. Наш prev=3 («уже перекрывал») подавлял бамп ровно на кадре смены ряда, а в падении ряд меняется почти каждый кадр — переход 0→1 на стене приходился как раз на него. Порт трёх рядов дословно. Воспроизведено и закрыто на харнессе (новый набор t_wall: свип по 20 стартовым X, 4 давали проход сквозь кладку); 1723 трассы t_phys НЕ изменились — правка поведение-сохраняющая. Живьём подтвердил пользователь. BUG-GUARD-DEAF-1 (Major) — is_guard_notice не взводился НИГДЕ, поэтому неактивный страж не оборачивался на Кида за спиной никогда. Портированы все пять мест оригинала: опкод SOUND в play_seq (звуки 0..2), bumped_sound, мягкое/среднее приземление, обрушенная плита, щелчок кнопки. Ждёт игровой проверки боем в комнате 11 уровня 2. BUG-SEAM-WEDGE-1 — клин кладки в пустом (2,0). Сосед угла снизу-слева лежит в комнате по диагонали (room_BL); мы безусловно считали его стеной, оригинал (load_rowbelow, seg008:368) — только когда такой комнаты нет. Ряд «снизу» стал 11-байтным: [10] = тайл (0,9) диагональной комнаты. BUG-LOOSE-3 — чёрный бар под упавшей плитой-потолком. pop_ceil_bake_empty стирал полосу и восстанавливал только два тайла ряда −1, а в полосу лезет графика соседа слева и верхушки ряда 0. Теперь перерисовываются ряды −1 и 0, колонки col−1..col+1. Проверено попиксельной сверкой с эталонной перерисовкой: 0 различий. Плюс карта связности комнат уровней 1–3 (TASKS.md): на ур. 2 недостижимых нет, на ур. 3 это 23 и 24 — те же односторонние ссылки, что дали 13/18/24 на уровне 1, только комнаты полностью пустые. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,8 @@ OBJS_phys := build/eng_pop_geom.rel build/eng_pop_kid.rel \
|
||||
|
||||
# Пробный набор (разведка, без эталонов) линкуется тем же составом.
|
||||
OBJS_grab := $(OBJS_phys)
|
||||
# t_wall — удар о стену в воздухе (BUG-JUMPWALL-1), состав тот же.
|
||||
OBJS_wall := $(OBJS_phys)
|
||||
|
||||
include $(TESTKIT)/host-tests.mk
|
||||
|
||||
|
||||
@@ -194,3 +194,7 @@ kframe pop_gframe;
|
||||
int8_t can_guard_see_kid;
|
||||
int8_t guard_refrac, kid_sword_strike;
|
||||
int8_t offguard, holding_sword;
|
||||
/* «Кид нашумел» — физика взводит его на ударе о стену, приземлении и
|
||||
* обрушенной плите (BUG-GUARD-DEAF-1); читает только автопилот стража,
|
||||
* которого в наборе нет. */
|
||||
int8_t is_guard_notice;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* t_wall.c — удар о стену В ВОЗДУХЕ (BUG-JUMPWALL-1).
|
||||
*
|
||||
* Наблюдение с приёмки уровня 3 (комната 14): Кид прыгает, не долетает и
|
||||
* вместо удара о кладку с последующим сползанием ВДОЛЬ неё пролетает
|
||||
* сквозь стену «по свободной траектории». Класс отказа шире одной
|
||||
* комнаты, поэтому проверяем его отдельным набором, а не сценарием в
|
||||
* t_phys: там характеризация (трасса == эталон), здесь — утверждение о
|
||||
* поведении («сквозь кладку нельзя»), которое не должно молча
|
||||
* переснашиваться вместе с эталонами.
|
||||
*
|
||||
* Оригинал: bumped_fall (seg004:04E4) на ударе гасит `Char.fall_x`, то есть
|
||||
* горизонтальный снос обнуляется и дальше Кид падает вертикально. Кто
|
||||
* решает, что удар был, — check_collisions (seg004:0004) + check_bumped.
|
||||
*
|
||||
* Проверка — свипом по стартовому X, а не одним прыжком: исход зависит от
|
||||
* фазы, и «с одной X работает» ничего не доказывает (ровно так и вышло с
|
||||
* первым сценарием — из центра плиты стена держит).
|
||||
*/
|
||||
#include "tcheck.h"
|
||||
#include "scene.h"
|
||||
#include "stubs.h"
|
||||
#include "pop_kid.h"
|
||||
#include "pop_map.h"
|
||||
|
||||
#define E 0
|
||||
#define F 1
|
||||
#define W 20
|
||||
|
||||
/* Комната 14 уровня 3 с одной правкой: шахте колонок 6–7 подложено дно
|
||||
* (ряд 2), потому что соседних комнат у сцены нет, а в игре Кид улетает
|
||||
* вниз в комнату 13. Остальное — как в данных: площадка (0,8), провал
|
||||
* (0,6)/(0,7), СТЕНА в колонке 5 рядов 1–2, площадка (0,5) за ней. */
|
||||
static const uint8_t room14[30] = {
|
||||
F, F, F, E, E, F, E, E, F, E,
|
||||
W, W, W, E, E, W, E, E, W, E,
|
||||
W, W, W, F, F, W, F, F, W, W,
|
||||
};
|
||||
|
||||
/* Плита (0,8) по X: колонка 8 — это [177, 191), плюс шов с пустой (0,9). */
|
||||
#define X_LO 177
|
||||
#define X_HI 196
|
||||
|
||||
/* Прыгнуть влево со стартовой X. Возврат — код исхода:
|
||||
* 'L' — долетел до площадки (0,5) и стоит на ней (ряд 0) — законно;
|
||||
* '.' — не долетел и упал на дно шахты колонок 6–7 — тоже законно;
|
||||
* цифра — колонка, в которой Кид оказался ЛЕВЕЕ стены, то есть прошёл
|
||||
* сквозь кладку колонки 5 (это и есть баг). */
|
||||
static char jump_left_from(uint8_t x)
|
||||
{
|
||||
sc_room(room14, 14);
|
||||
sc_kid_at_x(8, 0, x, -1 /* лицом влево */);
|
||||
sc_trace_clear();
|
||||
/* Клавиши держим только на сам прыжок: если удерживать их всю сцену,
|
||||
* Кид, ДОЛЕТЕВШИЙ до (0,5), тут же прыгает с неё второй раз — и исход
|
||||
* говорит уже не о стене, а о втором прыжке. */
|
||||
sc_run(SC_L | SC_U, 6);
|
||||
sc_run(0, 34);
|
||||
if (!sc_len) return '?';
|
||||
{
|
||||
int8_t col = sc_trace[sc_len - 1].col;
|
||||
int8_t row = sc_trace[sc_len - 1].row;
|
||||
if (row == 0) return 'L'; /* остался на верхнем ряду */
|
||||
if (col >= 6) return '.'; /* сполз вдоль стены в шахту */
|
||||
return (char)('0' + (col < 0 ? 0 : col));
|
||||
}
|
||||
}
|
||||
|
||||
static void put(char c)
|
||||
{
|
||||
if (tc_result.logn < TC_LOGSZ) tc_result.log[tc_result.logn++] = (uint8_t)c;
|
||||
}
|
||||
static void puts_(const char *s) { while (*s) put(*s++); }
|
||||
|
||||
TC_TEST(wall_stops_undershot_jump)
|
||||
{
|
||||
uint8_t x, bad = 0;
|
||||
/* Карта исходов по всей ширине плиты: 'L' — долетел до (0,5), '.' —
|
||||
* сполз вдоль стены в шахту, цифра — просочился сквозь кладку. */
|
||||
puts_("x=177..196: ");
|
||||
for (x = X_LO; x <= X_HI; x++) {
|
||||
char r = jump_left_from(x);
|
||||
put(r);
|
||||
if (r != 'L' && r != '.') bad++;
|
||||
}
|
||||
put('\n');
|
||||
TC_EQ(bad, 0);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
sc_init();
|
||||
TC_RUN(wall_stops_undershot_jump);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user