Fallstudie * Touhou 4: Lotus Land Geschichte

Rekonstruktion des TH04
aufzählungsmuster.

Ein Kugelring beginnt mit einer kurzen Winkelberechnung. Verwenden Sie REA, um die ursprüngliche DOS-Funktion zu überprüfen, und folgen Sie dann den Anweisungen in lesbares C ++.

PC-98 · 16-Bit-DOS · C++ und Assemblierung

Sehen Sie sich die Rekonstruktion des TH04 an

Von der Originalanleitung zur geprüften Quelle

  1. 01 * Original-SpielWICHTIGSTEN.EXEDie ausführbare Datei PC-98 und ihr Aufzählungswinkel-Helfer.
  2. 02 * Inspektion mit REA Anleitungen + ReferenzenÜberprüfen Sie den geladenen DOS-Code und lesen Sie die Winkelberechnung aus der ausführbaren Datei.
  3. 03 * Lesen Sie die C ++Leertaste → Zielen → DrehenVerbinden Sie jede Operation mit der gepflegten Rekonstruktion.
  4. 04 * Überprüfen Sie die Quelle2.139 übereinstimmende BytesAufgezeichnete Compilerprüfungen decken den Code zur Aufzählungszeichengenerierung ab, der diesen Helfer enthält.
REA gibt den Originalcode und seine Analysebeweise zurück. Das Projekt TH04 liefert die gepflegten Quell- und Compilerprüfungen.

Wie ein Ring auf den Spieler zielt

Ellys Angriff fordert einen gezielten Ring mit einer anfänglichen Anzahl von 16 an. Ein Helfer berechnet die Richtung jeder Kugel. Derselbe Ring kann in eine feste Richtung zeigen oder sich dem Spieler zuwenden.

Ihr Codierungsagent

Verwenden Sie REA, um herauszufinden, wie TH04 einen Kugelring erstellt und auf den Spieler richtet. Erklären Sie die Berechnung und zeigen Sie den Code.

Eine Beispiel-Eingabeaufforderung, bei der die ursprüngliche ausführbare Datei und der Rekonstruktions-Checkout lokal verfügbar sind.

TH04 speichert eine volle Drehung im Uhrzeigersinn in 256 Winkeleinheiten. Bei 16 Aufzählungszeichen addiert jeder Index 16 Einheiten: 0, 16, 32, …, 240. Das Hinzufügen der Richtung des Spielers dreht diese Positionen zusammen.

Zwei Diagramme eines 16-Kugeln-Rings. Der feste Ring beginnt bei Winkel Null. Wenn Sie eine Spielerrichtung von 40 hinzufügen, wird jede Richtung um den gleichen Betrag gedreht. Der hervorgehobene erste Punkt zeigt auf den Spieler. Beide halten einen Abstand von 16 Winkeleinheiten oder 22,5 Grad ein.
Eine Illustration der wiederhergestellten Winkelmathematik für Zählung 16, Spielerrichtung 40 und Schablonendrehung 0. Offene Figur

Die Zündvorlage in der wiederhergestellten Quelle

Ellys Ringangriff * Quellenauszug
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();

Diese Linien wählen das Muster vor der Schwierigkeits- und Leistungsabstimmung aus. Lesen Sie die Quelle des Angriffs.

Was REA zurückgibt

Wir prüfen bullet_velocity_and_angle_set(), die Funktion, die die Geschwindigkeit und den Winkel jedes Geschosses festlegt. REA gibt seine Anweisungen, Pseudocode und Referenzen zurück. Drei Teile dieses Ergebnisses erklären das Muster.

  1. Überprüfen Sie das DOS-Image, bevor Sie den Code lesen

    Vertreter → REA
    open_binary
    {"path": "MAIN.EXE"}
    
    inspect_native_load_image
    {}
    REA → Agent * ausgewählte Felder
    status: "verified"
    format: "dos-mz"
    load_segment: 4096
    header_bytes: 6144
    module_bytes: 150114

    Die Prüfung bindet den geladenen Code und die Umzugsdatensätze an die gelieferte ausführbare Datei. Der obige Pfad ist für die Anzeige verkürzt.

  2. Lesen Sie die Multiplikation und Division des Rings

    Vertreter → REA · analyze_function
    {"procedure": "0x2cfc8"}
    REA → Agent * Anweisungsauszug
    0x2d0eb: MOV AX, SI
    0x2d0ed: SHL AX, 0x8
    0x2d0f0: MOV DL, byte ptr [0x53af]
    0x2d0f9: IDIV BX

    SI enthält den Aufzählungszeichenindex. Die Verschiebung multipliziert es mit 256, dann verwendet die Division die gelesene Zählung DS:53AF. Die gepflegte Quelle benennt dieses Feld bullet_template.count. Die vollständige Sequenz erscheint unten.

  3. Finde heraus, wo sich das Muster dem Spieler zuwendet

    Gleiches Funktionsergebnis * Zielauszug
    0x2d190: SUB AX, word ptr [0x53a6]
    0x2d198: SUB AX, word ptr [0x53a4]
    0x2d19d: CALLF 0x1000:1da8
    0x2d1a2: ADD word ptr [BP + -0x2], AX
    Entsprechendes gepflegtes C ++
    group_angle_offset += iatan2(
      player_pos.cur.y - bullet_template.origin.y,
      player_pos.cur.x - bullet_template.origin.x
    );

    Die Anweisungsoperanden legen zwei Koordinatendifferenzen und einen Richtungshelfer offen. Sein Rückgabewert wird zum relativen Ringwinkel addiert. Quellennamen machen diese Adressen lesbar; Mit REA kann der Agent die ursprünglichen Vorgänge dahinter überprüfen.

Von Assembly zu lesbarem C ++

Wählen Sie einen Schritt aus, um die ursprünglichen Anweisungen mit der Winkelberechnung abzugleichen. Diese Zusammenfassung folgt dem Zielringpfad; Die vollständige Quelle behandelt auch Spreads, Stapel und Zufallsmuster.

REA * originale 16-Bit-Anleitung
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
Lesbare C ++ * zielgerichtete Ring-Zusammenfassung
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 * Lesen Sie den Aufzählungszeichenindex. Das Stapelargument wird geladen in SI. In einem 16-Punkte-Ring verläuft dieser Mitgliederindex von 0 bis 15.

Die Baugruppe wählt den Zielringzweig, die Zielberechnung und den Endspeicher aus. Das obige C ++ ist eine lesbare Zusammenfassung. Die folgenden Compiler-Prüfungen gelten für die gepflegte Quelle im verknüpften Projekt.

Lesen Sie die gepflegte Ring- und Zielquelle
Ringmakro * TH04 Zweig, Auszug
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
    group_complete = true;
}
goto aim_or_no_aim;
Winkel und Geschwindigkeit * Quellenauszug
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);

Ringmakro · Ziel- und Geschwindigkeitsquelle · Winkeldarstellung

Überprüfen der gepflegten Quelle

Die aufgezeichneten Überprüfungen des TH04-Projekts kompilieren den Code zur Bullet-Generierung, einschließlich dieses Helpers, mit seiner angehefteten Turbo C ++ 4.0J-Toolchain.

2.139 übereinstimmende Bytes

Der kompilierte Code zur Aufzählungszeichengenerierung entspricht einem 2.139 Byte großen Abschnitt der ursprünglichen ausführbaren Datei.

Zwei saubere Builds

Zwei separate Builds erzeugen dieselben übereinstimmenden Bytes. Die aufgezeichneten Eingabe-Hashes stimmen mit der hier gezeigten gepflegten Quelle überein.

Aufgenommen am 3. Oktober 2026. Lesen Sie die Compiler-Prüfungen.

Zielidentität und Analyseumfang
Ursprüngliches Ziel MAIN.EXE, 156.258 bytes, ZWEI MZ
Hilfseintrag 0x2cfc8 im geladenen Bild von REA
Versatz der ursprünglichen Datei 0x1e7c8, zurückgegeben von address_to_file_offset
Inspektion aufgezeichneter Codes REA 4.1.0 · 7. Oktober 2026

Compiler-Prüfungen decken den gesamten Abschnitt zum Hinzufügen von Code mit Aufzählungszeichen ab, einschließlich dieses Hilfsprogramms. Sie vergleichen auch den Kartenbeitrag und die überlappende Verlagerung.

REA hat das statische DOS-Ladebild am Ladesegment überprüft 0x1000. Seine Adressen beschreiben dieses Analysebild. Das Funktionsergebnis meldet 503 Körperbytes in zwei Bereichen über einen Zeitraum von 517 Byte; Die oben ausgewählten Anweisungen liegen in diesen gemeldeten Bereichen.

Die Quellnamen und Compilerprüfungen stammen vom Prüfpunkt TH04 0d72e980. Frühere Rekonstruktionsbeobachtungen verwendeten die projekteigenen Analyseskripte; Diese Seite fügt eine neue REA-Inspektion desselben ursprünglichen Ziels hinzu. Die Identität des gelieferten Spiels wird durch sein Repository-Manifest festgelegt, wobei die unabhängige Herkunft des unberührten Dumps noch offen ist.

Die Abbildung veranschaulicht die Winkelberechnung. Steuerung des vollständigen Spiels, Timing und Verhalten der PC-98-Hardware haben separate Laufzeitprüfungen im Rekonstruktionsprojekt.

Die vollständige TH04-Rekonstruktion

Das Projekt erstellt die vier DOS-Produkte des Spiels aus gepflegtem C ++ und Assembly. Über die Aufzählungszeichenerzeugung hinaus umfasst die Quelle Stufen, Bosse, Rendering, Eingabe, Menüs, Endungen und Partiturbehandlung.

Erkunden Sie das TH04-Repository

Oberen