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

[Головний](https://rea.tools/uk/) сторінка / [Вітрина](https://rea.tools/uk/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/uk/figures/th04-bullet-ring.svg)

Ілюстрація відновленого математичного розрахунку кута для рахунку 16, напрямку гравця 40 і повороту шаблону 0. [Відкрити малюнок](https://rea.tools/assets/localized/uk/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.0 J.

### 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.
