diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index c76c60aa..090b7e47 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -780,7 +780,6 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 { // 18 (S->C): License verification result (PC/V3) // Behaves exactly the same as 9A (S->C). No arguments except header.flag. -// TODO: Check if this command exists on DC v1/v2. // 19 (S->C): Reconnect to different address // Internal name: RcvPort @@ -2421,9 +2420,9 @@ struct C_SetBlockedSenders_BB_C6 : C_SetBlockedSenders_C6<28> { // Same as 60, but only send to Episode 3 clients. // This command is identical to C9, except that CB is not valid on Episode 3 // Trial Edition (whereas C9 is valid). -// TODO: Presumably this command is meant to be forwarded from spectator teams -// to the primary team, whereas 6x and C9 commands are not. I haven't verified -// this or implemented this behavior yet though. +// Unlike the 6x and C9 commands, subcommands sent with the CB command are +// forwarded from spectator teams to the primary team. The client only uses this +// behavior for the 6xBE command (sound chat), and newserv enforces this rule. // CC (S->C): Confirm tournament entry (Episode 3) // This command is not valid on Episode 3 Trial Edition. @@ -3410,6 +3409,11 @@ struct G_ObjectIDHeader { uint8_t size = 0; le_uint16_t object_id = 0; // >= 0x4000, != 0xFFFF } __packed__; +struct G_ParameterHeader { + uint8_t subcommand = 0; + uint8_t size = 0; + le_uint16_t param = 0; +} __packed__; struct G_UnusedHeader { uint8_t subcommand = 0; uint8_t size = 0; @@ -3534,7 +3538,7 @@ struct G_EnemyHitByPlayer_6x0A { G_EnemyIDHeader header; // Note: enemy_id (in header) is in the range [0x1000, 0x4000) le_uint16_t enemy_id; - le_uint16_t damage; + le_uint16_t remaining_hp; be_uint32_t flags; } __packed__; @@ -3547,6 +3551,7 @@ struct G_BoxDestroyed_6x0B { } __packed__; // 6x0C: Add condition (poison/slow/etc.) +// 6x0D: Remove condition (poison/slow/etc.) struct G_AddOrRemoveCondition_6x0C_6x0D { G_ClientIDHeader header; @@ -3554,9 +3559,6 @@ struct G_AddOrRemoveCondition_6x0C_6x0D { le_uint32_t unknown_a2; } __packed__; -// 6x0D: Remove condition (poison/slow/etc.) -// Same format as 6x0C - // 6x0E: Unknown struct G_Unknown_6x0E { @@ -3588,7 +3590,7 @@ struct G_DeRolLeBossActions_6x13 { le_uint16_t unknown_a3; } __packed__; -// 6x14: Unknown (supported; game only; not valid on Episode 3) +// 6x14: De Rol Le boss actions (not valid on Episode 3) // Same format as 6x10 // 6x15: Vol Opt boss actions (not valid on Episode 3) @@ -3609,7 +3611,7 @@ struct G_VolOptBossActions_6x16 { le_uint16_t unknown_a3; } __packed__; -// 6x17: Unknown (supported; game only; not valid on Episode 3) +// 6x17: Vol Opt phase 2 boss actions (not valid on Episode 3) struct G_Unknown_6x17 { G_ClientIDHeader header; @@ -3619,7 +3621,7 @@ struct G_Unknown_6x17 { le_uint32_t unknown_a5; } __packed__; -// 6x18: Unknown (supported; game only; not valid on Episode 3) +// 6x18: Vol Opt phase 2 boss actions (not valid on Episode 3) struct G_Unknown_6x18 { G_ClientIDHeader header; @@ -3653,9 +3655,9 @@ struct G_Unknown_6x1C { // 6x1D: Invalid subcommand // 6x1E: Invalid subcommand -// 6x1F: Unknown (supported; lobby & game) +// 6x1F: Set player area -struct G_Unknown_6x1F { +struct G_SetPlayerArea_6x1F { G_ClientIDHeader header; le_uint32_t area; } __packed__; @@ -3664,7 +3666,7 @@ struct G_Unknown_6x1F { // Existing clients send this when a new client joins a lobby/game, so the new // client knows where to place them. -struct G_Unknown_6x20 { +struct G_SetPosition_6x20 { G_ClientIDHeader header; le_uint32_t area; le_float x; @@ -3682,12 +3684,13 @@ struct G_InterLevelWarp_6x21 { // 6x22: Set player invisible // 6x23: Set player visible +// These are generally used while a player is in the process of changing areas. struct G_SetPlayerVisibility_6x22_6x23 { G_ClientIDHeader header; } __packed__; -// 6x24: Unknown (supported; game only) +// 6x24: Teleport player struct G_Unknown_6x24 { G_ClientIDHeader header; @@ -3698,6 +3701,7 @@ struct G_Unknown_6x24 { } __packed__; // 6x25: Equip item +// 6x26: Unequip item struct G_EquipOrUnequipItem_6x25_6x26 { G_ClientIDHeader header; @@ -3705,9 +3709,6 @@ struct G_EquipOrUnequipItem_6x25_6x26 { le_uint32_t equip_slot; // Unused for 6x26 (unequip item) } __packed__; -// 6x26: Unequip item -// Same format as 6x25 - // 6x27: Use item struct G_UseItem_6x27 { @@ -3807,19 +3808,19 @@ struct G_LevelUp_6x30 { le_uint16_t unknown_a1; // Must be 0 or 1 } __packed__; -// 6x31: Medical center +// 6x31: Resurrect player struct G_UseMedicalCenter_6x31 { G_ClientIDHeader header; } __packed__; -// 6x32: Unknown (occurs when using Medical Center) +// 6x32: Resurrect player (Medical Center) struct G_Unknown_6x32 { G_UnusedHeader header; } __packed__; -// 6x33: Revive player (e.g. with moon atomizer) +// 6x33: Resurrect player (with Moon Atomizer) struct G_RevivePlayer_6x33 { G_ClientIDHeader header; @@ -3843,7 +3844,7 @@ struct G_PhotonBlast_6x37 { le_uint16_t unused; } __packed__; -// 6x38: Unknown +// 6x38: Donate to photon blast struct G_Unknown_6x38 { G_ClientIDHeader header; @@ -3890,9 +3891,9 @@ struct G_StopAtPosition_6x3E { struct G_SetPosition_6x3F { G_ClientIDHeader header; le_uint16_t unknown_a1; - le_uint16_t unknown_a2; + le_uint16_t angle; le_uint16_t area; - le_uint16_t unknown_a3; + le_uint16_t room; le_float x; le_float y; le_float z; @@ -3904,7 +3905,7 @@ struct G_WalkToPosition_6x40 { G_ClientIDHeader header; le_float x; le_float z; - le_uint32_t unknown_a1; + le_uint32_t action; } __packed__; // 6x41: Unknown @@ -3919,6 +3920,8 @@ struct G_RunToPosition_6x42 { } __packed__; // 6x43: First attack +// 6x44: Second attack +// 6x45: Third attack struct G_Attack_6x43_6x44_6x45 { G_ClientIDHeader header; @@ -3926,22 +3929,16 @@ struct G_Attack_6x43_6x44_6x45 { le_uint16_t unknown_a2; } __packed__; -// 6x44: Second attack -// Same format as 6x43 - -// 6x45: Third attack -// Same format as 6x43 - // 6x46: Attack finished (sent after each of 43, 44, and 45) struct G_AttackFinished_6x46 { G_ClientIDHeader header; le_uint32_t count; - struct Entry { + struct TargetEntry { le_uint16_t unknown_a1; le_uint16_t unknown_a2; } __packed__; - Entry entries[11]; + TargetEntry targets[11]; } __packed__; // 6x47: Cast technique @@ -3974,7 +3971,7 @@ struct G_CastTechniqueComplete_6x48 { le_uint16_t level; } __packed__; -// 6x49: Subtract PB energy +// 6x49: Subtract photon blast energy struct G_SubtractPBEnergy_6x49 { G_ClientIDHeader header; @@ -3997,6 +3994,7 @@ struct G_ShieldAttack_6x4A { } __packed__; // 6x4B: Hit by enemy +// 6x4C: Hit by enemy struct G_HitByEnemy_6x4B_6x4C { G_ClientIDHeader header; @@ -4006,40 +4004,37 @@ struct G_HitByEnemy_6x4B_6x4C { le_float z_velocity; } __packed__; -// 6x4C: Hit by enemy -// Same format as 6x4B +// 6x4D: Player died -// 6x4D: Unknown (supported; lobby & game) - -struct G_Unknown_6x4D { +struct G_PlayerDied_6x4D { G_ClientIDHeader header; le_uint32_t unknown_a1; } __packed__; -// 6x4E: Unknown (supported; lobby & game) +// 6x4E: Player died -struct G_Unknown_6x4E { +struct G_PlayerDied_6x4E { G_ClientIDHeader header; } __packed__; -// 6x4F: Unknown (supported; lobby & game) +// 6x4F: Player resurrected (via Scape Doll) -struct G_Unknown_6x4F { +struct G_PlayerUsedScapeDoll_6x4F { G_ClientIDHeader header; } __packed__; -// 6x50: Unknown (supported; lobby & game) +// 6x50: Switch interaction -struct G_Unknown_6x50 { +struct G_SwitchInteraction_6x50 { G_ClientIDHeader header; le_uint32_t unknown_a1; } __packed__; // 6x51: Invalid subcommand -// 6x52: Toggle shop/bank interaction +// 6x52: Toggle counter (shop/bank) interaction -struct G_Unknown_6x52 { +struct G_ToggleCounterInteraction_6x52 { G_ClientIDHeader header; le_uint16_t unknown_a1; le_uint16_t unknown_a2; @@ -4084,11 +4079,11 @@ struct G_Unknown_6x57 { G_ClientIDHeader header; } __packed__; -// 6x58: Unknown (supported; game only) +// 6x58: Lobby animation -struct G_Unknown_6x58 { +struct G_LobbyAnimation_6x58 { G_ClientIDHeader header; - le_uint16_t unknown_a1; + le_uint16_t animation_number; le_uint16_t unused; } __packed__; @@ -4164,20 +4159,19 @@ struct G_DropItem_PC_V3_BB_6x5F { // 6x60: Request for item drop (handled by the server on BB) -struct G_EnemyDropItemRequest_DC_6x60 { +struct G_StandardDropItemRequest_DC_6x60 { G_UnusedHeader header; uint8_t area; uint8_t rt_index; - le_uint16_t enemy_id; + le_uint16_t entity_id; le_float x; le_float z; le_uint16_t unknown_a1; - le_uint16_t unknown_a2; + le_uint16_t ignore_def; } __packed__; -struct G_EnemyDropItemRequest_PC_V3_BB_6x60 { - G_EnemyDropItemRequest_DC_6x60 basic_cmd; - le_uint32_t unknown_a2; +struct G_StandardDropItemRequest_PC_V3_BB_6x60 : G_StandardDropItemRequest_DC_6x60 { + le_float unknown_a2; } __packed__; // 6x61: Feed MAG @@ -4191,7 +4185,7 @@ struct G_FeedMAG_6x61 { // 6x62: Unknown // This subcommand is completely ignored (at least, by PSO GC). -// 6x63: Destroy item on the ground (used when too many items have been dropped) +// 6x63: Destroy ground item (used when too many items have been dropped) struct G_DestroyGroundItem_6x63 { G_UnusedHeader header; @@ -4223,7 +4217,7 @@ struct G_CreateEnemySet_6x67 { le_uint32_t unused2; } __packed__; -// 6x68: Telepipe/Ryuker +// 6x68: Create telepipe / cast Ryuker struct G_CreateTelepipe_6x68 { G_UnusedHeader header; @@ -4237,9 +4231,9 @@ struct G_CreateTelepipe_6x68 { le_uint32_t unused3; } __packed__; -// 6x69: Unknown (supported; game only) +// 6x69: Create NPC -struct G_Unknown_6x69 { +struct G_CreateNPC_6x69 { G_UnusedHeader header; le_uint16_t client_id2; le_uint16_t unknown_a1; @@ -4247,9 +4241,9 @@ struct G_Unknown_6x69 { le_uint16_t unknown_a2; } __packed__; -// 6x6A: Unknown (supported; game only; not valid on Episode 3) +// 6x6A: Use boss warp (not valid on Episode 3) -struct G_Unknown_6x6A { +struct G_UseBossWarp_6x6A { G_ClientIDHeader header; le_uint16_t unknown_a1; le_uint16_t unused; @@ -4413,9 +4407,9 @@ struct G_Unknown_6x71 { G_UnusedHeader header; } __packed__; -// 6x72: Unknown (used while loading into game) +// 6x72: Player done loading into game -struct G_Unknown_6x72 { +struct G_DoneLoadingIntoGame_6x72 { G_UnusedHeader header; } __packed__; @@ -4436,17 +4430,16 @@ struct G_WordSelect_6x74 { le_uint32_t unknown_a4; } __packed__; -// 6x75: Phase setup (supported; game only) +// 6x75: Set quest flag -// TODO: Not sure about PC format here. Is this first struct DC-only? -struct G_PhaseSetup_DC_PC_6x75 { +struct G_SetQuestFlag_DC_PC_6x75 { G_UnusedHeader header; - le_uint16_t phase; // Must be < 0x400 - le_uint16_t unknown_a1; // Must be 0 or 1 + le_uint16_t flag; // Must be < 0x400 + le_uint16_t action; // 0 = set flag, 1 = clear flag } __packed__; -struct G_PhaseSetup_V3_BB_6x75 { - G_PhaseSetup_DC_PC_6x75 basic_cmd; +struct G_SetQuestFlag_V3_BB_6x75 { + G_SetQuestFlag_DC_PC_6x75 basic_cmd; le_uint16_t difficulty; le_uint16_t unused; } __packed__; @@ -4501,9 +4494,9 @@ struct G_Unknown_6x7B { G_ClientIDHeader header; } __packed__; -// 6x7C: Unknown (supported; game only; not valid on Episode 3) +// 6x7C: Set challenge mode data (not valid on Episode 3) -struct G_Unknown_6x7C { +struct G_SetChallengeModeData_6x7C { G_UnusedHeader header; le_uint16_t client_id; parray unknown_a1; @@ -4526,9 +4519,9 @@ struct G_Unknown_6x7C { Entry entries[3]; } __packed__; -// 6x7D: Unknown (supported; game only; not valid on Episode 3) +// 6x7D: Set battle mode data (not valid on Episode 3) -struct G_Unknown_6x7D { +struct G_SetBattleModeData_6x7D { G_UnusedHeader header; uint8_t unknown_a1; // Must be < 7; used in jump table parray unused; @@ -4601,22 +4594,22 @@ struct G_HitDestructibleObject_6x86 { le_uint16_t unknown_a4; } __packed__; -// 6x87: Unknown +// 6x87: Shrink player -struct G_Unknown_6x87 { +struct G_ShrinkPlayer_6x87 { G_ClientIDHeader header; le_float unknown_a1; } __packed__; -// 6x88: Unknown (supported; game only) +// 6x88: Restore shrunken player -struct G_Unknown_6x88 { +struct G_RestoreShrunkenPlayer_6x88 { G_ClientIDHeader header; } __packed__; -// 6x89: Unknown (supported; game only) +// 6x89: Player killed by monster -struct G_Unknown_6x89 { +struct G_PlayerKilledByMonster_6x89 { G_ClientIDHeader header; le_uint16_t unknown_a1; le_uint16_t unused; @@ -4636,6 +4629,8 @@ struct G_Unknown_6x8A { // This subcommand is completely ignored (at least, by PSO GC). // 6x8D: Set technique level override +// This command is sent immediately before 6x47 if the technique level is above +// 15. Presumably this was done for some backward-compatibility reason. struct G_SetTechniqueLevelOverride_6x8D { G_ClientIDHeader header; @@ -4682,9 +4677,9 @@ struct G_Unknown_6x92 { le_float unknown_a2; } __packed__; -// 6x93: Timed switch activated (not valid on Episode 3) +// 6x93: Activate timed switch (not valid on Episode 3) -struct G_TimedSwitchActivated_6x93 { +struct G_ActivateTimedSwitch_6x93 { G_UnusedHeader header; le_uint16_t area; le_uint16_t switch_id; @@ -4769,18 +4764,18 @@ struct G_Unknown_6x9D { // 6x9E: Unknown (not valid on Episode 3) // This subcommand is completely ignored (at least, by PSO GC). -// 6x9F: Gal Gryphon actions (not valid on PC or Episode 3) +// 6x9F: Gal Gryphon boss actions (not valid on pre-V3 or Episode 3) -struct G_GalGryphonActions_6x9F { +struct G_GalGryphonBossActions_6x9F { G_EnemyIDHeader header; le_uint32_t unknown_a1; le_float unknown_a2; le_float unknown_a3; } __packed__; -// 6xA0: Gal Gryphon actions (not valid on PC or Episode 3) +// 6xA0: Gal Gryphon boss actions (not valid on pre-V3 or Episode 3) -struct G_GalGryphonActions_6xA0 { +struct G_GalGryphonBossActions_6xA0 { G_EnemyIDHeader header; le_float x; le_float y; @@ -4791,56 +4786,47 @@ struct G_GalGryphonActions_6xA0 { parray unknown_a4; } __packed__; -// 6xA1: Unknown (not valid on PC) +// 6xA1: Unknown (not valid on pre-V3) +// Part of revive process. Occurs right after revive command; function unclear. struct G_Unknown_6xA1 { G_ClientIDHeader header; } __packed__; -// 6xA2: Request for item drop from box (not valid on PC; handled by server on BB) +// 6xA2: Specializable item drop request (not valid on pre-V3; handled by +// server on BB) -struct G_BoxItemDropRequest_6xA2 { - G_UnusedHeader header; - uint8_t area; - uint8_t unknown_a1; - le_uint16_t request_id; - le_float x; - le_float z; - le_uint16_t unknown_a2; - le_uint16_t unknown_a3; - parray unknown_a4; - le_uint32_t unknown_a5; - le_uint32_t unknown_a6; - le_uint32_t unknown_a7; - le_uint32_t unknown_a8; +struct G_SpecializableItemDropRequest_6xA2 : G_StandardDropItemRequest_PC_V3_BB_6x60 { + le_float def_a1; + parray def; } __packed__; -// 6xA3: Episode 2 boss actions (not valid on PC or Episode 3) +// 6xA3: Olga Flow boss actions (not valid on pre-V3 or Episode 3) -struct G_Episode2BossActions_6xA3 { +struct G_OlgaFlowBossActions_6xA3 { G_EnemyIDHeader header; uint8_t unknown_a1; uint8_t unknown_a2; parray unknown_a3; } __packed__; -// 6xA4: Olga Flow phase 1 actions (not valid on PC or Episode 3) +// 6xA4: Olga Flow phase 1 boss actions (not valid on pre-V3 or Episode 3) -struct G_OlgaFlowPhase1Actions_6xA4 { +struct G_OlgaFlowPhase1BossActions_6xA4 { G_EnemyIDHeader header; uint8_t what; parray unknown_a3; } __packed__; -// 6xA5: Olga Flow phase 2 actions (not valid on PC or Episode 3) +// 6xA5: Olga Flow phase 2 boss actions (not valid on pre-V3 or Episode 3) -struct G_OlgaFlowPhase2Actions_6xA5 { +struct G_OlgaFlowPhase2BossActions_6xA5 { G_EnemyIDHeader header; uint8_t what; parray unknown_a3; } __packed__; -// 6xA6: Modify trade proposal (not valid on PC) +// 6xA6: Modify trade proposal (not valid on pre-V3) struct G_ModifyTradeProposal_6xA6 { G_ClientIDHeader header; @@ -4851,36 +4837,36 @@ struct G_ModifyTradeProposal_6xA6 { le_uint32_t unknown_a5; } __packed__; -// 6xA7: Unknown (not valid on PC) +// 6xA7: Unknown (not valid on pre-V3) // This subcommand is completely ignored (at least, by PSO GC). -// 6xA8: Gol Dragon actions (not valid on PC or Episode 3) +// 6xA8: Gol Dragon boss actions (not valid on pre-V3 or Episode 3) -struct G_GolDragonActions_6xA8 { +struct G_GolDragonBossActions_6xA8 { G_EnemyIDHeader header; le_uint16_t unknown_a1; le_uint16_t unknown_a2; le_uint32_t unknown_a3; } __packed__; -// 6xA9: Barba Ray actions (not valid on PC or Episode 3) +// 6xA9: Barba Ray boss actions (not valid on pre-V3 or Episode 3) -struct G_BarbaRayActions_6xA9 { +struct G_BarbaRayBossActions_6xA9 { G_EnemyIDHeader header; le_uint16_t unknown_a1; le_uint16_t unknown_a2; } __packed__; -// 6xAA: Episode 2 boss actions (not valid on PC or Episode 3) +// 6xAA: Barba Ray boss actions (not valid on pre-V3 or Episode 3) -struct G_Episode2BossActions_6xAA { +struct G_BarbaRayBossActions_6xAA { G_EnemyIDHeader header; le_uint16_t unknown_a1; le_uint16_t unknown_a2; le_uint32_t unknown_a3; } __packed__; -// 6xAB: Create lobby chair (not valid on PC) +// 6xAB: Create lobby chair (not valid on pre-V3) struct G_CreateLobbyChair_6xAB { G_ClientIDHeader header; @@ -4888,7 +4874,7 @@ struct G_CreateLobbyChair_6xAB { le_uint16_t unknown_a2; } __packed__; -// 6xAC: Unknown (not valid on PC) +// 6xAC: Unknown (not valid on pre-V3) struct G_Unknown_6xAC { G_ClientIDHeader header; @@ -4896,9 +4882,10 @@ struct G_Unknown_6xAC { parray item_ids; } __packed__; -// 6xAD: Unknown (not valid on PC, Episode 3, or GC Trial Edition) +// 6xAD: Olga Flow subordinate boss actions (not valid on pre-V3, Episode 3, or +// GC Trial Edition) -struct G_Unknown_6xAD { +struct G_OlgaFlowSubordinateBossActions_6xAD { G_UnusedHeader header; // The first byte in this array seems to have a special meaning parray unknown_a1; @@ -4915,24 +4902,24 @@ struct G_SetLobbyChairState_6xAE { le_uint32_t unknown_a4; } __packed__; -// 6xAF: Turn lobby chair (not valid on PC or GC Trial Edition) +// 6xAF: Turn lobby chair (not valid on pre-V3 or GC Trial Edition) struct G_TurnLobbyChair_6xAF { G_ClientIDHeader header; le_uint32_t angle; // In range [0x0000, 0xFFFF] } __packed__; -// 6xB0: Move lobby chair (not valid on PC or GC Trial Edition) +// 6xB0: Move lobby chair (not valid on pre-V3 or GC Trial Edition) struct G_MoveLobbyChair_6xB0 { G_ClientIDHeader header; le_uint32_t unknown_a1; } __packed__; -// 6xB1: Unknown (not valid on PC or GC Trial Edition) +// 6xB1: Unknown (not valid on pre-V3 or GC Trial Edition) // This subcommand is completely ignored (at least, by PSO GC). -// 6xB2: Unknown (not valid on PC or GC Trial Edition) +// 6xB2: Unknown (not valid on pre-V3 or GC Trial Edition) // TODO: It appears this command is sent when the snapshot file is written on // PSO GC. Verify this. @@ -5204,14 +5191,21 @@ struct G_SellItemAtShop_BB_6xC0 { le_uint32_t amount; } __packed__; -// 6xC1: Unknown (BB) -// 6xC2: Unknown (BB) +// 6xC1: Invite to team (BB) +// 6xC2: Accept invitation to team (BB) + +struct G_TeamInvitationAction_BB_6xC1_6xC2_6xCD_6xCE { + G_ClientIDHeader header; + le_uint32_t guild_card_number; + le_uint32_t action; // 0 or 1 for 6xC1, 2 (or not 2) for 6xC2 + parray unknown_a1; +} __packed__; // 6xC3: Split stacked item (BB; handled by the server) // Note: This is not sent if an entire stack is dropped; in that case, a normal // item drop subcommand is generated instead. -struct G_SplitStackedItem_6xC3 { +struct G_SplitStackedItem_BB_6xC3 { G_ClientIDHeader header; le_uint16_t area; le_uint16_t unused2; @@ -5223,51 +5217,136 @@ struct G_SplitStackedItem_6xC3 { // 6xC4: Sort inventory (BB; handled by the server) -struct G_SortInventory_6xC4 { +struct G_SortInventory_BB_6xC4 { G_UnusedHeader header; le_uint32_t item_ids[30]; } __packed__; // 6xC5: Medical center used (BB) -// 6xC6: Invalid subcommand -// 6xC7: Invalid subcommand + +// 6xC6: Steal experience (BB) + +struct G_StealEXP_BB_6xC6 { + G_ClientIDHeader header; + uint8_t unknown_a1; + uint8_t unknown_a2; + le_uint16_t enemy_id; +} __packed__; + +// 6xC7: Charge attack (BB) + +struct G_ChargeAttack_BB_6xC7 { + G_ClientIDHeader header; + // Tethealla (at least, the ancient public version of it) treats this as + // signed, and gives the player money in that case. We don't do so. + le_uint32_t meseta_amount; +} __packed__; // 6xC8: Enemy killed (BB; handled by the server) -struct G_EnemyKilled_6xC8 { +struct G_EnemyKilled_BB_6xC8 { G_EnemyIDHeader header; le_uint16_t enemy_id; le_uint16_t killer_client_id; le_uint32_t unused; } __packed__; -// 6xC9: Invalid subcommand -// 6xCA: Invalid subcommand -// 6xCB: Unknown (BB) -// 6xCC: Unknown (BB) -// 6xCD: Unknown (BB) -// 6xCE: Unknown (BB) -// 6xCF: Unknown (BB; supported; game only; handled by the server) -// 6xD0: Invalid subcommand -// 6xD1: Invalid subcommand -// 6xD2: Unknown (BB) +// 6xC9: Meseta reward from quest (BB; handled by server) +// 6xCA: Item reward from quest (BB; handled by server) + +// 6xCB: Request to transfer item (BB) + +struct G_ItemTransferRequest_BB_6xCB { + G_ClientIDHeader header; + le_uint32_t unknown_a1; + le_uint32_t unknown_a2; +} __packed__; + +// 6xCC: Exchange item for team points (BB) + +struct G_ExchangeItemForTeamPoints_BB_6xCC { + G_ClientIDHeader header; + le_uint32_t item_id; + le_uint32_t unknown_a2; +} __packed__; + +// 6xCD: Transfer master (BB) +// Same format as 6xC1 + +// 6xCE: Accept master transfer (BB) +// Same format as 6xC1 + +// 6xCF: Restart battle (BB) + +// 6xD0: Battle mode level up (BB; handled by server) +// 6xD1: Challenge mode grave (BB; handled by server) + +// 6xD2: Set quest data 2 (BB) +// Writes 4 bytes to the 32-bit field specified by index. + +struct G_SetQuestData2_BB_6xD2 { + G_ClientIDHeader header; + le_uint32_t index; + le_uint32_t value; +} __packed__; + // 6xD3: Invalid subcommand + // 6xD4: Unknown (BB) -// 6xD5: Invalid subcommand -// 6xD6: Invalid subcommand -// 6xD7: Invalid subcommand -// 6xD8: Invalid subcommand -// 6xD9: Invalid subcommand -// 6xDA: Invalid subcommand -// 6xDB: Unknown (BB) -// 6xDC: Unknown (BB) -// 6xDD: Unknown (BB) -// 6xDE: Invalid subcommand -// 6xDF: Invalid subcommand -// 6xE0: Invalid subcommand -// 6xE1: Invalid subcommand -// 6xE2: Invalid subcommand + +struct G_Unknown_BB_6xD4 { + G_UnusedHeader header; + le_uint16_t action; // Must be in [0, 4] + uint8_t unknown_a1; // Must be in [0, 15] + uint8_t unused; + // THe format is not fully known; there are likely more fields here. +} __packed__; + +// 6xD5: Exchange item in quest (BB; handled by server) +// 6xD6: Wrap item (BB; handled by server) +// 6xD7: Paganini Photon Drop exchange (BB; handled by server) +// 6xD8: Add S-rank weapon special (BB; handled by server) +// 6xD9: Momoka item exchange (BB; handled by server) +// 6xDA: Upgrade weapon attribute (BB; handled by server) + +// 6xDB: Exchange item in quest (BB) + +struct G_ExchangeItemInQuest_BB_6xDB { + G_ClientIDHeader header; + le_uint32_t unknown_a1; + le_uint32_t unknown_a2; + le_uint32_t unknown_a3; +} __packed__; + +// 6xDC: Saint-Million boss actions (BB) + +struct G_SaintMillionBossActions_BB_6xDC { + G_UnusedHeader header; + le_uint16_t unknown_a1; + le_uint16_t unknown_a2; +} __packed__; + +// 6xDD: Set EXP multiplier (BB) +// header.param specifies the EXP multiplier. It is 1-based, so the value 2 +// means all EXP is doubled, for example. + +struct G_SetEXPMultiplier_BB_6xDD { + G_ParameterHeader header; +} __packed__; + +// 6xDE: Good Luck quest (BB; handled by server) +// 6xDF: Black Paper's Deal Photon Drop exchange (BB; handled by server) +// 6xE0: Black Paper's Deal rewards (BB; handled by server) +// 6xE1: Gallon's Plan quest (BB; handled by server) +// 6xE2: Coren actions (BB) + // 6xE3: Unknown (BB) + +struct G_Unknown_BB_6xE3 { + G_ClientIDHeader header; + ItemData unknown_a1; +} __packed__; + // 6xE4: Invalid subcommand // 6xE5: Invalid subcommand // 6xE6: Invalid subcommand