use crate::param::BULLET_PARAM_ST;
use crate::position::{DirectionalVector, HavokPosition};
use crate::rotation::Quaternion;
use std::ffi::OsStr;
use std::ptr::NonNull;
use vtable_rs::VPtr;
use super::{CSBulletTargetingSystemOwner, CSTargetingSystemBase, FieldInsBaseVmt, FieldInsHandle};
use fromsoftware_shared::{Subclass, Superclass};
#[repr(C)]
pub struct BulletParamLookupResult {
pub param_row: Option<NonNull<BULLET_PARAM_ST>>,
pub param_id: i32,
version: u8,
_padd: [u8; 3],
}
#[repr(C)]
pub struct CSBulletIns {
vftable: VPtr<dyn FieldInsBaseVmt, Self>,
pub field_ins_handle: FieldInsHandle,
pub physics: BulletPhysics,
unk50: u32,
unk54: u32,
unk58: u32,
unk5c: u32,
sfx_ctrl: [u8; 0x420],
unk480: u32,
unk484: u32,
unk488_sound_type: u32,
unk48c_sound_type: i32,
unk490_sound_type: i32,
unk494_sound_type: i32,
unk498_sound_type_ptr: usize,
unk4a0: u32,
unk4a4: u32,
unk4a8: u32,
unk4ac: u32,
unk4b0_struct: [u8; 0x660],
pub time_alive: f32,
life: f32,
life_max: f32,
accel_time: f32,
create_interval_time_left: f32,
create_time_timer: f32,
unkb28: u32,
unkb2c: u32,
pub targeting_owner: CSBulletTargetingSystemOwner,
pub targeting_system: CSTargetingSystemBase,
unkd30_struct: [u8; 0x50],
unkd80: u8,
unkd81: u8,
unkd82: u8,
unkd83: u8,
unkd84: u8,
unkd85: u8,
unkd86: u8,
unkd87: u8,
unkd88: i32,
pub wait_state: CSBulletWaitState,
pub fly_state: CSBulletFlyState,
pub exp_state: CSBulletExplosionState,
pub next_bullet: Option<NonNull<CSBulletIns>>,
unke20: u64,
unke28: u64,
}
#[repr(C)]
pub struct BulletPhysics {
pub position: HavokPosition,
pub orientation: Quaternion,
pub velocity: DirectionalVector,
velocity2: DirectionalVector,
}
#[vtable_rs::vtable]
pub trait CSBulletStateVmt {
fn destructor(&mut self, should_free: bool);
fn set_bullet_param_and_get_hit_bullet(&mut self, row_id: u32) -> i32;
fn on_update(&mut self, bullet: &mut CSBulletIns, dt: f32);
fn on_creation(&mut self, bullet: &mut CSBulletIns);
fn on_death(&mut self, bullet: &mut CSBulletIns);
fn unk28(&mut self, param_row: usize, param_3: usize);
fn unk30(&self) -> bool;
fn unk38(&self) -> bool;
fn unk40(&self) -> bool;
fn get_state_label(&self) -> &OsStr;
}
#[repr(C)]
#[derive(Superclass)]
#[superclass(children(
CSBulletWaitState,
CSBulletFlyState,
CSBulletExplosionState,
CSBulletNULLState
))]
pub struct CSBulletState {
pub vftable: VPtr<dyn CSBulletStateVmt, Self>,
pub param: BulletParamLookupResult,
unk18: f32,
unk1c: f32,
unk20: u32,
unk24: u32,
}
#[repr(C)]
#[derive(Subclass)]
pub struct CSBulletWaitState {
pub base: CSBulletState,
unk28: u32,
_pad2c: [u8; 4],
}
#[repr(C)]
#[derive(Subclass)]
pub struct CSBulletFlyState {
pub base: CSBulletState,
unk28: u16,
unk2a: u8,
_pad2c: [u8; 5],
}
#[repr(C)]
#[derive(Subclass)]
pub struct CSBulletExplosionState {
pub base: CSBulletState,
}
#[repr(C)]
#[derive(Subclass)]
pub struct CSBulletNULLState {
pub base: CSBulletState,
}
#[cfg(test)]
mod test {
use crate::cs::{
CSBulletExplosionState, CSBulletFlyState, CSBulletIns, CSBulletNULLState, CSBulletState,
CSBulletWaitState,
};
#[test]
fn proper_sizes() {
assert_eq!(0xe30, size_of::<CSBulletIns>());
assert_eq!(0x28, size_of::<CSBulletState>());
assert_eq!(0x30, size_of::<CSBulletWaitState>());
assert_eq!(0x30, size_of::<CSBulletFlyState>());
assert_eq!(0x28, size_of::<CSBulletExplosionState>());
assert_eq!(0x28, size_of::<CSBulletNULLState>());
}
}