Бессмертие: два уровня вместо тумблера

1 — только бой: удары мечом не отнимают HP (ветка в hurt_by_sword).
2 — плюс мелкий урон: не проходят «минус деление» от падения с двух
    этажей и от падающей плиты (pop_take_hp гасит count < 100).
Мгновенная смерть остаётся на обоих: пики, чомпер, падение с трёх этажей
и удар вне боевой стойки приходят с count = 100.  В коде ровно два
значения урона, 1 и 100, поэтому граница точная, а не эвристическая.

Заодно ушёл костыль «снять бессмертие на время вызова take_hp(100)» в
hurt_by_sword — он был нужен только потому, что прежний чит глушил и
смертельный урон.

Клавиша I идёт по кругу 0 -> 1 -> 2 -> 0; в отладочной метке число
красных палочек = уровень.
This commit is contained in:
2026-08-20 10:08:52 +03:00
parent 10b920f156
commit 0ef8c4b60e
6 changed files with 33 additions and 11 deletions
+7 -6
View File
@@ -973,14 +973,15 @@ static void hurt_by_sword(void)
* нет ни одной — управление зависало намертво: Кид стоял в боевой
* стойке без меча и не разворачивался к сопернику (BUG-CHEAT-IMM-1).
*
* Ветку глушим на время вызова, а не правим pop_take_hp: тот общий
* с физикой (падения/пики/чомперы), и там бессмертие обязано
* работать при любом положении меча. */
uint8_t imm = pop_immortal;
pop_immortal = 0;
* Костыля «снять бессмертие на время вызова» здесь БОЛЬШЕ НЕТ:
* pop_take_hp гасит только урон меньше 100, а тут ровно 100. */
pop_take_hp(100);
pop_immortal = imm;
pop_char_set_seq(SEQ_85_STABBED_TO_DEATH);
} else if (Char.charid == CHARID_0_KID && pop_immortal) {
/* ЧИТ, уровень 1 и выше: в боевой стойке удары не отнимают HP.
* Кадр «получил удар» оставляем — иначе бой перестаёт читаться,
* да и оригинал на выживший удар ставит ровно его. */
pop_char_set_seq(SEQ_74_HIT_BY_SWORD);
} else if (Char.charid != CHARID_4_SKELETON && pop_take_hp(1)) {
pop_char_set_seq(SEQ_85_STABBED_TO_DEATH); /* HP кончились */
} else {
+3 -1
View File
@@ -19,7 +19,9 @@
extern uint8_t pop_cheats; /* 0 = выключены, иначе включены */
#define KBD_CHEAT_KILL 0x42 /* K (PS/2 set 2) — kill guard */
#define KBD_CHEAT_IMMO 0x43 /* I (PS/2 set 2) — бессмертие Кида (toggle) */
#define KBD_CHEAT_IMMO 0x43 /* I (PS/2 set 2) — бессмертие Кида по кругу
* 0 -> 1 (только бой) -> 2 (и мелкий урон) -> 0;
* уровни расписаны в pop_state.h */
#define KBD_CHEAT_SWORD 0x1B /* S (PS/2 set 2) — выдать Киду меч */
#define KBD_CHEAT_NEXTLVL 0x4B /* Shift+L (PS/2 set 2) — следующий уровень */
#define KBD_CHEAT_XDEC 0x54 /* [ (PS/2 set 2) — сдвинуть Кида на 1 px влево */
+8 -1
View File
@@ -85,7 +85,14 @@ void pop_guard_kill(void)
uint8_t pop_take_hp(uint8_t count)
{
if (Char.charid == CHARID_0_KID) {
if (pop_immortal) return 0;
/* ЧИТ БЕССМЕРТИЯ, уровень 2 (pop_state.h): гасим ТОЛЬКО мелкий урон
* — падение с двух этажей, придавливание плитой. Мгновенная смерть
* (пики, чомпер, падение с трёх этажей, удар вне боевой стойки)
* приходит с count = 100 и проходит всегда: у читa нет задачи
* отменять смерть, у него задача отменить «минус одно деление».
* Уровень 1 сюда не вмешивается вовсе — он живёт в hurt_by_sword и
* гасит только удары мечом. */
if (pop_immortal >= 2 && count < 100) return 0;
if (count >= hitp_curr) { hitp_delta = (int8_t)-hitp_curr; return 1; }
hitp_delta = (int8_t)-(int8_t)count;
} else {
+9
View File
@@ -45,6 +45,15 @@ extern uint8_t pop_nav_hold;
/* Чит «бессмертие» (I): Кида бьют, но HP не убавляется. Читают пути урона
* (боёвка в банке, пики в pop_map), переключает главный цикл. */
/* ЧИТ БЕССМЕРТИЯ, три состояния (клавиша I по кругу):
* 0 — выключено;
* 1 — только БОЙ: удары мечом не отнимают HP (pop_take_hp тут ни при
* чём, ветка живёт в hurt_by_sword, guards.c);
* 2 — бой И мелкий урон: не проходят «минус одно деление» от падения с
* двух этажей и от падающей плиты (pop_take_hp гасит count < 100).
* МГНОВЕННАЯ СМЕРТЬ остаётся на любом уровне: пики, чомпер, падение с
* трёх этажей, удар мечом вне боевой стойки — все они приходят с
* count = 100. Чит отменяет потерю HP, а не смерть. */
extern uint8_t pop_immortal;
/* Габариты ПОСЛЕДНЕЙ нарисованной двери уровня — порт глобалов
+4 -1
View File
@@ -312,7 +312,10 @@ int main(void)
uint8_t xd = kbd_raw_down(KBD_CHEAT_XDEC);
uint8_t xi = kbd_raw_down(KBD_CHEAT_XINC);
if (pop_cheats && k && !cheat_prev) pop_guard_kill();
if (pop_cheats && i && !immo_prev) pop_immortal = !pop_immortal;
/* Бессмертие по кругу: 0 выкл -> 1 «только бой» -> 2 «бой и
* мелкий урон» -> 0. Что означают уровни — pop_state.h. */
if (pop_cheats && i && !immo_prev)
pop_immortal = (uint8_t)(pop_immortal >= 2 ? 0 : pop_immortal + 1);
if (pop_cheats && s && !sword_prev) pop_have_sword = 1;
if (pop_cheats && nl && !nlvl_prev && pop_current_level < POP_LAST_LEVEL)
pop_next_level = (uint8_t)(pop_current_level + 1);
+2 -2
View File
@@ -302,7 +302,7 @@ uint8_t pop_dbg_roomnav(uint8_t dir) __banked
* жёлтый x 10.. 85 уровень (1..15)
* белый x 100..175 комната (1..24)
* голубой x 190..205 скорость (1 палочка NORMAL, 2 FAST, 3 FASTEST)
* красный x 220..225 бессмертие (палочка есть = включено)
* красный x 220..230 бессмертие (1 палочка = только бой, 2 = и мелкий урон)
*
* ЦВЕТА — индексы ИГРОВОЙ палитры, и выбраны они не по вкусу, а по двум
* ограничениям.
@@ -370,7 +370,7 @@ void pop_dbg_room_label(uint8_t room) __banked
if (imm) { /* бессмертие — красный */
setfillstyle(SOLID_FILL, 0x3C);
label_bars(220, 1);
label_bars(220, imm); /* палочек = уровень (1 или 2) */
}
room_label_redraw--;
}