Мышь уровня 8 + холодная половина главного цикла в банк 8
Спецсобытие уровня 8 (SDLPoP seg003:0545/0ABA, seg002:07EB): когда дверь уровня открыта, а Кид остаётся в комнате 16, через 150 кадров приходит мышь, пробегает справа налево по верхнему ряду, наступает на кнопку (0,7) — решётка (0,3) открывается — и убегает. Ассетов не потребовалось: кадры 186..188 идут по таблице Кида, их спрайты (images 130..132) уже лежат в kid16.atl, отрисовка подхватывает мышь сама. - guards.c: pop_check_mouse, autocontrol_mouse, ветки мыши в autocontrol_opponent / play_guard / check_can_guard_see_kid; - pop_leveldoor_open стал word, как в оригинале (в него же считается задержка — байт переполнился бы через 255 кадров); - leave_guard больше не записывает тень и мышь в данные уровня (seg002:02F5); - полосы HP у мыши нет (seg000:1159); - tests-host/t_mouse: 17 проверок, единственный набор с guards.c. Разгрузка резидента (куча в huge упала до 879 Б): pop_start_level, find_start_level_door, чит-навигация по комнатам и лейбл номера уехали в roomtest_cold.c (--bank 8, n_banks = 8). _CODE 25653 -> 24825, куча -> 1707 Б; кадровый путь не тронут. Проверено: tests-host 6/6, make size-check OK, живьём в MAME (мышь появилась, нажала кнопку, решётка поехала вверх, мышь ушла). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,10 @@ void pop_check_can_guard_see_kid(void) __banked
|
||||
int16_t left_pos, right_pos;
|
||||
uint8_t tile;
|
||||
|
||||
/* МЫШЬ Кида «не видит» (seg003:0965): иначе он выхватит меч на зверька,
|
||||
* пробегающего мимо. */
|
||||
if (Guard.charid == CHARID_24_MOUSE) { can_guard_see_kid = 0; return; }
|
||||
|
||||
/* Первый множитель — порт seg003:702. ТЕНЬ боевая только на 12-м
|
||||
* уровне; на 4/5/6 она Кида «не видит», и это не косметика: увидев её,
|
||||
* Кид достаёт меч (control_standing, seg005:352), а сама тень идёт той
|
||||
@@ -198,6 +202,50 @@ void pop_check_skel(void) __banked
|
||||
is_guard_notice = guard_refrac = 0;
|
||||
}
|
||||
|
||||
/* ---- Мышь: спецсобытие уровня 8 (do_timers seg003:0545 + do_mouse) --- *
|
||||
*
|
||||
* Кнопка (0,7) комнаты 16 открывает решётку (0,3), но с левой площадки
|
||||
* верхнего ряда до кнопки не дойти — между ними провал в три колонки.
|
||||
* Поэтому, когда дверь уровня уже открыта, а Кид всё ещё в комнате 16,
|
||||
* оригинал через POP_MOUSE_DELAY кадров присылает мышь: она пробегает
|
||||
* справа налево, наступает на кнопку (кнопку жмёт ОБЩИЙ check_press из
|
||||
* физики соперника, как и любой персонаж) и убегает обратно.
|
||||
*
|
||||
* Счётчик — сам pop_leveldoor_open, как в оригинале: он растёт ТОЛЬКО пока
|
||||
* Кид в комнате 16, поэтому «12,5 секунды» отсчитываются с момента, когда
|
||||
* игрок туда вернулся, а не с открытия двери. Ради этого он и word
|
||||
* (см. pop_state.c).
|
||||
*
|
||||
* Слот соперника занимаем БЕЗ проверки «свободен ли» — так в оригинале, и
|
||||
* на уровне 8 конфликта нет: в данных комнаты 16 стража нет
|
||||
* (guards_tile[15] = 30 = «пусто»). */
|
||||
#define SEQ_105_MOUSE_FORWARD 105
|
||||
#define SEQ_107_MOUSE_STAND_UP_GO 107
|
||||
|
||||
void pop_check_mouse(void) __banked
|
||||
{
|
||||
if (pop_current_level != POP_MOUSE_LEVEL) return;
|
||||
if (Kid.room != POP_MOUSE_ROOM) return;
|
||||
if (!pop_leveldoor_open) return;
|
||||
if (++pop_leveldoor_open != POP_MOUSE_DELAY) return;
|
||||
|
||||
/* do_mouse (seg003:0ABA) поднимает мышь В ОКНЕ Char, начиная с КИДА
|
||||
* (loadkid): поля, которых нет в списке ниже — frame/action/room/
|
||||
* fall_x/fall_y — наследуются от него. Комната как раз оттуда и
|
||||
* берётся, отдельного присваивания в оригинале нет. */
|
||||
pop_loadkid();
|
||||
Char.charid = CHARID_24_MOUSE;
|
||||
Char.x = POP_MOUSE_START_X;
|
||||
Char.curr_row = 0;
|
||||
Char.y = (uint8_t)pop_y_land[1];
|
||||
Char.alive = -1;
|
||||
Char.direction = -1; /* dir_FF_left */
|
||||
guardhp_curr = 1;
|
||||
pop_char_set_seq(SEQ_105_MOUSE_FORWARD);
|
||||
play_seq();
|
||||
pop_saveshad();
|
||||
}
|
||||
|
||||
/* ---- Тень: спецсобытие входа в комнату (check_shadow, seg002:0064) -- *
|
||||
*
|
||||
* На «шадоу»-уровнях слот соперника занимает ТЕНЬ, и занимает его ВМЕСТО
|
||||
@@ -638,6 +686,26 @@ static void autocontrol_shadow_level6(void)
|
||||
move_1_forward();
|
||||
}
|
||||
|
||||
/* autocontrol_mouse (seg002:07EB). Весь «ИИ» мыши — два порога по X:
|
||||
* добежала влево до POP_MOUSE_TURN_X → seq_107 (встать, поднять голову,
|
||||
* развернуться и уйти), вернулась вправо до POP_MOUSE_LEAVE_X → исчезнуть.
|
||||
*
|
||||
* Почему проверка на исчезновение висит на action == 0 (стойка), хотя мышь
|
||||
* при этом БЕЖИТ: seq_107 заканчивается прыжком на метку `Mscurry1`, которая
|
||||
* стоит ПОСЛЕ опкода act(actions_1_run_jump) в seq_105 — то есть на обратном
|
||||
* пути кадры бега проигрываются, а action остаётся стоечным. Именно этим
|
||||
* оригинал и различает «бежит туда» и «бежит обратно». */
|
||||
static void autocontrol_mouse(void)
|
||||
{
|
||||
if (Char.direction == DIR_56_NONE) return;
|
||||
if (Char.action == 0) {
|
||||
if (Char.x >= POP_MOUSE_LEAVE_X) clear_char();
|
||||
} else if (Char.x < POP_MOUSE_TURN_X) {
|
||||
pop_char_set_seq(SEQ_107_MOUSE_STAND_UP_GO);
|
||||
play_seq();
|
||||
}
|
||||
}
|
||||
|
||||
/* autocontrol_shadow (seg002:081D) — по уровням. Ветка 12 появится со своим
|
||||
* уровнем. */
|
||||
static void autocontrol_shadow(void)
|
||||
@@ -658,6 +726,8 @@ static void autocontrol_opponent(void)
|
||||
/* autocontrol_skeleton (seg002:685): у скелета меч вынут ВСЕГДА — он не
|
||||
* бывает «неактивным», поэтому ветка inactive ему недоступна. */
|
||||
if (Char.charid == CHARID_4_SKELETON) Char.sword = SWORD_2_DRAWN;
|
||||
/* МЫШЬ — своей веткой (seg002:0643), первой в цепочке charid'ов. */
|
||||
if (Char.charid == CHARID_24_MOUSE) { autocontrol_mouse(); return; }
|
||||
/* ТЕНЬ идёт своей веткой ЦЕЛИКОМ (seg002:0647): к стражьему ИИ она не
|
||||
* сводится — на уровне 4 не дерётся вовсе. */
|
||||
if (Char.charid == CHARID_1_SHADOW) { autocontrol_shadow(); return; }
|
||||
@@ -780,6 +850,11 @@ void pop_check_sword_hurt(void) __banked
|
||||
* доигрывает последовательность. */
|
||||
static void play_guard(void)
|
||||
{
|
||||
/* МЫШЬ (seg006:0D85, первая ветка): ей положен ТОЛЬКО автоконтроль.
|
||||
* Диспетчер control() ей не нужен и вреден — он бы гонял её по
|
||||
* стоечным веткам управления, а вся её «жизнь» уже описана
|
||||
* последовательностями seq_105/107. */
|
||||
if (Char.charid == CHARID_24_MOUSE) { autocontrol_opponent(); return; }
|
||||
if (Char.alive < 0 && guardhp_curr == 0) {
|
||||
Char.alive = 0;
|
||||
/* on_guard_killed (seg006:1927) — у нас пока только звук победы,
|
||||
|
||||
Reference in New Issue
Block a user