Mercurial > touhou-doc
changeset 8:c5b074b0abbd
Add T6RP documentation
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Tue, 23 Aug 2011 13:18:17 +0200 |
parents | 2a7b9d62c0c4 |
children | 6d47bfc23c64 |
files | 06/t6rp.xhtml index.xhtml |
diffstat | 2 files changed, 89 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/06/t6rp.xhtml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="utf-8"?> +<?xml-stylesheet type="text/css" href="../style.css"?> +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> + <head> + <title>T6RP format</title> + </head> + <body> + <h1>T6RP format</h1> + <p>The T6RP format is the replay format used by EoSD.</p> + + <p>It is composed of a header and an "encrypted" data section, which is itself composed of a header, per-stage structures and lists of keystates.</p> + + + <h2>Header</h2> +<pre> +typedef struct { + char magic[4]; // T6RP + uint16_t unknown; //TODO: always 0x0102 + // Seems to be a switch, if 0x0102 do something, else (whatever the value is), do something else + uint8_t player; // 0 = ReimuA, 1 = ReimuB, 2 = MarisaA, 3 = MarisaB + uint8_t rank; // 0 = Easy, 3 = Lunatic, 4 = Extra + uint32_t checksum; // (0x3f000318 + key + sum(c for c in decrypted_data)) % (2 ** 32) + uint16_t unknown2; //TODO: seems to be ignored by the game + uint8_t key; + char crypted_data[]; // crypted(a, i) = (a + key + 7*i) % 256 + // decrypted(c, i) = (c - key - 7*i) % 256 +} thrpy6_header_t; +</pre> + + <h2>Decrypting the data section.</h2> + <p>As stated earlier, the data section is encrypted. Luckily, this encryption is quite simplistic, and encrypting/decrypting it is easy (see this snippet of python3 code):</p> +<pre> +def decrypt(key, data): + return bytes((c - key - 7 * i) % 256 for i, c in enumerate(data)) + +def encrypt(key, data): + return bytes((c + key + 7 * i) % 256 for i, c in enumerate(data)) +</pre> + + <h2>Encrypted header</h2> +<pre> +typedef struct { + uint8_t unknown; //TODO: seems to be ignored by the game + char date[9]; // null-terminated string + char name[9]; // null-terminated string + uint16_t unknown2; //TODO: seems to be ignored by the game + uint32_t score; //TODO: Total score. seems to be ignored by the game + uint32_t unknown3; //TODO: seems to be ignored by the game + float slowdown_rate; // As a percentage, not a proper rate + uint8_t unknwon[4]; //TODO: seems to have no effect + uint32_t stage1_offset; // Offset of a thrpy6_stage_t from the start of the file (including the unencrypted header) + uint32_t stage2_offset; + uint32_t stage3_offset; + uint32_t stage4_offset; + uint32_t stage5_offset; + uint32_t stage6_offset; + uint32_t stage7_offset; +} thrpy6_encrypted_header; +</pre> + + <h2>Stage entry</h2> +<pre> +typedef struct { + uint32_t score; + uint16_t random_seed; + uint16_t unknown1; //TODO: seems to be ignored by the game + uint8_t power; + int8_t lives; + int8_t bombs; + uint8_t difficulty; //TODO: WARNING: This has a huge effect on the game! + // It is also called rank (but we use the term "difficulty" because "rank" is the official name for Easy/Normal/Hard/Lunatic/Extra) + // See: http://en.touhouwiki.net/wiki/Embodiment_of_Scarlet_Devil/Gameplay#Rank + uint8_t unknown3[3]; //TODO: seems to be ignored by the game. Padding? + thrpy6_keystate_t keystates[]; +} thrpy6_stage_t; +</pre> + + <h2>Keystates</h2> +<pre> +struct { + uint32_t time; // Time of the event, most probably exprimed in frames + uint16_t keys; // 1 = shoot, 2 = bomb, 4 = focus, 8 = ?, 16 = up, 32 = down, 64 = left, 128 = right + uint16_t unknown; //TODO: seems to be ignored by the game +} thrpy6_keystate_t; +</pre> + </body> +</html>
--- a/index.xhtml +++ b/index.xhtml @@ -12,6 +12,7 @@ <li><a href="06/pbg3.xhtml">PBG3</a> (dat archives)</li> <li><a href="06/std.xhtml">STD</a> (stages)</li> <li><a href="06/ecl.xhtml">ECL</a> (enemies and patterns)</li> + <li><a href="06/t6rp.xhtml">T6RP</a> (replays)</li> </ul> <h3>Opcodes</h3> <ul>