PoP roomtest: страж замечает Кида и достаёт меч (ИИ, шаг 1)
Первый самостоятельный кусок ИИ стража (план, пункт 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>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include <kbd_raw.h>
|
||||
#include "pop_kid.h"
|
||||
#include "pop_map.h"
|
||||
#include "pop_guard.h" /* charid, состояние меча, seq стража */
|
||||
|
||||
/* Отладочные клавиши осторожного шага (эмуляция Shift+стрелка) для тестов в
|
||||
* MAME, где Shift трудно подать: J = шаг влево, L = шаг вправо. PS/2 set2
|
||||
@@ -74,7 +75,7 @@
|
||||
* X LEFT/-1..RIGHT/+1); *_forward/backward/up/down/shift2 — конечный
|
||||
* автомат held/released/ignore (авто-повтор); ctrl1_* — их память между
|
||||
* кадрами (rest/save). */
|
||||
static int8_t control_x, control_y, control_shift;
|
||||
int8_t control_x, control_y, control_shift;
|
||||
/* НЕ static: в оригинале это глобалы, через которые ИИ стража подаёт
|
||||
* СИНТЕТИЧЕСКИЙ ввод (autocontrol_*, seg002), а дальше работает тот же
|
||||
* control(), что и у игрока. Поэтому шина общая. */
|
||||
@@ -324,7 +325,43 @@ static void control_jumpup(void)
|
||||
standing_jump();
|
||||
}
|
||||
|
||||
/* control() — диспетчер по кадру (seg005.c:252), Kid жив, без меча. */
|
||||
/* draw_sword (seg005:945): достать меч. Кид переходит в seq_55 (подъём
|
||||
* клинка со звуком), соперник — сразу в стойку en garde (seq_90). Стрелки
|
||||
* гасятся, чтобы «вперёд», которым меч достали, не сработало второй раз
|
||||
* уже как выпад. */
|
||||
static void draw_sword(void)
|
||||
{
|
||||
uint8_t seq_id = SEQ_55_DRAW_SWORD;
|
||||
control_forward = control_shift2 = release_arrows();
|
||||
if (Char.charid != CHARID_0_KID && Char.charid != CHARID_1_SHADOW)
|
||||
seq_id = SEQ_90_EN_GARDE;
|
||||
/* TODO: у Кида здесь play_sound(19) + offguard = 0 — звука пока нет. */
|
||||
Char.sword = SWORD_2_DRAWN;
|
||||
seqtbl_offset_char(seq_id);
|
||||
}
|
||||
|
||||
/* control_guard_inactive (seg006:2123): неактивный страж реагирует ТОЛЬКО в
|
||||
* кадре 166 (стойка) и только на «вниз»: вниз+вперёд — достать меч,
|
||||
* вниз без «вперёд» — развернуться (stand flipped). */
|
||||
static void control_guard_inactive(void)
|
||||
{
|
||||
if (Char.frame == FRAME_166_STAND_INACTIVE && control_down == CONTROL_HELD) {
|
||||
if (control_forward == CONTROL_HELD) {
|
||||
draw_sword();
|
||||
} else {
|
||||
control_down = CONTROL_IGNORE;
|
||||
seqtbl_offset_char(SEQ_80_STAND_FLIPPED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* control_with_sword (seg005:964) — боёвка. Порт следующим шагом; пока
|
||||
* персонаж с обнажённым мечом просто держит стойку. */
|
||||
static void control_with_sword(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* control() — диспетчер по кадру (seg005.c:252) для АКТИВНОГО персонажа. */
|
||||
void pop_control(void)
|
||||
{
|
||||
uint8_t f = Char.frame;
|
||||
@@ -338,7 +375,13 @@ void pop_control(void)
|
||||
release_arrows();
|
||||
return;
|
||||
}
|
||||
if (f == FRAME_15_STAND || (f >= FRAME_50_TURN && f < 53))
|
||||
/* Порядок веток — как в seg005: меч старше charid, charid старше кадров.
|
||||
* Пока Kid безоружен, обе ветки — про стража. */
|
||||
if (Char.sword == SWORD_2_DRAWN)
|
||||
control_with_sword();
|
||||
else if (Char.charid >= CHARID_2_GUARD)
|
||||
control_guard_inactive();
|
||||
else if (f == FRAME_15_STAND || (f >= FRAME_50_TURN && f < 53))
|
||||
control_standing();
|
||||
else if (f == FRAME_48_TURN)
|
||||
control_turning();
|
||||
|
||||
Reference in New Issue
Block a user