PoP roomtest: меч — отрисовка на полу, подъём по Shift, статус have_sword
Комната 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 | недостижима в игре | |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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).
|
||||
* Приложение переключает комнату по соответствующей связи и снимает флаг. */
|
||||
|
||||
@@ -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(); /* нарисовать новый кадр (детект выхода за поле) */
|
||||
|
||||
Reference in New Issue
Block a user