---
title: TH04リバースエンジニアリング:DOS弾丸パターン-REA
url: https://rea.tools/ja/showcase/th04/
---

[ホーム](https://rea.tools/ja/) / [展示会のご案内](https://rea.tools/ja/showcase/) /TH04

ケーススタディ\*東方4：蓮の国物語

# TH04の再構築 弾丸のパターン。

弾丸のリングは、短い角度の計算で始まります。 REAを使用して元のDOS関数を検査し、その指示に従って読み取り可能なC++に従います。

PC-98\*16ビットDOS·C++およびアセンブリ

[TH04再構成を見る](https://github.com/N0zoM1z0/th04)

元の指示からチェックされたソースへ

1. 01\*オリジナルゲーム

   **メイン...EXE**

   PC-98実行可能ファイルとそのbullet-angleヘルパー。
2. 02\*REAと点検して下さい

   **説明書+参考文献**

   ロードされたDOSコードを確認し、実行可能ファイルから角度計算を読み取ります。
3. 03\*C++を読む

   **スペース→狙い→回転**

   各操作を維持された再構成に接続します。
4. 04\*ソースを確認する

   **一致するバイト数2,139件**

   記録されたコンパイラチェックは、このヘルパーを含む箇条書き生成コードをカバーします。

REAは、元のコードとその分析証拠を返します。 TH04プロジェクトは、保守されたソースとコンパイラのチェックを提供します。

## リングがプレーヤーをどのように狙うか

エリーの攻撃は、最初のカウント16の目的としたリングを要求します。 一つのヘルパーは、各弾丸の方向を計算します。 同じリングは、固定方向に直面したり、プレイヤーに向かって回すことができます。

あなたのコーディングエージェント

REAを使用して、TH04が弾丸のリングを作成し、プレイヤーにそれを向ける方法を見つけます。 計算を説明し、コードを表示します。

元の実行可能ファイルと再構築チェックアウトがローカルで利用可能なプロンプトの例。

TH04は256の角度の単位で完全な右回りの回転を貯える。 16箇条書きの場合、各インデックスには16単位が追加されます: `0, 16, 32, …, 240`. プレイヤーの方向を追加すると、それらの位置が一緒に回転します。

![16弾のリングの2つの図。 固定リングは角度ゼロから始まります。 40のプレイヤーの方向を追加すると、すべての方向が同じ量だけ回転します。強調表示された最初の箇条書きは、プレイヤーに向かって指します。 どちらも16角度単位、つまり22.5度の間隔を保ちます。](https://rea.tools/assets/localized/ja/figures/th04-bullet-ring.svg)

カウント16、プレイヤーの方向40、およびテンプレートの回転0のための回収された角度の数学の図。 [オープンフィギュア](https://rea.tools/assets/localized/ja/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は、その命令、擬似コード、および参照を返します。 その結果の3つの部分がパターンを説明しています。

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. #### パターンがプレイヤーに向かって回転する場所を見つける

   同じ機能結果-目安抜粋

   ```
   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
   );
   ```

   命令オペランドは、2つの座標差と方向ヘルパーを公開します。 その戻り値は相対的なリング角度に追加されます。 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
```

-----------

```
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` 256で乗算します。 カウントはゼロです-単語に拡張され、その後 `IDIV` 積をその数で除算します。 カウント16の場合、各インデックスは16の角度単位を進めます。

**03\*プレイヤーの方向を追加します。** 2つの減算は、プレーヤーマイナス原点座標を形成します。 方向ヘルパーは、角度を返します `AX`;それを追加すると、リング全体がプレイヤーに向かって変わります。

**04\*パターンの回転を追加します。** `ADD AL,[0x53ad]` テンプレートの角度を追加します。 Ellyの初期テンプレートはそれをゼロに設定します;他のパターンは回転で同じヘルパーを使うことができます。

**05\*最終的な角度を1バイトに保ちます。** 店は書いています `AL` spawn-angleフィールドに移動します。 値は、符号なしバイトのキャストと同じように、255の後に折り返します。 周囲のソースもこの角度と速度を速度に変換します。

アセンブリは目的とされたリング枝、目的の計算および最終的な店を選ぶ。 上記の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件

コンパイルされた箇条書き生成コードは、元の実行可能ファイルの2,139バイトのセクションに一致します。

### 二つのクリーンビルド

2つの別々のビルドでは、同じ一致するバイトが生成されます。 記録された入力ハッシュは、ここに示されている維持されたソースと一致します。

2026年10月3日に録音されました。 [コンパイラチェックを読む](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/reconstruction/product/TH04_SEMANTIC_BULLET_GENERATION_V1236.md#validation).

ターゲットidと分析範囲

|  |  |
| --- | --- |
| 元のターゲット | `MAIN.EXE`、156,258バイト、DOS MZ |
| ヘルパーエントリー | `0x2cfc8` REAのロードされたイメージで |
| 元のファイルオフセット | `0x1e7c8`、によって返される `address_to_file_offset` |
| 記録されたコード検査 | REA4.1.0•2026年10月7日 |

コンパイラチェックは、このヘルパーを含む完全なbullet-add codeセクションをカバーしています。 彼らはまた、そのマップの貢献と重複した再配置を比較します。

REAは負荷セグメントで静的DOS負荷イメージを検証しました `0x1000`. そのアドレスは、その分析画像を記述します。 関数の結果は、517バイトのスパンにわたって2つの範囲で503のボディバイトを報告します。上記の選択された命令は、それらの報告された範囲にあります。

ソース名とコンパイラチェックはTH04チェックポイントから来ています `0d72e980`. このページでは、同じ元のターゲットの新しいREA検査を追加します。 提供されたゲームのアイデンティティは、リポジトリマニフェストによって固定されており、独立した原始的なダンプの出所はまだ開いています。

図は角度の計算を示しています。 完全なゲームコントロール、タイミング、およびPC-98ハードウェアの動作には、再構築プロジェクトで別々のランタイムチェックがあります。

## フルTH04の再構成

このプロジェクトは、維持されたC++とアセンブリからゲームの4つのDOS製品を構築します。 弾丸の生成を超えて、ソースはステージ、ボス、レンダリング、入力、メニュー、エンディングとスコアの処理をカバーしています。

[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ポート。
