2025-03-29 14:14:03 -04:00
|
|
|
use binrw::binrw;
|
2025-04-18 14:32:39 -04:00
|
|
|
use serde::{Deserialize, Serialize};
|
2025-03-29 14:14:03 -04:00
|
|
|
|
|
|
|
use crate::common::{ObjectTypeId, read_quantized_rotation, write_quantized_rotation};
|
|
|
|
|
2025-04-18 13:11:29 -04:00
|
|
|
// TODO: this might be a flag?
|
2025-03-30 10:01:41 -04:00
|
|
|
#[binrw]
|
2025-04-18 14:32:39 -04:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)]
|
2025-03-30 10:01:41 -04:00
|
|
|
#[brw(repr = u8)]
|
2025-04-18 13:11:29 -04:00
|
|
|
pub enum DamageKind {
|
|
|
|
#[default]
|
|
|
|
Normal = 0x0,
|
|
|
|
Critical = 0x1,
|
|
|
|
DirectHit = 0x2,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binrw]
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default)]
|
2025-03-30 10:01:41 -04:00
|
|
|
pub enum EffectKind {
|
|
|
|
#[default]
|
2025-04-18 13:11:29 -04:00
|
|
|
#[brw(magic = 0u8)]
|
|
|
|
Miss, // FIXME: is this correct?
|
|
|
|
#[brw(magic = 3u8)]
|
|
|
|
Damage {
|
|
|
|
damage_kind: DamageKind,
|
|
|
|
#[br(temp)]
|
|
|
|
#[bw(calc = 0)]
|
|
|
|
param1: u8,
|
|
|
|
#[br(calc = DamageType::from(param1 & 0x0F))]
|
|
|
|
#[bw(ignore)]
|
|
|
|
damage_type: DamageType,
|
|
|
|
#[br(calc = DamageElement::from(param1 >> 4))]
|
|
|
|
#[bw(ignore)]
|
|
|
|
damage_element: DamageElement,
|
|
|
|
bonus_percent: u8,
|
|
|
|
unk3: u8,
|
|
|
|
unk4: u8,
|
|
|
|
amount: u16,
|
|
|
|
},
|
|
|
|
#[brw(magic = 27u8)]
|
|
|
|
BeginCombo,
|
|
|
|
}
|
|
|
|
|
2025-04-18 14:32:39 -04:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)]
|
2025-04-18 13:11:29 -04:00
|
|
|
pub enum DamageType {
|
|
|
|
Unknown,
|
|
|
|
Slashing,
|
|
|
|
Piercing,
|
|
|
|
Blunt,
|
|
|
|
Shot,
|
|
|
|
Magic,
|
|
|
|
Breath,
|
|
|
|
#[default]
|
|
|
|
Physical,
|
|
|
|
LimitBreak,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for DamageType {
|
|
|
|
fn from(value: u8) -> Self {
|
|
|
|
match value {
|
|
|
|
0 => Self::Unknown,
|
|
|
|
1 => Self::Slashing,
|
|
|
|
2 => Self::Piercing,
|
|
|
|
3 => Self::Blunt,
|
|
|
|
4 => Self::Shot,
|
|
|
|
5 => Self::Magic,
|
|
|
|
6 => Self::Breath,
|
|
|
|
7 => Self::Physical,
|
|
|
|
8 => Self::LimitBreak,
|
|
|
|
_ => Self::Unknown,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-04-18 14:32:39 -04:00
|
|
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)]
|
2025-04-18 13:11:29 -04:00
|
|
|
pub enum DamageElement {
|
|
|
|
Unknown,
|
|
|
|
Fire,
|
|
|
|
Ice,
|
|
|
|
Air,
|
|
|
|
Earth,
|
|
|
|
Lightning,
|
|
|
|
Water,
|
|
|
|
#[default]
|
|
|
|
Unaspected,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for DamageElement {
|
|
|
|
fn from(value: u8) -> Self {
|
|
|
|
match value {
|
|
|
|
0 => Self::Unknown,
|
|
|
|
1 => Self::Fire,
|
|
|
|
2 => Self::Ice,
|
|
|
|
3 => Self::Air,
|
|
|
|
4 => Self::Earth,
|
|
|
|
5 => Self::Lightning,
|
|
|
|
6 => Self::Water,
|
|
|
|
7 => Self::Unaspected,
|
|
|
|
_ => Self::Unknown,
|
|
|
|
}
|
|
|
|
}
|
2025-03-30 10:01:41 -04:00
|
|
|
}
|
|
|
|
|
2025-03-29 14:14:03 -04:00
|
|
|
#[binrw]
|
|
|
|
#[brw(little)]
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct ActionEffect {
|
2025-04-18 13:11:29 -04:00
|
|
|
#[brw(pad_size_to = 8)]
|
2025-03-30 10:01:41 -04:00
|
|
|
pub kind: EffectKind,
|
2025-03-29 14:14:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[binrw]
|
|
|
|
#[brw(little)]
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
|
|
pub struct ActionResult {
|
|
|
|
pub main_target: ObjectTypeId,
|
|
|
|
pub action_id: u32,
|
|
|
|
pub unk1: u32,
|
|
|
|
pub animation_lock_time: f32,
|
|
|
|
pub unk2: u32,
|
|
|
|
pub hidden_animation: u16,
|
|
|
|
#[br(map = read_quantized_rotation)]
|
|
|
|
#[bw(map = write_quantized_rotation)]
|
|
|
|
pub rotation: f32,
|
|
|
|
pub action_animation_id: u16,
|
|
|
|
pub variation: u8,
|
|
|
|
pub flag: u8,
|
|
|
|
pub unk3: u8,
|
|
|
|
pub effect_count: u8,
|
|
|
|
pub unk4: u16,
|
|
|
|
pub unk5: [u8; 6],
|
|
|
|
pub effects: [ActionEffect; 8],
|
2025-03-29 14:38:40 -04:00
|
|
|
#[brw(pad_before = 6, pad_after = 4)]
|
|
|
|
pub target_id_again: ObjectTypeId,
|
2025-03-29 14:14:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::{fs::read, io::Cursor, path::PathBuf};
|
|
|
|
|
|
|
|
use binrw::BinRead;
|
|
|
|
|
|
|
|
use crate::common::ObjectId;
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn read_actionresult() {
|
|
|
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
|
|
d.push("resources/tests/action_result.bin");
|
|
|
|
|
|
|
|
let buffer = read(d).unwrap();
|
|
|
|
let mut buffer = Cursor::new(&buffer);
|
|
|
|
|
|
|
|
let action_result = ActionResult::read_le(&mut buffer).unwrap();
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.main_target.object_id, ObjectId(0x40070E42));
|
2025-03-29 14:14:03 -04:00
|
|
|
assert_eq!(action_result.action_id, 31);
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.unk1, 2662353); // TODO: probably means this field is wrong
|
2025-03-29 14:14:03 -04:00
|
|
|
assert_eq!(action_result.animation_lock_time, 0.6);
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.unk2, 3758096384); // TODO: ditto
|
|
|
|
assert_eq!(action_result.hidden_animation, 1);
|
|
|
|
assert_eq!(action_result.rotation, 1.207309);
|
2025-03-29 14:14:03 -04:00
|
|
|
assert_eq!(action_result.action_animation_id, 31);
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.variation, 0);
|
2025-03-29 14:14:03 -04:00
|
|
|
assert_eq!(action_result.flag, 1);
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.unk3, 0);
|
2025-03-29 14:14:03 -04:00
|
|
|
assert_eq!(action_result.effect_count, 1);
|
2025-04-18 12:38:02 -04:00
|
|
|
assert_eq!(action_result.unk4, 0);
|
|
|
|
assert_eq!(action_result.unk5, [0; 6]);
|
2025-03-29 14:14:03 -04:00
|
|
|
|
|
|
|
// effect 0: attack
|
2025-04-18 13:11:29 -04:00
|
|
|
assert_eq!(
|
|
|
|
action_result.effects[0].kind,
|
|
|
|
EffectKind::Damage {
|
|
|
|
damage_kind: DamageKind::Normal,
|
|
|
|
damage_type: DamageType::Slashing,
|
|
|
|
damage_element: DamageElement::Unaspected,
|
|
|
|
bonus_percent: 0,
|
|
|
|
unk3: 0,
|
|
|
|
unk4: 0,
|
|
|
|
amount: 22
|
|
|
|
}
|
|
|
|
);
|
2025-03-29 14:14:03 -04:00
|
|
|
|
|
|
|
// effect 1: start action combo
|
2025-03-30 17:49:45 -04:00
|
|
|
assert_eq!(action_result.effects[1].kind, EffectKind::BeginCombo);
|
2025-04-18 12:38:02 -04:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
action_result.target_id_again.object_id,
|
|
|
|
ObjectId(0x40070E42)
|
|
|
|
);
|
2025-03-29 14:14:03 -04:00
|
|
|
}
|
|
|
|
}
|