Первый самостоятельный кусок ИИ стража (план, пункт 2). В оригинале у
соперника нет своего диспетчера: autocontrol_* (seg002) выставляет те же
глобалы control_*, что и ввод игрока, а дальше исполняется общий control().
Инфраструктура под это встала прошлым коммитом, здесь — сама логика.
Порт:
- check_can_guard_see_kid (seg003:688) — луч видимости по ряду: стены и
верхи дверей рвут его совсем, loose/чомпер/дыра/неподнятые ворота дают
«вижу, но не пойду». В guards.c (банк 1);
- Opp + loadshad_and_opp (seg006:841) и char_opp_dist (seg006:2135);
- autocontrol_guard_inactive (seg002:710) + move_* (seg002:0706..);
- ветки control(): control_guard_inactive (seg006:2123) и draw_sword
(seg005:945) — соперник уходит сразу в seq_90 en garde;
- pop_guard_tick перестроен по play_guard_frame (seg000:1246): окно
Char/Opp вокруг ИИ, диспетчера и play_seq.
По дороге:
- Kid.alive не выставлялся (= 0 = «мёртв» в семантике оригинала), из-за
чего луч видимости не мог сработать в принципе — ставим -1 в kid_init;
- Kid.room не выставлялась вовсе; условие Kid.room == Guard.room всегда
было ложным. Ставим в enter_room (полная модель Kid.room != drawn_room
у шва по-прежнему впереди);
- pop_tile_at — тайл текущей комнаты наружу из pop_map (луч видимости);
- control_x/y/shift открыты в шину: ИИ заполняет оси как есть, без
flip_control_x (его «вперёд» уже в системе персонажа).
Проверено в MAME (комната 3, страж на tile 17): страж переходит из
стойки 166 в 171 stand_with_sword, sword=2, can_guard_see_kid=2; ввод
игрока не пострадал. Клинок отдельным спрайтом пока не рисуется —
sword.atl содержит только кадры 229..237 (подъём меча Кидом), остальные
строки sword_tbl приедут с боёвкой.
Бюджет (225 кадров, комната 3): 384 168 – 384 636 тактов, 0.893–0.895
кадра, запас 45 364. Прошлый замер 382 584 – 383 064 — шаг стоил ~1 570.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Инфраструктура пункта 2. В оригинале у соперника НЕТ своего диспетчера:
autocontrol_* (seg002) выставляет те же глобалы control_*, что и ввод
игрока, а дальше исполняется тот же control() (seg005:252). Значит перед
портом ИИ надо было привести к этому обе половины:
- control_forward/backward/up/down/shift2 перестали быть static в
pop_ctrl.c — это общая шина синтетического ввода, объявлена в pop_ctrl.h
вместе с POP_CONTROL_*;
- control() переименован в pop_control() и работает с Char, а не с Kid;
- ввод игрока обёрнут в окно Char (loadkid/user_control/savekid), как в
play_frame оригинала.
Ловушка по дороге (ввод отвалился целиком, Kid не двигался): макрос
seqtbl_offset_char вёл на kid_set_seq, который пишет прямо в Kid, а
следом savekid затирал Kid копией Char со старой curr_seq. В оригинале
seqtbl_offset_char работает именно с Char — макрос переведён на
pop_char_set_seq. kid_set_seq остался для вызовов ВНЕ окна (pop_map).
Добавлен pop_savekid_state (Kid = Char без кадра): control() кадр не
трогает, а cur_frame в этот момент принадлежит тому, кто последним крутил
play_seq.
Проверено в MAME: бег и упор в стену работают как прежде.
Бюджет (комната 3, 125 кадров): 382 584..383 064 против 380 292..381 282,
то есть +2 300 тактов на копии окна. 0.891 кадра, запас 46 936.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Порт SDLPoP seg004/005/006 «hang state»:
- pop_map: check_grab (зацеп за уступ в падении по Shift → seq_15 → вис),
can_grab/can_grab_front_above + tile-запросы над/за персонажем;
pop_jump_up_seq (check_jump_up: ↑ в стойке = чистый прыжок seq_28/14
ЛИБО прыжок-с-зацепом seq_8/24/16 за уступ выше → запрыгнуть на этаж);
pop_hang_* (climb_up seq_10/73, hang_fall seq_23/11, hang-у-стены);
pop_down_action (спуск seq_68 у края лицом от края / отступ / присед).
- pop_ctrl: control_hanging/can_climb_up/hang_fall, control_jumpup,
jump_up через pop_jump_up_seq, down_pressed через pop_down_action;
pop_ctrl_shift_held() для check_grab.
Ключевой фикс check_bumped (seg004 guard'ы): не бампить при action
hang_climb/hang_straight, на кадрах подъёма/спуска 135..148 И на кадрах
виса 87..99. Без последнего спуск (seq_68) на кадре frame_91 (action
ещё midair, act(hang_climb) идёт следующим опкодом) ловил отскок у стены
и рвал цепочку hang→hang_fall→seq_11, приземляя не туда.
Проверено в MAME (HDD-тест, покадровая трасса через мост): прыжок-с-
зацепом [row2 col4]→вис→подтягивание→[row1 col3]; спуск [row1 col3]→
[row2 col4] с корректной позицией у стены (x=122, совпадает с SDLPoP).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>