/* * pop_guard.c — СОСТОЯНИЕ и ЛОГИКА стража (W1/W2). См. pop_guard.h. * * Здесь только то, что должно оставаться достижимым из банка (guards.c): * поля Guard, HP, вход в комнату, чит-убийство, чтение кадра из таблицы. * ОТРИСОВКА — в pop_gdraw.c, резиденте W3 (её зовёт лишь главный цикл). */ #include #include "pop_guard.h" #include "pop_geom.h" #include "pop_level.h" #include "pop_kid.h" /* Char/play_seq — интерпретатор общий */ #include "kid_data.h" pop_char_t Guard; uint8_t guardhp_curr, guardhp_max; int8_t guardhp_delta; int8_t can_guard_see_kid; int8_t is_guard_notice; /* Кадр стража (порт cur_frame для Char). Глобальный, а не статик: его * заполняет логика (W1/W2), а читает отрисовка из резидента W3. */ kframe pop_gframe; uint8_t pop_guard_present(void) { return (uint8_t)(Guard.charid != 0 && Guard.alive < 0 && guardhp_curr != 0); } void pop_guard_reset(void) { Guard.charid = 0; Guard.alive = 0; Guard.direction = 0; guardhp_curr = 0; guardhp_delta = 0; can_guard_see_kid = 0; is_guard_notice = 0; } /* kill guard cheat (seg000:786): * if (Guard.charid != charid_4_skeleton) { * guardhp_delta = -guardhp_curr; * Guard.alive = 0; * } * Скелета чит не убивает — он и в оригинале бессмертен. */ void pop_guard_kill(void) { if (Guard.charid == CHARID_4_SKELETON) return; if (!pop_guard_present()) return; guardhp_delta = (int8_t)-guardhp_curr; guardhp_curr = 0; Guard.alive = 0; } /* load_frame для стража (seg006:0293 ветка charid_2_guard): таблица у * стражей СВОЯ (frame_tbl_guard), индекс = frame + add_frame − 149, где * add_frame = 70 для кадров 102..106 (seg006:535). */ void pop_guard_load_frame(void) { int16_t idx = (int16_t)Guard.frame; if (idx >= 102 && idx < 107) idx += 70; /* add_frame */ idx -= 149; if (idx < 0 || idx >= KID_NGFRAMES) { pop_gframe.image = 255; return; } pop_kid_data_frame(KID_BIN_GFRAMES_OFF, (uint8_t)idx, (uint8_t *)&pop_gframe); } void pop_guard_enter(uint8_t room) { uint8_t tile, color, skill; int8_t dir; pop_guard_reset(); if (!pop_level_guard(room, &tile, &dir, &color, &skill)) return; /* enter_guard (seg002:0112) + pos_guards (seg003): X считается из * колонки тайла, а не берётся из файла. */ Guard.room = room; Guard.curr_row = (int8_t)(tile / 10); Guard.y = (uint8_t)pop_y_land[Guard.curr_row + 1]; Guard.x = (uint8_t)(pop_x_bump[(tile % 10) + FIRST_ONSCREEN_COLUMN] + TILE_SIZEX); Guard.curr_col = (int8_t)(tile % 10); Guard.direction = dir; Guard.charid = CHARID_2_GUARD; Guard.sword = 0; /* sword_0_sheathed */ Guard.alive = -1; Guard.action = 1; /* actions_1_run_jump */ Guard.fall_x = Guard.fall_y = 0; guardhp_max = guardhp_curr = 3; /* get_guard_hp: skill 0, уровень 1 */ guardhp_delta = 0; /* enter_guard (seg002:0208): seqtbl_offset_char(seq_77_guard_stand_inactive). * Последовательность крутит общий интерпретатор (pop_guard_play), а * таблицу кадров он выбирает по Char.charid — у стража своя. */ pop_loadshad(); pop_char_set_seq(SEQ_77_GUARD_STAND_INACTIVE); pop_saveshad(); pop_guard_play(); /* до первого кадра */ }