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

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

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

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

Δείτε την ανακατασκευή του 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 μοιρών.
Απεικόνιση της ανακτημένης αριθμητικής γωνιών για πλήθος 16, κατεύθυνση παίκτη 40 και περιστροφή προτύπου 0. Ανοίξτε το σχήμα

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

Επίθεση δακτυλίου της Elly · απόσπασμα πηγαίου κώδικα
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();

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

Τι επιστρέφει το 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.

Ο κώδικας 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);

Μακροεντολή δακτυλίου · Πηγαίος κώδικας στόχευσης και διανύσματος ταχύτητας · Αναπαράσταση γωνίας

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

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

2,139 ίδια byte

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

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

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

Καταγράφηκε στις 3 Οκτωβρίου 2026. Διαβάστε τους ελέγχους μεταγλώττισης.

Ταυτότητα στόχου και πεδίο ανάλυσης
Αρχικός στόχος 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

Κορυφή