diff --git a/resources/opcodes.json b/resources/opcodes.json index e60b5fb..405f241 100644 --- a/resources/opcodes.json +++ b/resources/opcodes.json @@ -304,6 +304,11 @@ "name": "UpdateInventorySlot", "opcode": 435, "size": 64 + }, + { + "name": "EffectResult", + "opcode": 431, + "size": 96 } ], "ClientZoneIpcType": [ diff --git a/src/ipc/zone/action_result.rs b/src/ipc/zone/action_result.rs index 033f06e..d848e5b 100644 --- a/src/ipc/zone/action_result.rs +++ b/src/ipc/zone/action_result.rs @@ -39,6 +39,8 @@ pub enum EffectKind { }, #[brw(magic = 27u8)] BeginCombo, + #[brw(magic = 14u8)] + Unk1 { unk1: u8, unk2: u32, effect_id: u8 }, // seen during sprint } #[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] @@ -190,4 +192,41 @@ mod tests { ObjectId(0x40070E42) ); } + + #[test] + fn read_actionresult_sprint() { + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("resources/tests/action_result_sprint.bin"); + + let buffer = read(d).unwrap(); + let mut buffer = Cursor::new(&buffer); + + let action_result = ActionResult::read_le(&mut buffer).unwrap(); + assert_eq!(action_result.main_target.object_id, ObjectId(277554542)); + assert_eq!(action_result.action_id, 3); + assert_eq!(action_result.unk1, 776386); // TODO: probably means this field is wrong + assert_eq!(action_result.animation_lock_time, 0.6); + assert_eq!(action_result.unk2, 3758096384); // TODO: ditto + assert_eq!(action_result.hidden_animation, 1); + assert_eq!(action_result.rotation, 2.6254003); + assert_eq!(action_result.action_animation_id, 3); + assert_eq!(action_result.variation, 0); + assert_eq!(action_result.flag, 1); + assert_eq!(action_result.unk3, 0); + assert_eq!(action_result.effect_count, 1); + assert_eq!(action_result.unk4, 0); + assert_eq!(action_result.unk5, [0; 6]); + + // effect 0: unk + assert_eq!( + action_result.effects[0].kind, + EffectKind::Unk1 { + unk1: 0, + unk2: 7728, + effect_id: 50 + } + ); + + assert_eq!(action_result.target_id_again.object_id, ObjectId(277554542)); + } } diff --git a/src/ipc/zone/effect_result.rs b/src/ipc/zone/effect_result.rs new file mode 100644 index 0000000..4f44117 --- /dev/null +++ b/src/ipc/zone/effect_result.rs @@ -0,0 +1,58 @@ +use binrw::binrw; + +use crate::common::ObjectId; + +#[binrw] +#[brw(little)] +#[derive(Clone, Debug, Default)] +pub struct EffectEntry { + pub index: u8, + pub unk1: u8, + pub id: u16, + pub param: u16, + pub unk2: u16, + pub duration: f32, + pub source_actor_id: ObjectId, +} + +#[binrw] +#[brw(little)] +#[derive(Clone, Debug, Default)] +pub struct EffectResult { + pub unk1: u32, + pub unk2: u32, + pub target_id: ObjectId, + pub current_hp: u32, + pub max_hp: u32, + pub current_mp: u16, + pub unk3: u8, + pub class_id: u8, + pub shield: u8, + pub entry_count: u8, + pub unk4: u16, + #[brw(pad_after = 4)] // padding + pub statuses: [EffectEntry; 4], +} + +#[cfg(test)] +mod tests { + use std::{fs::read, io::Cursor, path::PathBuf}; + + use binrw::BinRead; + + use super::*; + + #[test] + fn read_effectresult() { + let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + d.push("resources/tests/effect_result.bin"); + + let buffer = read(d).unwrap(); + let mut buffer = Cursor::new(&buffer); + + let effect_result = EffectResult::read_le(&mut buffer).unwrap(); + assert_eq!(effect_result.unk1, 1); + assert_eq!(effect_result.unk2, 776386); + assert_eq!(effect_result.target_id, ObjectId(277554542)); + } +} diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index e9c6880..9a9d711 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -94,6 +94,9 @@ pub use object_spawn::ObjectSpawn; mod quest_active_list; pub use quest_active_list::QuestActiveList; +mod effect_result; +pub use effect_result::EffectResult; + use crate::COMPLETED_LEVEQUEST_BITMASK_SIZE; use crate::COMPLETED_QUEST_BITMASK_SIZE; use crate::TITLE_UNLOCK_BITMASK_SIZE; @@ -523,6 +526,8 @@ pub enum ServerZoneIpcData { /// Always 0x7530_0000 unk4: u32, }, + #[br(pre_assert(*magic == ServerZoneIpcType::EffectResult))] + EffectResult(EffectResult), Unknown { #[br(count = size - 32)] unk: Vec, @@ -1034,6 +1039,10 @@ mod tests { unk4: 0, }, ), + ( + ServerZoneIpcType::EffectResult, + ServerZoneIpcData::EffectResult(EffectResult::default()), + ), ]; for (opcode, data) in &ipc_types {