a3aaa30e53
КОД ИГРЫ НЕ МЕНЯЛСЯ. Новый набор t_death — 9 проверок, всего наборов 16. Заведён ПЕРЕД правкой находок 12/13, чтобы поймать деградацию: правка 13 в изоляции уже ломала смерть (мёртвый оставался с ненулевой скоростью падения, проваливался за нижнюю границу, игра уходила на рестарт, не показав тела). Поэтому проверяется ровно то, на что эти правки влияют: * удар не в боевой стойке смертелен независимо от запаса HP; * удар с мечом снимает одно HP, на последнем — убивает; * ПЕРЕЖИВШИЙ удар ставится на пол своего ряда с нулевой скоростью падения (в оригинале это единственная ветка, где координата трогается); * тело после смерти остаётся в своём ряду — и на ровном полу, и у самого обрыва (целевая сцена находки 12; после правки ожидание изменится осознанно). По дороге тест дважды показал не баг движка, а мои ошибки в самой сцене: обвязка выставляет признак «жив» только стражу, а урон применяется не сразу — удар выставляет дельту, и HP меняет отдельный шаг кадра, как в оригинале. Оба раза чинился тест. VANILLA/BUGFIXED: записано, что переключатель уже существует в настройках и зафиксирован в положении VANILLA, второй заводить не нужно. Отмечено главное следствие — наш «ванильный» билд УЖЕ не чистая ваниль (часть ванильных багов пофикшена), поэтому при разделении режимов придётся пройтись по сделанным отступлениям и распределить их; отдельные фиксы (падение сквозь стену) могут быть сделаны и в нынешнем билде. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011MsUsEFAQfsjjQpJ7RtKVY
127 lines
5.6 KiB
C
127 lines
5.6 KiB
C
/*
|
|
* 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;
|
|
}
|