add DCv1 save file structure
This commit is contained in:
@@ -537,7 +537,7 @@ Some commands only work on the game server and not on the proxy server. The chat
|
||||
|
||||
* Cheat mode commands
|
||||
* `$cheat` (game server only): Enables or disables cheat mode for the current game. All other cheat mode commands do nothing if cheat mode is disabled. By default, cheat mode is off in new games but can be enabled; there is an option in config.json that allows you to disable cheat mode entirely, or set it to on by default in new games. Cheat mode is always enabled on the proxy server, unless cheat mode is disabled on the entire server.
|
||||
* `$infhp`: Enables or disables infinite HP mode. Applies to only you; does not affect other players. When enabled, one-hit KO attacks will still kill you, but on most versions of the game (not DCv1, GC US 1.2, or GC JP 1.5), the server can automatically revive you. On all versions except GC US 1.2 and GC JP 1.5, infinite HP also automatically cures status ailments.
|
||||
* `$infhp`: Enables or disables infinite HP mode. Applies to only you; does not affect other players. When enabled, one-hit KO attacks will still kill you, but on most versions of the game (not DCv1, GC US 1.2, or GC JP 1.5), the server will automatically revive you if you die. On all versions except GC US 1.2 and GC JP 1.5, infinite HP also automatically cures status ailments.
|
||||
* `$inftp`: Enables or disables infinite TP mode. Applies to only you; does not affect other players.
|
||||
* `$warpme <floor-id>` (or `$warp <floor-id>`): Warps yourself to the given floor.
|
||||
* `$warpall <floor-id>`: Warps everyone in the game to the given floor. You must be the leader to use this command, unless you're on the proxy server.
|
||||
|
||||
+117
-93
@@ -24,15 +24,15 @@ struct PSOVMSFileHeader {
|
||||
/* 0000 */ pstring<TextEncoding::MARKED, 0x10> short_desc;
|
||||
/* 0010 */ pstring<TextEncoding::MARKED, 0x20> long_desc;
|
||||
/* 0030 */ pstring<TextEncoding::MARKED, 0x10> creator_id;
|
||||
/* 0040 */ le_uint16_t num_icons;
|
||||
/* 0042 */ le_uint16_t animation_speed;
|
||||
/* 0044 */ le_uint16_t eyecatch_type;
|
||||
/* 0046 */ le_uint16_t crc;
|
||||
/* 0048 */ le_uint32_t data_size; // Not including header and icons
|
||||
/* 0040 */ le_uint16_t num_icons = 1;
|
||||
/* 0042 */ le_uint16_t animation_speed = 1;
|
||||
/* 0044 */ le_uint16_t eyecatch_type = 0;
|
||||
/* 0046 */ le_uint16_t crc = 0;
|
||||
/* 0048 */ le_uint32_t data_size = 0; // Not including header and icons
|
||||
/* 004C */ parray<uint8_t, 0x14> unused;
|
||||
/* 0060 */ parray<le_uint16_t, 0x10> icon_palette;
|
||||
// Variable-length field:
|
||||
/* 0080 */ // parray<uint8_t, num_icons> icon;
|
||||
/* 0080 */ // parray<parray<uint8_t, 0x200>, num_icons> icon;
|
||||
|
||||
bool checksum_correct() const;
|
||||
} __packed_ws__(PSOVMSFileHeader, 0x80);
|
||||
@@ -47,33 +47,33 @@ struct PSOGCIFileHeader {
|
||||
/* 0000 */ parray<char, 4> game_id; // 'GPOE', 'GPSP', etc.
|
||||
/* 0004 */ parray<char, 2> developer_id; // '8P' for Sega
|
||||
// There is a structure for this part of the header, but we don't use it.
|
||||
/* 0006 */ uint8_t unused;
|
||||
/* 0007 */ uint8_t image_flags;
|
||||
/* 0006 */ uint8_t unused = 0;
|
||||
/* 0007 */ uint8_t image_flags = 0;
|
||||
/* 0008 */ pstring<TextEncoding::MARKED, 0x20> internal_file_name;
|
||||
/* 0028 */ be_uint32_t modification_time;
|
||||
/* 002C */ be_uint32_t image_data_offset;
|
||||
/* 0030 */ be_uint16_t icon_formats;
|
||||
/* 0032 */ be_uint16_t icon_animation_speeds;
|
||||
/* 0034 */ uint8_t permission_flags;
|
||||
/* 0035 */ uint8_t copy_count;
|
||||
/* 0036 */ be_uint16_t first_block_index;
|
||||
/* 0038 */ be_uint16_t num_blocks;
|
||||
/* 0028 */ be_uint32_t modification_time = 0;
|
||||
/* 002C */ be_uint32_t image_data_offset = 0;
|
||||
/* 0030 */ be_uint16_t icon_formats = 0;
|
||||
/* 0032 */ be_uint16_t icon_animation_speeds = 0;
|
||||
/* 0034 */ uint8_t permission_flags = 0;
|
||||
/* 0035 */ uint8_t copy_count = 0;
|
||||
/* 0036 */ be_uint16_t first_block_index = 0;
|
||||
/* 0038 */ be_uint16_t num_blocks = 0;
|
||||
/* 003A */ parray<uint8_t, 2> unused2;
|
||||
/* 003C */ be_uint32_t comment_offset;
|
||||
/* 003C */ be_uint32_t comment_offset = 0;
|
||||
// GCI header ends here (and memcard file data begins here)
|
||||
// game_name is e.g. "PSO EPISODE I & II" or "PSO EPISODE III"
|
||||
/* 0040 */ pstring<TextEncoding::MARKED, 0x1C> game_name;
|
||||
/* 005C */ be_uint32_t embedded_seed; // Used in some of Ralf's quest packs
|
||||
/* 005C */ be_uint32_t embedded_seed = 0; // Used in some of Ralf's quest packs
|
||||
/* 0060 */ pstring<TextEncoding::MARKED, 0x20> file_name;
|
||||
/* 0080 */ parray<uint8_t, 0x1800> banner;
|
||||
/* 1880 */ parray<uint8_t, 0x800> icon;
|
||||
// data_size specifies the number of bytes remaining in the file. In all cases
|
||||
// except for the system file, this data is encrypted.
|
||||
/* 2080 */ be_uint32_t data_size;
|
||||
/* 2080 */ be_uint32_t data_size = 0;
|
||||
// To compute checksum, set checksum to zero, then compute the CRC32 of all
|
||||
// fields in this struct starting with gci_header.game_name. (Yes, including
|
||||
// the checksum field, which is temporarily zero.) See checksum_correct below.
|
||||
/* 2084 */ be_uint32_t checksum;
|
||||
/* 2084 */ be_uint32_t checksum = 0;
|
||||
/* 2088 */
|
||||
|
||||
bool checksum_correct() const;
|
||||
@@ -223,51 +223,51 @@ struct PSOPCCreationTimeFile { // PSO______FLS
|
||||
// for the other save files, but only if the serial number isn't set in the
|
||||
// Windows registry.
|
||||
/* 0000 */ parray<uint8_t, 0x624> unused1;
|
||||
/* 0624 */ le_uint32_t creation_timestamp;
|
||||
/* 0624 */ le_uint32_t creation_timestamp = 0;
|
||||
/* 0628 */ parray<uint8_t, 0xDD8> unused2;
|
||||
/* 1400 */
|
||||
} __packed_ws__(PSOPCCreationTimeFile, 0x1400);
|
||||
|
||||
struct PSOPCSystemFile { // PSO______COM
|
||||
/* 0000 */ le_uint32_t checksum;
|
||||
/* 0000 */ le_uint32_t checksum = 0;
|
||||
// Most of these fields are guesses based on the format used in GC and the
|
||||
// assumption that Sega didn't change much between versions.
|
||||
/* 0004 */ le_int16_t music_volume;
|
||||
/* 0006 */ int8_t sound_volume;
|
||||
/* 0007 */ uint8_t language;
|
||||
/* 0008 */ le_int32_t server_time_delta_frames;
|
||||
/* 0004 */ le_int16_t music_volume = 0;
|
||||
/* 0006 */ int8_t sound_volume = 0;
|
||||
/* 0007 */ uint8_t language = 1;
|
||||
/* 0008 */ le_int32_t server_time_delta_frames = 1728000;
|
||||
/* 000C */ parray<le_uint16_t, 0x10> unknown_a4; // Last one is always 0x1234?
|
||||
/* 002C */ parray<uint8_t, 0x100> event_flags;
|
||||
/* 012C */ le_uint32_t round1_seed;
|
||||
/* 012C */ le_uint32_t round1_seed = 0;
|
||||
/* 0130 */ parray<uint8_t, 0xD0> end_padding;
|
||||
/* 0200 */
|
||||
} __packed_ws__(PSOPCSystemFile, 0x200);
|
||||
|
||||
struct PSOGCSystemFile {
|
||||
/* 0000 */ be_uint32_t checksum;
|
||||
/* 0004 */ be_int16_t music_volume; // 0 = full volume; -250 = min volume
|
||||
/* 0006 */ int8_t sound_volume; // 0 = full volume; -100 = min volume
|
||||
/* 0007 */ uint8_t language;
|
||||
/* 0000 */ be_uint32_t checksum = 0;
|
||||
/* 0004 */ be_int16_t music_volume = 0; // 0 = full volume; -250 = min volume
|
||||
/* 0006 */ int8_t sound_volume = 0; // 0 = full volume; -100 = min volume
|
||||
/* 0007 */ uint8_t language = 1;
|
||||
// This field stores the effective time zone offset between the server and
|
||||
// client, in frames. The default value is 1728000, which corresponds to 16
|
||||
// hours. This is recomputed when the client receives a B1 command.
|
||||
/* 0008 */ be_int32_t server_time_delta_frames;
|
||||
/* 000C */ be_uint16_t udp_behavior; // 0 = auto, 1 = on, 2 = off
|
||||
/* 000E */ be_uint16_t surround_sound_enabled;
|
||||
/* 0008 */ be_int32_t server_time_delta_frames = 1728000;
|
||||
/* 000C */ be_uint16_t udp_behavior = 0; // 0 = auto, 1 = on, 2 = off
|
||||
/* 000E */ be_uint16_t surround_sound_enabled = 0;
|
||||
/* 0010 */ parray<uint8_t, 0x100> event_flags; // Can be set by quest opcode D8 or E8
|
||||
/* 0110 */ parray<uint8_t, 8> unknown_a7;
|
||||
// This timestamp is the number of seconds since 12:00AM on 1 January 2000.
|
||||
// This field is also used as the round1 seed for encrypting the character and
|
||||
// Guild Card files.
|
||||
/* 0118 */ be_uint32_t creation_timestamp;
|
||||
/* 0118 */ be_uint32_t creation_timestamp = 0;
|
||||
/* 011C */
|
||||
} __packed_ws__(PSOGCSystemFile, 0x11C);
|
||||
|
||||
struct PSOGCEp3SystemFile {
|
||||
/* 0000 */ PSOGCSystemFile base;
|
||||
/* 011C */ int8_t unknown_a1;
|
||||
/* 011C */ int8_t unknown_a1 = 0;
|
||||
/* 011D */ parray<uint8_t, 11> unknown_a2;
|
||||
/* 0128 */ be_uint32_t unknown_a3;
|
||||
/* 0128 */ be_uint32_t unknown_a3 = 0;
|
||||
/* 012C */
|
||||
} __packed_ws__(PSOGCEp3SystemFile, 0x12C);
|
||||
|
||||
@@ -304,6 +304,29 @@ struct PSOBBFullSystemFile {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Character files
|
||||
|
||||
struct PSODCV1CharacterFile {
|
||||
// See PSOGCCharacterFile::Character for descriptions of fields' meanings.
|
||||
/* 0000:---- */ PlayerInventory inventory;
|
||||
/* 034C:---- */ PlayerDispDataDCPCV3 disp;
|
||||
/* 041C:0000 */ le_uint32_t flags = 0;
|
||||
/* 0420:0004 */ le_uint32_t creation_timestamp = 0;
|
||||
/* 0424:0008 */ le_uint32_t signature = 0xA205B064;
|
||||
/* 0428:000C */ le_uint32_t play_time_seconds = 0;
|
||||
/* 042C:0010 */ le_uint32_t option_flags = 0x00040058;
|
||||
/* 0430:0014 */ le_uint32_t save_count = 1;
|
||||
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
|
||||
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
|
||||
/* 0460:0044 */ QuestFlagsV1 quest_flags;
|
||||
/* 05E0:01C4 */ PlayerBank60 bank;
|
||||
/* 0B88:076C */ GuildCardDC guild_card;
|
||||
/* 0C05:07E9 */ parray<uint8_t, 3> unknown_s1; // Probably actually unused
|
||||
/* 0C08:07EC */ parray<SaveFileSymbolChatEntryDCXB, 12> symbol_chats;
|
||||
/* 1028:0C0C */ parray<SaveFileShortcutEntryDC, 20> shortcuts;
|
||||
/* 1528:110C */ pstring<TextEncoding::ASCII, 0x10> v1_serial_number;
|
||||
/* 1538:111C */ pstring<TextEncoding::ASCII, 0x10> v1_access_key;
|
||||
/* 1548:112C */
|
||||
} __packed_ws__(PSODCV1CharacterFile, 0x1548);
|
||||
|
||||
struct PSODCV2CharacterFile {
|
||||
// See PSOGCCharacterFile::Character for descriptions of fields' meanings.
|
||||
/* 0000:---- */ PlayerInventory inventory;
|
||||
@@ -313,7 +336,7 @@ struct PSODCV2CharacterFile {
|
||||
/* 0424:0008 */ le_uint32_t signature = 0xA205B064;
|
||||
/* 0428:000C */ le_uint32_t play_time_seconds = 0;
|
||||
/* 042C:0010 */ le_uint32_t option_flags = 0x00040058;
|
||||
/* 0430:0014 */ le_uint32_t save_count = 0;
|
||||
/* 0430:0014 */ le_uint32_t save_count = 1;
|
||||
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
|
||||
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
|
||||
/* 0460:0044 */ QuestFlags quest_flags;
|
||||
@@ -341,23 +364,23 @@ struct PSODCV2CharacterFile {
|
||||
|
||||
struct PSOPCCharacterFile { // PSO______SYS and PSO______SYD
|
||||
// See PSOGCCharacterFile::Character for descriptions of fields' meanings.
|
||||
/* 00000 */ le_uint32_t signature; // 'CAEN' (stored as 4E 45 41 43)
|
||||
/* 00004 */ le_uint32_t extra_headers; // 1
|
||||
/* 00008 */ le_uint32_t num_entries; // 0x80
|
||||
/* 0000C */ le_uint32_t entry_size; // 0x1D54 (actual entry size is +0x40)
|
||||
/* 00000 */ le_uint32_t signature = 0x4341454E; // 'CAEN' (stored as 4E 45 41 43)
|
||||
/* 00004 */ le_uint32_t extra_headers = 1;
|
||||
/* 00008 */ le_uint32_t num_entries = 0x80;
|
||||
/* 0000C */ le_uint32_t entry_size = 0x1D54; // Actual entry size is +0x40
|
||||
/* 00010 */ parray<uint8_t, 0x430> unknown_a1;
|
||||
struct CharacterEntry {
|
||||
/* 0000 */ le_uint32_t present; // 1 if character present, 0 if empty
|
||||
/* 0000 */ le_uint32_t present = 1; // 1 if character present, 0 if empty
|
||||
struct Character {
|
||||
/* 0000 */ le_uint32_t checksum;
|
||||
/* 0000 */ le_uint32_t checksum = 0;
|
||||
/* 0004 */ PlayerInventory inventory;
|
||||
/* 0350 */ PlayerDispDataDCPCV3 disp;
|
||||
/* 0420 */ be_uint32_t flags;
|
||||
/* 0424 */ be_uint32_t creation_timestamp;
|
||||
/* 0428 */ be_uint32_t signature; // == 0x6C5D889E?
|
||||
/* 042C */ be_uint32_t play_time_seconds;
|
||||
/* 0430 */ be_uint32_t option_flags; // TODO: document bits in this field
|
||||
/* 0434 */ be_uint32_t save_count;
|
||||
/* 0420 */ be_uint32_t flags = 0;
|
||||
/* 0424 */ be_uint32_t creation_timestamp = 0;
|
||||
/* 0428 */ be_uint32_t signature = 0x6C5D889E;
|
||||
/* 042C */ be_uint32_t play_time_seconds = 0;
|
||||
/* 0430 */ be_uint32_t option_flags = 0x00040058;
|
||||
/* 0434 */ be_uint32_t save_count = 1;
|
||||
// TODO: Figure out what this is. On GC, this is where the bank data goes.
|
||||
/* 0438 */ parray<uint8_t, 0x7D4> unknown_a2;
|
||||
/* 0C0C */ GuildCardPC guild_card;
|
||||
@@ -369,7 +392,7 @@ struct PSOPCCharacterFile { // PSO______SYS and PSO______SYD
|
||||
/* 1D04 */ parray<uint8_t, 0x2C> unknown_a4;
|
||||
/* 1D30 */ pstring<TextEncoding::ASCII, 0x10> serial_number; // As %08X (not decimal)
|
||||
/* 1D40 */ pstring<TextEncoding::ASCII, 0x10> access_key; // As decimal
|
||||
/* 1D50 */ le_uint32_t round2_seed;
|
||||
/* 1D50 */ le_uint32_t round2_seed = 0;
|
||||
/* 1D54 */
|
||||
} __packed_ws__(Character, 0x1D54);
|
||||
/* 0004 */ Character character;
|
||||
@@ -381,7 +404,7 @@ struct PSOPCCharacterFile { // PSO______SYS and PSO______SYD
|
||||
} __packed_ws__(PSOPCCharacterFile, 0xECE40);
|
||||
|
||||
struct PSOGCCharacterFile {
|
||||
/* 00000 */ be_uint32_t checksum;
|
||||
/* 00000 */ be_uint32_t checksum = 0;
|
||||
struct Character {
|
||||
// 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
|
||||
@@ -391,7 +414,8 @@ struct PSOGCCharacterFile {
|
||||
// Known bits in the flags field:
|
||||
// 00000001: Character was not saved after disconnecting (and the message
|
||||
// about items being deleted is shown in the select menu)
|
||||
// 00000002: Used for something, but it's not known what it does
|
||||
// 00000002: Used, but purpose is unknown
|
||||
// 00000008: Used, but purpose is unknown
|
||||
// 00000010: Character has ever possessed a hacked item, according to the
|
||||
// check_for_hacked_item function in DCv2 (TODO: Does this exist in V3+
|
||||
// also? If so, is the logic the same?)
|
||||
@@ -420,7 +444,7 @@ struct PSOGCCharacterFile {
|
||||
// Q = Button config (0 = normal; 1 = L/R reversed)
|
||||
// R = Map direction (0 = non-fixed; 1 = fixed)
|
||||
/* 042C:0010 */ be_uint32_t option_flags = 0x00040058;
|
||||
/* 0430:0014 */ be_uint32_t save_count = 0;
|
||||
/* 0430:0014 */ be_uint32_t save_count = 1;
|
||||
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
|
||||
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
|
||||
/* 0460:0044 */ QuestFlags quest_flags;
|
||||
@@ -449,35 +473,35 @@ struct PSOGCCharacterFile {
|
||||
/* 1152C */ pstring<TextEncoding::ASCII, 0x10> serial_number; // As %08X (not decimal)
|
||||
/* 1153C */ pstring<TextEncoding::ASCII, 0x10> access_key;
|
||||
/* 1154C */ pstring<TextEncoding::ASCII, 0x10> password;
|
||||
/* 1155C */ be_uint64_t bgm_test_songs_unlocked;
|
||||
/* 11564 */ be_uint32_t save_count;
|
||||
/* 11568 */ be_uint32_t round2_seed;
|
||||
/* 1155C */ be_uint64_t bgm_test_songs_unlocked = 0;
|
||||
/* 11564 */ be_uint32_t save_count = 1;
|
||||
/* 11568 */ be_uint32_t round2_seed = 0;
|
||||
/* 1156C */
|
||||
} __packed_ws__(PSOGCCharacterFile, 0x1156C);
|
||||
|
||||
struct PSOGCEp3CharacterFile {
|
||||
/* 00000 */ be_uint32_t checksum; // crc32 of this field (as 0) through end of struct
|
||||
/* 00000 */ be_uint32_t checksum = 0; // crc32 of this field (as 0) through end of struct
|
||||
struct Character {
|
||||
// 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 flags;
|
||||
/* 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;
|
||||
/* 041C:0000 */ be_uint32_t flags = 0;
|
||||
/* 0420:0004 */ be_uint32_t creation_timestamp = 0;
|
||||
/* 0424:0008 */ be_uint32_t signature = 0xA204B064;
|
||||
/* 0428:000C */ be_uint32_t play_time_seconds = 0;
|
||||
// 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;
|
||||
/* 042C:0010 */ be_uint32_t option_flags = 0x00040058;
|
||||
/* 0430:0014 */ be_uint32_t save_count = 1;
|
||||
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
|
||||
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
|
||||
// seq_vars is an array of 8192 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:0044 */ parray<uint8_t, 0x400> seq_vars;
|
||||
/* 0860:0444 */ be_uint32_t death_count;
|
||||
/* 0860:0444 */ be_uint32_t death_count = 0;
|
||||
// Curiously, Episode 3 characters do have item banks, but there are only 4
|
||||
// item slots. Sega presumably didn't completely remove the bank in Ep3
|
||||
// because they would have to change too much code.
|
||||
@@ -492,9 +516,9 @@ struct PSOGCEp3CharacterFile {
|
||||
/* 157C:1160 */ parray<uint8_t, 4> unknown_a10;
|
||||
/* 1580:1164 */ PlayerRecordsChallengeV3BE::Stats challenge_record_stats;
|
||||
/* 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;
|
||||
/* 39A8:358C */ be_uint32_t unknown_a11 = 0;
|
||||
/* 39AC:3590 */ be_uint32_t unknown_a12 = 0;
|
||||
/* 39B0:3594 */ be_uint32_t unknown_a13 = 0;
|
||||
/* 39B4:3598 */
|
||||
} __packed_ws__(Character, 0x39B4);
|
||||
/* 00004 */ parray<Character, 7> characters;
|
||||
@@ -505,8 +529,8 @@ struct PSOGCEp3CharacterFile {
|
||||
// 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;
|
||||
/* 19420 */ be_uint64_t bgm_test_songs_unlocked = 0;
|
||||
/* 19428 */ be_uint32_t save_count = 1;
|
||||
// This is an array of 999 bits, represented here as 128 bytes (the last bit
|
||||
// is never used). Each bit corresponds to a card ID with the bit's index; if
|
||||
// the bit is set, then during offline play, the card's rank is replaced with
|
||||
@@ -517,7 +541,7 @@ struct PSOGCEp3CharacterFile {
|
||||
// to prevent broken cards from being used offline, but there's no indication
|
||||
// that they ever used this functionality.
|
||||
/* 1942C */ parray<uint8_t, 0x80> card_rank_override_flags;
|
||||
/* 194AC */ be_uint32_t round2_seed;
|
||||
/* 194AC */ be_uint32_t round2_seed = 0;
|
||||
/* 194B0 */
|
||||
} __packed_ws__(PSOGCEp3CharacterFile, 0x194B0);
|
||||
|
||||
@@ -533,7 +557,7 @@ struct PSOXBCharacterFileCharacter {
|
||||
/* 0424:0008 */ le_uint32_t signature = 0xC87ED5B1;
|
||||
/* 0428:000C */ le_uint32_t play_time_seconds = 0;
|
||||
/* 042C:0010 */ le_uint32_t option_flags = 0x00040058;
|
||||
/* 0430:0014 */ le_uint32_t save_count = 0;
|
||||
/* 0430:0014 */ le_uint32_t save_count = 1;
|
||||
/* 0434:0018 */ pstring<TextEncoding::ASCII, 0x1C> ppp_username;
|
||||
/* 0450:0034 */ pstring<TextEncoding::ASCII, 0x10> ppp_password;
|
||||
/* 0460:0044 */ QuestFlags quest_flags;
|
||||
@@ -555,7 +579,7 @@ struct PSOXBCharacterFileCharacter {
|
||||
/* 27BC:23A0 */ PlayerRecordsBattle offline_battle_records;
|
||||
/* 27D4:23B8 */ parray<uint8_t, 4> unknown_a7;
|
||||
struct UnknownA8Entry {
|
||||
/* 00 */ le_uint32_t unknown_a1;
|
||||
/* 00 */ le_uint32_t unknown_a1 = 0;
|
||||
/* 04 */ parray<uint8_t, 0x1C> unknown_a2;
|
||||
/* 20 */ parray<le_float, 4> unknown_a3;
|
||||
/* 30 */
|
||||
@@ -576,7 +600,7 @@ struct PSOBBCharacterFile {
|
||||
/* 04E4 */ le_uint32_t signature = 0xC87ED5B1;
|
||||
/* 04E8 */ le_uint32_t play_time_seconds = 0;
|
||||
/* 04EC */ le_uint32_t option_flags = 0x00040058;
|
||||
/* 04F0 */ le_uint32_t save_count = 0;
|
||||
/* 04F0 */ le_uint32_t save_count = 1;
|
||||
/* 04F4 */ QuestFlags quest_flags;
|
||||
/* 06F4 */ le_uint32_t death_count = 0;
|
||||
/* 06F8 */ PlayerBank200 bank;
|
||||
@@ -646,31 +670,31 @@ struct PSOBBCharacterFile {
|
||||
// Guild Card files
|
||||
|
||||
struct PSOPCGuildCardFile { // PSO______GUD
|
||||
/* 0000 */ le_uint32_t checksum;
|
||||
/* 0000 */ le_uint32_t checksum = 0;
|
||||
// TODO: Figure out the PC guild card format.
|
||||
/* 0004 */ parray<uint8_t, 0x7980> unknown_a1;
|
||||
/* 7984 */ le_uint32_t creation_timestamp;
|
||||
/* 7988 */ le_uint32_t round2_seed;
|
||||
/* 7984 */ le_uint32_t creation_timestamp = 0;
|
||||
/* 7988 */ le_uint32_t round2_seed = 0;
|
||||
/* 798C */ parray<uint8_t, 0x74> end_padding;
|
||||
/* 7A00 */
|
||||
} __packed_ws__(PSOPCGuildCardFile, 0x7A00);
|
||||
|
||||
struct PSOGCGuildCardFile {
|
||||
/* 0000 */ be_uint32_t checksum;
|
||||
/* 0000 */ be_uint32_t checksum = 0;
|
||||
/* 0004 */ parray<uint8_t, 0xC0> unknown_a1;
|
||||
struct GuildCardEntry {
|
||||
/* 0000 */ GuildCardGCBE base;
|
||||
/* 0090 */ uint8_t unknown_a1;
|
||||
/* 0091 */ uint8_t unknown_a2;
|
||||
/* 0092 */ uint8_t unknown_a3;
|
||||
/* 0093 */ uint8_t unknown_a4;
|
||||
/* 0090 */ uint8_t unknown_a1 = 0;
|
||||
/* 0091 */ uint8_t unknown_a2 = 0;
|
||||
/* 0092 */ uint8_t unknown_a3 = 0;
|
||||
/* 0093 */ uint8_t unknown_a4 = 0;
|
||||
/* 0094 */ pstring<TextEncoding::MARKED, 0x6C> comment;
|
||||
/* 0100 */
|
||||
} __packed_ws__(GuildCardEntry, 0x100);
|
||||
/* 00C4 */ parray<GuildCardEntry, 0xD2> entries;
|
||||
/* D2C4 */ parray<GuildCardGCBE, 0x1C> blocked_senders;
|
||||
/* E284 */ be_uint32_t creation_timestamp;
|
||||
/* E288 */ be_uint32_t round2_seed;
|
||||
/* E284 */ be_uint32_t creation_timestamp = 0;
|
||||
/* E288 */ be_uint32_t round2_seed = 0;
|
||||
/* E28C */
|
||||
} __packed_ws__(PSOGCGuildCardFile, 0xE28C);
|
||||
|
||||
@@ -699,15 +723,15 @@ struct PSOBBGuildCardFile {
|
||||
// Snapshot files
|
||||
|
||||
struct PSOGCSnapshotFile {
|
||||
/* 00000 */ be_uint32_t checksum;
|
||||
/* 00004 */ be_uint16_t width;
|
||||
/* 00006 */ be_uint16_t height;
|
||||
/* 00000 */ be_uint32_t checksum = 0;
|
||||
/* 00004 */ be_uint16_t width = 0x100;
|
||||
/* 00006 */ be_uint16_t height = 0xC0;
|
||||
// Pixels are stored as 4x4 blocks of RGB565 values. See the implementation
|
||||
// of decode_image for details.
|
||||
/* 00008 */ parray<be_uint16_t, 0xC000> pixels;
|
||||
/* 18008 */ uint8_t unknown_a1; // Always 0x18?
|
||||
/* 18009 */ uint8_t unknown_a2;
|
||||
/* 1800A */ be_int16_t max_players;
|
||||
/* 18008 */ uint8_t unknown_a1 = 0x18; // Always 0x18?
|
||||
/* 18009 */ uint8_t unknown_a2 = 0;
|
||||
/* 1800A */ be_int16_t max_players = 0;
|
||||
/* 1800C */ parray<be_uint32_t, 12> players_present;
|
||||
/* 1803C */ parray<be_uint32_t, 12> player_levels;
|
||||
/* 1806C */ parray<pstring<TextEncoding::ASCII, 0x18>, 12> player_names;
|
||||
@@ -737,7 +761,7 @@ struct LegacySavedPlayerDataBB { // .nsc file format
|
||||
/* 19B4 */ PlayerInventory inventory;
|
||||
/* 1D00 */ parray<uint8_t, 4> unknown_a2;
|
||||
/* 1D04 */ QuestFlags quest_flags;
|
||||
/* 1F04 */ le_uint32_t death_count;
|
||||
/* 1F04 */ le_uint32_t death_count = 0;
|
||||
/* 1F08 */ parray<le_uint32_t, 0x0016> quest_counters;
|
||||
/* 1F60 */ parray<le_uint16_t, 0x0014> tech_menu_shortcut_entries;
|
||||
/* 1F88 */
|
||||
@@ -750,8 +774,8 @@ struct LegacySavedAccountDataBB { // .nsa file format
|
||||
/* 0040 */ parray<le_uint32_t, 0x001E> blocked_senders;
|
||||
/* 00B8 */ PSOBBGuildCardFile guild_card_file;
|
||||
/* D648 */ PSOBBFullSystemFile system_file;
|
||||
/* E138 */ le_uint32_t unused;
|
||||
/* E13C */ le_uint32_t option_flags;
|
||||
/* E138 */ le_uint32_t unused = 0;
|
||||
/* E13C */ le_uint32_t option_flags = 0x00040058;
|
||||
/* E140 */ parray<SaveFileShortcutEntryBB, 0x10> shortcuts;
|
||||
/* EB80 */ parray<SaveFileSymbolChatEntryBB, 0x0C> symbol_chats;
|
||||
/* F060 */ pstring<TextEncoding::UTF16_ALWAYS_MARKED, 0x10> team_name;
|
||||
|
||||
Reference in New Issue
Block a user