Estudio de caso * Touhou 4: Historia de Lotus Land

Reconstruyendo los TH04
patrones de bala.

Un anillo de balas comienza con un cálculo de ángulo corto. Use REA para inspeccionar la función DOS original, luego siga sus instrucciones en C ++ legible.

PC-98 · DOS de 16 bits * C++ y ensamblado

Ver la reconstrucción del TH04

De las instrucciones originales a la fuente verificada

  1. 01 * Juego originalPRINCIPAL.EXEEl ejecutable PC-98 y su ayudante de ángulo de bala.
  2. 02 * Inspeccionar con REA Instrucciones + referenciasVerifique el código DOS cargado y lea el cálculo del ángulo del ejecutable.
  3. 03 * Leer el C++Espacio → apuntar → rotarConecte cada operación a la reconstrucción mantenida.
  4. 04 * Verifique la fuente2.139 bytes coincidentesLas comprobaciones grabadas del compilador cubren el código de generación de viñetas que contiene este ayudante.
REA devuelve el código original y su evidencia de análisis. El proyecto TH04 proporciona las comprobaciones de código fuente y compilador mantenidas.

Cómo apunta un anillo al jugador

El ataque de Elly solicita un anillo apuntado con un conteo inicial de 16. Un ayudante calcula la dirección de cada bala. El mismo anillo puede mirar en una dirección fija o girar hacia el jugador.

Su agente de codificación

Usa REA para descubrir cómo TH04 crea un anillo de balas y lo apunta al jugador. Explique el cálculo y muestre el código.

Un indicador de ejemplo, con el ejecutable original y el pago de reconstrucción disponibles localmente.

TH04 almacena un giro completo en el sentido de las agujas del reloj en 256 unidades de ángulo. Para 16 viñetas, cada índice agrega 16 unidades: 0, 16, 32, …, 240. Al agregar la dirección del jugador, se rotan esas posiciones juntas.

Dos diagramas de un anillo de 16 balas. El anillo fijo comienza en ángulo cero. Agregar una dirección del jugador de 40 gira cada dirección en la misma cantidad; la primera viñeta resaltada apunta hacia el jugador. Ambos mantienen un espaciado de 16 unidades de ángulo, o 22.5 grados.
Una ilustración de la matemática del ángulo recuperado para el conteo 16, la dirección del jugador 40 y la rotación de la plantilla 0. Figura abierta

La plantilla de cocción en la fuente recuperada

Ataque anular de Elly * extracto de la fuente
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();

Estas líneas seleccionan el patrón antes de la dificultad y el ajuste del rendimiento. Lea la fuente del ataque.

Qué devuelve REA

Inspeccionamos bullet_velocity_and_angle_set(), la función que establece la velocidad y el ángulo de cada bala. REA devuelve sus instrucciones, pseudocódigo y referencias. Tres partes de ese resultado explican el patrón.

  1. Verifique la imagen de DOS antes de leer su código

    Agente → REA
    open_binary
    {"path": "MAIN.EXE"}
    
    inspect_native_load_image
    {}
    REA → agente * campos seleccionados
    status: "verified"
    format: "dos-mz"
    load_segment: 4096
    header_bytes: 6144
    module_bytes: 150114

    La comprobación vincula el código cargado y los registros de reubicación al ejecutable suministrado. La ruta anterior se acorta para su visualización.

  2. Lee el anillo multiplica y divide

    Agente → REA · analyze_function
    {"procedure": "0x2cfc8"}
    REA → extracto de instrucciones del agente ·
    0x2d0eb: MOV AX, SI
    0x2d0ed: SHL AX, 0x8
    0x2d0f0: MOV DL, byte ptr [0x53af]
    0x2d0f9: IDIV BX

    SI sostiene el índice de bala. El desplazamiento lo multiplica por 256, luego la división usa el recuento leído de DS:53AF. La fuente mantenida nombra ese campo bullet_template.count. La secuencia completa aparece a continuación.

  3. Encuentra dónde se dirige el patrón hacia el jugador

    Resultado de la misma función · extracto del objetivo
    0x2d190: SUB AX, word ptr [0x53a6]
    0x2d198: SUB AX, word ptr [0x53a4]
    0x2d19d: CALLF 0x1000:1da8
    0x2d1a2: ADD word ptr [BP + -0x2], AX
    Correspondiente C ++ mantenido
    group_angle_offset += iatan2(
      player_pos.cur.y - bullet_template.origin.y,
      player_pos.cur.x - bullet_template.origin.x
    );

    Los operandos de instrucción exponen dos diferencias de coordenadas y un ayudante de dirección. Su valor de retorno se suma al ángulo relativo del anillo. Los nombres de origen hacen que esas direcciones sean legibles; REA permite al agente verificar las operaciones originales detrás de ellas.

Del ensamblado al C ++ legible

Seleccione un paso para que coincida con las instrucciones originales con el cálculo del ángulo. Este resumen sigue la ruta del anillo objetivo; la fuente completa también maneja spreads, pilas y patrones aleatorios.

REA * instrucciones originales de 16 bits
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
Resumen de anillo dirigido legible por 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 * Lea el índice de viñetas. El argumento de la pila se carga en SI. En un anillo de 16 balas, este índice de miembros va de 0 a 15.

El conjunto selecciona la rama del anillo objetivo, el cálculo del objetivo y el almacén final. El C++ anterior es un resumen legible. Las comprobaciones del compilador a continuación se aplican a la fuente mantenida en el proyecto vinculado.

Lea el anillo mantenido y apunte la fuente
Macro de anillo * Rama TH04, extracto
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
    group_complete = true;
}
goto aim_or_no_aim;
Ángulo y velocidad · extracto de la fuente
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 de anillo · Objetivo y fuente de velocidad · Representación de ángulos

Comprobación de la fuente mantenida

Las comprobaciones grabadas del proyecto TH04 compilan el código de generación de viñetas, incluido este ayudante, con su cadena de herramientas Turbo C++ 4.0 J anclada.

2.139 bytes coincidentes

El código compilado de generación de viñetas coincide con una sección de 2139 bytes del ejecutable original.

Dos construcciones limpias

Dos compilaciones separadas producen los mismos bytes coincidentes. Los hashes de entrada grabados coinciden con la fuente mantenida que se muestra aquí.

Grabado el 3 de octubre de 2026. Leer las comprobaciones del compilador.

Identidad del objetivo y alcance del análisis
Objetivo original MAIN.EXE, 156,258 bytes, DOS MZ
Entrada auxiliar 0x2cfc8 en la imagen cargada de REA
Desplazamiento del archivo original 0x1e7c8, devuelto por address_to_file_offset
Inspección de código grabado REA 4.1.0 * 7 de octubre de 2026

Las comprobaciones del compilador cubren la sección completa de código de adición de viñetas, incluido este ayudante. También comparan su contribución al MAPA y la reubicación superpuesta.

REA verificó la imagen de carga estática de DOS en el segmento de carga 0x1000. Sus direcciones describen esa imagen de análisis. El resultado de la función informa 503 bytes de cuerpo en dos rangos en un intervalo de 517 bytes; las instrucciones seleccionadas anteriormente se encuentran en esos rangos informados.

Los nombres de origen y las comprobaciones del compilador provienen del punto de control TH04 0d72e980. Las observaciones de reconstrucción anteriores utilizaron los propios scripts de análisis del proyecto; esta página agrega una nueva inspección REA del mismo objetivo original. La identidad del juego suministrado está anclada por su manifiesto de repositorio, con la procedencia independiente de volcado prístino aún abierta.

La figura ilustra el cálculo del ángulo. Los controles de juego completo, el tiempo y el comportamiento del hardware PC-98 tienen comprobaciones de tiempo de ejecución separadas en el proyecto de reconstrucción.

La reconstrucción completa del TH04

El proyecto construye los cuatro productos DOS del juego a partir de C++ y ensamblado mantenidos. Más allá de la generación de viñetas, la fuente cubre etapas, jefes, renderizado, entrada, menús, finales y manejo de partituras.

Explore el repositorio TH04

Arriba