L4-MIRROR шаг 4: прыжок сквозь зеркало и рождение тени
Порт seg003:0798..08A9 + seg004:0239 + seg002:081D/1131 + seg006:1945. - is_obstacle (pop_map.c): ветка зеркала — Кид, кадры бегового прыжка 39..43, направление ВЛЕВО -> modif = 0x56, pop_jumped_mirror = -1, препятствия нет (пролетает насквозь). - mirror_image / jump_through_mirror / pop_check_mirror (pop_map.c): отражённый Char уходит в слот Guard как CHARID_1_SHADOW, guardhp = hitp_max, у Кида hitp_curr = 1. savekid НЕ делается — как в оригинале, отражается только копия. Полосы HP перерисует pop_hp_draw сам. - pop_check_mirror() зовётся из главного цикла ПЕРЕД отрисовкой персонажей (в оригинале — первая строка draw_people, seg008:228A). - autocontrol_shadow + autocontrol_shadow_level4 + clear_char (guards.c): тень идёт СВОЕЙ веткой целиком, к стражьему ИИ не сводится — на уровне 4 она не дерётся, а бежит влево и при x < 80 исчезает. АТЛАС ТЕНИ — вскрылось при чтении seg006:0532. Тень вне боевых кадров 150..189 ходит по таблице КИДА, и image оттуда индексирует спрайты Кида, а не стража. Выбор атласа в pop_cdraw шёл по СЛОТУ, то есть тень рисовалась бы спрайтами стража. Условие вынесено в pop_frame_tbl_is_guard() (pop_kid.c) — его теперь читают и load_frame, и отрисовка, разъехаться не могут. Заодно из pop_load_fram_det_col выделен pop_load_frame() без determine_col: jump_through_mirror берёт ось отражения из curr_col, и пересчёт колонки по x там был бы вреден. Константы MIRROR_* и DIR_56_NONE переехали в pop_guard.h — нужны и постановке тайла (банк 6), и ИИ тени (банк 1). Звука sound_45_jump_through_mirror в порте нет, пропущен. Шаг 5 (клип тени слева от зеркала) НЕ сделан и оказался не однострочником: в pop_cdraw есть клип сверху/снизу/справа, левого нет вовсе — нужен новый примитив либо срез исходных колонок. Расписано в TASKS_OPEN. Цена: _CODE +18 Б, банк 1 2311 -> 2367, банк 3 10328 -> 10551, банк 4 8243 -> 8267. tests-host: все 5 наборов прошли. НЕ ПРОВЕРЕНО В MAME — сценарий проверки записан в TASKS_OPEN. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1746,7 +1746,19 @@ static uint8_t is_obstacle_at_col(int8_t col)
|
||||
if (t == TILE_CHOMPER) /* закрыт только при modif==2 */
|
||||
return (uint8_t)(col >= 0 && col <= 9 &&
|
||||
pop_trob_modif(g_room)[Char.curr_row * 10 + col] == 2);
|
||||
/* ветка «прыжок сквозь зеркало» (seg004:239) — уровень 4, не портируем */
|
||||
/* Прыжок СКВОЗЬ ЗЕРКАЛО (seg004:0239). Зеркало вообще-то «стена слева»
|
||||
* (wall_type = 2), но для Кида в БЕГОВОМ ПРЫЖКЕ справа налево оно
|
||||
* перестаёт быть препятствием: он пролетает насквозь, зеркало «бьётся»
|
||||
* (modif 0x56) и взводится флаг рождения тени. Условия — все четыре, как
|
||||
* в оригинале: только Кид, только кадры бегового прыжка 39..43, только
|
||||
* направление влево. */
|
||||
if (t == TILE_MIRROR && Char.charid == CHARID_0_KID &&
|
||||
Char.frame >= 39 && Char.frame < 44 && Char.direction < 0 &&
|
||||
col >= 0 && col <= 9) {
|
||||
pop_trob_modif(g_room)[Char.curr_row * 10 + col] = 0x56;
|
||||
pop_jumped_mirror = -1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2552,3 +2564,60 @@ void pop_guard_phys_tick(void) __banked
|
||||
}
|
||||
pop_saveshad_and_opp();
|
||||
}
|
||||
|
||||
/* ---- Зеркало уровня 4 (порт seg003:0798..08A9) ---------------------- *
|
||||
*
|
||||
* Тайл зеркала ставится в рантайме (pop_trob.c place_mirror), а «стеной
|
||||
* слева» он уже был — wall_type = 2 портирован давно. Здесь вторая часть:
|
||||
* что происходит ПОСЛЕ того, как Кид пролетел сквозь него беговым прыжком
|
||||
* (флаг pop_jumped_mirror взводит is_obstacle выше по файлу). */
|
||||
|
||||
/* check_mirror_image (seg003:085B). МУТИРУЕТ Char НА МЕСТЕ: x отражается
|
||||
* относительно оси зеркала, direction инвертируется. Возвращает
|
||||
* distance_mirror — насколько персонаж вошёл в тайл (оригинал по нему
|
||||
* решает, рисовать ли отражение; нам это понадобится на шаге «отражение»).
|
||||
*
|
||||
* Мутация Char здесь ЗАДУМАНА, а не побочный эффект: оригинал зовёт эту
|
||||
* функцию из двух мест, и оба на неё рассчитывают — при рисовании отражения
|
||||
* (в Char временная копия Кида, обратно она не сохраняется) и при рождении
|
||||
* тени (мутированный Char уходит в слот Guard). */
|
||||
static int8_t mirror_image(void)
|
||||
{
|
||||
/* +10 — смещение оси зеркала внутри тайла; в оригинале так и написано
|
||||
* комментарием («I think 10 is the offset for mirror collision»). */
|
||||
int xpos = pop_x_bump[Char.curr_col + FIRST_ONSCREEN_COLUMN] + 10;
|
||||
int distance = distance_to_edge_weight();
|
||||
if (Char.direction >= 0) distance = ~distance + TILE_SIZEX;
|
||||
Char.x = (uint8_t)((xpos << 1) - (int)Char.x);
|
||||
Char.direction = (int8_t)~Char.direction;
|
||||
return (int8_t)(distance - 2);
|
||||
}
|
||||
|
||||
/* jump_through_mirror (seg003:080A): рождение ТЕНИ. Кид копируется в слот
|
||||
* Guard уже отражённым; HP меняются местами — у тени полное здоровье Кида, у
|
||||
* самого Кида остаётся 1. Полосы HP отдельно перерисовывать не надо:
|
||||
* pop_hp_draw сравнивает числа и смену увидит сам.
|
||||
*
|
||||
* savekid здесь НЕТ и в оригинале: собственные x/direction Кида остаются
|
||||
* прежними, отражается только копия, уходящая в слот Guard. */
|
||||
static void jump_through_mirror(void)
|
||||
{
|
||||
pop_loadkid();
|
||||
pop_load_frame(); /* mirror_image смотрит на dx/flags КАДРА */
|
||||
(void)mirror_image();
|
||||
pop_jumped_mirror = 0;
|
||||
Char.charid = CHARID_1_SHADOW;
|
||||
/* play_sound(45) — звука в порте пока нет */
|
||||
pop_saveshad();
|
||||
guardhp_max = guardhp_curr = hitp_max;
|
||||
hitp_curr = 1;
|
||||
}
|
||||
|
||||
void pop_check_mirror(void) __banked
|
||||
{
|
||||
if (pop_jumped_mirror == -1) jump_through_mirror();
|
||||
/* Ветка ОТРИСОВКИ ОТРАЖЕНИЯ (шаг 3 задачи L4-MIRROR) сюда добавится
|
||||
* позже: пока Кид стоит на тайле зеркала, оригинал каждый кадр рисует
|
||||
* его зеркальную копию типом 4 objtable с клипом left = (curr_col<<5)+9
|
||||
* и top = y_clip[curr_row+1]. */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user