個案研究·東方4:蓮花地故事

重建TH04
子彈圖案。

一圈彈幕從一段簡短的角度計算開始。用 REA 檢查原始 DOS 函式,再把指令對應到可讀的 C++ 程式碼。

PC-98·16位DOS · C++和彙編

檢視TH04重建

從原始指令到經過驗證的原始碼

  1. 01 · 原創遊戲主要。EXE檔案該 PC-98 可執行檔案及其子彈角助手。
  2. 02 · 用 REA 檢查指令 + 引用驗證載入的 DOS 程式碼,再從可執行檔案中讀取角度計算。
  3. 03 · 閱讀 C++等分 → 瞄準 → 旋轉把每個操作對應到維護中的重建原始碼。
  4. 04 · 驗證原始碼2,139 位元組匹配已記錄的編譯器檢查覆蓋了包含這個輔助函式的彈幕生成程式碼。
REA 返回原始程式碼和分析證據。TH04 專案提供維護中的原始碼,以及編譯器檢查結果。

環形彈幕如何瞄準玩家

Elly 的攻擊請求一個初始數量為 16 的自機狙環形彈幕。輔助函式計算每顆子彈的方向。同一圈彈幕既可以朝向固定方向,也可以轉向玩家。

你的程式設計助手

使用REA查詢TH04如何建立一個子彈環並將其瞄準玩家。 解釋計算並顯示程式碼。

一個示例提示,原始可執行檔案和重建簽出可在本地使用。

TH04 用 256 個角度單位表示順時針轉一整圈。16 顆子彈之間各隔 16 個單位:0, 16, 32, …, 240。再加上玩家方向,就能讓所有方向一起旋轉。

兩幅圖展示 16 顆子彈的環。固定環從角度 0 開始。加上玩家方向 40 後,每個方向都旋轉相同角度,高亮的第一顆子彈指向玩家。兩者都保持 16 個角度單位的間距,即 22.5 度。
圖中演示還原出的角度計算:子彈數量為 16,玩家方向為 40,模板旋轉角為 0。檢視大圖

還原原始碼中的發射模板

Elly 的環形攻擊 · 原始碼節選
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();

這些線在難度和效能調整之前選擇模式。 閱讀攻擊的來源.

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. 找到模式轉向玩家的位置

    相同的函式結果 · 目標摘錄
    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++ · 自機狙環形彈幕摘要
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 · 讀取子彈索引。 棧引數載入到 SI。在 16 顆子彈的環中,索引從 0 到 15。

彙編節選展示自機狙環形分支、瞄準計算和最終儲存。上面的 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);

環宏 · 目標和速度源 · 角度表示

檢查維護的源

TH04 專案記錄的檢查使用指定的 Turbo C++ 4.0J 工具鏈,編譯包含這個輔助函式的彈幕生成程式碼。

2,139匹配位元組

編譯的子彈生成程式碼與原始可執行檔案的2,139位元組部分相匹配。

兩個乾淨的構建

兩個單獨的構建產生相同的匹配位元組。 記錄的輸入雜湊值與此處顯示的維護源匹配。

2026年10月3日錄得。 閱讀編譯器檢查.

目標身份和分析範圍
原始目標 MAIN.EXE,156,258位元組,DOS MZ
傭工入境 0x2cfc8 在REA的載入影象
原始檔案偏移量 0x1e7c8,返回 address_to_file_offset
記錄程式碼檢查 REA4.1.0*2026年10月7日

編譯器檢查覆蓋完整的彈幕新增程式碼段,包括這個輔助函式。檢查還比較它在 map 檔案中的貢獻,以及重疊的重定位項。

REA 驗證了載入段為 0x1000 的靜態 DOS 載入映像。地址描述的是分析映像。函式結果在一個 517 位元組範圍內報告了兩段程式碼,共 503 位元組;上方節選的指令都位於這些已報告的程式碼範圍內。

原始碼名稱和編譯器檢查來自 TH04 檢查點 0d72e980。較早的重建分析使用專案自身的指令碼;這個頁面新增了用 REA 對同一原始目標的檢查。遊戲檔案的身份由儲存庫清單確定,獨立原始轉儲的來源仍未確定。

圖中說明的是角度計算。完整遊戲的控制、時序和 PC-98 硬體行為,在重建專案中有各自的執行時檢查。

完整的TH04重建

專案用維護中的 C++ 和彙編構建遊戲的四個 DOS 程式。除了彈幕生成,原始碼還覆蓋關卡、Boss、渲染、輸入、選單、結局和分數處理。

探索 TH04 程式碼儲存庫

頂部