use std::fmt;
use crate::common::utils::csv;
#[derive(Debug)]
pub enum ParamError {
EmptyFile,
}
impl fmt::Display for ParamError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParamError::EmptyFile => write!(f, "The provided file bytes contained no valid param data."),
}
}
}
impl std::error::Error for ParamError {}
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
pub struct Param {
pub unknown_1: i32, pub unknown_2: i32, pub unknown_3: i32, pub unknown_4: i32, pub unknown_5: i32, pub unknown_6: i32, pub unknown_7: i32, pub unknown_8: i32, pub unknown_9: i32, pub unknown_10: i32, pub unknown_11: i32, pub unknown_12: i32, pub unknown_13: i32, pub unknown_14: i32, pub unknown_15: i32, pub unknown_16: i32, pub unknown_17: i32, pub hold_cat_details_time: i32, pub time_until_death_surge: i32, pub behemoth_slayer_attack_multiplier: f32, pub behemoth_slayer_defense_multiplier: f32, pub unknown_22: i32, pub logo_superfeline_roll_timer: i32, pub logo_superfeline_chance_success: i32, pub logo_superfeline_failure_increase: i32, pub unknown_26: i32, pub unknown_27: i32, pub unknown_28: i32, pub unknown_29: i32, pub unknown_30: i32, pub unknown_31: i32, pub unknown_32: i32, pub unknown_33: i32, pub volume_setting_percent_small: i32, pub volume_setting_percent_medium: i32, pub volume_setting_percent_large: i32, pub spirit_position_offset: i32, pub sage_type_resist_weaken: f32, pub sage_type_resist_freeze: f32, pub sage_type_resist_slow: f32, pub sage_type_resist_curse: f32, pub sage_type_resist_knockback: f32, pub sage_slayer_resist_weaken: f32, pub sage_slayer_resist_freeze: f32, pub sage_slayer_resist_slow: f32, pub sage_slayer_resist_curse: f32, pub sage_slayer_resist_other: f32, pub sage_slayer_resist_warp: f32, pub sage_slayer_attack_multiplier: f32, pub sage_slayer_defense_multiplier: f32, pub metal_killer_hitpoint_behavior: i32, pub unknown_52: i32, pub unknown_53: i32, pub story_sequence_hold_speed: i32, pub explosion_start_time: i32, pub explosion_hitbox_duration: i32, pub explosion_delay_before_deletion: i32, pub explosion_delay_until_spike: i32, pub explosion_big_width: f32, pub explosion_medium_width: f32, pub explosion_small_width: f32, pub explosion_big_damage_multiplier: f32, pub explosion_medium_damage_multiplier: f32, pub explosion_small_damage_multiplier: f32, pub unknown_65: i32, pub unknown_66: i32, pub unknown_67: i32, pub unknown_68: i32, pub unknown_69: i32, pub unknown_70: i32, pub unknown_71: i32, pub unknown_72: i32, pub unknown_73: i32, pub unknown_74: i32, pub unknown_75: i32, pub unknown_76: i32, pub unknown_77: i32, pub unknown_78: i32, pub comeback_treasure_festival_days: i32, pub unknown_80: i32, pub unknown_81: i32, pub rest: Vec<i32>,
}
impl Param {
pub fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<Self, ParamError> {
parse_inner(bytes.as_ref())
}
}
fn parse_inner(bytes: &[u8]) -> Result<Param, ParamError> {
let file_content = csv::scrub(bytes);
let mut values = Vec::new();
for line in file_content.lines() {
if line.trim().is_empty() { continue; }
if let Some(val_str) = line.split_whitespace().last() {
if let Ok(val) = val_str.parse::<i32>() {
values.push(val);
} else {
values.push(0);
}
}
}
if values.is_empty() {
return Err(ParamError::EmptyFile);
}
let get_val = |index: usize| -> i32 { values.get(index).copied().unwrap_or(0) };
let mut rest_vector = Vec::new();
if values.len() > 81 {
rest_vector.extend_from_slice(&values[81..]);
}
Ok(Param {
unknown_1: get_val(0),
unknown_2: get_val(1),
unknown_3: get_val(2),
unknown_4: get_val(3),
unknown_5: get_val(4),
unknown_6: get_val(5),
unknown_7: get_val(6),
unknown_8: get_val(7),
unknown_9: get_val(8),
unknown_10: get_val(9),
unknown_11: get_val(10),
unknown_12: get_val(11),
unknown_13: get_val(12),
unknown_14: get_val(13),
unknown_15: get_val(14),
unknown_16: get_val(15),
unknown_17: get_val(16),
hold_cat_details_time: get_val(17),
time_until_death_surge: get_val(18),
behemoth_slayer_attack_multiplier: get_val(19) as f32 / 1000.0,
behemoth_slayer_defense_multiplier: get_val(20) as f32 / 1000.0,
unknown_22: get_val(21),
logo_superfeline_roll_timer: get_val(22),
logo_superfeline_chance_success: get_val(23),
logo_superfeline_failure_increase: get_val(24),
unknown_26: get_val(25),
unknown_27: get_val(26),
unknown_28: get_val(27),
unknown_29: get_val(28),
unknown_30: get_val(29),
unknown_31: get_val(30),
unknown_32: get_val(31),
unknown_33: get_val(32),
volume_setting_percent_small: get_val(33),
volume_setting_percent_medium: get_val(34),
volume_setting_percent_large: get_val(35),
spirit_position_offset: get_val(36),
sage_type_resist_weaken: get_val(37) as f32 / 100.0,
sage_type_resist_freeze: get_val(38) as f32 / 100.0,
sage_type_resist_slow: get_val(39) as f32 / 100.0,
sage_type_resist_curse: get_val(40) as f32 / 100.0,
sage_type_resist_knockback: get_val(41) as f32 / 100.0,
sage_slayer_resist_weaken: get_val(42) as f32 / 100.0,
sage_slayer_resist_freeze: get_val(43) as f32 / 100.0,
sage_slayer_resist_slow: get_val(44) as f32 / 100.0,
sage_slayer_resist_curse: get_val(45) as f32 / 100.0,
sage_slayer_resist_other: get_val(46) as f32 / 100.0,
sage_slayer_resist_warp: get_val(47) as f32 / 100.0,
sage_slayer_attack_multiplier: get_val(48) as f32 / 1000.0,
sage_slayer_defense_multiplier: get_val(49) as f32 / 1000.0,
metal_killer_hitpoint_behavior: get_val(50),
unknown_52: get_val(51),
unknown_53: get_val(52),
story_sequence_hold_speed: get_val(53),
explosion_start_time: get_val(54),
explosion_hitbox_duration: get_val(55),
explosion_delay_before_deletion: get_val(56),
explosion_delay_until_spike: get_val(57),
explosion_big_width: get_val(58) as f32 / 4.0,
explosion_medium_width: get_val(59) as f32 / 4.0,
explosion_small_width: get_val(60) as f32 / 4.0,
explosion_big_damage_multiplier: get_val(61) as f32 / 100.0,
explosion_medium_damage_multiplier: get_val(62) as f32 / 100.0,
explosion_small_damage_multiplier: get_val(63) as f32 / 100.0,
unknown_65: get_val(64),
unknown_66: get_val(65),
unknown_67: get_val(66),
unknown_68: get_val(67),
unknown_69: get_val(68),
unknown_70: get_val(69),
unknown_71: get_val(70),
unknown_72: get_val(71),
unknown_73: get_val(72),
unknown_74: get_val(73),
unknown_75: get_val(74),
unknown_76: get_val(75),
unknown_77: get_val(76),
unknown_78: get_val(77),
comeback_treasure_festival_days: get_val(78),
unknown_80: get_val(79),
unknown_81: get_val(80),
rest: rest_vector,
})
}