---
title: 'Engenharia reversa de TH04: testes padrões da bala do DOS-REA'
url: https://rea.tools/pt-BR/showcase/th04/
---

[Casa](https://rea.tools/pt-BR/) / [Vitrines](https://rea.tools/pt-BR/showcase/) / TH04

Estudo de caso · Touhou 4: História da Lotus Land

# Reconstrução de TH04 padrões de bala.

Um anel de balas começa com um cálculo de ângulo curto. Use REA para inspecionar a função DOS original e, em seguida, siga suas instruções em C++legível.

PC-98 · 16-bit DOS \* C++ e montagem

[Ver a reconstrução TH04](https://github.com/N0zoM1z0/th04)

Das instruções originais à fonte verificada

1. 01 \* jogo Original

   **Principal.EXE**

   O executável PC-98 e seu auxiliar de ângulo de bala.
2. 02 \* inspeccionar com REA

   **Instruções + referências**

   Verifique o código dos carregado e leia o cálculo do ângulo do executável.
3. 03 \* leia o c++

   **Espaço \* objectivo \* rotação**

   Ligar cada operação à reconstrução mantida.
4. 04 \* verificar a fonte

   **2.139 bytes correspondentes**

   As verificações do compilador gravadas cobrem o código de geração de marcadores que contém este auxiliar.

REA retorna o código original e sua evidência de análise. O projeto TH04 fornece as verificações de origem e compilador mantidas.

## Como um anel visa o jogador

O ataque de Elly solicita um anel apontado Com uma contagem inicial de 16. Um auxiliar calcula a direção de cada bala. O mesmo anel pode estar voltado para uma direção fixa ou virar em direção ao jogador.

O seu agente de codificação

Use REA para descobrir como TH04 cria um anel de balas e o aponta para o jogador. Explique o cálculo e mostre o código.

Um exemplo de prompt, com o executável original e o checkout de reconstrução disponíveis localmente.

TH04 armazena uma volta completa no sentido horário em 256 unidades do ângulo. Para 16 marcadores, cada índice adiciona 16 unidades: `0, 16, 32, …, 240`. Adicionar a direção do jogador gira essas posições juntas.

![Dois diagramas de um anel de 16 balas. O anel fixo começa no ângulo zero. Adicionar uma direção de Jogador de 40 gira todas as direções na mesma quantidade; o primeiro marcador destacado aponta para o jogador. Ambos mantêm um espaçamento de 16 unidades de ângulo, ou 22,5 graus.](https://rea.tools/assets/localized/pt-BR/figures/th04-bullet-ring.svg)

Uma ilustração da matemática do ângulo recuperado para a contagem 16, direção do jogador 40 e rotação do Modelo 0. [Figura aberta](https://rea.tools/assets/localized/pt-BR/figures/th04-bullet-ring.svg)

### O modelo de disparo na fonte recuperada

Elly's ring attack \* trecho da fonte

```
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();
```

Essas linhas selecionam o padrão antes da dificuldade e do ajuste de desempenho. [Leia a fonte do ataque](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/boss/elly_phase_ring16.cpp#L26).

## O que REA retorna

Nós inspecionamos `bullet_velocity_and_angle_set()`, a função que define a velocidade e o ângulo de cada bala. REA retorna suas instruções, pseudocódigo e referências. Três partes desse resultado explicam o padrão.

1. #### Verifique a imagem do DOS antes de ler seu código

   Agente REA

   ```
   open_binary
   {"path": "MAIN.EXE"}

   inspect_native_load_image
   {}
   ```

   REA extraterritorial \* campos seleccionados

   ```
   status: "verified"
   format: "dos-mz"
   load_segment: 4096
   header_bytes: 6144
   module_bytes: 150114
   ```

   A verificação vincula o código carregado e os registros de realocação ao executável fornecido. O caminho acima é encurtado para exibição.
2. #### Leia o anel multiplicar e dividir

   Agente REA · `analyze_function`

   ```
   {"procedure": "0x2cfc8"}
   ```

   REA7 agente \* excerto de instruções

   ```
   0x2d0eb: MOV AX, SI
   0x2d0ed: SHL AX, 0x8
   0x2d0f0: MOV DL, byte ptr [0x53af]
   0x2d0f9: IDIV BX
   ```

   `SI` mantém o índice de marcadores. O deslocamento o multiplica por 256, então a divisão usa a contagem lida de `DS:53AF`. Os nomes de origem mantidos nesse campo `bullet_template.count`. A sequência completa é apresentada abaixo.
3. #### Encontre onde o padrão gira em direção ao jogador

   Resultado da mesma função \* trecho aim

   ```
   0x2d190: SUB AX, word ptr [0x53a6]
   0x2d198: SUB AX, word ptr [0x53a4]
   0x2d19d: CALLF 0x1000:1da8
   0x2d1a2: ADD word ptr [BP + -0x2], AX
   ```

   C++mantido correspondente

   ```
   group_angle_offset += iatan2(
     player_pos.cur.y - bullet_template.origin.y,
     player_pos.cur.x - bullet_template.origin.x
   );
   ```

   Os operandos de instrução expõem duas diferenças de coordenadas e um auxiliar de direção. O seu valor de retorno é adicionado ao ângulo relativo do anel. Os nomes de origem tornam esses endereços legíveis; REA permite que o agente verifique as operações originais por trás deles.

## Da montagem ao C++legível

Selecione uma etapa para corresponder às instruções originais com o cálculo do ângulo. Este resumo segue a trajectória do anel visado; a fonte completa também lida com spreads, stacks e padrões aleatórios.

REA \* instruções originais 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
```

C++ legível · resumo do anel direcionado

```
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 \* leia o índice do marcador.** O argumento stack é carregado em `SI`. Num anel de 16 marcadores, este índice de membros vai de 0 a 15.

**02 \* Espaço as direções em torno de uma volta completa.** `SHL AX,8` multiplicado por 256. A contagem é zero-estendida em uma palavra, então `IDIV` divide o produto por essa contagem. Para a contagem 16, cada Índice avança 16 unidades angulares.

**03 \* adicione a direção do jogador.** As duas subtrações formam coordenadas Jogador-menos-origem. O Auxiliar de direção retorna um ângulo em `AX`; adicionando-o vira todo o anel em direção ao jogador.

**04 \* adicionar a rotação do padrão.** `ADD AL,[0x53ad]` adiciona o ângulo do modelo. O modelo inicial de Elly o define como zero; outros padrões podem usar o mesmo auxiliar com uma rotação.

**05 \* mantenha o ângulo final em um byte.** A loja escreve `AL` para o campo spawn-angle. Valores wrap após 255, assim como o elenco unsigned-byte faz. A fonte circundante também converte este ângulo e velocidade em velocidade.

O conjunto selecciona a ramificação do anel de mira, o cálculo da mira e o armazenamento final. O C++ acima é um resumo legível. As verificações do compilador abaixo se aplicam à fonte mantida no projeto vinculado.

Leia o anel mantido e aim fonte

Macro do anel \* ramificação TH04, excerto

```
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
    group_complete = true;
}
goto aim_or_no_aim;
```

Ângulo e velocidade \* excerto da fonte

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

[Anel macro](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add_impl.hpp#L4) · [Alvo e fonte de velocidade](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L422) · [Representação do ângulo](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/types.hpp#L6)

## Verificação da fonte mantida

As verificações registadas do projecto TH04 compilam o código de geração de marcadores, incluindo este auxiliar, com a sua cadeia de ferramentas Turbo C++ 4.0 j fixada.

### 2.139 bytes correspondentes

O código compilado de geração de marcadores corresponde a uma seção de 2.139 bytes do executável original.

### Duas construções limpas

Duas compilações separadas produzem os mesmos bytes correspondentes. Os hashes de entrada gravados correspondem à fonte mantida mostrada aqui.

Gravado em 3 de outubro de 2026. [Leia as verificações do compilador](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/reconstruction/product/TH04_SEMANTIC_BULLET_GENERATION_V1236.md#validation).

Identidade-alvo e âmbito de análise

|  |  |
| --- | --- |
| Alvo Original | `MAIN.EXE`, 156.258 bytes, dos MZ |
| Entrada auxiliar | `0x2cfc8` na imagem carregada de REA |
| Deslocamento do ficheiro Original | `0x1e7c8`, devolvido por `address_to_file_offset` |
| Inspecção do Código registado | REA 4.1.0 \* 7 de outubro de 2026 |

As verificações do compilador cobrem a seção completa do código de adição de marcadores, incluindo este auxiliar. Eles também comparam a contribuição do mapa e a deslocalização sobreposta.

REA verificou a imagem estática de Carga Dos no segmento de carga `0x1000`. Os seus endereços descrevem essa imagem de análise. O resultado da função reporta 503 bytes de corpo em dois intervalos num intervalo de 517 bytes; as instruções seleccionadas acima situam-se nesses intervalos comunicados.

Os nomes de origem e as verificações do compilador vêm do ponto de verificação TH04 `0d72e980`. As observações de reconstrução anteriores utilizaram os próprios scripts de análise do projecto; esta página inclui uma nova inspecção REA do mesmo alvo original. A identidade do jogo fornecido é fixada por seu manifesto de repositório, com proveniência independente de despejo intocado ainda aberta.

A figura ilustra o cálculo do ângulo. Os controlos completos do jogo, a temporização e o comportamento do hardware PC-98 têm verificações de tempo de execução separadas no projecto de reconstrução.

## A reconstrução completa do TH04

O projeto constrói os quatro produtos DOS do jogo a partir de C++ e assembly mantidos. Além da geração de marcadores, a fonte abrange estágios, chefes, renderização, entrada, menus, finais e manipulação de pontuação.

[Explore o repositório TH04](https://github.com/N0zoM1z0/th04)

- [Fonte de geração de marcadores](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L292)O auxiliar completo, outros tipos de padrões e ajuste de modelos.
- [Guia de construção e execução do DOS](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/DOS_BUILD.md)Construa a fonte e teste-a no fluxo de trabalho do emulador PC-98 do projeto.
- [Estado actual do projecto](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/RE_HANDOFF.md)Verificação DOS e a porta x64 nativa separada.
