use std::io::Read;
use anyhow::Result;
use crate::core::uoid::{Uoid, read_key_uoid};
use crate::resource::prp::PlasmaRead;
#[allow(dead_code)]
pub mod brain_flags {
pub const CUT_POS: u32 = 1 << 0;
pub const CUT_POS_ONCE: u32 = 1 << 1;
pub const CUT_POA: u32 = 1 << 2;
pub const CUT_POA_ONCE: u32 = 1 << 3;
pub const ANIMATE_FOV: u32 = 1 << 4;
pub const FOLLOW_LOCAL_AVATAR: u32 = 1 << 5;
pub const PANIC_VELOCITY: u32 = 1 << 6;
pub const RAIL_COMPONENT: u32 = 1 << 7;
pub const SUBJECT: u32 = 1 << 8;
pub const CIRCLE_TARGET: u32 = 1 << 9;
pub const MAINTAIN_LOS: u32 = 1 << 10;
pub const ZOOM_ENABLED: u32 = 1 << 11;
pub const IS_TRANSITION_CAMERA: u32 = 1 << 12;
pub const WORLDSPACE_POA: u32 = 1 << 13;
pub const WORLDSPACE_POS: u32 = 1 << 14;
pub const CUT_POS_WHILE_PAN: u32 = 1 << 15;
pub const CUT_POA_WHILE_PAN: u32 = 1 << 16;
pub const NON_PHYS: u32 = 1 << 17;
pub const NEVER_ANIMATE_FOV: u32 = 1 << 18;
pub const IGNORE_SUBWORLD_MOVEMENT: u32 = 1 << 19;
pub const FALLING: u32 = 1 << 20;
pub const RUNNING: u32 = 1 << 21;
pub const VERTICAL_WHEN_FALLING: u32 = 1 << 22;
pub const SPEED_UP_WHEN_RUNNING: u32 = 1 << 23;
pub const FALLING_STOPPED: u32 = 1 << 24;
pub const BEGIN_FALLING: u32 = 1 << 25;
}
#[allow(dead_code)]
pub mod circle_flags {
pub const LAGGED: u32 = 0x01;
pub const ABSOLUTE_LAG: u32 = 0x03; pub const FARTHEST: u32 = 0x04;
pub const TARGETTED: u32 = 0x08;
pub const HAS_CENTER_OBJECT: u32 = 0x10;
pub const POA_OBJECT: u32 = 0x20;
pub const CIRCLE_LOCAL_AVATAR: u32 = 0x40;
}
#[derive(Debug, Clone, Copy)]
pub struct CameraAccel {
pub accel: f32,
pub decel: f32,
pub max_vel: f32,
}
impl Default for CameraAccel {
fn default() -> Self {
Self {
accel: 30.0,
decel: 30.0,
max_vel: 30.0,
}
}
}
#[derive(Debug, Clone)]
pub struct BrainBase {
pub self_key: Option<Uoid>,
pub poa_offset: [f32; 3],
pub subject_key: Option<Uoid>,
pub rail_key: Option<Uoid>,
pub flags: u32,
pub accel: CameraAccel,
pub poa_accel: CameraAccel,
pub x_pan_limit: f32,
pub z_pan_limit: f32,
pub zoom_rate: f32,
pub zoom_min: f32,
pub zoom_max: f32,
}
impl BrainBase {
pub fn has_flag(&self, flag: u32) -> bool {
self.flags & flag != 0
}
pub fn read(reader: &mut impl Read) -> Result<Self> {
let self_key = read_key_uoid(reader)?;
let poa_x = reader.read_f32()?;
let poa_y = reader.read_f32()?;
let poa_z = reader.read_f32()?;
let subject_key = read_key_uoid(reader)?;
let rail_key = read_key_uoid(reader)?;
let num_words = reader.read_u32()?;
let mut flags: u32 = 0;
for i in 0..num_words {
let bits = reader.read_u32()?;
if i == 0 {
flags = bits;
}
}
let accel_val = reader.read_f32()?;
let decel_val = reader.read_f32()?;
let velocity = reader.read_f32()?;
let poa_accel_val = reader.read_f32()?;
let poa_decel_val = reader.read_f32()?;
let poa_velocity = reader.read_f32()?;
let x_pan_limit = reader.read_f32()?;
let z_pan_limit = reader.read_f32()?;
let zoom_rate = reader.read_f32()?;
let zoom_min = reader.read_f32()?;
let zoom_max = reader.read_f32()?;
Ok(Self {
self_key,
poa_offset: [poa_x, poa_y, poa_z],
subject_key,
rail_key,
flags,
accel: CameraAccel { accel: accel_val, decel: decel_val, max_vel: velocity },
poa_accel: CameraAccel { accel: poa_accel_val, decel: poa_decel_val, max_vel: poa_velocity },
x_pan_limit,
z_pan_limit,
zoom_rate,
zoom_min,
zoom_max,
})
}
}
#[derive(Debug, Clone)]
pub struct AvatarBrainParams {
pub base: BrainBase,
pub offset: [f32; 3],
}
impl AvatarBrainParams {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = BrainBase::read(reader)?;
let off_x = reader.read_f32()?;
let off_y = reader.read_f32()?;
let off_z = reader.read_f32()?;
Ok(Self {
base,
offset: [off_x, off_y, off_z],
})
}
}
#[derive(Debug, Clone)]
pub struct FirstPersonBrainParams {
pub base: BrainBase,
pub offset: [f32; 3],
}
impl FirstPersonBrainParams {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = BrainBase::read(reader)?;
let off_x = reader.read_f32()?;
let off_y = reader.read_f32()?;
let off_z = reader.read_f32()?;
Ok(Self {
base,
offset: [off_x, off_y, off_z],
})
}
}
#[derive(Debug, Clone)]
pub struct FixedBrainParams {
pub base: BrainBase,
pub target_point: Option<Uoid>,
}
impl FixedBrainParams {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = BrainBase::read(reader)?;
let target_point = read_key_uoid(reader)?;
Ok(Self {
base,
target_point,
})
}
}
#[derive(Debug, Clone)]
pub struct CircleBrainParams {
pub base: BrainBase,
pub circle_flags: u32,
pub center: [f32; 3],
pub radius: f32,
pub center_object: Option<Uoid>,
pub poa_object: Option<Uoid>,
pub cir_per_sec: f32,
}
impl CircleBrainParams {
pub fn read(reader: &mut impl Read) -> Result<Self> {
let base = BrainBase::read(reader)?;
let circle_flags = reader.read_u32()?;
let cx = reader.read_f32()?;
let cy = reader.read_f32()?;
let cz = reader.read_f32()?;
let radius = reader.read_f32()?;
let center_object = read_key_uoid(reader)?;
let poa_object = read_key_uoid(reader)?;
let cir_per_sec = reader.read_f32()?;
Ok(Self {
base,
circle_flags,
center: [cx, cy, cz],
radius,
center_object,
poa_object,
cir_per_sec,
})
}
}
#[derive(Debug, Clone)]
pub enum CameraBrain {
Avatar(AvatarBrainParams),
FirstPerson(FirstPersonBrainParams),
Fixed(FixedBrainParams),
Circle(CircleBrainParams),
Drive,
Base(BrainBase),
}
impl CameraBrain {
pub fn base(&self) -> Option<&BrainBase> {
match self {
CameraBrain::Avatar(p) => Some(&p.base),
CameraBrain::FirstPerson(p) => Some(&p.base),
CameraBrain::Fixed(p) => Some(&p.base),
CameraBrain::Circle(p) => Some(&p.base),
CameraBrain::Base(b) => Some(b),
CameraBrain::Drive => None,
}
}
pub fn self_key(&self) -> Option<&Uoid> {
self.base().and_then(|b| b.self_key.as_ref())
}
pub fn read_by_class(class_id: u16, reader: &mut impl Read) -> Result<Self> {
use crate::core::class_index::ClassIndex;
match class_id {
ClassIndex::PL_CAMERA_BRAIN1_AVATAR => {
Ok(CameraBrain::Avatar(AvatarBrainParams::read(reader)?))
}
ClassIndex::PL_CAMERA_BRAIN1_FIRST_PERSON => {
Ok(CameraBrain::FirstPerson(FirstPersonBrainParams::read(reader)?))
}
ClassIndex::PL_CAMERA_BRAIN1_FIXED => {
Ok(CameraBrain::Fixed(FixedBrainParams::read(reader)?))
}
ClassIndex::PL_CAMERA_BRAIN1_CIRCLE => {
Ok(CameraBrain::Circle(CircleBrainParams::read(reader)?))
}
ClassIndex::PL_CAMERA_BRAIN1 => {
Ok(CameraBrain::Base(BrainBase::read(reader)?))
}
_ => anyhow::bail!("Unknown camera brain class 0x{:04X}", class_id),
}
}
pub fn type_name(&self) -> &'static str {
match self {
CameraBrain::Avatar(_) => "Avatar",
CameraBrain::FirstPerson(_) => "FirstPerson",
CameraBrain::Fixed(_) => "Fixed",
CameraBrain::Circle(_) => "Circle",
CameraBrain::Drive => "Drive",
CameraBrain::Base(_) => "Base",
}
}
}