use std::fs;
use std::path::Path;
const MAGIC: &[u8; 4] = b"E21D";
const STATE_SIZE: usize = 4 + 21 * 4;
pub struct EmotionalState21D {
pub vector: [f32; 21],
}
impl EmotionalState21D {
pub fn load_or_init(path: &Path) -> Self {
if path.exists() {
if let Ok(data) = fs::read(path) {
if data.len() >= STATE_SIZE && &data[0..4] == MAGIC {
let mut vector = [0.0f32; 21];
for (i, v) in vector.iter_mut().enumerate() {
let off = 4 + i * 4;
*v = f32::from_le_bytes(data[off..off + 4].try_into().unwrap_or([0u8; 4]));
}
for v in &mut vector {
if v.is_nan() || v.is_infinite() {
*v = 0.0;
}
}
return Self { vector };
}
}
}
Self {
vector: [0.0f32; 21],
}
}
pub fn save(&self, path: &Path) -> Result<(), String> {
let mut buf = Vec::with_capacity(STATE_SIZE);
buf.extend_from_slice(MAGIC);
for &v in &self.vector {
buf.extend_from_slice(&v.to_le_bytes());
}
let tmp_path = path.with_extension("bin.tmp");
fs::write(&tmp_path, &buf).map_err(|e| format!("write emotion_21d.bin: {}", e))?;
fs::rename(&tmp_path, path).map_err(|e| format!("rename emotion_21d.bin: {}", e))
}
}
pub fn emotion_21d_bias(state: &EmotionalState21D) -> (f32, f32, f32) {
let intensity: f32 = state
.vector
.iter()
.map(|x| x * x)
.sum::<f32>()
.sqrt()
.min(1.0);
if intensity.is_nan() {
return (0.0, 0.0, 0.0);
}
let dx = state.vector[0].clamp(-1.0, 1.0) * intensity;
let dy = state.vector[1].clamp(-1.0, 1.0) * intensity;
let dz = state.vector[2].clamp(-1.0, 1.0) * intensity;
(dx * 0.1, dy * 0.1, dz * 0.1)
}