diff --git a/resources/opcodes.json b/resources/opcodes.json index 8b0bf93..80825fa 100644 --- a/resources/opcodes.json +++ b/resources/opcodes.json @@ -289,6 +289,11 @@ "name": "QuestActiveList", "opcode": 398, "size": 480 + }, + { + "name": "LevequestCompleteList", + "opcode": 371, + "size": 232 } ], "ClientZoneIpcType": [ diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index bcfa6f1..71d9a19 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -94,6 +94,7 @@ pub use object_spawn::ObjectSpawn; mod quest_active_list; pub use quest_active_list::QuestActiveList; +use crate::COMPLETED_LEVEQUEST_BITMASK_SIZE; use crate::COMPLETED_QUEST_BITMASK_SIZE; use crate::TITLE_UNLOCK_BITMASK_SIZE; use crate::common::ObjectTypeId; @@ -472,6 +473,16 @@ pub enum ServerZoneIpcData { }, #[br(pre_assert(*magic == ServerZoneIpcType::QuestActiveList))] QuestActiveList(QuestActiveList), + #[br(pre_assert(*magic == ServerZoneIpcType::LevequestCompleteList))] + LevequestCompleteList { + #[br(count = COMPLETED_LEVEQUEST_BITMASK_SIZE)] + #[bw(pad_size_to = COMPLETED_LEVEQUEST_BITMASK_SIZE)] + completed_levequests: Vec, + // TODO: what is in ehre? + #[br(count = 6)] + #[bw(pad_size_to = 6)] + unk2: Vec, + }, Unknown { #[br(count = size - 32)] unk: Vec, @@ -952,6 +963,13 @@ mod tests { ServerZoneIpcType::QuestActiveList, ServerZoneIpcData::QuestActiveList(QuestActiveList::default()), ), + ( + ServerZoneIpcType::LevequestCompleteList, + ServerZoneIpcData::LevequestCompleteList { + completed_levequests: Vec::default(), + unk2: Vec::default(), + }, + ), ]; for (opcode, data) in &ipc_types { diff --git a/src/lib.rs b/src/lib.rs index 6dd1da3..c40ea29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,6 +79,9 @@ pub const COMPLETED_QUEST_BITMASK_SIZE: usize = 691; /// The size of the unlocked title bitmask. pub const TITLE_UNLOCK_BITMASK_SIZE: usize = 112; +/// The size of the completed levequest bitmask. +pub const COMPLETED_LEVEQUEST_BITMASK_SIZE: usize = 226; + /// The size of various classjob arrays. pub const CLASSJOB_ARRAY_SIZE: usize = 32; diff --git a/src/world/connection.rs b/src/world/connection.rs index 1d00701..fa30cad 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -9,7 +9,7 @@ use mlua::Function; use tokio::net::TcpStream; use crate::{ - CLASSJOB_ARRAY_SIZE, COMPLETED_QUEST_BITMASK_SIZE, + CLASSJOB_ARRAY_SIZE, COMPLETED_LEVEQUEST_BITMASK_SIZE, COMPLETED_QUEST_BITMASK_SIZE, common::{ GameData, ObjectId, ObjectTypeId, Position, timestamp_secs, value_to_flag_byte_index_value, }, @@ -1333,5 +1333,27 @@ impl ZoneConnection { }) .await; } + + // levequest complete list + // NOTE: all levequests are unlocked by default + { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::LevequestCompleteList, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::LevequestCompleteList { + completed_levequests: vec![0xFF; COMPLETED_LEVEQUEST_BITMASK_SIZE], + unk2: Vec::default(), + }, + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_data.actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc, + data: SegmentData::Ipc { data: ipc }, + }) + .await; + } } }