diff --git a/src/Episode3/DataIndex.hh b/src/Episode3/DataIndex.hh index a6311687..56748eb3 100644 --- a/src/Episode3/DataIndex.hh +++ b/src/Episode3/DataIndex.hh @@ -582,23 +582,26 @@ struct DeckDefinition { } __attribute__((packed)); // 0x84 bytes in total struct PlayerConfig { - // The first offsets in the comments in this struct are relative to the start - // of the 61/98 command; the second are relative to the start of the - // Ep3PlayerDataSegment structure in the reverse-engineering project; the - // third are relative to the start of this struct. // TODO: Fill in the unknown fields here by looking around callsites of // get_player_data_segment - /* 0728:----:0000 */ parray unknown_a1; - /* 087C:0000:0154 */ uint8_t is_encrypted; - /* 087D:0001:0155 */ uint8_t basis; - /* 087E:0002:0156 */ parray unused; + /* 0000 */ ptext rank_text; // From B7 command + /* 000C */ parray unknown_a1; + /* 0028 */ parray tech_menu_shortcut_entries; + /* 0050 */ parray choice_search_config; + /* 0078 */ parray scenario_progress; + /* 0138 */ be_uint16_t unknown_a2; + /* 013A */ be_uint16_t unknown_a3; + /* 013C */ parray unknown_a4; + /* 0154 */ uint8_t is_encrypted; + /* 0155 */ uint8_t basis; + /* 0156 */ parray unused; // The following fields (here through the beginning of decks) are encrypted // using the trivial algorithm, with the basis specified above, if // is_encrypted is equal to 1. // It appears the card counts field in this structure is actually 1000 (0x3E8) // bytes long, even though in every other place the counts array appears it's // 0x2F0 bytes long. They presumably did this because of the checksum logic. - /* 0880:0004:0158 */ parray card_counts; + /* 0158 */ parray card_counts; // These appear to be an attempt at checksumming the card counts array, but // the algorithm don't cover the entire array and instead reads from later // parts of this structure. This appears to be due to a copy/paste error in @@ -607,26 +610,26 @@ struct PlayerConfig { // [69] and puts the result in card_count_checksums[1], etc. Presumably they // intended to use 20 as the stride instead of 50, which would have exactly // covered the entire card_counts array. - /* 0C68:03EC:0540 */ parray card_count_checksums; + /* 0540 */ parray card_count_checksums; // Yes, these are actually 64-bit integers. They include card IDs and some // other data, encoded in a way I don't fully understand yet. - /* 0CCC:0450:05A4 */ parray unknown_a4; - /* 1ADC:1260:13B4 */ parray unknown_a7; - /* 1B5C:12E0:1434 */ parray decks; - /* 2840:1FC4:2118 */ parray unknown_a8; - /* 2848:1FCC:2120 */ be_uint32_t offline_clv_exp; // CLvOff = this / 100 - /* 284C:1FD0:2124 */ be_uint32_t online_clv_exp; // CLvOn = this / 100 + /* 05A4 */ parray unknown_a5; + /* 13B4 */ parray unknown_a7; + /* 1434 */ parray decks; + /* 2118 */ parray unknown_a8; + /* 2120 */ be_uint32_t offline_clv_exp; // CLvOff = this / 100 + /* 2124 */ be_uint32_t online_clv_exp; // CLvOn = this / 100 struct PlayerReference { /* 00 */ be_uint32_t guild_card_number; /* 04 */ ptext player_name; } __attribute__((packed)); // TODO: What do these player references mean? When are entries added to or // removed from this list? - /* 2850:1FD4:2128 */ parray unknown_a9; - /* 294C:20D0:2224 */ parray unknown_a10; - /* 299C:2120:2274 */ ptext name; - /* 29AC:2130:2284 */ parray unknown_a11; - /* 2A78:21FC:2350 */ + /* 2128 */ parray unknown_a9; + /* 2224 */ parray unknown_a10; + /* 2274 */ ptext name; + /* 2284 */ parray unknown_a11; + /* 2350 */ void decrypt(); void encrypt(uint8_t basis); diff --git a/src/SaveFileFormats.hh b/src/SaveFileFormats.hh index bb7d2fd9..da21c048 100644 --- a/src/SaveFileFormats.hh +++ b/src/SaveFileFormats.hh @@ -135,8 +135,26 @@ struct PSOGCCharacterFile { // The signature field holds the value 0xA205B064, which is 2718281828 in // decimal - approximately e * 10^9. It's unknown why Sega chose this value. /* 0424 */ be_uint32_t signature; - /* 0428 */ be_uint32_t unknown_a2; - /* 042C */ be_uint32_t unknown_a3; + /* 0428 */ be_uint32_t play_time_seconds; + // This field is a collection of several flags and small values. The known + // fields are: + // ------zA BCDEFG-- HHHIIIJJ KLMNOPQR + // z = Function key setting (BB; 0 = menu shortcuts; 1 = chat shortcuts). + // This bit is unused by PSO GC. + // A = Keyboard controls (BB; 0 = on; 1 = off). Note that A is also used + // by PSO GC, but its function is currently unknown. + // G = Choice search setting (0 = enabled; 1 = disabled) + // H = Player lobby labels (0 = name; 1 = name, language, and level; + // 2 = W/D counts; 3 = challenge rank; 4 = nothing) + // I = Idle disconnect time (0 = 15 mins; 1 = 30 mins; 2 = 45 mins; + // 3 = 60 mins; 4 or 5: immediately; 6: 16 seconds; 7: 32 seconds). + // Obviously the behaviors for 4-7 are unintended; this is the result + // of a missing bounds check. + // J = Message speed (0 = slow; 1 = normal; 2 = fast; 3 = very fast) + // P = Cursor position (0 = saved; 1 = non-saved) + // Q = Button config (0 = normal; 1 = L/R reversed) + // R = Map direction (0 = non-fixed; 1 = fixed) + /* 042C */ be_uint32_t option_flags; /* 0430 */ be_uint32_t save_count; /* 0434 */ parray unknown_a4; /* 0664 */ PlayerBank bank; @@ -163,37 +181,54 @@ struct PSOGCCharacterFile { struct PSOGCEp3CharacterFile { /* 00000 */ be_uint32_t checksum; // crc32 of this field (as 0) through end of struct struct Character { - /* 0000 */ PlayerInventory inventory; - /* 034C */ PlayerDispDataDCPCV3 disp; - /* 041C */ be_uint32_t unknown_a1; - /* 0420 */ be_uint32_t creation_timestamp; - /* 0424 */ be_uint32_t signature; // Same value as for Episodes 1&2 (above) - /* 0428 */ be_uint32_t unknown_a2; - /* 042C */ be_uint32_t unknown_a3; - /* 0430 */ be_uint32_t save_count; - /* 0434 */ parray unknown_a4; - /* 0450 */ parray unknown_a5; + // This structure is internally split into two by the game. The offsets here + // are relative to the start of this structure (first column), and relative + // to the start of the second internal structure (second column). + /* 0000:---- */ PlayerInventory inventory; + /* 034C:---- */ PlayerDispDataDCPCV3 disp; + /* 041C:0000 */ be_uint32_t unknown_a1; + /* 0420:0004 */ be_uint32_t creation_timestamp; + /* 0424:0008 */ be_uint32_t signature; // Same value as for Episodes 1&2 (above) + /* 0428:000C */ be_uint32_t play_time_seconds; + // See the comment in PSOGCCharacterFile::Character about what the bits in + // this field mean. + /* 042C:0010 */ be_uint32_t option_flags; + /* 0430:0014 */ be_uint32_t save_count; + /* 0434:0018 */ parray unknown_a2; + /* 0450:0034 */ parray unknown_a3; // seq_vars is an array of 1024 bits, which contain all the Episode 3 quest // progress flags. This includes things like which maps are unlocked, which // NPC decks are unlocked, and whether the player has a VIP card or not. - /* 0460 */ parray seq_vars; - /* 0860 */ parray unknown_a6; - /* 08CC */ GuildCardV3 guild_card; - /* 095C */ parray symbol_chats; - /* 0D7C */ parray chat_shortcuts; - /* 140C */ parray unknown_a7; - /* 14B8 */ ptext info_board; - /* 1564 */ parray unknown_a8; - /* 1658 */ Episode3::PlayerConfig ep3_config; - /* 39A8 */ be_uint32_t unknown_a9; - /* 39AC */ be_uint32_t unknown_a10; - /* 39B0 */ be_uint32_t unknown_a11; - /* 39B4 */ + /* 0460:0044 */ parray seq_vars; + /* 0860:0444 */ be_uint32_t unknown_a4; + /* 0864:0448 */ be_uint32_t unknown_a5; + /* 0868:044C */ be_uint32_t unknown_a6; + /* 086C:0450 */ parray unknown_a7; + /* 08CC:04B0 */ GuildCardV3 guild_card; + /* 095C:0540 */ parray symbol_chats; + /* 0D7C:0960 */ parray chat_shortcuts; + /* 140C:0FF0 */ ptext auto_reply; + /* 14B8:109C */ ptext info_board; + /* 1564:1148 */ be_uint16_t win_count; + /* 1566:114A */ be_uint16_t lose_count; + /* 1568:114C */ parray unknown_a8; + /* 1572:1156 */ parray unused; + /* 1574:1158 */ parray unknown_a9; + /* 157C:1160 */ parray unknown_a10; + /* 1658:123C */ Episode3::PlayerConfig ep3_config; + /* 39A8:358C */ be_uint32_t unknown_a11; + /* 39AC:3590 */ be_uint32_t unknown_a12; + /* 39B0:3594 */ be_uint32_t unknown_a13; + /* 39B4:3598 */ } __attribute__((packed)); /* 00004 */ parray characters; /* 193F0 */ ptext serial_number; // As %08X (not decimal) /* 19400 */ ptext access_key; /* 19410 */ ptext password; + // In Episode 3, this field still exists, but is unused since BGM test was + // removed from the options menu in favor of the jukebox. The jukebox is + // accessible online only, and which songs are available there is controlled + // by the B7 command sent by the server instead. /* 19420 */ be_uint64_t bgm_test_songs_unlocked; /* 19428 */ be_uint32_t save_count; // This is an array of 1000 bits, represented here as 128 bytes, the last few