use std::collections::HashMap; use wicked_waifus_protocol::{ArrayIntInt, RoleInfo}; use crate::config; use crate::logic::utils::growth_utils::get_role_props_by_level; use crate::logic::utils::load_role_info::load_key_value; pub use formation::RoleFormation; use wicked_waifus_commons::time_util; use wicked_waifus_data::{role_info_data, BasePropertyData}; use wicked_waifus_protocol_internal::{RoleData, RoleStats}; use crate::logic::player::Element; const MAIN_CHARACTER_MALE_SPECTRO_ID: i32 = 1501; const MAIN_CHARACTER_FEMALE_SPECTRO_ID: i32 = 1502; const MAIN_CHARACTER_MALE_HAVOC_ID: i32 = 1605; const MAIN_CHARACTER_FEMALE_HAVOC_ID: i32 = 1604; const MAIN_CHARACTER_MALE_AERO_ID: i32 = 1406; const MAIN_CHARACTER_FEMALE_AERO_ID: i32 = 1408; const MAIN_CHARACTER_ARRAY: &[i32] = &[ MAIN_CHARACTER_MALE_SPECTRO_ID, MAIN_CHARACTER_FEMALE_SPECTRO_ID, MAIN_CHARACTER_MALE_HAVOC_ID, MAIN_CHARACTER_FEMALE_HAVOC_ID, MAIN_CHARACTER_MALE_AERO_ID, MAIN_CHARACTER_FEMALE_AERO_ID, ]; mod formation; pub struct Role { pub role_id: i32, pub name: String, pub level: i32, pub exp: i32, pub breakthrough: i32, pub skill_map: HashMap, pub star: i32, pub favor: i32, pub create_time: u32, pub equip_weapon: i32, pub skin_id: i32, pub resonant_chain_group_index: i32, pub hp: i32, pub energy: i32, pub special_energy_1: i32, pub special_energy_2: i32, pub special_energy_3: i32, pub special_energy_4: i32, pub element_energy: i32, pub favor_level: i32, pub favor_exp: i32, } impl Role { #[inline(always)] pub fn get_all_roles_except_mc() -> Vec { role_info_data::iter() .filter(|role| role.role_type == 1 && !MAIN_CHARACTER_ARRAY.contains(&role.id)) .map(|role| role.id) .collect() } #[inline(always)] pub fn get_mc_id_based_on_sex(sex: i32, current_element: Element) -> i32 { match current_element { Element::Glacio => unreachable!(), Element::Fusion => unreachable!(), Element::Electro => unreachable!(), Element::Aero => match sex { 0 => MAIN_CHARACTER_MALE_AERO_ID, 1 => MAIN_CHARACTER_FEMALE_AERO_ID, _ => unreachable!(), } Element::Spectro => match sex { 0 => MAIN_CHARACTER_FEMALE_SPECTRO_ID, 1 => MAIN_CHARACTER_MALE_SPECTRO_ID, _ => unreachable!(), } Element::Havoc => match sex { 0 => MAIN_CHARACTER_MALE_HAVOC_ID, 1 => MAIN_CHARACTER_FEMALE_HAVOC_ID, _ => unreachable!(), } } } #[inline(always)] pub fn get_mc_based_on_sex(sex: i32, current_element: Element) -> Self { Role::new(Self::get_mc_id_based_on_sex(sex, current_element)) } pub fn get_mc_unlock_variations(unlocked_elements: Vec) -> Vec { let mut variations: Vec = Vec::new(); for element in unlocked_elements { match element { Element::Glacio => {}, Element::Fusion => {}, Element::Electro => {}, Element::Aero => { variations.push(MAIN_CHARACTER_MALE_AERO_ID); variations.push(MAIN_CHARACTER_FEMALE_AERO_ID); }, Element::Spectro => { variations.push(MAIN_CHARACTER_MALE_SPECTRO_ID); variations.push(MAIN_CHARACTER_FEMALE_SPECTRO_ID); }, Element::Havoc => { variations.push(MAIN_CHARACTER_MALE_HAVOC_ID); variations.push(MAIN_CHARACTER_FEMALE_HAVOC_ID); }, } } variations } pub fn new(role_id: i32) -> Self { let data = role_info_data::iter().find(|d| d.id == role_id).unwrap(); let default_unlocks = &config::get_config().default_unlocks; let (level, breakthrough) = if default_unlocks.unlock_all_roles_max_level { (data.max_level, 6) } else { (1, 0) }; let resonant_chain_group_index = if default_unlocks.unlock_all_roles_all_sequences { 6 } else { 0 }; let base_stats = &get_role_props_by_level(role_id, level, breakthrough); Self { role_id, name: String::with_capacity(0), level, exp: 0, // TODO: Compute based on level?? breakthrough, skill_map: HashMap::new(), // TODO! star: 0, favor: 0, create_time: time_util::unix_timestamp() as u32, equip_weapon: data.init_weapon_item_id, skin_id: data.skin_id, resonant_chain_group_index, hp: base_stats.life, energy: base_stats.energy, special_energy_1: base_stats.special_energy_1, special_energy_2: base_stats.special_energy_2, special_energy_3: base_stats.special_energy_3, special_energy_4: base_stats.special_energy_4, element_energy: base_stats.element_energy, favor_level: 0, favor_exp: 0, } } pub fn get_base_properties(&self) -> BasePropertyData { // Overwrite dynamic attributes with stores values let mut base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough); // TODO: Integrity check, value has to be between 0 and max base_stats.life = self.hp; base_stats.energy = self.energy; base_stats.special_energy_1 = self.special_energy_1; base_stats.special_energy_2 = self.special_energy_2; base_stats.special_energy_3 = self.special_energy_3; base_stats.special_energy_4 = self.special_energy_4; base_stats.element_energy = self.element_energy; base_stats } pub fn to_protobuf(&self) -> RoleInfo { let base_prop: HashMap = load_key_value(&self.get_base_properties()); RoleInfo { role_id: self.role_id, name: self.name.clone(), level: self.level, exp: self.exp, breakthrough: self.breakthrough, create_time: self.create_time, skills: self .skill_map .iter() .map(|(k, v)| ArrayIntInt { key: *k, value: *v }) .collect(), base_prop: base_prop .iter() .map(|(&k, &v)| ArrayIntInt { key: k, value: v }) .collect(), skin_id: self.skin_id, resonant_chain_group_index: self.resonant_chain_group_index, ..Default::default() } } pub fn load_from_save(data: RoleData) -> (i32, Self) { ( data.role_id, Self { role_id: data.role_id, name: data.name, level: data.level, exp: data.exp, breakthrough: data.breakthrough, skill_map: data.skill_map, star: data.star, favor: data.favor, create_time: data.create_time, equip_weapon: data.equip_weapon, skin_id: data.skin_id, resonant_chain_group_index: data.resonant_chain_group_index, hp: data.stats.unwrap().hp, energy: data.stats.unwrap().energy, special_energy_1: data.stats.unwrap().special_energy_1, special_energy_2: data.stats.unwrap().special_energy_2, special_energy_3: data.stats.unwrap().special_energy_3, special_energy_4: data.stats.unwrap().special_energy_4, element_energy: data.stats.unwrap().element_energy, favor_level: data.favor_level, favor_exp: data.favor_exp, }, ) } pub fn build_save_data(&self) -> RoleData { RoleData { role_id: self.role_id, name: self.name.clone(), level: self.level, exp: self.exp, breakthrough: self.breakthrough, skill_map: self.skill_map.clone(), // phantom_map: Default::default(), star: self.star, favor: self.favor, create_time: self.create_time, // cur_model: 0, // models: vec![], // skill_node_state: vec![], resonant_chain_group_index: self.resonant_chain_group_index, equip_weapon: self.equip_weapon, skin_id: self.skin_id, stats: Some(RoleStats { hp: self.hp, energy: self.energy, special_energy_1: self.special_energy_1, special_energy_2: self.special_energy_2, special_energy_3: self.special_energy_3, special_energy_4: self.special_energy_4, element_energy: self.element_energy, }), favor_level: self.favor_level, favor_exp: self.favor_exp, ..Default::default() } } }