/* * t_death — смерть от меча: что происходит с координатой и состоянием. * * Набор заведён ПЕРЕД правкой находок 12/13 (docs/sdlpop_audit.md), чтобы * зафиксировать нынешнее поведение и поймать деградацию. История вопроса: * правка 13 в изоляции уже ломала смерть — мёртвый Кид оставался с * ненулевой скоростью падения, проваливался за нижнюю границу и игра * уходила на рестарт, не показав тела. * * Проверяем ровно то, на что эти правки влияют: * - HP и признак смерти; * - КООРДИНАТУ по Y и остаточную скорость падения (в этом вся суть); * - что смерть наступает при ударе не в боевой стойке (порт оригинала: * «ранение вне боевой стойки означает смерть»). */ #include "tcheck.h" #include "scene.h" #include "stubs.h" #include "pop_kid.h" #include "pop_map.h" #include "pop_guard.h" #define E 0 #define F 1 #define W 20 /* Ровный пол во всю ширину: ряд 2 — пол, выше пусто. Комната без краёв, * чтобы смерть не смешивалась с падением. */ static const uint8_t room_flat[30] = { E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, F, F, F, F, F, F, F, F, F, F, }; /* Площадка, обрывающаяся справа: колонки 0-4 — пол, 5-9 пусто. Кид у * самого края спиной к обрыву — целевая сцена находки 12 (в оригинале * такой удар отправляет в отдельную последовательность падения замертво). */ static const uint8_t room_ledge[30] = { E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, F, F, F, F, F, E, E, E, E, E, }; /* Поставить сцену «страж бьёт Кида» и нанести удар. */ static void strike_kid(const uint8_t *room, uint8_t col, uint8_t hp, uint8_t sword) { sc_room(room, 1); sc_kid_at(col, 2, 1 /* лицом вправо */); hitp_curr = hp; Kid.sword = sword; pop_kid_dead = 0; /* Признак «жив» обвязка ставит только стражу, поэтому Киду задаём его * сами: обработчик удара первым делом отсекает уже мёртвого. */ Kid.alive = -1; /* Удар оформляется действием 99 «ранен» — так его помечает боевая * проверка оригинала, а разбирает pop_check_sword_hurt. */ Kid.action = 99; pop_check_sword_hurt(); /* Удар выставляет ДЕЛЬТУ, а HP меняет отдельный шаг кадра — как в * оригинале. Без него hitp_curr остался бы прежним, и тест мерил бы * не то. */ pop_do_delta_hp(); } TC_TEST(death_unarmed_hit_is_lethal) { strike_kid(room_flat, 4, 3 /* HP */, 0 /* без меча */); /* Удар не в боевой стойке смертелен независимо от запаса HP. */ TC_EQ(hitp_curr, 0); } TC_TEST(death_armed_hit_costs_one_hp) { strike_kid(room_flat, 4, 3, 2 /* меч вынут */); TC_EQ(hitp_curr, 2); } TC_TEST(death_armed_last_hp_kills) { strike_kid(room_flat, 4, 1, 2); TC_EQ(hitp_curr, 0); } /* --- КООРДИНАТА ПОСЛЕ УДАРА: суть находок 12 и 13 -------------------- */ TC_TEST(survivor_is_placed_on_floor) { /* Пережил удар — оригинал ставит его на пол своего ряда и гасит * скорость падения. Это единственная ветка, где он так делает. */ strike_kid(room_flat, 4, 3, 2); TC_EQ(Kid.fall_y, 0); TC_EQ(Kid.y, pop_y_land[Kid.curr_row + 1]); } TC_TEST(death_on_flat_floor_keeps_body_in_place) { /* Смерть на ровном полу: тело обязано остаться в своём ряду. Если * координата или скорость падения уедут, физика утащит труп вниз — * ровно так ломалась игра при правке 13 в одиночку. */ strike_kid(room_flat, 4, 1, 2); TC_EQ(Kid.curr_row, 2); TC_EQ(Kid.fall_y, 0); } TC_TEST(death_at_ledge_keeps_body_in_place) { /* Смерть у самого обрыва — целевая сцена находки 12. Сейчас мы * ставим «заколот на месте» и удерживаем тело; в оригинале здесь * своя последовательность падения замертво. Тест фиксирует НЫНЕШНЕЕ * поведение: после правки 12+13 ожидание изменится осознанно. */ strike_kid(room_ledge, 4, 1, 2); TC_EQ(Kid.curr_row, 2); TC_EQ(Kid.fall_y, 0); } int main(void) { sc_init(); TC_RUN(death_unarmed_hit_is_lethal); TC_RUN(death_armed_hit_costs_one_hp); TC_RUN(death_armed_last_hp_kills); TC_RUN(survivor_is_placed_on_floor); TC_RUN(death_on_flat_floor_keeps_body_in_place); TC_RUN(death_at_ledge_keeps_body_in_place); return 0; }