67d62e3e8b
Уровень 12 (тень) — порт seg002/seg006: - check_shadow: подъём тени в комнате 15 по условию «меч подобран», init_shad_12, вход падением (seq 7); - autocontrol_shadow_level12: ждать Кида, бой, сближение, СЛИЯНИЕ; - общий урон (ранил тень — ранил себя) и check_killed_shadow (убил тень — убил себя); - таймер вспышки слияния 42 -> -1, sword_disappears при уходе из комнаты 18, появление плит в комнатах 2/13 после слияния. Переход 12 -> 13 бесшовный: двери у уровня нет, он кончается фактом попадания в комнату 23 (tbl_seamless_exit); флаг pop_seamless не даёт сбросить HP. Чит навигации по комнатам этот триггер придерживает — иначе комнату 23 двенадцатого уровня не посмотреть в принципе. Уровень 13 (Джафар): guard_notice_timer (фора после встречи), on_guard_killed + Jaffar_exit, check_fall_flo (гряда плит сверху) и три исключения loose-механики. Плюс спрайты визиря VIZIER.DAT — без них он рисовался обычным стражем; заодно цвет из данных комнаты применяется только к обычному стражу, как в оригинале. Падающие плиты — семь дефектов, найденных прогонами: - MOB_MAX 4 -> 14: check_fall_flo роняет шесть плит разом, лишние терялись без щебня; - одиночные сигналы посадки/провала больше не затираются в кадре; - честный loose_fall: сбитая плита рождается в том же кадре, от места удара, с половинной скоростью; - при снятии плиты метится и сосед справа (висел передний торец); - heal и отрисовка кусков разнесены на два прохода; - куски рисуются ПОСЛЕ фона, порядок между собой — по убыванию y (compare_curr_objs для пары 0x80 сортирует наоборот); - wall_pattern убран из ceil_over_kid_tile: у оригинала узор из draw_tile_bottom идёт в фон, а не в передний слой. Хост-тесты: два новых набора, t_shadow (45 проверок) и t_jaffar (44). TK_ROOMS 8 -> 24 — спецсобытия адресуют комнаты по реальным номерам. Осознанные расхождения (docs/impl_diff.md): нет мигания Кида спрайтами тени при слиянии, чит навигации не запускает бесшовный переход, чит K убивает через штатный путь смерти. Открытым остаётся разбор слоёв: MOB-CLIP-RIGHT, MID-OVERLAY-LAYER, GUARD-FALLOUT-VICTORY, BG-ONCE (BUGS_OPEN.md / TASKS_OPEN.md). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
372 lines
24 KiB
C
372 lines
24 KiB
C
/*
|
||
* pop_guard.h — СОСТОЯНИЕ стража и точки входа в его логику.
|
||
*
|
||
* Разделение по окнам (docs/layout_plan_v2.md §4, подтверждено пробником
|
||
* tests/w3bankgfx):
|
||
* - СОСТОЯНИЕ живёт здесь, в W1/W2. Писучие статики __banked-модуля
|
||
* линкуются В СТРАНИЦУ БАНКА и снаружи не читаются, поэтому банк —
|
||
* только код;
|
||
* - ЛОГИКА (ИИ, боёвка) — в guards.c, собираемом как --bank 1=guards.c;
|
||
* - ОТРИСОВКА стража — в pop_cdraw.c (банк 4), общая на всех Char: её зовёт
|
||
* только главный цикл, а из банка резидент недостижим. Так код
|
||
* отрисовки не занимает дефицитные W1/W2 (куча).
|
||
*
|
||
* Поля char_type — как в оригинале (types.h:302), чтобы порт seg005/seg006
|
||
* ложился один в один.
|
||
*/
|
||
#ifndef POP_GUARD_H
|
||
#define POP_GUARD_H
|
||
|
||
#include <stdint.h>
|
||
#include "kid_data.h" /* kframe */
|
||
#include "pop_char.h"
|
||
#include "pop_geom.h" /* pop_rnd_t — сид бросков боёвки */
|
||
|
||
/* seqids (types.h:1052+) — последовательности боя и стойки. */
|
||
#define SEQ_55_DRAW_SWORD 55
|
||
#define SEQ_56_GUARD_FORWARD 56 /* шаг вперёд с мечом (страж) */
|
||
#define SEQ_57_BACK_WITH_SWORD 57
|
||
#define SEQ_58_GUARD_STRIKE 58
|
||
#define SEQ_60_TURN_WITH_SWORD 60
|
||
#define SEQ_61_PARRY_AFTER_STRIKE 61
|
||
#define SEQ_62_PARRY 62
|
||
#define SEQ_66_STRIKE_AFTER_PARRY 66
|
||
#define SEQ_71_DYING 71
|
||
#define SEQ_75_STRIKE 75 /* удар (Кид) */
|
||
#define SEQ_63_GUARD_ACTIVE_AFTER_FALL 63 /* стойка АКТИВНОГО (скелет) */
|
||
#define SEQ_77_GUARD_STAND_INACTIVE 77
|
||
#define SEQ_88_SKEL_WAKE_UP 88 /* скелет встаёт (спецсобытие) */
|
||
#define SEQ_80_STAND_FLIPPED 80
|
||
#define SEQ_86_FORWARD_WITH_SWORD 86 /* шаг вперёд с мечом (Кид) */
|
||
#define SEQ_87_GUARD_BECOME_INACT 87
|
||
#define SEQ_90_EN_GARDE 90
|
||
#define SEQ_92_PUT_SWORD_AWAY 92
|
||
#define SEQ_93_PUT_SWORD_AWAY_FAST 93
|
||
|
||
/* frameids (types.h:911+) и состояния меча (types.h:332). */
|
||
#define FRAME_150_PARRY 150
|
||
#define FRAME_151_STRIKE_1 151
|
||
#define FRAME_152_STRIKE_2 152
|
||
#define FRAME_153_STRIKE_3 153
|
||
#define FRAME_157_WALK_WITH_SWORD 157
|
||
#define FRAME_158_STAND_WITH_SWORD 158
|
||
#define FRAME_161_PARRY 161
|
||
#define FRAME_162_BLOCK_TO_STRIKE 162
|
||
#define FRAME_165_WALK_WITH_SWORD 165
|
||
#define FRAME_166_STAND_INACTIVE 166
|
||
#define FRAME_167_BLOCKED 167
|
||
#define FRAME_168_BACK 168
|
||
#define FRAME_169_BEGIN_BLOCK 169
|
||
#define FRAME_170_STAND_WITH_SWORD 170
|
||
#define FRAME_171_STAND_WITH_SWORD 171
|
||
#define SWORD_0_SHEATHED 0
|
||
#define SWORD_2_DRAWN 2
|
||
|
||
/* charids (types.h:320) — нужны хотя бы для «скелет не убивается читом». */
|
||
#define CHARID_0_KID 0
|
||
#define CHARID_1_SHADOW 1
|
||
#define CHARID_2_GUARD 2
|
||
/* charid_3 не используется: Джафар (уровень 13) — обычный charid_2_guard,
|
||
* своим charid оригинал помечает ТОЛЬКО скелета (enter_guard, seg002:196).
|
||
* Отличают Джафара набор спрайтов (VIZIER.DAT), skill 9 и три события. */
|
||
#define CHARID_4_SKELETON 4
|
||
#define CHARID_5_PRINCESS 5
|
||
/* МЫШЬ (спецсобытие уровня 8) — тоже персонаж слота Guard: своей таблицы
|
||
* кадров у неё нет, кадры 186..188 лежат в таблице КИДА (load_frame,
|
||
* seg006:0293 — общий case с charid_0_kid), а спрайты (images 130..132) —
|
||
* в атласах Кида, страница kid16.atl. Поэтому отрисовка её подхватывает
|
||
* без единой правки: pop_frame_tbl_is_guard(24,…) отдаёт 0. */
|
||
#define CHARID_24_MOUSE 24
|
||
|
||
/* dir_56_none (types.h:402): «направления нет» — им clear_char убирает
|
||
* персонажа со сцены. Значение 0x56 в int8_t = 86, то есть заведомо не
|
||
* dir_0_right (0) и не dir_FF_left (-1). */
|
||
#define DIR_56_NONE 0x56
|
||
|
||
/* Спецсобытие «зеркало» (custom->mirror_*, дефолты SDLPoP): уровень 4,
|
||
* комната 4, колонка 4, верхний ряд. Здесь, а не в pop_trob.c: константы
|
||
* нужны и постановке тайла (банк 6), и ИИ тени (банк 1). */
|
||
#define MIRROR_LEVEL 4
|
||
#define MIRROR_ROOM 4
|
||
#define MIRROR_COL 4
|
||
#define MIRROR_ROW 0
|
||
#define MIRROR_TILEPOS (MIRROR_ROW * 10 + MIRROR_COL)
|
||
|
||
/* Спецсобытие «тень крадёт зелье» (custom->shadow_steal_*, дефолты SDLPoP):
|
||
* уровень 5, комната 24. Тень появляется при ВХОДЕ в комнату, если зелье
|
||
* (колонка 3, верхний ряд) ещё на месте; ждёт, пока откроются ворота
|
||
* (колонка 1, верхний ряд), идёт к зелью, выпивает его и уходит за левый
|
||
* край. Боя нет. Как и MIRROR_*, константы нужны в двух банках. */
|
||
#define SHADOW_STEAL_LEVEL 5
|
||
#define SHADOW_STEAL_ROOM 24
|
||
#define SHADOW_POTION_TILEPOS 3 /* (кол 3, ряд 0) — зелье */
|
||
#define SHADOW_DOOR_TILEPOS 1 /* (кол 1, ряд 0) — ворота */
|
||
#define SHADOW_DOOR_OPEN_MIN 80 /* openness, при которой тень идёт */
|
||
|
||
/* Спецсобытие «тень захлопывает решётку» (custom->shadow_step_*, дефолты
|
||
* SDLPoP): уровень 6, комната 1. Кид жмёт opener (1,7), решётка (1,2)
|
||
* поднимается, он прыгает через пропасть и цепляется за её порожек — и
|
||
* ровно в этот момент тень делает ОДИН осторожный шаг с границы (1,0)-(1,1)
|
||
* на closer (1,1), роняя решётку. Обе плиты комнаты ведут на тот же тайл
|
||
* 12 (проверено по LINKLOC/LINKMAP уровня). */
|
||
#define SHADOW_STEP_LEVEL 6
|
||
#define SHADOW_STEP_ROOM 1
|
||
|
||
/* Спецсобытие «выход/вход падением» (custom->falling_*, дефолты SDLPoP).
|
||
* Уровень 6 не заканчивается дверью: Кид проваливается вниз из комнаты 1 и
|
||
* этим переходит на уровень 7, где появляется в комнате 17 — но экран сразу
|
||
* переводится на комнату ПОД ней, так что он влетает сверху. Комната 3
|
||
* (шахта под комнатой 1) в переходе не участвует: leave_room перехватывает
|
||
* уход раньше, чем сработала бы связь вниз. */
|
||
#define FALLING_EXIT_LEVEL 6
|
||
#define FALLING_EXIT_ROOM 1
|
||
#define FALLING_ENTRY_LEVEL 7
|
||
#define FALLING_ENTRY_ROOM 17
|
||
|
||
/* Комната, которую проходят СВЕРХУ ВНИЗ спуском через зацеп: Кид висит на
|
||
* кромке кнопки (0,2), отпускает и цепляется за кромку (2,2). Нужна ЧИТУ
|
||
* навигации (`+`/`−` в roomtest.c): он ставит Кида на нижний пол, а отсюда
|
||
* этот спуск не проверить — для этой комнаты старт в ряду 0. */
|
||
#define GRAB_DOWN_LEVEL 7
|
||
#define GRAB_DOWN_ROOM 14
|
||
|
||
/* Единственный уровень, где тень — БОЕВОЙ персонаж (seg003:702). На всех
|
||
* остальных (4 зеркало, 5 зелье, 6 плита) она Кида «не видит»: см.
|
||
* pop_check_can_guard_see_kid.
|
||
*
|
||
* Сцена целиком (seg002:0070 + seg002:1184): в комнате 15 лежит МЕЧ (0,1);
|
||
* пока он на месте, тень не появляется. Кид его берёт — тень падает в ту
|
||
* же комнату, и дальше либо бой (у обоих клинки), либо, если Кид уберёт
|
||
* меч, — слияние. Комната 18 при уходе ВПРАВО «съедает» меч с карты
|
||
* (sword_disappears), чтобы вернуться и подобрать его второй раз было
|
||
* нельзя. Проверено по res2012.bin, ../docs/levels_12_15_plan.md §7.3. */
|
||
#define SHADOW_FIGHT_LEVEL 12
|
||
#define SHADOW_FIGHT_ROOM 15
|
||
#define SHADOW_SWORD_TILEPOS 1 /* (кол 1, ряд 0) — меч уровня 12 */
|
||
#define SWORD_GONE_ROOM 18 /* уход ВПРАВО отсюда убирает меч */
|
||
/* Слияние (autocontrol_shadow_level12): дистанция, вспышка, её длительность. */
|
||
#define SHADOW_UNITE_DIST 10
|
||
#define SHADOW_UNITE_TIME 42
|
||
|
||
/* Уровень 13 — ДЖАФАР (custom->jaffar_*, дефолты SDLPoP). Своего ИИ у него
|
||
* нет вовсе: `autocontrol_Jaffar` (seg002:085A) — это `autocontrol_guard`,
|
||
* то есть обычный бой стражи. Отличают его только данные (VIZIER.DAT,
|
||
* skill 9, 6 HP — всё уже в pop_level_cold.c) и три события ниже.
|
||
*
|
||
* Встреча: Кид уходит ВПРАВО из комнаты 3 — а `комната 3.right = 1`, где
|
||
* Джафар и стоит (проверено по res2013.bin, ../docs/levels_12_15_plan.md
|
||
* §7.2). Ему даётся фора JAFFAR_NOTICE_TIME кадров: пока таймер идёт, он не
|
||
* встаёт в боевую стойку, и это единственная пауза во всей сцене.
|
||
*
|
||
* Выход: смерть Джафара сама дверь НЕ открывает — она ставит
|
||
* pop_leveldoor_open = 2, а дверь открывает КНОПКА комнаты 24 (tilepos 0,
|
||
* реальный opener), «нажимаемая» при уходе Кида ВЛЕВО. */
|
||
#define JAFFAR_LEVEL 13
|
||
#define JAFFAR_MEET_ROOM 3 /* уход ВПРАВО отсюда будит Джафара */
|
||
#define JAFFAR_NOTICE_TIME 28 /* ≈2,3 с форы (28/12) */
|
||
#define JAFFAR_EXIT_ROOM 24
|
||
#define JAFFAR_EXIT_TILEPOS 0
|
||
#define JAFFAR_FLASH_TIME 18
|
||
|
||
/* Градаций мастерства стража (seg002: таблицы вероятностей по 12 записей). */
|
||
#define NUM_GUARD_SKILLS 12
|
||
|
||
/* Тип персонажа — в pop_char.h (общий с Кидом и Char). */
|
||
|
||
extern pop_char_t Guard; /* страж ТЕКУЩЕЙ комнаты (как в оригинале) */
|
||
extern uint8_t guardhp_curr, guardhp_max;
|
||
extern int8_t guardhp_delta; /* <0 = в этом кадре отняли HP */
|
||
|
||
/* take_hp (seg006:06BD): отнять count HP у АКТИВНОГО персонажа (Char) —
|
||
* Киду из `hitp_*`, любому другому из `guardhp_*`. Возврат 1 = HP кончились
|
||
* (для вызывающего это «умер»); саму дельту применяет pop_do_delta_hp раз в
|
||
* кадр, как в оригинале.
|
||
*
|
||
* Живёт в резиденте W1/W2, потому что зовут ОБА банка: боёвка (guards.c,
|
||
* банк 1) и физика (pop_map.c, банк 3) — раньше у каждого была своя копия,
|
||
* причём у pop_map неверная (правила hitp_curr напрямую, мимо дельты, и не
|
||
* знала про не-Кидов). Чит бессмертия ловится здесь же. */
|
||
uint8_t pop_take_hp(uint8_t count);
|
||
|
||
/* Взводится в кадре, когда СТРАЖУ убавили HP (guardhp_delta < 0 оригинала):
|
||
* по нему pop_char_draw рисует «брызги» удара, как draw_guard в seg008:1654.
|
||
* Снимает главный цикл после отрисовки — стража могло не оказаться в
|
||
* отрисованной комнате, и тогда флаг обязан просто пропасть. */
|
||
extern uint8_t pop_guard_hurt;
|
||
|
||
/* Видит ли страж Кида (порт can_guard_see_kid, seg003:688):
|
||
* 0 — не видит, 1 — видит, но не пойдёт (между ними loose/чомпер/дыра),
|
||
* 2 — видит и пойдёт. Считает pop_check_can_guard_see_kid (банк) раз в
|
||
* кадр ДО логики персонажей; читают ИИ (autocontrol_*) и боёвка. */
|
||
extern int8_t can_guard_see_kid;
|
||
|
||
/* Кид «нашумел» (порт is_guard_notice, seg000:364): заставляет неактивного
|
||
* стража обернуться, даже если Кид у него за спиной. Ставит источник шума,
|
||
* снимает сам ИИ. */
|
||
extern int8_t is_guard_notice;
|
||
|
||
/* Боевые таймеры/уровень мастерства (seg000:295..311). Все убывают раз в
|
||
* кадр в autocontrol_opponent — как в оригинале.
|
||
* guard_skill — 0..11, из данных уровня; индекс в таблицы вероятностей;
|
||
* guard_refrac — «отдышка» стража: пока >0, он не атакует и не наступает;
|
||
* justblocked — Кид только что парировал (влияет на вероятность блока);
|
||
* kid_sword_strike — Кид только что бил (стража это придерживает). */
|
||
extern uint8_t guard_skill;
|
||
extern int8_t guard_refrac, justblocked, kid_sword_strike;
|
||
|
||
/* Состояние меча КИДА (seg005/seg006):
|
||
* offguard — меч убран НАМЕРЕННО (вниз в бою): пока стоит, Кид не
|
||
* достаёт клинок автоматически, даже видя стража;
|
||
* holding_sword — клинок в руке (для индикатора HP стража). */
|
||
extern int8_t offguard, holding_sword;
|
||
|
||
/* Спецсобытие уровня 12 — СЛИЯНИЕ С ТЕНЬЮ (united_with_shadow, seg000:288).
|
||
* Значение читается как три разных состояния, и это НЕ флаг:
|
||
* 0 — тень ещё отдельный персонаж (или уровень не 12);
|
||
* >0 — идёт вспышка слияния, счётчик кадров (42 → 1), убывает в
|
||
* pop_shadow_timer; пока он идёт, Кид мигает спрайтами тени;
|
||
* −1 — «уже слились», навсегда до конца уровня. Именно по нему
|
||
* check_shadow больше не поднимает тень, а в комнатах 2/13
|
||
* появляются недостающие плиты пола.
|
||
* Переход 0 → −1 идёт ЧЕРЕЗ счётчик: таймер, досчитав до нуля, уводит его
|
||
* ещё на единицу вниз (seg003:503) — отсюда и знаковый тип.
|
||
*
|
||
* pop_shadow_init (shadow_initialized, seg000:309) — «тень уже дождалась
|
||
* Кида в комнате 15»: до этого autocontrol_shadow_level12 роняет её заново
|
||
* каждый кадр, чтобы Кид застал падение, а не готовую стойку. */
|
||
extern int8_t pop_united_shadow;
|
||
extern uint8_t pop_shadow_init;
|
||
|
||
/* Сид бросков боёвки (свой домен последовательности, см. pop_geom.h). */
|
||
extern pop_rnd_t pop_fight_seed;
|
||
|
||
/* Луч видимости стража — раз в кадр, ДО тиков персонажей (в оригинале
|
||
* check_can_guard_see_kid стоит в play_frame перед play_kid_frame). */
|
||
void pop_check_can_guard_see_kid(void) __banked;
|
||
|
||
/* check_skel (seg002:1042) — СПЕЦСОБЫТИЕ уровня 3: скелета нет в данных
|
||
* уровня (guards_tile пуст во всех комнатах), он поднимается сам, когда Кид
|
||
* доходит до нужной колонки комнаты 1 при открытой двери уровня. Звать раз
|
||
* в кадр, ДО логики персонажей (порядок play_frame, seg000:868). */
|
||
void pop_check_skel(void) __banked;
|
||
|
||
/* Спецсобытие уровня 8 — МЫШЬ (do_timers seg003:0545 + do_mouse seg003:0ABA).
|
||
* Условие запуска: дверь уровня открыта И Кид в комнате 16; тогда счётчик
|
||
* pop_leveldoor_open растёт кадрами, и на 150-м мышь появляется у правого
|
||
* края верхнего ряда. Звать раз в кадр рядом с pop_check_skel. */
|
||
void pop_check_mouse(void) __banked;
|
||
|
||
/* check_shadow (seg002:0064) — СПЕЦСОБЫТИЕ входа в комнату: на «шадоу»-
|
||
* уровнях слот соперника занимает ТЕНЬ, а не страж из данных. Звать ВМЕСТО
|
||
* pop_guard_enter при входе в комнату; вернула 1 — событие обработано и
|
||
* стража поднимать НЕ надо.
|
||
*
|
||
* Тонкость оригинала, которую легко потерять: на уровне 5 в комнате 24
|
||
* страж В ДАННЫХ ЕСТЬ (`guards_tile[23] = 8`), но enter_guard там не
|
||
* вызывается НИКОГДА — ни когда тень поднимается, ни когда зелье уже
|
||
* выпито (в обоих случаях seg002:0064 делает return). Поэтому 1
|
||
* возвращается и во втором случае тоже. */
|
||
uint8_t pop_check_shadow(uint8_t room) __banked;
|
||
|
||
/* sword_disappears (seg002:0536) — спецсобытие уровня 12: уход ВПРАВО из
|
||
* комнаты 18 убирает меч из комнаты 15. Звать при уходе вбок ДО смены
|
||
* комнаты, рядом с чекпойнтом уровня 3. */
|
||
void pop_sword_disappears(void) __banked;
|
||
|
||
/* meet_Jaffar (seg002:0544) — уход ВПРАВО из комнаты 3 уровня 13 даёт
|
||
* Джафару фору; звать рядом с pop_sword_disappears (та же ветка leave_room).
|
||
* Jaffar_exit (seg002:0517) — уход ВЛЕВО при pop_leveldoor_open == 2 жмёт
|
||
* кнопку комнаты 24 и открывает дверь уровня. */
|
||
void pop_meet_jaffar(void) __banked;
|
||
void pop_jaffar_exit(void) __banked;
|
||
|
||
/* check_killed_shadow (seg006:2033) — спецсобытие уровня 12: смерть тени
|
||
* убивает Кида и наоборот. Звать раз в кадр ДО тиков персонажей, рядом с
|
||
* pop_check_skel; на прочих уровнях выходит первой строкой. */
|
||
void pop_check_killed_shadow(void) __banked;
|
||
|
||
/* timers (seg003:0735) — кадровые счётчики спецсобытий: вспышка слияния с
|
||
* тенью и фора Джафара. Звать раз в кадр из главного цикла. Резидент: два
|
||
* вычитания, банк ради них не разворачиваем. */
|
||
void pop_frame_timers(void);
|
||
|
||
/* guard_notice_timer (seg000:307) — фора Джафара после встречи: пока >0, он
|
||
* не встаёт в боевую стойку. Ставит pop_meet_jaffar, убавляет
|
||
* pop_frame_timers, читает autocontrol_guard_inactive. */
|
||
extern int8_t pop_guard_notice_timer;
|
||
|
||
/* Боёвка: пометить попадания (обе стороны) и применить их. Порядок в
|
||
* кадре как в play_frame: hurting -> hurt -> do_delta_hp. */
|
||
void pop_check_sword_hurting(void) __banked;
|
||
void pop_check_sword_hurt(void) __banked;
|
||
|
||
/* Текущий кадр стража (порт cur_frame для Char): заполняет логика в W1/W2,
|
||
* читает отрисовка в резиденте W3. image == 255 — рисовать нечего. */
|
||
extern kframe pop_gframe;
|
||
void pop_guard_load_frame(void);
|
||
|
||
/* check_guard_fallout (seg002:0241): убрать персонажа слота Guard, если он
|
||
* провалился ниже комнаты. Звать раз в кадр после физики и HP — как
|
||
* play_frame (seg000:884). */
|
||
void pop_guard_fallout(void);
|
||
|
||
/* Есть ли живой страж в отрисованной комнате (для главного цикла). */
|
||
uint8_t pop_guard_present(void);
|
||
|
||
/* Атласы стража (GUARD\\g0..g4.atl) — грузить ДО initgraph, как Kid.
|
||
* 0 — OK, -1 — ошибка (тогда страж просто не рисуется). */
|
||
int pop_guard_load(void) __banked;
|
||
|
||
/* Зеркальный ПО ВЕРТИКАЛИ набор соперника (файлы *_v.atl) — для зелья
|
||
* инверсии; зовётся из pop_vflip_load_all (pop_vflip.h). Живёт рядом с
|
||
* pop_guard_load: там же gp[] и выбор GUARD/SKEL. */
|
||
int pop_guard_vflip_load(void) __banked;
|
||
void pop_guard_free(void) __banked;
|
||
|
||
/* Вход в комнату: поднять стража из данных уровня (порт enter_guard,
|
||
* seg002:0112) либо убрать его, если в комнате стража нет. */
|
||
void pop_guard_enter(uint8_t room);
|
||
|
||
/* Запомнить стража УХОДЯЩЕЙ комнаты (порт leave_guard). Звать в начале
|
||
* enter_room, пока Guard ещё держит прежнего. */
|
||
void pop_guard_leave(void);
|
||
|
||
/* Страж идёт ЗА КИДОМ в соседнюю комнату — порт ветки стража из exit_room
|
||
* (seg002:0340) + follow_guard (seg002:039E). Звать ВМЕСТО пары
|
||
* leave/enter при смене комнаты: 1 = страж уже перенесён в new_room (ни
|
||
* leave, ни enter звать нельзя), 0 = остаётся в старой (всё как раньше).
|
||
* side — куда ушёл КИД: 0 left, 1 right, 2 up, 3 down. */
|
||
uint8_t pop_guard_follow(uint8_t new_room, uint8_t side);
|
||
|
||
/* Полоса HP (Кид слева, страж справа) в статус-полосе. Рисует главный цикл
|
||
* ПОСЛЕ персонажей — она ничего не перекрывает. */
|
||
void pop_hp_draw(void) __banked;
|
||
/* Полоса стёрта перерисовкой фона (вход в комнату) — обновить обе страницы. */
|
||
void pop_hp_invalidate(void) __banked;
|
||
|
||
/* Цвет стража — подменой 16 слотов палитры (порт set_chtab_palette,
|
||
* seg003:257): спрайты лежат в индексах POP_GUARD_PAL_BASE + v, а цвет
|
||
* задаёт level.guards_color[room-1] (1..7; 0 = не менять). Звать ДО
|
||
* отрисовки комнаты, как это делает redraw_screen. */
|
||
void pop_guard_set_palette(uint8_t color) __banked;
|
||
|
||
/* Отрисовка соперника — общая на всех Char: pop_char_draw(POP_CH_OPP) и
|
||
* компания, см. pop_cdraw.h. Метрики его последнего кадра (в т.ч. ширина
|
||
* спрайта для char_width_half) — pop_cd[POP_CH_OPP]. */
|
||
|
||
/* Убрать стража со сцены (смена комнаты / инициализация). */
|
||
void pop_guard_reset(void);
|
||
|
||
/* Чит «убить стража» (seg000:786, K): скелета не берёт. Вызывать только
|
||
* при включённых читах — проверку делает вызывающий. */
|
||
void pop_guard_kill(void);
|
||
|
||
/* do_delta_hp (seg003): применить дельту HP, накопленную за кадр. Звать
|
||
* раз в кадр ПОСЛЕ тиков персонажей (в оригинале — в play_frame). */
|
||
void pop_do_delta_hp(void);
|
||
|
||
/* Тик логики стража — В БАНКЕ (guards.c). Состояние берёт отсюда. */
|
||
void pop_guard_tick(void) __banked;
|
||
|
||
#endif
|