---
title: 'TH04 Обратный инжиниринг: шаблоны маркеров DOS — REA'
url: https://rea.tools/ru/showcase/th04/
---

[Главная](https://rea.tools/ru/) страница / [Витрины](https://rea.tools/ru/showcase/) / TH04

Тематическое исследование · Тохоу 4: История земли лотосов

# Реконструкции TH04 с узоры пули.

Набор маркеров начинается с вычисления короткого угла. Используйте REA для проверки исходной функции DOS, затем следуйте ее инструкциям на удобочитаемом C++.

PC-98 · 16-разрядная версия DOS · C++ и сборка

[Посмотреть реконструкцию TH04](https://github.com/N0zoM1z0/th04)

От оригинальных инструкций к проверенному источнику

1. 01 · Основная часть оригинальной игры

   **.ЗАПУСТИТЕ исполняемый**

   файл PC-98 и его вспомогательный инструмент bullet-angle.
2. 02 · Проверьте с помощью

    **инструкций REA + ссылок**

   , проверьте загруженный код DOS и прочитайте расчет угла из исполняемого файла.
3. 03 · Прочитайте пробел C++

    **→ aim → rotate**

   , чтобы связать каждую операцию с сохраняемой реконструкцией.
4. 04 · Проверьте исходные

    **2139 совпадающих байт**

   , записанных компилятором, проверки охватывают код генерации маркеров, содержащий этот вспомогательный элемент.

REA возвращает исходный код и результаты его анализа. Проект TH04 предоставляет поддерживаемые проверки исходного кода и компилятора.

## Как кольцо нацеливается на игрока

Для атаки Элли требуется прицельное кольцо с начальным счетом 16. Один из помощников рассчитывает направление полета каждой пули. Одно и то же кольцо может быть направлено в фиксированном направлении или повернуто в сторону игрока.

Ваш кодирующий агент

Используйте REA, чтобы узнать, как TH04 создает кольцо из пуль и направляет его на игрока. Объясните расчет и покажите код.

Пример запроса с исходным исполняемым файлом и восстановлением, доступным локально.

TH04 сохраняет полный оборот по часовой стрелке в 256 угловых единицах. Для 16 пуль каждый индекс добавляет по 16 единиц.: `0, 16, 32, …, 240`. При добавлении направления движения игрока эти позиции меняются местами.

![Две диаграммы кольца из 16 точек. Неподвижное кольцо начинается с нулевого угла. При добавлении направления движения игрока, равного 40, все стороны поворачиваются на одинаковую величину; выделенная первая точка указывает на игрока. В обоих случаях расстояние между точками составляет 16 угловых единиц, или 22,5 градуса.](https://rea.tools/assets/localized/ru/figures/th04-bullet-ring.svg)

Иллюстрация восстановленного математического расчета угла для счета 16, направления игрока 40 и поворота шаблона 0. [Открыть рисунок](https://rea.tools/assets/localized/ru/figures/th04-bullet-ring.svg)

### Шаблон запуска в восстановленном источнике

Нападение Элли на кольцо · отрывок из источника

```
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();
```

В этих строках выбирается шаблон перед настройкой сложности и производительности. [Прочитайте источник атаки](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/boss/elly_phase_ring16.cpp#L26).

## Что возвращает REA

Мы проверяем `bullet_velocity_and_angle_set()`, которые задают скорость и угол наклона каждой пули. REA возвращает свои инструкции, псевдокод и ссылки. Три части этого результата объясняют закономерность.

1. #### Проверьте образ DOS, прежде чем читать его код

   Агент → REA

   ```
   open_binary
   {"path": "MAIN.EXE"}

   inspect_native_load_image
   {}
   ```

   REA → агент · выбранные поля

   ```
   status: "verified"
   format: "dos-mz"
   load_segment: 4096
   header_bytes: 6144
   module_bytes: 150114
   ```

   Проверка привязывает загруженный код и записи о перемещении к предоставленному исполняемому файлу. Путь, указанный выше, сокращен для отображения.
2. #### Прочитайте надпись на кольце "умножай и дели"

   Агент → REA · функция `analyze_function`

   ```
   {"procedure": "0x2cfc8"}
   ```

   REA → агент · отрывок из инструкции

   ```
   0x2d0eb: MOV AX, SI
   0x2d0ed: SHL AX, 0x8
   0x2d0f0: MOV DL, byte ptr [0x53af]
   0x2d0f9: IDIV BX
   ```

   `SI` записан общий индекс. При сдвиге значение умножается на 256, затем при делении используется значение, считанное из `DS:53AF`. Имена поддерживаемых источников, которые указаны в поле `bullet_template.count`. Полная последовательность приведена ниже.
3. #### Найдите, где рисунок поворачивается в сторону игрока

   Результат той же функции · выдержка из aim

   ```
   0x2d190: SUB AX, word ptr [0x53a6]
   0x2d198: SUB AX, word ptr [0x53a4]
   0x2d19d: CALLF 0x1000:1da8
   0x2d1a2: ADD word ptr [BP + -0x2], AX
   ```

   Соответствующий поддерживаемый C++

   ```
   group_angle_offset += iatan2(
     player_pos.cur.y - bullet_template.origin.y,
     player_pos.cur.x - bullet_template.origin.x
   );
   ```

   Операнды команд предоставляют две разности координат и вспомогательное значение направления. Возвращаемое значение добавляется к относительному кольцевому углу. Имена источников делают эти адреса удобочитаемыми; REA позволяет агенту проверять исходные операции, стоящие за ними.

## От ассемблера к удобочитаемому C++

Выберите шаг, который соответствует первоначальным инструкциям по расчету угла. В этом обзоре приведена схема прицельного кольца; полный исходный код также содержит данные о разбросах, стопках и случайных моделях.

REA · оригинальные 16-разрядные инструкции

```
0x2cfcf: MOV SI, word ptr [BP + 0x4]
0x2d0eb: MOV AX, SI
0x2d0ed: SHL AX, 0x8
0x2d0f0: MOV DL, byte ptr [0x53af]
0x2d0f4: MOV DH, 0x0
0x2d0f6: PUSH DX
0x2d0f7: CWD
0x2d0f8: POP BX
0x2d0f9: IDIV BX
0x2d0fb: MOV word ptr [BP + -0x2], AX
0x2d18d: MOV AX, [0x4650]
0x2d190: SUB AX, word ptr [0x53a6]
0x2d194: PUSH AX
0x2d195: MOV AX, [0x464e]
0x2d198: SUB AX, word ptr [0x53a4]
0x2d19c: PUSH AX
0x2d19d: CALLF 0x1000:1da8
0x2d1a2: ADD word ptr [BP + -0x2], AX
0x2d1b9: MOV AL, byte ptr [BP + -0x2]
0x2d1bc: ADD AL, byte ptr [0x53ad]
0x2d1c0: MOV [0xbcc8], AL
```

Читаемый C++ · краткое описание aimed-ring

```
unsigned char aimed_ring_angle(
    int index, int count,
    int player_direction,
    unsigned char rotation)
{
    int angle = index;
    angle = (angle * 256) / count;
    angle += player_direction;
    angle += rotation;
    return (unsigned char)angle;
}
```

**01 · Считываем маркерный индекс.** Аргумент stack загружается в `SI`. В кольце из 16 маркеров этот индекс элемента находится в диапазоне от 0 до 15.

**02 · Расставьте направления на полный оборот.** `SHL AX,8` 8 умножается на 256. Число умножается на ноль и преобразуется в слово, затем `IDIV` делит результат на это число. Для числа 16 каждый индекс умножается на 16 угловых единиц.

**03 · Добавьте направление движения игрока.** Два вычитания образуют координаты игрока минус исходная точка. Вспомогательный инструмент direction возвращает угол в `AX`; при сложении все кольцо поворачивается к игроку.

**04 · Добавьте поворот шаблона.** `ADD AL,[0x53ad]` добавляет угол наклона шаблона. В исходном шаблоне Elly он равен нулю; другие шаблоны могут использовать тот же вспомогательный элемент с поворотом.

**05 · Сохраняйте конечный угол в одном байте.** Хранилище записывает `AL` в поле "Угол появления". Значения переносятся после 255, точно так же, как это происходит при преобразовании беззнаковых байт. Окружающий источник также преобразует этот угол и скорость в скорость вращения.

В сборке выбирается ветвь aimed-ring, вычисление aim и конечное хранилище. Приведенный выше текст на C++ представляет собой удобочитаемую сводку. Приведенные ниже проверки компилятора применяются к поддерживаемому исходному тексту в связанном проекте.

Ознакомьтесь с сохраняемым кольцом и прицелитесь в источник

Кольцевой макрос · Ветвь TH04, фрагмент

```
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
    group_complete = true;
}
goto aim_or_no_aim;
```

Угол и скорость · выдержка из источника

```
aim:
    group_angle_offset += iatan2(
        (player_pos.cur.y - bullet_template.origin.y),
        (player_pos.cur.x - bullet_template.origin.x)
    );

no_aim:
    vector2_near(
        bullet_template.velocity,
        (group_angle_offset + bullet_template.angle),
        speed
    );
    bullet_spawn_angle = (group_angle_offset + bullet_template.angle);
```

[Кольцевой макрос](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add_impl.hpp#L4) · [Цель и источник скорости](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L422) · [Представление угла](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/types.hpp#L6)

## Проверка поддерживаемого источника

Записанные проверки проекта TH04 позволяют скомпилировать код для генерации маркеров, включая этот помощник, с помощью закрепленного набора инструментов Turbo C++ 4.0J.

### 2,139 совпадающих байта

Скомпилированный код генерации маркеров соответствует 2139-байтовому разделу исходного исполняемого файла.

### Две чистые сборки

Две отдельные сборки генерируют одинаковые совпадающие байты. Записанные входные хэши соответствуют показанному здесь сохраненному источнику.

Записано 3 октября 2026 года. [Ознакомьтесь с проверками компилятора](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/reconstruction/product/TH04_SEMANTIC_BULLET_GENERATION_V1236.md#validation).

Идентификация цели и объем анализа

|  |  |
| --- | --- |
| Первоначальная цель | `MAIN.EXE` , 156 258 байт, DOS MZ |
| Вспомогательная запись | `0x2cfc8` в загруженном изображении REA |
| Смещение исходного файла | `0x1e7c8`, возвращаемый параметром `address_to_file_offset` |
| Проверка записанного кода | REA 4.1.0 · 7 октября 2026 |

Проверки компилятора охватывают весь раздел кода для добавления маркеров, включая этот вспомогательный инструмент. Они также сравнивают его вклад в отображение и перекрывающееся перемещение.

REA проверил статический загрузочный образ DOS в сегменте загрузки `0x1000`. Его адреса описывают этот аналитический образ. Результат функции сообщает о 503 байтах тела в двух диапазонах по 517 байт; выбранные инструкции, приведенные выше, находятся в этих сообщенных диапазонах.

Имена исходных текстов и проверки компилятором исходят из контрольной точки TH04 `0d72e980`. В предыдущих наблюдениях за реконструкцией использовались собственные аналитические скрипты проекта; на этой странице добавлена новая проверка REA для той же исходной цели. Предоставленная игра идентифицируется в манифесте репозитория, при этом независимое происхождение нетронутого дампа все еще открыто.

На рисунке показан расчет угла. Элементы управления в полной версии игры, хронометраж и поведение аппаратного обеспечения PC-98 проверяются во время выполнения в проекте реконструкции отдельно.

## Полная реконструкция TH04

Проект создает четыре DOS-продукта для игры на поддерживаемом C++ и ассемблере. Помимо генерации маркеров, в исходном коде описаны этапы, боссы, рендеринг, ввод, меню, концовки и обработка результатов.

[Изучите репозиторий TH04](https://github.com/N0zoM1z0/th04)

- [Источник для генерации маркеров -](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L292) это полный вспомогательный инструмент, другие типы шаблонов и настройка шаблона.
- [Руководство по сборке и запуску DOS](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/DOS_BUILD.md) Создайте исходный код и протестируйте его в рабочем процессе эмулятора PC-98 проекта.
- [Текущая проверка состояния проекта](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/RE_HANDOFF.md) DOS и отдельный собственный порт x64.
