/* * 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; }