- move structs inside `sr_tools.rs` into individual file - implement in-game equip handler (relic & lightcone)
287 lines
8.8 KiB
Rust
287 lines
8.8 KiB
Rust
use std::collections::{BTreeMap, HashMap};
|
|
|
|
use proto::{
|
|
Avatar, AvatarSkillTree, AvatarType, BattleAvatar, BattleBuff, ExtraLineupType, Gender,
|
|
LineupAvatar, LineupInfo, MultiPathAvatarType, SpBarInfo,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::sr_tools::FreesrData;
|
|
|
|
use super::{lightcone::Lightcone, relic::Relic};
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Copy, PartialEq, Eq, Default)]
|
|
#[repr(u32)]
|
|
pub enum MultiPathAvatar {
|
|
MalePyhsical = 8001,
|
|
FemalePhysical = 8002,
|
|
MalePreservation = 8003,
|
|
FemalePreservation = 8004,
|
|
MaleHarmony = 8005,
|
|
FemaleHarmony = 8006,
|
|
MaleRememberance = 8007,
|
|
FemaleRememberance = 8008,
|
|
MarchHunt = 1224,
|
|
MarchPreservation = 1001,
|
|
#[default]
|
|
Unk = 0,
|
|
}
|
|
|
|
impl From<u32> for MultiPathAvatar {
|
|
fn from(value: u32) -> Self {
|
|
match value {
|
|
8001 => Self::MalePyhsical,
|
|
8002 => Self::FemalePhysical,
|
|
8003 => Self::MalePreservation,
|
|
8004 => Self::FemalePreservation,
|
|
8005 => Self::MaleHarmony,
|
|
8006 => Self::FemaleHarmony,
|
|
8007 => Self::MaleRememberance,
|
|
8008 => Self::FemaleRememberance,
|
|
1224 => Self::MarchHunt,
|
|
1001 => Self::MarchPreservation,
|
|
_ => Self::Unk,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<MultiPathAvatar> for u32 {
|
|
fn from(value: MultiPathAvatar) -> Self {
|
|
match value {
|
|
MultiPathAvatar::MalePyhsical => 8001,
|
|
MultiPathAvatar::FemalePhysical => 8002,
|
|
MultiPathAvatar::MalePreservation => 8003,
|
|
MultiPathAvatar::FemalePreservation => 8004,
|
|
MultiPathAvatar::MaleHarmony => 8005,
|
|
MultiPathAvatar::FemaleHarmony => 8006,
|
|
MultiPathAvatar::MaleRememberance => 8007,
|
|
MultiPathAvatar::FemaleRememberance => 8008,
|
|
MultiPathAvatar::MarchHunt => 1224,
|
|
MultiPathAvatar::MarchPreservation => 1001,
|
|
_ => 8006,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MultiPathAvatar {
|
|
#[allow(unused)]
|
|
pub fn get_gender(&self) -> Gender {
|
|
if (*self as u32) < 8000 {
|
|
Gender::None
|
|
} else if *self as u32 % 2 == 1 {
|
|
Gender::Man
|
|
} else {
|
|
Gender::Woman
|
|
}
|
|
}
|
|
|
|
pub fn get_type(&self) -> MultiPathAvatarType {
|
|
match *self {
|
|
MultiPathAvatar::MalePyhsical => MultiPathAvatarType::BoyWarriorType,
|
|
MultiPathAvatar::FemalePhysical => MultiPathAvatarType::GirlWarriorType,
|
|
MultiPathAvatar::MalePreservation => MultiPathAvatarType::BoyKnightType,
|
|
MultiPathAvatar::FemalePreservation => MultiPathAvatarType::GirlKnightType,
|
|
MultiPathAvatar::MaleHarmony => MultiPathAvatarType::BoyShamanType,
|
|
MultiPathAvatar::FemaleHarmony => MultiPathAvatarType::GirlShamanType,
|
|
MultiPathAvatar::MarchHunt => MultiPathAvatarType::Mar7thRogueType,
|
|
MultiPathAvatar::MarchPreservation => MultiPathAvatarType::Mar7thKnightType,
|
|
MultiPathAvatar::Unk => MultiPathAvatarType::None,
|
|
MultiPathAvatar::MaleRememberance => MultiPathAvatarType::BoyMemoryType,
|
|
MultiPathAvatar::FemaleRememberance => MultiPathAvatarType::GirlMemoryType,
|
|
}
|
|
}
|
|
|
|
pub fn is_mc(&self) -> bool {
|
|
(*self as u32) > 8000
|
|
}
|
|
|
|
pub fn to_vec() -> Vec<MultiPathAvatar> {
|
|
vec![
|
|
Self::MalePyhsical,
|
|
Self::FemalePhysical,
|
|
Self::MalePreservation,
|
|
Self::FemalePreservation,
|
|
Self::MaleHarmony,
|
|
Self::FemaleHarmony,
|
|
Self::MaleRememberance,
|
|
Self::FemaleRememberance,
|
|
Self::MarchHunt,
|
|
Self::MarchPreservation,
|
|
]
|
|
}
|
|
}
|
|
|
|
// AVATAR
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct AvatarJson {
|
|
// #[serde(alias = "ownerUid")]
|
|
// pub owner_uid: u32,
|
|
#[serde(alias = "avatarId")]
|
|
pub avatar_id: u32,
|
|
pub data: AvatarData,
|
|
pub level: u32,
|
|
pub promotion: u32,
|
|
#[serde(alias = "use_technique")]
|
|
#[serde(alias = "useTechnique")]
|
|
pub techniques: Vec<u32>,
|
|
#[serde(alias = "spValue")]
|
|
pub sp_value: Option<u32>,
|
|
#[serde(alias = "spMax")]
|
|
pub sp_max: Option<u32>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct AvatarData {
|
|
pub rank: u32,
|
|
pub skills: HashMap<u32, u32>,
|
|
}
|
|
|
|
impl AvatarJson {
|
|
pub fn to_avatar_proto(&self, lightcone: Option<&Lightcone>, relics: Vec<&Relic>) -> Avatar {
|
|
// TODO: HARDCODED
|
|
let base_avatar_id = if self.avatar_id > 8000 {
|
|
8001
|
|
} else if self.avatar_id == 1001 || self.avatar_id == 1224 {
|
|
1001
|
|
} else {
|
|
self.avatar_id
|
|
};
|
|
|
|
Avatar {
|
|
base_avatar_id,
|
|
level: self.level,
|
|
promotion: self.promotion,
|
|
rank: self.data.rank,
|
|
skilltree_list: self
|
|
.data
|
|
.skills
|
|
.iter()
|
|
.map(|v| AvatarSkillTree {
|
|
point_id: *v.0,
|
|
level: *v.1,
|
|
})
|
|
.collect::<Vec<_>>(),
|
|
equipment_unique_id: lightcone.map(|v| v.get_unique_id()).unwrap_or_default(),
|
|
first_met_timestamp: 1712924677,
|
|
equip_relic_list: relics.iter().map(|v| (*v).into()).collect::<Vec<_>>(),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn to_battle_avatar_proto(
|
|
&self,
|
|
index: u32,
|
|
lightcone: Option<&Lightcone>,
|
|
relics: Vec<&Relic>,
|
|
) -> (BattleAvatar, Vec<BattleBuff>) {
|
|
let battle_avatar = BattleAvatar {
|
|
index,
|
|
avatar_type: AvatarType::AvatarUpgradeAvailableType.into(),
|
|
id: self.avatar_id,
|
|
level: self.level,
|
|
rank: self.data.rank,
|
|
skilltree_list: self
|
|
.data
|
|
.skills
|
|
.iter()
|
|
.map(|v| AvatarSkillTree {
|
|
point_id: *v.0,
|
|
level: *v.1,
|
|
})
|
|
.collect::<Vec<_>>(),
|
|
equipment_list: if let Some(lc) = lightcone {
|
|
vec![lc.into()]
|
|
} else {
|
|
vec![]
|
|
},
|
|
hp: 10_000,
|
|
promotion: self.promotion,
|
|
relic_list: relics.iter().map(|v| (*v).into()).collect::<Vec<_>>(),
|
|
world_level: 6,
|
|
sp_bar: Some(SpBarInfo {
|
|
cur_sp: self.sp_value.unwrap_or(10_000),
|
|
max_sp: self.sp_max.unwrap_or(10_000),
|
|
}),
|
|
..Default::default()
|
|
};
|
|
|
|
let mut battle_buff = Vec::<BattleBuff>::new();
|
|
for buff_id in &self.techniques {
|
|
battle_buff.push(BattleBuff {
|
|
wave_flag: 0xffffffff,
|
|
owner_id: index,
|
|
level: 1,
|
|
id: *buff_id,
|
|
dynamic_values: HashMap::from([(String::from("SkillIndex"), 2.0)]),
|
|
..Default::default()
|
|
});
|
|
}
|
|
|
|
(battle_avatar, battle_buff)
|
|
}
|
|
|
|
pub fn to_lineup_avatar_proto(&self, slot: u32) -> LineupAvatar {
|
|
LineupAvatar {
|
|
id: self.avatar_id,
|
|
hp: 10_000,
|
|
satiety: 100,
|
|
avatar_type: AvatarType::AvatarFormalType.into(),
|
|
sp_bar: Some(SpBarInfo {
|
|
cur_sp: self.sp_value.unwrap_or(10_000),
|
|
max_sp: self.sp_max.unwrap_or(10_000),
|
|
}),
|
|
slot,
|
|
}
|
|
}
|
|
|
|
pub fn to_lineup_avatars(player: &FreesrData) -> Vec<LineupAvatar> {
|
|
let avatar_ids = player
|
|
.avatars
|
|
.values()
|
|
.map(|v| &v.avatar_id)
|
|
.collect::<Vec<_>>();
|
|
|
|
player
|
|
.lineups
|
|
.iter()
|
|
.filter(|(slot, v)| **slot < 4 && v > &&0 && avatar_ids.contains(v))
|
|
.map(|(slot, avatar_id)| {
|
|
player
|
|
.avatars
|
|
.get(avatar_id)
|
|
.unwrap()
|
|
.to_lineup_avatar_proto(*slot)
|
|
})
|
|
.collect::<Vec<LineupAvatar>>()
|
|
}
|
|
|
|
pub fn to_lineup_info(lineups: &BTreeMap<u32, u32>) -> LineupInfo {
|
|
let mut lineup_info = LineupInfo {
|
|
extra_lineup_type: ExtraLineupType::LineupNone.into(),
|
|
name: "Squad 1".to_string(),
|
|
mp: 5,
|
|
max_mp: 5,
|
|
..Default::default()
|
|
};
|
|
|
|
for id in lineups.values() {
|
|
if *id == 0 {
|
|
continue;
|
|
}
|
|
lineup_info.avatar_list.push(LineupAvatar {
|
|
id: *id,
|
|
hp: 10_000,
|
|
satiety: 100,
|
|
avatar_type: AvatarType::AvatarFormalType.into(),
|
|
sp_bar: Some(SpBarInfo {
|
|
cur_sp: 10_000,
|
|
max_sp: 10_000,
|
|
}),
|
|
slot: lineup_info.avatar_list.len() as u32,
|
|
});
|
|
}
|
|
|
|
lineup_info
|
|
}
|
|
}
|