---
title: 'Αντίστροφη μηχανική του TH04: Σχηματισμοί βολίδων DOS — REA'
url: https://rea.tools/el/showcase/th04/
---

[Αρχική](https://rea.tools/el/) / [Μελέτες](https://rea.tools/el/showcase/) / TH04

Μελέτη · Touhou 4: Lotus Land Story

# Ανακατασκευή των σχηματισμών βολίδων του TH04.

Ένας δακτύλιος βολίδων ξεκινά με έναν σύντομο υπολογισμό γωνίας. Χρησιμοποιήστε το REA για να εξετάσετε την αρχική συνάρτηση DOS και έπειτα ακολουθήστε τις εντολές της μέχρι τον ευανάγνωστο κώδικα C++.

PC-98 · DOS 16 bit · C++ και assembly

[Δείτε την ανακατασκευή του TH04](https://github.com/N0zoM1z0/th04)

Από τις αρχικές εντολές σε ελεγμένο πηγαίο κώδικα

1. 01 · Αρχικό παιχνίδι

   **MAIN.EXE**

   Το εκτελέσιμο PC-98 και η βοηθητική συνάρτηση γωνίας βολίδων.
2. 02 · Εξετάστε με το REA

   **Εντολές + αναφορές**

   Επαληθεύστε τον φορτωμένο κώδικα DOS και διαβάστε τον υπολογισμό γωνίας από το εκτελέσιμο.
3. 03 · Διαβάστε τον κώδικα C++

   **Κατανομή → στόχευση → περιστροφή**

   Συνδέστε κάθε πράξη με τη συντηρούμενη ανακατασκευή.
4. 04 · Ελέγξτε τον πηγαίο κώδικα

   **2,139 ίδια byte**

   Οι καταγεγραμμένοι έλεγχοι μεταγλώττισης καλύπτουν τον κώδικα δημιουργίας βολίδων που περιέχει αυτή τη βοηθητική συνάρτηση.

Το REA επιστρέφει τον αρχικό κώδικα και τα στοιχεία ανάλυσής του. Το έργο TH04 παρέχει τον συντηρούμενο πηγαίο κώδικα και τους ελέγχους μεταγλώττισης.

## Πώς ένας δακτύλιος στοχεύει τον παίκτη

Η επίθεση της Elly ζητά έναν στοχευμένο δακτύλιο με αρχικό πλήθος 16. Μια βοηθητική συνάρτηση υπολογίζει την κατεύθυνση κάθε βολίδας. Ο ίδιος δακτύλιος μπορεί να έχει σταθερή κατεύθυνση ή να στρέφεται προς τον παίκτη.

Ο βοηθός προγραμματισμού σας

Χρησιμοποιήστε το REA για να βρείτε πώς το TH04 δημιουργεί έναν δακτύλιο βολίδων και τον στοχεύει στον παίκτη. Εξηγήστε τον υπολογισμό και δείξτε τον κώδικα.

Παράδειγμα προτροπής, με το αρχικό εκτελέσιμο και το τοπικό αντίγραφο της ανακατασκευής διαθέσιμα τοπικά.

Το TH04 αποθηκεύει μια πλήρη δεξιόστροφη περιστροφή σε 256 μονάδες γωνίας. Για 16 βολίδες, κάθε δείκτης προσθέτει 16 μονάδες: `0, 16, 32, …, 240`. Η πρόσθεση της κατεύθυνσης του παίκτη περιστρέφει αυτές τις θέσεις μαζί.

![Δύο διαγράμματα δακτυλίου 16 βολίδων. Ο σταθερός δακτύλιος ξεκινά από γωνία μηδέν. Η πρόσθεση κατεύθυνσης παίκτη 40 περιστρέφει κάθε κατεύθυνση κατά το ίδιο ποσό· η επισημασμένη πρώτη βολίδα δείχνει προς τον παίκτη. Και οι δύο διατηρούν απόσταση 16 μονάδων γωνίας, ή 22.5 μοιρών.](https://rea.tools/assets/localized/el/figures/th04-bullet-ring.svg)

Απεικόνιση της ανακτημένης αριθμητικής γωνιών για πλήθος 16, κατεύθυνση παίκτη 40 και περιστροφή προτύπου 0. [Ανοίξτε το σχήμα](https://rea.tools/assets/localized/el/figures/th04-bullet-ring.svg)

### Το πρότυπο βολής στον ανακτημένο πηγαίο κώδικα

Επίθεση δακτυλίου της Elly · απόσπασμα πηγαίου κώδικα

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

Αυτές οι γραμμές επιλέγουν τον σχηματισμό πριν από τη ρύθμιση της δυσκολίας και της απόδοσης. [Διαβάστε τον πηγαίο κώδικα της επίθεσης](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/boss/elly_phase_ring16.cpp#L26).

## Τι επιστρέφει το 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 επιτρέπει στον βοηθό να ελέγξει τις αρχικές πράξεις πίσω από αυτές.

## Από assembly σε ευανάγνωστο κώδικα C++

Επιλέξτε ένα βήμα για να αντιστοιχίσετε τις αρχικές εντολές με τον υπολογισμό γωνίας. Αυτή η σύνοψη ακολουθεί τη διαδρομή του στοχευμένου δακτυλίου· ο πλήρης πηγαίος κώδικας χειρίζεται επίσης βεντάλιες βολίδων, στοίβες και τυχαίους σχηματισμούς.

REA · αρχικές εντολές 16 bit

```
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.

**02 · Κατανείμετε τις κατευθύνσεις σε μια πλήρη περιστροφή.** Η `SHL AX,8` πολλαπλασιάζει επί 256. Το πλήθος επεκτείνεται με μηδενικά σε μια λέξη και έπειτα η `IDIV` διαιρεί το γινόμενο με αυτό το πλήθος. Για πλήθος 16, κάθε δείκτης προχωρά κατά 16 μονάδες γωνίας.

**03 · Προσθέστε την κατεύθυνση του παίκτη.** Οι δύο αφαιρέσεις σχηματίζουν συντεταγμένες παίκτη μείον αρχής. Η βοηθητική συνάρτηση κατεύθυνσης επιστρέφει μια γωνία στον `AX`· η πρόσθεσή της στρέφει ολόκληρο τον δακτύλιο προς τον παίκτη.

**04 · Προσθέστε την περιστροφή του σχηματισμού.** Η `ADD AL,[0x53ad]` προσθέτει τη γωνία του προτύπου. Το αρχικό πρότυπο της Elly την ορίζει σε μηδέν· άλλοι σχηματισμοί μπορούν να χρησιμοποιούν την ίδια βοηθητική συνάρτηση με περιστροφή.

**05 · Κρατήστε την τελική γωνία σε ένα byte.** Η αποθήκευση γράφει τον `AL` στο πεδίο γωνίας δημιουργίας. Οι τιμές επανέρχονται στο μηδέν μετά το 255, όπως και η μετατροπή σε μη προσημασμένο byte. Ο περιβάλλων πηγαίος κώδικας μετατρέπει επίσης αυτή τη γωνία και το μέτρο ταχύτητας σε διάνυσμα ταχύτητας.

Ο κώδικας assembly επιλέγει τον κλάδο στοχευμένου δακτυλίου, τον υπολογισμό στόχευσης και την τελική αποθήκευση. Ο παραπάνω κώδικας 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);
```

[Μακροεντολή δακτυλίου](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add_impl.hpp#L4) · [Πηγαίος κώδικας στόχευσης και διανύσματος ταχύτητας](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L422) · [Αναπαράσταση γωνίας](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/types.hpp#L6)

## Έλεγχος του συντηρούμενου πηγαίου κώδικα

Οι καταγεγραμμένοι έλεγχοι του έργου TH04 μεταγλωττίζουν τον κώδικα δημιουργίας βολίδων, μαζί με αυτή τη βοηθητική συνάρτηση, με τη συγκεκριμένη αλυσίδα εργαλείων Turbo C++ 4.0J.

### 2,139 ίδια byte

Ο μεταγλωττισμένος κώδικας δημιουργίας βολίδων συμφωνεί με ένα τμήμα 2,139 byte του αρχικού εκτελέσιμου.

### Δύο καθαρές μεταγλωττίσεις

Δύο ξεχωριστές μεταγλωττίσεις παράγουν τα ίδια byte που συμφωνούν με το πρωτότυπο. Οι καταγεγραμμένοι κατακερματισμοί εισόδου συμφωνούν με τον συντηρούμενο πηγαίο κώδικα που εμφανίζεται εδώ.

Καταγράφηκε στις 3 Οκτωβρίου 2026. [Διαβάστε τους ελέγχους μεταγλώττισης](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/reconstruction/product/TH04_SEMANTIC_BULLET_GENERATION_V1236.md#validation).

Ταυτότητα στόχου και πεδίο ανάλυσης

|  |  |
| --- | --- |
| Αρχικός στόχος | `MAIN.EXE`, 156,258 byte, DOS MZ |
| Σημείο εισόδου βοηθητικής συνάρτησης | `0x2cfc8` στη φορτωμένη εικόνα του REA |
| Μετατόπιση στο αρχικό αρχείο | `0x1e7c8`, επιστρέφεται από την `address_to_file_offset` |
| Καταγεγραμμένη εξέταση κώδικα | REA 4.1.0 · 7 Οκτωβρίου 2026 |

Οι έλεγχοι μεταγλώττισης καλύπτουν ολόκληρο το τμήμα κώδικα προσθήκης βολίδων, μαζί με αυτή τη βοηθητική συνάρτηση. Συγκρίνουν επίσης τη συνεισφορά του στο MAP και την επικαλυπτόμενη μετεγκατάσταση.

Το REA επαλήθευσε τη στατική εικόνα φόρτωσης DOS στο τμήμα φόρτωσης `0x1000`. Οι διευθύνσεις του περιγράφουν αυτή την εικόνα ανάλυσης. Το αποτέλεσμα συνάρτησης αναφέρει 503 byte σώματος σε δύο περιοχές μέσα σε έκταση 517 byte· οι παραπάνω επιλεγμένες εντολές βρίσκονται μέσα σε αυτές τις αναφερόμενες περιοχές.

Τα ονόματα του πηγαίου κώδικα και οι έλεγχοι μεταγλώττισης προέρχονται από το ορόσημο TH04 `0d72e980`. Προηγούμενες παρατηρήσεις ανακατασκευής χρησιμοποίησαν τα script ανάλυσης του ίδιου του έργου· αυτή η σελίδα προσθέτει μια νέα εξέταση REA του ίδιου αρχικού στόχου. Η ταυτότητα του παρεχόμενου παιχνιδιού καθορίζεται από το δηλωτικό του αποθετηρίου του, ενώ η ανεξάρτητη τεκμηρίωση προέλευσης ενός ανέπαφου αντιγράφου παραμένει ανοικτή.

Το σχήμα απεικονίζει τον υπολογισμό γωνίας. Ο χειρισμός του πλήρους παιχνιδιού, ο χρονισμός και η συμπεριφορά του υλικού PC-98 έχουν ξεχωριστούς ελέγχους κατά την εκτέλεση στο έργο ανακατασκευής.

## Η πλήρης ανακατασκευή του TH04

Το έργο μεταγλωττίζει τα τέσσερα προϊόντα DOS του παιχνιδιού από συντηρούμενο κώδικα C++ και assembly. Πέρα από τη δημιουργία βολίδων, ο πηγαίος κώδικας καλύπτει στάδια, αρχηγούς, απόδοση γραφικών, είσοδο, μενού, φινάλε και χειρισμό βαθμολογίας.

[Εξερευνήστε το αποθετήριο TH04](https://github.com/N0zoM1z0/th04)

- [Πηγαίος κώδικας δημιουργίας βολίδων](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/src/main/bullet/add.cpp#L292)Η πλήρης βοηθητική συνάρτηση, άλλοι τύποι σχηματισμών και ρύθμιση προτύπων.
- [Οδηγός μεταγλώττισης και εκτέλεσης DOS](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/DOS_BUILD.md)Μεταγλωττίστε τον πηγαίο κώδικα και δοκιμάστε τον στη ροή εξομοιωτή PC-98 του έργου.
- [Τρέχουσα κατάσταση του έργου](https://github.com/N0zoM1z0/th04/blob/0d72e9801a5c14c10384efcbb6734ceccb74ee63/docs/RE_HANDOFF.md)Επαλήθευση DOS και η ξεχωριστή μεταφορά σε εγγενή κώδικα x64.
