From 1c91c5f92adbb8ef5e26357eceaac71969a42652 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Wed, 29 Jul 2026 16:46:09 +0300 Subject: [PATCH] =?UTF-8?q?PoP=20roomtest:=20=D0=BC=D0=B5=D1=87=20?= =?UTF-8?q?=E2=80=94=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=83,=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D1=8A=D1=91=D0=BC=20=D0=BF=D0=BE=20Shift,=20=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=82=D1=83=D1=81=20have=5Fsword?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Комната 15, тайл (2,2): меч не рисовался вовсе — в draw_tile не было ветки tiles_22_sword (seg008 draw_tile_anim): add_midtable(chtab_1, (modifier == 1) + 10, draw_xh, 0, draw_main_y - 3, ...) Спрайты уже лежали в нашем pot-атласе (chtab_1 пакуется целиком, id 1..23), так что понадобился только вызов. У нас предмет рисуется статикой в фоне, а не в midtable: пока меч лежит, он не анимируется, а Kid и так поверх фона. Подъём — порт цепочки оригинала: - check_get_item/get_item (seg005:061F/073E) -> pop_get_item_action() в pop_map (тайлы): стоя НА предмете отступить на тайл назад, подровняться по кромке и присесть; из приседа над мечом — поднять; - do_pickup (seg006:1671): тайл -> пол, pop_item_taken = tilepos+1; roomtest запекает пол на ОБЕИХ страницах (pop_floor_bake) и пишет per-room override, чтобы меч не воскресал при возврате в комнату; - триггер — Shift (control_shift2) в стойке и в приседе, как в control_standing/control_crouched; - seq_91 pickupsword: опкод SEQ_GET_ITEM с аргументом 1 в play_seq теперь зовёт pop_proc_get_object (seg006:16CB) -> pop_have_sword = 1. Статус: pop_have_sword. Боевой режим (стойка с мечом, бой) НЕ делаем и он тут не нужен: seq_91 сам заканчивается убиранием меча в ножны (кадры 230..240) и возвратом в обычную стойку — как в оригинале до встречи со стражем. Питьё зелий не портировано: над зельем Kid только приседает (get_item возвращает «не обработано»). Проверено в MAME (комната 15): меч виден на полу, Shift над ним даёт присед -> кадр 229 «нашёл меч» -> ножны -> стойка; меч с пола исчезает, pop_have_sword = 1. Co-Authored-By: Claude Opus 5 --- applications/PoP/roomtest/bug_list.md | 2 +- applications/PoP/roomtest/hang_variants.png | Bin 0 -> 15800 bytes applications/PoP/roomtest/pop_bg.c | 6 ++ applications/PoP/roomtest/pop_ctrl.c | 24 ++++++++ applications/PoP/roomtest/pop_kid.c | 5 +- applications/PoP/roomtest/pop_map.c | 62 ++++++++++++++++++++ applications/PoP/roomtest/pop_map.h | 9 +++ applications/PoP/roomtest/roomtest.c | 14 +++++ 8 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 applications/PoP/roomtest/hang_variants.png diff --git a/applications/PoP/roomtest/bug_list.md b/applications/PoP/roomtest/bug_list.md index a4f7ebd..8ef936a 100644 --- a/applications/PoP/roomtest/bug_list.md +++ b/applications/PoP/roomtest/bug_list.md @@ -451,7 +451,7 @@ Kid ставится на первый пол, `pop_trob_reset()` возвращ | 12 | пофикшено | вис/подтягивание на кромке loose-плиты: плита рисовалась ПОД Кидом. Не хватало двух кусков `draw_tile`: (а) `draw_loose` кладёт нижнюю грань плиты И в foretable (поверх персонажа), (б) `draw_tile_base` подставляет верх плиты из `loose_fram_left`, а в нашем midtable-оверлее стоял голый `base_id` (у loose он 0). Голова Кида поверх падающей на него плиты — см. «НЕ БАГИ» | | 13 | недостижима в игре | | | 14 | | | -| 15 | | | +| 15 | сделано | меч (2,2) не рисовался: тайл 22 в draw_tile_anim не был портирован. Добавлены отрисовка предмета (chtab_1 id 10/11 на draw_main_y−3), подъём по Shift (check_get_item/get_item/do_pickup: присед → seq_91 pickupsword → меч исчезает с пола) и статус `pop_have_sword` | | 16 | | | | 17 | | | | 18 | недостижима в игре | | diff --git a/applications/PoP/roomtest/hang_variants.png b/applications/PoP/roomtest/hang_variants.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c177c156e31bd91554672edf54897594b7064c GIT binary patch literal 15800 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 D*UIZ( literal 0 HcmV?d00001 diff --git a/applications/PoP/roomtest/pop_bg.c b/applications/PoP/roomtest/pop_bg.c index bd6371a..f214448 100644 --- a/applications/PoP/roomtest/pop_bg.c +++ b/applications/PoP/roomtest/pop_bg.c @@ -583,6 +583,12 @@ static void draw_tile(int row, int col) if (sf > 0 && sf < 10 && SPIKES_FRAM_LEFT[sf]) env_b(SPIKES_FRAM_LEFT[sf], x, dmy - 2); } + /* Меч-предмет на полу (тот же draw_tile_anim, case tiles_22_sword): + * chtab_1 (наш pot-атлас), id = (modif==1)+10, низ на draw_main_y-3. + * В оригинале это midtable (рисуется вместе с объектами) — у нас статикой + * в фоне: пока меч лежит, он не анимируется, а Kid и так поверх фона. */ + if (row >= 0 && code == 22) + pot_b((uint8_t)((tile_mod(row, col) == 1) + 10), x, dmy - 3); /* --- draw_tile_fore (seg008.c:690) --- */ if (code == 20) { diff --git a/applications/PoP/roomtest/pop_ctrl.c b/applications/PoP/roomtest/pop_ctrl.c index 10bdc6e..9e435ae 100644 --- a/applications/PoP/roomtest/pop_ctrl.c +++ b/applications/PoP/roomtest/pop_ctrl.c @@ -51,6 +51,7 @@ #define SEQ_49_STAND_UP_FROM_CROUCH 49 #define SEQ_50_CROUCH 50 #define SEQ_79_CROUCH_HOP 79 +#define SEQ_91_PICKUP_SWORD 91 /* поднять меч (pickupsword) */ #define SEQ_STEP_BASE 28 /* +distance(1..14) = seq 29..42 шаг-N */ #define SEQ_39_UNSAFE_STEP 39 /* шаг за кромку (distance 11) */ #define SEQ_44_STEP_ON_EDGE 44 @@ -104,6 +105,22 @@ static void standing_jump(void) seqtbl_offset_char(SEQ_3_STANDING_JUMP); } +/* check_get_item (seg005:061F): решение по тайлам принимает pop_map, здесь + * только исполнение. Триггер в оригинале — Shift (control_shift2) в стойке + * или в приседе: первый раз Kid приседает к предмету, второй — поднимает. + * Возврат 1 = управление обработано (caller делает return). */ +static uint8_t get_item_action(void) +{ + uint8_t a = pop_get_item_action(); + if (a == 1) { crouch(); return 1; } + if (a == 2) { + control_shift2 = CONTROL_IGNORE; /* do_pickup: без авто-повтора */ + seqtbl_offset_char(SEQ_91_PICKUP_SWORD); + return 1; + } + return 0; +} + static void run_jump(void) { /* Оригинал выравнивает Kid по краю пола (нужны tile-запросы) — это @@ -191,6 +208,8 @@ static void safe_step(void) /* ---- control_* обработчики состояний ------------------------------ */ static void control_crouched(void) { + /* Shift в приседе — поднять предмет (seg005 control_crouched). */ + if (control_shift2 == CONTROL_HELD && get_item_action()) return; if (control_y != CONTROL_HELD_DOWN) { seqtbl_offset_char(SEQ_49_STAND_UP_FROM_CROUCH); } else if (control_forward == CONTROL_HELD) { @@ -201,6 +220,11 @@ static void control_crouched(void) static void control_standing(void) { + /* Shift в стойке над предметом — присесть к нему (seg005:0358, первая + * строка control_standing). Идёт ДО остальных shift-веток. */ + if (control_shift2 == CONTROL_HELD && control_shift == CONTROL_HELD && + get_item_action()) + return; /* Kid charid_0, без меча: остаётся нижняя часть control_standing. */ if (control_shift == CONTROL_HELD) { if (control_backward == CONTROL_HELD) back_pressed(); diff --git a/applications/PoP/roomtest/pop_kid.c b/applications/PoP/roomtest/pop_kid.c index c725e94..261dab7 100644 --- a/applications/PoP/roomtest/pop_kid.c +++ b/applications/PoP/roomtest/pop_kid.c @@ -125,7 +125,10 @@ void play_seq(void) break; case 0xF1: /* END_LEVEL */ break; - case 0xF3: /* GET_ITEM — потребить 1 байт */ + case 0xF3: /* GET_ITEM: аргумент 1 — применить эффект предмета + * (порт play_seq -> proc_get_object, seg006) */ + if (SEQ(Kid.curr_seq) == 1) + pop_proc_get_object(); Kid.curr_seq++; break; case 0xF6: /* DIE nop */ diff --git a/applications/PoP/roomtest/pop_map.c b/applications/PoP/roomtest/pop_map.c index 819e92d..0f1a9ca 100644 --- a/applications/PoP/roomtest/pop_map.c +++ b/applications/PoP/roomtest/pop_map.c @@ -69,6 +69,9 @@ #define SEQ_73_CLIMB_UP_TO_GATE 73 /* подъём к закрытой калитке */ #define SEQ_51_SPIKED 51 /* напороться на пики (смерть) */ +#define TILE_FLOOR 1 +#define FRAME_109_CROUCH 109 + /* Кадры анимации для check_spiked (seg006:0658). */ #define FRAME_7_RUN 7 #define FRAME_26_STANDJUMP_LAND 26 @@ -763,6 +766,65 @@ uint8_t pop_down_action(void) return 0; } +/* ---- Предметы: меч (seg005 check_get_item/get_item + seg006 do_pickup/ + * proc_get_object) --------------------------------------------------- * + * pop_have_sword — порт глобала have_sword: «меч у Кида». Боевой режим + * (стойка с мечом, бой) НЕ реализован и здесь не нужен: сиквенс подъёма + * seq_91 сам заканчивается убиранием меча в ножны (кадры 230..240 sheathe) + * и возвратом в обычную стойку — как в оригинале до встречи со стражем. */ +uint8_t pop_have_sword; +uint8_t pop_item_taken; /* 0 = нет; иначе tilepos+1 поднятого */ +static int8_t pickup_obj_type; /* -1 = меч (порт pickup_obj_type) */ + +/* do_pickup (seg006:1671): стереть предмет с карты (тайл → пол) и запомнить + * тип; сам эффект применяет опкод GET_ITEM внутри сиквенса. */ +static void do_pickup(int8_t obj_type, uint8_t tilepos) +{ + pickup_obj_type = obj_type; + g_fg[tilepos] = TILE_FLOOR; + pop_item_taken = (uint8_t)(tilepos + 1); +} + +/* proc_get_object (seg006:16CB): эффект поднятого предмета. Зовётся из + * play_seq по опкоду SEQ_GET_ITEM с аргументом 1 (pop_kid). */ +void pop_proc_get_object(void) +{ + if (pickup_obj_type == -1) + pop_have_sword = 1; /* в оригинале have_sword = -1 */ + pickup_obj_type = 0; /* зелья (типы 1..6) не портированы */ +} + +/* check_get_item + get_item (seg005:061F/073E). Возврат: 0 — предмета нет + * (управление идёт обычной веткой); 1 — присесть (caller зовёт crouch()); + * 2 — поднять меч (caller ставит seq_91). */ +uint8_t pop_get_item_action(void) +{ + uint8_t t; + int8_t icol; + t = get_tile_at_char(); + if (t == TILE_POTION || t == TILE_SWORD) { /* стоим НА предмете */ + if (!tile_is_floor(get_tile_behind_char())) return 0; + Kid.x = (uint8_t)char_dx_forward(-TILE_SIZEX); /* отступить на тайл */ + determine_col(); + } + t = get_tile_infrontof_char(); /* заодно ставит g_infrontx */ + if (t != TILE_POTION && t != TILE_SWORD) return 0; + icol = g_infrontx; + if (icol < 0 || icol > 9) return 0; /* предмет за швом — не наш */ + if (Kid.frame != FRAME_109_CROUCH) { + /* Ещё стоим: подровняться к предмету и присесть. */ + int d = pop_edge_distance(); /* ставит g_edge_type */ + if (g_edge_type != EDGE_FLOOR) + Kid.x = (uint8_t)char_dx_forward((int8_t)d); + if (Kid.direction >= 0) + Kid.x = (uint8_t)char_dx_forward((int8_t)((t == TILE_POTION) - 2)); + return 1; + } + if (t != TILE_SWORD) return 0; /* питьё зелий не портировано */ + do_pickup(-1, (uint8_t)(Kid.curr_row * 10 + icol)); + return 2; +} + /* ---- Диспетчер ----------------------------------------------------- */ static void check_on_floor(void) { diff --git a/applications/PoP/roomtest/pop_map.h b/applications/PoP/roomtest/pop_map.h index 5b0a5e2..317d4ae 100644 --- a/applications/PoP/roomtest/pop_map.h +++ b/applications/PoP/roomtest/pop_map.h @@ -37,6 +37,15 @@ extern uint8_t pop_kid_dead; extern uint8_t hitp_curr; void pop_kid_hp_reset(void); +/* Предметы (seg005 check_get_item/get_item, seg006 do_pickup/proc_get_object). + * pop_have_sword — «меч у Кида» (порт have_sword). pop_item_taken — 0 или + * tilepos+1 только что поднятого предмета: вызывающий обязан запечь тайл + * (он стал полом) на ОБЕИХ страницах и записать override комнаты. */ +extern uint8_t pop_have_sword; +extern uint8_t pop_item_taken; +uint8_t pop_get_item_action(void); /* 0 нет / 1 присесть / 2 поднять меч */ +void pop_proc_get_object(void); /* эффект — из play_seq (опкод GET_ITEM) */ + /* Уход из комнаты ВБОК/ВВЕРХ: 0=нет; 1=left,2=right,3=up (= side+1 для * pop_room_link). Координаты Kid уже репроецированы (x∓140 / y+189). * Приложение переключает комнату по соответствующей связи и снимает флаг. */ diff --git a/applications/PoP/roomtest/roomtest.c b/applications/PoP/roomtest/roomtest.c index 967d085..4f91d1b 100644 --- a/applications/PoP/roomtest/roomtest.c +++ b/applications/PoP/roomtest/roomtest.c @@ -85,9 +85,13 @@ static uint8_t room_label_redraw; * в docs/gates_spikes_plan.md, P0.) */ #define TILE_DEBRIS 0x0E #define TILE_EMPTY 0x00 +#define TILE_FLOOR 0x01 #define OVR_MAX 8 static uint8_t ovr_room[OVR_MAX], ovr_pos[OVR_MAX], ovr_tile[OVR_MAX], ovr_cnt; +/* Поднятый предмет (меч): tilepos и счётчик «запечь пол» по страницам. */ +static uint8_t item_pos, item_bake; + static void add_tile_override(uint8_t room, uint8_t pos, uint8_t tile) { uint8_t i; @@ -378,6 +382,16 @@ int main(void) add_tile_override(cur_room, (uint8_t)(pop_debris_at - 1), TILE_DEBRIS); pop_debris_at = 0; } + if (pop_item_taken) { /* предмет поднят → тайл стал полом */ + item_pos = (uint8_t)(pop_item_taken - 1); + item_bake = 2; /* запечь на ОБЕИХ страницах */ + add_tile_override(cur_room, item_pos, TILE_FLOOR); + pop_item_taken = 0; + } + if (item_bake) { /* стереть спрайт меча из фона страницы */ + pop_floor_bake(item_pos / 10, item_pos % 10); + item_bake--; + } io_border = 4; /* зеленый */ update_kid_render_dx(); /* straddle: смещение спрайта, если kid_room≠cur_room */ kid_draw(); /* нарисовать новый кадр (детект выхода за поле) */