wicked-waifus-rs/wicked-waifus-game-server/src/logic/role/mod.rs
2025-04-04 02:36:52 +07:00

256 lines
9.1 KiB
Rust

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<i32, i32>,
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<i32> {
role_info_data::iter()
.filter(|role| (role.role_type == 1 && !MAIN_CHARACTER_ARRAY.contains(&role.id)) || role.id == 5101)
.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<Element>) -> Vec<i32> {
let mut variations: Vec<i32> = 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<i32, i32> = 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()
}
}
}