1use std::io::Read;
14
15use anyhow::Result;
16
17use crate::core::uoid::{Uoid, read_key_uoid};
18use crate::resource::prp::PlasmaRead;
19
20#[allow(dead_code)]
23pub mod brain_flags {
24 pub const CUT_POS: u32 = 1 << 0;
25 pub const CUT_POS_ONCE: u32 = 1 << 1;
26 pub const CUT_POA: u32 = 1 << 2;
27 pub const CUT_POA_ONCE: u32 = 1 << 3;
28 pub const ANIMATE_FOV: u32 = 1 << 4;
29 pub const FOLLOW_LOCAL_AVATAR: u32 = 1 << 5;
30 pub const PANIC_VELOCITY: u32 = 1 << 6;
31 pub const RAIL_COMPONENT: u32 = 1 << 7;
32 pub const SUBJECT: u32 = 1 << 8;
33 pub const CIRCLE_TARGET: u32 = 1 << 9;
34 pub const MAINTAIN_LOS: u32 = 1 << 10;
35 pub const ZOOM_ENABLED: u32 = 1 << 11;
36 pub const IS_TRANSITION_CAMERA: u32 = 1 << 12;
37 pub const WORLDSPACE_POA: u32 = 1 << 13;
38 pub const WORLDSPACE_POS: u32 = 1 << 14;
39 pub const CUT_POS_WHILE_PAN: u32 = 1 << 15;
40 pub const CUT_POA_WHILE_PAN: u32 = 1 << 16;
41 pub const NON_PHYS: u32 = 1 << 17;
42 pub const NEVER_ANIMATE_FOV: u32 = 1 << 18;
43 pub const IGNORE_SUBWORLD_MOVEMENT: u32 = 1 << 19;
44 pub const FALLING: u32 = 1 << 20;
45 pub const RUNNING: u32 = 1 << 21;
46 pub const VERTICAL_WHEN_FALLING: u32 = 1 << 22;
47 pub const SPEED_UP_WHEN_RUNNING: u32 = 1 << 23;
48 pub const FALLING_STOPPED: u32 = 1 << 24;
49 pub const BEGIN_FALLING: u32 = 1 << 25;
50}
51
52#[allow(dead_code)]
55pub mod circle_flags {
56 pub const LAGGED: u32 = 0x01;
57 pub const ABSOLUTE_LAG: u32 = 0x03; pub const FARTHEST: u32 = 0x04;
59 pub const TARGETTED: u32 = 0x08;
60 pub const HAS_CENTER_OBJECT: u32 = 0x10;
61 pub const POA_OBJECT: u32 = 0x20;
62 pub const CIRCLE_LOCAL_AVATAR: u32 = 0x40;
63}
64
65#[derive(Debug, Clone, Copy)]
69pub struct CameraAccel {
70 pub accel: f32,
71 pub decel: f32,
72 pub max_vel: f32,
73}
74
75impl Default for CameraAccel {
76 fn default() -> Self {
77 Self {
79 accel: 30.0,
80 decel: 30.0,
81 max_vel: 30.0,
82 }
83 }
84}
85
86#[derive(Debug, Clone)]
90pub struct BrainBase {
91 pub self_key: Option<Uoid>,
92 pub poa_offset: [f32; 3],
93 pub subject_key: Option<Uoid>,
94 pub rail_key: Option<Uoid>,
95 pub flags: u32,
96 pub accel: CameraAccel,
97 pub poa_accel: CameraAccel,
98 pub x_pan_limit: f32,
99 pub z_pan_limit: f32,
100 pub zoom_rate: f32,
101 pub zoom_min: f32,
102 pub zoom_max: f32,
103}
104
105impl BrainBase {
106 pub fn has_flag(&self, flag: u32) -> bool {
107 self.flags & flag != 0
108 }
109
110 pub fn read(reader: &mut impl Read) -> Result<Self> {
113 let self_key = read_key_uoid(reader)?;
114
115 let poa_x = reader.read_f32()?;
116 let poa_y = reader.read_f32()?;
117 let poa_z = reader.read_f32()?;
118
119 let subject_key = read_key_uoid(reader)?;
120 let rail_key = read_key_uoid(reader)?;
121
122 let num_words = reader.read_u32()?;
124 let mut flags: u32 = 0;
125 for i in 0..num_words {
126 let bits = reader.read_u32()?;
127 if i == 0 {
128 flags = bits;
129 }
130 }
131
132 let accel_val = reader.read_f32()?;
133 let decel_val = reader.read_f32()?;
134 let velocity = reader.read_f32()?;
135 let poa_accel_val = reader.read_f32()?;
136 let poa_decel_val = reader.read_f32()?;
137 let poa_velocity = reader.read_f32()?;
138
139 let x_pan_limit = reader.read_f32()?;
140 let z_pan_limit = reader.read_f32()?;
141
142 let zoom_rate = reader.read_f32()?;
143 let zoom_min = reader.read_f32()?;
144 let zoom_max = reader.read_f32()?;
145
146 Ok(Self {
147 self_key,
148 poa_offset: [poa_x, poa_y, poa_z],
149 subject_key,
150 rail_key,
151 flags,
152 accel: CameraAccel { accel: accel_val, decel: decel_val, max_vel: velocity },
153 poa_accel: CameraAccel { accel: poa_accel_val, decel: poa_decel_val, max_vel: poa_velocity },
154 x_pan_limit,
155 z_pan_limit,
156 zoom_rate,
157 zoom_min,
158 zoom_max,
159 })
160 }
161}
162
163#[derive(Debug, Clone)]
168pub struct AvatarBrainParams {
169 pub base: BrainBase,
170 pub offset: [f32; 3],
171}
172
173impl AvatarBrainParams {
174 pub fn read(reader: &mut impl Read) -> Result<Self> {
177 let base = BrainBase::read(reader)?;
178 let off_x = reader.read_f32()?;
179 let off_y = reader.read_f32()?;
180 let off_z = reader.read_f32()?;
181
182 Ok(Self {
183 base,
184 offset: [off_x, off_y, off_z],
185 })
186 }
187}
188
189#[derive(Debug, Clone)]
194pub struct FirstPersonBrainParams {
195 pub base: BrainBase,
196 pub offset: [f32; 3],
197}
198
199impl FirstPersonBrainParams {
200 pub fn read(reader: &mut impl Read) -> Result<Self> {
201 let base = BrainBase::read(reader)?;
202 let off_x = reader.read_f32()?;
203 let off_y = reader.read_f32()?;
204 let off_z = reader.read_f32()?;
205
206 Ok(Self {
207 base,
208 offset: [off_x, off_y, off_z],
209 })
210 }
211}
212
213#[derive(Debug, Clone)]
218pub struct FixedBrainParams {
219 pub base: BrainBase,
220 pub target_point: Option<Uoid>,
221}
222
223impl FixedBrainParams {
224 pub fn read(reader: &mut impl Read) -> Result<Self> {
226 let base = BrainBase::read(reader)?;
227 let target_point = read_key_uoid(reader)?;
228
229 Ok(Self {
230 base,
231 target_point,
232 })
233 }
234}
235
236#[derive(Debug, Clone)]
241pub struct CircleBrainParams {
242 pub base: BrainBase,
243 pub circle_flags: u32,
244 pub center: [f32; 3],
245 pub radius: f32,
246 pub center_object: Option<Uoid>,
247 pub poa_object: Option<Uoid>,
248 pub cir_per_sec: f32,
249}
250
251impl CircleBrainParams {
252 pub fn read(reader: &mut impl Read) -> Result<Self> {
255 let base = BrainBase::read(reader)?;
256
257 let circle_flags = reader.read_u32()?;
258
259 let cx = reader.read_f32()?;
260 let cy = reader.read_f32()?;
261 let cz = reader.read_f32()?;
262
263 let radius = reader.read_f32()?;
264
265 let center_object = read_key_uoid(reader)?;
266 let poa_object = read_key_uoid(reader)?;
267
268 let cir_per_sec = reader.read_f32()?;
269
270 Ok(Self {
271 base,
272 circle_flags,
273 center: [cx, cy, cz],
274 radius,
275 center_object,
276 poa_object,
277 cir_per_sec,
278 })
279 }
280}
281
282#[derive(Debug, Clone)]
286pub enum CameraBrain {
287 Avatar(AvatarBrainParams),
288 FirstPerson(FirstPersonBrainParams),
289 Fixed(FixedBrainParams),
290 Circle(CircleBrainParams),
291 Drive,
292 Base(BrainBase),
293}
294
295impl CameraBrain {
296 pub fn base(&self) -> Option<&BrainBase> {
297 match self {
298 CameraBrain::Avatar(p) => Some(&p.base),
299 CameraBrain::FirstPerson(p) => Some(&p.base),
300 CameraBrain::Fixed(p) => Some(&p.base),
301 CameraBrain::Circle(p) => Some(&p.base),
302 CameraBrain::Base(b) => Some(b),
303 CameraBrain::Drive => None,
304 }
305 }
306
307 pub fn self_key(&self) -> Option<&Uoid> {
308 self.base().and_then(|b| b.self_key.as_ref())
309 }
310
311 pub fn read_by_class(class_id: u16, reader: &mut impl Read) -> Result<Self> {
313 use crate::core::class_index::ClassIndex;
314 match class_id {
315 ClassIndex::PL_CAMERA_BRAIN1_AVATAR => {
316 Ok(CameraBrain::Avatar(AvatarBrainParams::read(reader)?))
317 }
318 ClassIndex::PL_CAMERA_BRAIN1_FIRST_PERSON => {
319 Ok(CameraBrain::FirstPerson(FirstPersonBrainParams::read(reader)?))
320 }
321 ClassIndex::PL_CAMERA_BRAIN1_FIXED => {
322 Ok(CameraBrain::Fixed(FixedBrainParams::read(reader)?))
323 }
324 ClassIndex::PL_CAMERA_BRAIN1_CIRCLE => {
325 Ok(CameraBrain::Circle(CircleBrainParams::read(reader)?))
326 }
327 ClassIndex::PL_CAMERA_BRAIN1 => {
328 Ok(CameraBrain::Base(BrainBase::read(reader)?))
329 }
330 _ => anyhow::bail!("Unknown camera brain class 0x{:04X}", class_id),
331 }
332 }
333
334 pub fn type_name(&self) -> &'static str {
335 match self {
336 CameraBrain::Avatar(_) => "Avatar",
337 CameraBrain::FirstPerson(_) => "FirstPerson",
338 CameraBrain::Fixed(_) => "Fixed",
339 CameraBrain::Circle(_) => "Circle",
340 CameraBrain::Drive => "Drive",
341 CameraBrain::Base(_) => "Base",
342 }
343 }
344}