Étude de cas · Touhou 4: L'histoire de Lotus Land

Reconstruction TH04's
motifs de balles.

Un anneau de balles commence par un court calcul d'angle. Utilisez REA pour inspecter la fonction DOS d'origine, puis suivez ses instructions en C ++ lisible.

PC-98 * DOS 16 bits * C++ et assemblage

Voir le TH04 reconstruction

Des instructions originales à la source vérifiée

  1. 01 * Jeu originalPRINCIPALE.EXEL'exécutable PC-98 et son assistant d'angle de balle.
  2. 02 * Inspecter avec le modèle REA Instructions + référencesVérifiez le code DOS chargé et lisez le calcul de l'angle à partir de l'exécutable.
  3. 03 * Lire le C++Espace → viser → tournerReliez chaque opération à la reconstruction maintenue.
  4. 04 * Vérifiez la source2 139 octets correspondantsLes vérifications du compilateur enregistrées couvrent le code de génération de puces qui contient cette aide.
REA renvoie le code d'origine et ses preuves d'analyse. Le projet TH04 fournit les vérifications de source et de compilateur maintenues.

Comment un anneau vise le joueur

L'attaque d'Elly demande un anneau visé avec un compte initial de 16. Un assistant calcule la direction de chaque balle. Le même anneau peut faire face à une direction fixe ou se tourner vers le joueur.

Votre agent de codage

Utilisez REA pour découvrir comment TH04 crée un anneau de balles et le dirige vers le joueur. Expliquez le calcul et montrez le code.

Un exemple d'invite, avec l'exécutable d'origine et la récupération de reconstruction disponibles localement.

TH04 stocke un tour complet dans le sens des aiguilles d'une montre en 256 unités d'angle. Pour 16 puces, chaque index ajoute 16 unités: 0, 16, 32, …, 240. L'ajout de la direction du joueur fait pivoter ces positions ensemble.

Deux diagrammes d'un anneau de 16 balles. L'anneau fixe commence à l'angle zéro. L'ajout d'une direction de joueur de 40 fait pivoter toutes les directions de la même quantité; la première puce en surbrillance pointe vers le joueur. Les deux conservent un espacement de 16 unités d'angle, soit 22,5 degrés.
Une illustration des calculs d'angle récupérés pour le compte 16, la direction du joueur 40 et la rotation du gabarit 0. Figure ouverte

Le modèle de tir dans la source récupérée

L'attaque de l'anneau d'Elly * extrait de la source
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();

Ces lignes sélectionnent le motif avant le réglage de la difficulté et des performances. Lire la source de l'attaque.

Quels sont les retours de REA

Nous inspectons bullet_velocity_and_angle_set(), la fonction qui définit la vitesse et l'angle de chaque balle. REA renvoie ses instructions, son pseudocode et ses références. Trois parties de ce résultat expliquent le schéma.

  1. Vérifiez l'image DOS avant de lire son code

    Agent → REA
    open_binary
    {"path": "MAIN.EXE"}
    
    inspect_native_load_image
    {}
    REA → agent * champs sélectionnés
    status: "verified"
    format: "dos-mz"
    load_segment: 4096
    header_bytes: 6144
    module_bytes: 150114

    La vérification lie le code chargé et les enregistrements de relocalisation à l'exécutable fourni. Le chemin ci-dessus est raccourci pour l'affichage.

  2. Lire la multiplication et la division de l'anneau

    Agent → REA · analyze_function
    {"procedure": "0x2cfc8"}
    REA → extrait d'instructions de l'agent ·
    0x2d0eb: MOV AX, SI
    0x2d0ed: SHL AX, 0x8
    0x2d0f0: MOV DL, byte ptr [0x53af]
    0x2d0f9: IDIV BX

    SI tient l'index de la balle. Le décalage le multiplie par 256, puis la division utilise le décompte lu à partir de DS:53AF. Les noms de source conservés dans ce champ bullet_template.count. La séquence complète apparaît ci-dessous.

  3. Trouvez où le motif se tourne vers le joueur

    Même fonction résultat · extrait de but
    0x2d190: SUB AX, word ptr [0x53a6]
    0x2d198: SUB AX, word ptr [0x53a4]
    0x2d19d: CALLF 0x1000:1da8
    0x2d1a2: ADD word ptr [BP + -0x2], AX
    C++maintenu correspondant
    group_angle_offset += iatan2(
      player_pos.cur.y - bullet_template.origin.y,
      player_pos.cur.x - bullet_template.origin.x
    );

    Les opérandes d'instruction exposent deux différences de coordonnées et un assistant de direction. Sa valeur de retour est ajoutée à l'angle relatif de l'anneau. Les noms de source rendent ces adresses lisibles; REA permet à l'agent de vérifier les opérations d'origine derrière elles.

De l'assemblage au C++lisible

Sélectionnez une étape pour faire correspondre les instructions d'origine avec le calcul de l'angle. Ce résumé suit le chemin de l'anneau visé; la source complète gère également les spreads, les piles et les motifs aléatoires.

REA * instructions 16 bits d'origine
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
Résumé lisible de l'anneau visé 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 * Lire l'index des puces. L'argument de pile est chargé dans SI. Dans un anneau à 16 puces, cet indice de membre va de 0 à 15.

L'ensemble sélectionne la branche de la bague visée, le calcul de la visée et la mémorisation finale. Le C++ ci-dessus est un résumé lisible. Les vérifications du compilateur ci-dessous s'appliquent à la source maintenue dans le projet lié.

Lire l'anneau maintenu et la source de visée
Macro annulaire * Branche TH04, extrait
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
    group_complete = true;
}
goto aim_or_no_aim;
Angle et vélocité · extrait de la source
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);

Macro d'anneau · Source de visée et de vélocité · Représentation angulaire

Vérification de la source maintenue

Les vérifications enregistrées du projet TH04 compilent le code de génération de puces, y compris cet assistant, avec sa chaîne d'outils Turbo C++ 4.0 J épinglée.

2 139 octets correspondants

Le code de génération de puces compilé correspond à une section de 2 139 octets de l'exécutable d'origine.

Deux constructions propres

Deux builds distincts produisent les mêmes octets correspondants. Les hachages d'entrée enregistrés correspondent à la source maintenue illustrée ici.

Enregistré le 3 octobre 2026. Lire les vérifications du compilateur.

Identité cible et portée de l'analyse
Cible d'origine MAIN.EXE, 156 258 octets, sous-titres MZ
Entrée d'aide 0x2cfc8 dans l'image chargée de REA
Décalage du fichier d'origine 0x1e7c8, retourné par address_to_file_offset
Inspection du code enregistré REA 4.1.0 · 7 octobre 2026

Les vérifications du compilateur couvrent la section complète d'ajout de puces de code, y compris cette aide. Ils comparent également sa contribution à la CARTE et sa relocalisation qui se chevauchent.

REA a vérifié l'image de charge DOS statique au segment de charge 0x1000. Ses adresses décrivent cette image d'analyse. Le résultat de la fonction rapporte 503 octets de corps dans deux plages sur une étendue de 517 octets; les instructions sélectionnées ci-dessus se trouvent dans ces plages rapportées.

Les noms des sources et les vérifications du compilateur proviennent du point de contrôle TH04 0d72e980. Les observations de reconstruction antérieures utilisaient les propres scripts d'analyse du projet; cette page ajoute une nouvelle inspection REA de la même cible d'origine. L'identité du jeu fourni est épinglée par son manifeste de référentiel, avec une provenance de vidage vierge indépendante toujours ouverte.

La figure illustre le calcul de l'angle. Les contrôles complets du jeu, le timing et le comportement du matériel PC-98 ont des vérifications d'exécution distinctes dans le projet de reconstruction.

La reconstruction complète du TH04

Le projet construit les quatre produits DOS du jeu à partir de C++ et d'assembly maintenus. Au-delà de la génération de puces, la source couvre les étapes, les boss, le rendu, la saisie, les menus, les fins et la gestion des partitions.

Explorez le référentiel TH04

Haut