diff --git a/mona_core/src/character/character_config.rs b/mona_core/src/character/character_config.rs index 302eb614..6a922394 100644 --- a/mona_core/src/character/character_config.rs +++ b/mona_core/src/character/character_config.rs @@ -37,5 +37,8 @@ pub enum CharacterConfig { Xianyun { talent1_stack: f64, talent2_rate: f64, butianti_count: usize }, Chiori { talent2: bool }, Arlecchino { c6_ratio: f64 }, + Clorinde { talent1_stack: f64, talent2_stack: f64, c6_rate: f64 }, + Sigewinne { c6_rate: f64 }, + Sethos { c2_stack: f64 }, NoConfig, } diff --git a/mona_core/src/character/character_name.rs b/mona_core/src/character/character_name.rs index 0dc98537..71a7e0d2 100644 --- a/mona_core/src/character/character_name.rs +++ b/mona_core/src/character/character_name.rs @@ -108,4 +108,7 @@ pub enum CharacterName { Xianyun, Chiori, Arlecchino, + Clorinde, + Sigewinne, + Sethos, } \ No newline at end of file diff --git a/mona_core/src/character/characters/electro/clorinde.rs b/mona_core/src/character/characters/electro/clorinde.rs new file mode 100644 index 00000000..1aacb486 --- /dev/null +++ b/mona_core/src/character/characters/electro/clorinde.rs @@ -0,0 +1,311 @@ +use crate::attribute::{Attribute, AttributeName, AttributeCommon}; +use crate::character::{CharacterConfig, CharacterName, CharacterStaticData}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::character_sub_stat::CharacterSubStatFamily; +use crate::character::macros::{damage_enum, damage_ratio, skill_map, skill_type}; +use crate::character::skill_config::CharacterSkillConfig; +use crate::character::traits::{CharacterSkillMap, CharacterSkillMapItem, CharacterTrait}; +use crate::common::{ChangeAttribute, Element, SkillType, StatName, WeaponType}; +use crate::common::i18n::{locale, hit_n_dmg, plunging_dmg, charged_dmg}; +use crate::common::item_config_type::{ItemConfig, ItemConfigType}; +use crate::damage::damage_builder::DamageBuilder; +use crate::damage::DamageContext; +use crate::target_functions::TargetFunction; +use crate::team::TeamQuantization; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct ClorindeSkillType { + pub normal_dmg1: [f64; 15], + pub normal_dmg2: [f64; 15], + pub normal_dmg3: [f64; 15], + pub normal_dmg4: [f64; 15], + pub normal_dmg5: [f64; 15], + pub charged_dmg: [f64; 15], + pub plunging_dmg1: [f64; 15], + pub plunging_dmg2: [f64; 15], + pub plunging_dmg3: [f64; 15], + + pub e_dmg11: [f64; 15], + pub e_dmg12: [f64; 15], + pub e_dmg21: [f64; 15], + pub e_dmg22: [f64; 15], + pub e_dmg23: [f64; 15], + pub e_dmg3: [f64; 15], + + pub q_dmg1: [f64; 15], + pub q_life: [f64; 15], +} + +pub const CLORINDE_SKILL: ClorindeSkillType = ClorindeSkillType { + normal_dmg1: [0.5406, 0.5846, 0.6286, 0.6915, 0.7355, 0.7858, 0.8549, 0.924, 0.9932, 1.0686, 1.1441, 1.2195, 1.2949, 1.3703, 1.4458], + normal_dmg2: [0.5163, 0.5583, 0.6003, 0.6604, 0.7024, 0.7504, 0.8164, 0.8825, 0.9485, 1.0206, 1.0926, 1.1646, 1.2367, 1.3087, 1.3808], + normal_dmg3: [0.3419, 0.3697, 0.3975, 0.4373, 0.4651, 0.4969, 0.5406, 0.5843, 0.6281, 0.6758, 0.7235, 0.7712, 0.8189, 0.8666, 0.9143], + normal_dmg4: [0.2313, 0.2502, 0.269, 0.2959, 0.3147, 0.3363, 0.3658, 0.3954, 0.425, 0.4573, 0.4896, 0.5219, 0.5541, 0.5864, 0.6187], + normal_dmg5: [0.9001, 0.9734, 1.0466, 1.1513, 1.2246, 1.3083, 1.4234, 1.5385, 1.6537, 1.7793, 1.9049, 2.0305, 2.1561, 2.2817, 2.4072], + charged_dmg: [1.2814, 1.3857, 1.49, 1.639, 1.7433, 1.8625, 2.0264, 2.1903, 2.3542, 2.533, 2.7118, 2.8906, 3.0694, 3.2482, 3.427], + plunging_dmg1: [0.6393, 0.6914, 0.7434, 0.8177, 0.8698, 0.9293, 1.011, 1.0928, 1.1746, 1.2638, 1.353, 1.4422, 1.5314, 1.6206, 1.7098], + plunging_dmg2: [1.2784, 1.3824, 1.4865, 1.6351, 1.7392, 1.8581, 2.0216, 2.1851, 2.3486, 2.527, 2.7054, 2.8838, 3.0622, 3.2405, 3.4189], + plunging_dmg3: [1.5968, 1.7267, 1.8567, 2.0424, 2.1723, 2.3209, 2.5251, 2.7293, 2.9336, 3.1564, 3.3792, 3.602, 3.8248, 4.0476, 4.2704], + e_dmg11: [0.2676, 0.2894, 0.3112, 0.3423, 0.3641, 0.389, 0.4232, 0.4575, 0.4917, 0.529, 0.5664, 0.6037, 0.6411, 0.6784, 0.7158], + e_dmg12: [0.3879, 0.4194, 0.451, 0.4961, 0.5277, 0.5638, 0.6134, 0.663, 0.7126, 0.7667, 0.8208, 0.8749, 0.9291, 0.9832, 1.0373], + e_dmg21: [0.3297, 0.3566, 0.3834, 0.4217, 0.4486, 0.4793, 0.5214, 0.5636, 0.6058, 0.6518, 0.6978, 0.7438, 0.7898, 0.8358, 0.8818], + e_dmg22: [0.4396, 0.4754, 0.5112, 0.5623, 0.5981, 0.639, 0.6952, 0.7515, 0.8077, 0.869, 0.9304, 0.9917, 1.0531, 1.1144, 1.1758], + e_dmg23: [0.2511, 0.2716, 0.292, 0.3212, 0.3416, 0.365, 0.3971, 0.4292, 0.4614, 0.4964, 0.5314, 0.5665, 0.6015, 0.6366, 0.6716], + e_dmg3: [0.432, 0.4644, 0.4968, 0.54, 0.5724, 0.6048, 0.648, 0.6912, 0.7344, 0.7776, 0.8208, 0.864, 0.918, 0.972, 1.026], + q_dmg1: [1.2688, 1.364, 1.4591, 1.586, 1.6812, 1.7763, 1.9032, 2.0301, 2.157, 2.2838, 2.4107, 2.5376, 2.6962, 2.8548, 3.0134], + q_life: [0.66, 0.72, 0.78, 0.84, 0.9, 0.96, 1.02, 1.08, 1.14, 1.2, 1.26, 1.32, 1.38, 1.44, 1.5], +}; + +damage_enum!( + ClorindeDamageEnum + Normal1 + Normal2 + Normal3 + Normal4 + Normal5 + Charged + Plunging1 + Plunging2 + Plunging3 + E11 + E12 + E21 + E22 + E23 + E3 + Q1 +); + +impl ClorindeDamageEnum { + pub fn get_skill_type(&self) -> SkillType { + use ClorindeDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 | Normal4 | Normal5 | E11 | E12 | E21 | E22 | E23 => SkillType::NormalAttack, + Charged => SkillType::ChargedAttack, + Plunging1 => SkillType::PlungingAttackInAction, + Plunging2 | Plunging3 => SkillType::PlungingAttackOnGround, + E3 => SkillType::ElementalSkill, + Q1 => SkillType::ElementalBurst, + } + } + + pub fn get_element(&self) -> Element { + use ClorindeDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 | Normal4 | Normal5 | Charged | Plunging1 | Plunging2 | Plunging3 => Element::Physical, + E11 | E12 | E21 | E22 | E23 | E3 | Q1 => Element::Electro, + } + } +} + +pub struct ClorindeEffect { + pub talent1_stack: f64, + pub talent2_stack: f64, + pub c6_rate: f64, + pub constellation: usize, + pub has_talent2: bool, + pub has_talent1: bool, +} + +impl ChangeAttribute for ClorindeEffect { + fn change_attribute(&self, attribute: &mut A) { + if self.has_talent1 && self.talent1_stack > 0.0 { + let ratio = if self.constellation >= 2 { 0.3 } else { 0.2 }; + let max = if self.constellation >= 2 { 2700.0 } else { 1800.0 }; + attribute.add_edge1( + AttributeName::ATK, + AttributeName::ExtraDmgNormalAttack, + Box::new(move |atk, _| (atk * ratio).min(max)), + Box::new(|_x, _y, _grad| (0.0, 0.0)), + "天赋1「破夜的明焰」", + ); + attribute.add_edge1( + AttributeName::ATK, + AttributeName::ExtraDmgElementalBurst, + Box::new(move |atk, _| (atk * ratio).min(max)), + Box::new(|_x, _y, _grad| (0.0, 0.0)), + "天赋1「破夜的明焰」", + ) + } + if self.has_talent2 && self.talent2_stack > 0.0 { + let bonus = 0.1 * self.talent2_stack; + attribute.set_value_by(AttributeName::CriticalBase, "天赋「契令的酬偿」", bonus); + } + if self.constellation >= 6 && self.c6_rate > 0.0 { + attribute.set_value_by(AttributeName::CriticalBase, "C6「为此,勿将希望弃扬」", 0.1 * self.c6_rate); + attribute.set_value_by(AttributeName::CriticalDamageBase, "C6「为此,勿将希望弃扬」", 0.7 * self.c6_rate); + } + } +} + +pub struct Clorinde; + +impl CharacterTrait for Clorinde { + const STATIC_DATA: CharacterStaticData = CharacterStaticData { + name: CharacterName::Clorinde, + internal_name: "Clorinde", + name_locale: locale!( + zh_cn: "克洛琳德", + en: "Clorinde", + ), + element: Element::Electro, + hp: [1009, 2616, 3481, 5209, 5823, 6700, 7519, 8405, 9019, 9913, 10527, 11431, 12045, 12956], + atk: [26, 68, 91, 136, 152, 174, 196, 219, 235, 258, 274, 298, 314, 337], + def: [61, 158, 211, 315, 352, 405, 455, 509, 546, 600, 637, 692, 729, 784], + sub_stat: CharacterSubStatFamily::CriticalRate192, + weapon_type: WeaponType::Sword, + star: 5, + skill_name1: locale!( + zh_cn: "普通攻击·逐影之誓", + en: "Normal Attack: Oath of Hunting Shadows", + ), + skill_name2: locale!( + zh_cn: "狩夜之巡", + en: "Hunter's Vigil", + ), + skill_name3: locale!( + zh_cn: "残光将终", + en: "Last Lightfall", + ), + }; + type SkillType = ClorindeSkillType; + const SKILL: Self::SkillType = CLORINDE_SKILL; + type DamageEnumType = ClorindeDamageEnum; + type RoleEnum = (); + + #[cfg(not(target_family = "wasm"))] + const SKILL_MAP: CharacterSkillMap = CharacterSkillMap { + skill1: skill_map!( + ClorindeDamageEnum + Normal1 hit_n_dmg!(1) + Normal2 hit_n_dmg!(2) + Normal3 locale!(zh_cn: "三段伤害/2", en: "3-Hit DMG/2") + Normal4 locale!(zh_cn: "四段伤害/3", en: "4-Hit DMG/3") + Normal5 hit_n_dmg!(5) + Charged charged_dmg!() + Plunging1 plunging_dmg!(1) + Plunging2 plunging_dmg!(2) + Plunging3 plunging_dmg!(3) + ), + skill2: skill_map!( + ClorindeDamageEnum + E11 locale!(zh_cn: "驰猎伤害-1", en: "Swift Hunt DMG-1") + E12 locale!(zh_cn: "驰猎伤害-2", en: "Swift Hunt DMG-2") + E21 locale!(zh_cn: "贯夜伤害-1", en: "Impale the Night DMG-1") + E22 locale!(zh_cn: "贯夜伤害-2", en: "Impale the Night DMG-2") + E23 locale!(zh_cn: "贯夜伤害-3", en: "Impale the Night DMG-3") + E3 locale!(zh_cn: "流涌之刃伤害", en: "Surging Blade DMG") + ), + skill3: skill_map!( + ClorindeDamageEnum + Q1 locale!(zh_cn: "技能伤害", en: "Skill DMG") + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig { + name: "talent1_stack", + title: locale!( + zh_cn: "天赋1「破夜的明焰」层数", + en: "Talent1 Stack" + ), + config: ItemConfigType::Float { min: 0.0, max: 3.0, default: 0.0 } + }, + ItemConfig { + name: "talent2_stack", + title: locale!( + zh_cn: "天赋2「契令的酬偿」层数", + en: "Talent2 Stack" + ), + config: ItemConfigType::Float { min: 0.0, max: 2.0, default: 0.0 } + }, + ItemConfig { + name: "c6_rate", + title: locale!( + zh_cn: "C6「为此,勿将希望弃扬」比例", + en: "C6 Rate", + ), + config: ItemConfigType::Float { min: 0.0, max: 1.0, default: 0.0 } + }, + ]); + + #[cfg(not(target_family = "wasm"))] + const CONFIG_SKILL: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig { + name: "bond_of_life", + title: locale!( + zh_cn: "生命之契百分比", + en: "Bond of Life percentage" + ), + config: ItemConfigType::Float { min: 0.0, max: 5.0, default: 0.0 }, + } + ]); + + fn damage_internal(context: &DamageContext<'_, D::AttributeType>, s: usize, config: &CharacterSkillConfig, fumo: Option) -> D::Result { + let s: ClorindeDamageEnum = num::FromPrimitive::from_usize(s).unwrap(); + let (s1, s2, s3) = context.character_common_data.get_3_skill(); + + use ClorindeDamageEnum::*; + let ratio = match s { + Normal1 => CLORINDE_SKILL.normal_dmg1[s1], + Normal2 => CLORINDE_SKILL.normal_dmg2[s1], + Normal3 => CLORINDE_SKILL.normal_dmg3[s1], + Normal4 => CLORINDE_SKILL.normal_dmg4[s1], + Normal5 => CLORINDE_SKILL.normal_dmg5[s1], + Charged => CLORINDE_SKILL.charged_dmg[s1], + Plunging1 => CLORINDE_SKILL.plunging_dmg1[s1], + Plunging2 => CLORINDE_SKILL.plunging_dmg2[s1], + Plunging3 => CLORINDE_SKILL.plunging_dmg3[s1], + E11 => CLORINDE_SKILL.e_dmg11[s2], + E12 => CLORINDE_SKILL.e_dmg12[s2], + E21 => CLORINDE_SKILL.e_dmg21[s2], + E22 => CLORINDE_SKILL.e_dmg22[s2], + E23 => CLORINDE_SKILL.e_dmg23[s2], + E3 => CLORINDE_SKILL.e_dmg3[s2], + Q1 => CLORINDE_SKILL.q_dmg1[s3], + }; + let mut builder = D::new(); + builder.add_atk_ratio("技能倍率", ratio); + + let bond_of_life = match *config { + CharacterSkillConfig::Clorinde { bond_of_life } => bond_of_life, + _ => 0.0 + }; + + if s == Q1 && context.character_common_data.constellation >= 4 { + let bonus = (bond_of_life * 100.0).floor() * 0.02; + let bonus = bonus.min(2.0); + builder.add_extra_bonus("C4「铭记泪,生命与仁爱」", bonus); + } + + builder.damage( + &context.attribute, + &context.enemy, + s.get_element(), + s.get_skill_type(), + context.character_common_data.level, + fumo + ) + } + + fn new_effect(common_data: &CharacterCommonData, config: &CharacterConfig) -> Option>> { + match *config { + CharacterConfig::Clorinde { talent1_stack, talent2_stack, c6_rate } => { + Some(Box::new(ClorindeEffect { + talent1_stack, + talent2_stack, + c6_rate, + has_talent1: common_data.has_talent1, + has_talent2: common_data.has_talent2, + constellation: common_data.constellation as usize, + })) + }, + _ => None + } + } + + fn get_target_function_by_role(role_index: usize, team: &TeamQuantization, c: &CharacterCommonData, w: &WeaponCommonData) -> Box { + unimplemented!() + } +} diff --git a/mona_core/src/character/characters/electro/mod.rs b/mona_core/src/character/characters/electro/mod.rs index 96c75d96..b9f82511 100644 --- a/mona_core/src/character/characters/electro/mod.rs +++ b/mona_core/src/character/characters/electro/mod.rs @@ -9,6 +9,8 @@ pub mod yae_miko; pub mod cyno; pub mod fischl; pub mod dori; +pub mod clorinde; +pub mod sethos; pub use beidou::Beidou; pub use keqing::Keqing; @@ -21,3 +23,5 @@ pub use yae_miko::YaeMiko; pub use cyno::Cyno; pub use fischl::Fischl; pub use dori::Dori; +pub use clorinde::Clorinde; +pub use sethos::Sethos; diff --git a/mona_core/src/character/characters/electro/sethos.rs b/mona_core/src/character/characters/electro/sethos.rs new file mode 100644 index 00000000..4bff2a44 --- /dev/null +++ b/mona_core/src/character/characters/electro/sethos.rs @@ -0,0 +1,230 @@ +use crate::attribute::{Attribute, AttributeName, AttributeCommon}; +use crate::character::{CharacterConfig, CharacterName, CharacterStaticData}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::character_sub_stat::CharacterSubStatFamily; +use crate::character::macros::{damage_enum, damage_ratio, skill_map, skill_type}; +use crate::character::skill_config::CharacterSkillConfig; +use crate::character::traits::{CharacterSkillMap, CharacterSkillMapItem, CharacterTrait}; +use crate::common::{ChangeAttribute, Element, SkillType, StatName, WeaponType}; +use crate::common::i18n::{locale, hit_n_dmg, plunging_dmg, charged_dmg}; +use crate::common::item_config_type::{ItemConfig, ItemConfigType}; +use crate::damage::damage_builder::DamageBuilder; +use crate::damage::DamageContext; +use crate::target_functions::TargetFunction; +use crate::team::TeamQuantization; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct SethosSkillType { + pub normal_dmg1: [f64; 15], + pub normal_dmg21: [f64; 15], + pub normal_dmg22: [f64; 15], + pub normal_dmg3: [f64; 15], + pub charged_dmg1: [f64; 15], + pub charged_dmg2: [f64; 15], + pub charged_dmg31: [f64; 15], + pub charged_dmg32: [f64; 15], + pub plunging_dmg1: [f64; 15], + pub plunging_dmg2: [f64; 15], + pub plunging_dmg3: [f64; 15], + + pub e_dmg1: [f64; 15], + + pub q_dmg1: [f64; 15], +} + +pub const SETHOS_SKILL: SethosSkillType = SethosSkillType { + normal_dmg1: [0.5261, 0.569, 0.6118, 0.673, 0.7158, 0.7647, 0.832, 0.8993, 0.9666, 1.04, 1.1135, 1.1869, 1.2603, 1.3337, 1.4071], + normal_dmg21: [0.238, 0.2573, 0.2767, 0.3044, 0.3237, 0.3459, 0.3763, 0.4067, 0.4372, 0.4704, 0.5036, 0.5368, 0.57, 0.6032, 0.6364], + normal_dmg22: [0.2661, 0.2877, 0.3094, 0.3403, 0.362, 0.3868, 0.4208, 0.4548, 0.4889, 0.526, 0.5631, 0.6002, 0.6374, 0.6745, 0.7116], + normal_dmg3: [0.7399, 0.8001, 0.8603, 0.9463, 1.0066, 1.0754, 1.17, 1.2647, 1.3593, 1.4625, 1.5658, 1.669, 1.7722, 1.8755, 1.9787], + charged_dmg1: [0.4386, 0.4743, 0.51, 0.561, 0.5967, 0.6375, 0.6936, 0.7497, 0.8058, 0.867, 0.9282, 0.9894, 1.0506, 1.1118, 1.173], + charged_dmg2: [1.24, 1.333, 1.426, 1.55, 1.643, 1.736, 1.86, 1.984, 2.108, 2.232, 2.356, 2.48, 2.635, 2.79, 2.945], + charged_dmg31: [1.4, 1.505, 1.61, 1.75, 1.855, 1.96, 2.1, 2.24, 2.38, 2.52, 2.66, 2.8, 2.975, 3.15, 3.325], + charged_dmg32: [1.3456, 1.4465, 1.5474, 1.682, 1.7829, 1.8838, 2.0184, 2.153, 2.2875, 2.4221, 2.5566, 2.6912, 2.8594, 3.0276, 3.1958], + plunging_dmg1: [0.5683, 0.6145, 0.6608, 0.7269, 0.7731, 0.826, 0.8987, 0.9714, 1.0441, 1.1234, 1.2027, 1.282, 1.3612, 1.4405, 1.5198], + plunging_dmg2: [1.1363, 1.2288, 1.3213, 1.4535, 1.5459, 1.6517, 1.797, 1.9423, 2.0877, 2.2462, 2.4048, 2.5634, 2.7219, 2.8805, 3.039], + plunging_dmg3: [1.4193, 1.5349, 1.6504, 1.8154, 1.931, 2.063, 2.2445, 2.4261, 2.6076, 2.8057, 3.0037, 3.2018, 3.3998, 3.5979, 3.7959], + e_dmg1: [1.156, 1.2427, 1.3294, 1.445, 1.5317, 1.6184, 1.734, 1.8496, 1.9652, 2.0808, 2.1964, 2.312, 2.4565, 2.601, 2.7455], + q_dmg1: [1.9616, 2.1087, 2.2558, 2.452, 2.5991, 2.7462, 2.9424, 3.1386, 3.3347, 3.5309, 3.727, 3.9232, 4.1684, 4.4136, 4.6588], +}; + +damage_enum!( + SethosDamageEnum + Normal1 + Normal2 + Normal3 + Normal1Q + Normal2Q + Normal3Q + Charged1 + Charged2 + Charged3 + Plunging1 + Plunging2 + Plunging3 + E1 +); + +impl SethosDamageEnum { + pub fn get_skill_type(&self) -> SkillType { + use SethosDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 => SkillType::NormalAttack, + Charged1 | Charged2 | Charged3 | Normal1Q | Normal2Q | Normal3Q => SkillType::ChargedAttack, + Plunging1 => SkillType::PlungingAttackInAction, + Plunging2 | Plunging3 => SkillType::PlungingAttackOnGround, + E1 => SkillType::ElementalSkill, + } + } + + pub fn get_element(&self) -> Element { + use SethosDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 | Charged1 | Plunging1 | Plunging2 | Plunging3 => Element::Physical, + _ => Element::Electro, + } + } +} + +pub struct SethosEffect { + pub c2_stack: f64, +} + +impl ChangeAttribute for SethosEffect { + fn change_attribute(&self, attribute: &mut A) { + let bonus = self.c2_stack * 0.15; + attribute.set_value_by(AttributeName::BonusElectro, "C2「寂秘纸草经」", bonus); + } +} + +pub struct Sethos; + +impl CharacterTrait for Sethos { + const STATIC_DATA: CharacterStaticData = CharacterStaticData { + name: CharacterName::Sethos, + internal_name: "Sethos", + name_locale: locale!( + zh_cn: "赛索斯", + en: "Sethos" + ), + element: Element::Electro, + hp: [821, 2108, 2721, 4076, 4512, 5189, 5770, 6448, 6884, 7561, 7996, 8674, 9110, 9787], + atk: [19, 49, 63, 95, 105, 121, 134, 150, 160, 176, 186, 201, 212, 227], + def: [47, 121, 156, 233, 258, 297, 330, 369, 394, 432, 457, 496, 521, 560], + sub_stat: CharacterSubStatFamily::ElementalMastery96, + weapon_type: WeaponType::Bow, + star: 4, + skill_name1: locale!( + zh_cn: "普通攻击·王家苇箭术", + en: "Normal Attack: Royal Reed Archery" + ), + skill_name2: locale!( + zh_cn: "古仪·鸣砂掣雷", + en: "Ancient Rite: The Thundering Sands" + ), + skill_name3: locale!( + zh_cn: "秘仪·瞑光贯影", + en: "Secret Rite: Twilight Shadowpiercer" + ), + }; + type SkillType = SethosSkillType; + const SKILL: Self::SkillType = SETHOS_SKILL; + type DamageEnumType = SethosDamageEnum; + type RoleEnum = (); + + #[cfg(not(target_family = "wasm"))] + const SKILL_MAP: CharacterSkillMap = CharacterSkillMap { + skill1: skill_map!( + SethosDamageEnum + Normal1 hit_n_dmg!(1) + Normal2 hit_n_dmg!(2) + Normal3 hit_n_dmg!(3) + Charged1 locale!(zh_cn: "瞄准射击", en: "Aimed Shot") + Charged2 locale!(zh_cn: "一段蓄力瞄准射击", en: "Aimed Shot Charge Level 1") + Charged2 locale!(zh_cn: "贯影箭伤害", en: "Shadowpiercing Shot DMG") + Plunging1 plunging_dmg!(1) + Plunging2 plunging_dmg!(2) + Plunging3 plunging_dmg!(3) + ), + skill2: skill_map!( + SethosDamageEnum + E1 locale!(zh_cn: "技能伤害", en: "Skill DMG") + ), + skill3: skill_map!( + SethosDamageEnum + Normal1Q locale!(zh_cn: "瞑弦矢-1", en: "Dusk Bolt DMG-1") + Normal2Q locale!(zh_cn: "瞑弦矢-2", en: "Dusk Bolt DMG-2") + Normal3Q locale!(zh_cn: "瞑弦矢-3", en: "Dusk Bolt DMG-3") + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig { + name: "c2_stack", + title: locale!( + zh_cn: "C2「寂秘纸草经」比例", + en: "C2 Rate" + ), + config: ItemConfigType::Float { min: 0.0, max: 2.0, default: 0.0 } + } + ]); + + fn damage_internal(context: &DamageContext<'_, D::AttributeType>, s: usize, config: &CharacterSkillConfig, fumo: Option) -> D::Result { + let s: SethosDamageEnum = num::FromPrimitive::from_usize(s).unwrap(); + let (s1, s2, s3) = context.character_common_data.get_3_skill(); + + use SethosDamageEnum::*; + let atk_ratio = match s { + Normal1 | Normal1Q => SETHOS_SKILL.normal_dmg1[s1], + Normal2 | Normal2Q => SETHOS_SKILL.normal_dmg21[s1] + SETHOS_SKILL.normal_dmg22[s1], + Normal3 | Normal3Q => SETHOS_SKILL.normal_dmg3[s1], + Charged1 => SETHOS_SKILL.charged_dmg1[s1], + Charged2 => SETHOS_SKILL.charged_dmg2[s1], + Charged3 => SETHOS_SKILL.charged_dmg31[s1], + Plunging1 => SETHOS_SKILL.plunging_dmg1[s1], + Plunging2 => SETHOS_SKILL.plunging_dmg2[s1], + Plunging3 => SETHOS_SKILL.plunging_dmg3[s1], + E1 => SETHOS_SKILL.e_dmg1[s2], + }; + let mut em_ratio = match s { + Normal1Q | Normal2Q | Normal3Q => SETHOS_SKILL.q_dmg1[s3], + Charged3 => SETHOS_SKILL.charged_dmg32[s1], + _ => 0.0 + }; + + let mut builder = D::new(); + builder.add_atk_ratio("技能倍率", atk_ratio); + builder.add_em_ratio("技能倍率", em_ratio); + if context.character_common_data.has_talent2 && s == Charged3 { + builder.add_em_ratio("天赋「砂王的赐礼」", 7.0); + } + + builder.damage( + &context.attribute, + &context.enemy, + s.get_element(), + s.get_skill_type(), + context.character_common_data.level, + fumo + ) + } + + fn new_effect(common_data: &CharacterCommonData, config: &CharacterConfig) -> Option>> { + let c2_stack = match *config { + CharacterConfig::Sethos { c2_stack } => c2_stack, + _ => 0.0 + }; + if c2_stack > 0.0 && common_data.constellation >= 2 && common_data.has_talent1 { + Some(Box::new(SethosEffect { + c2_stack + })) + } else { + None + } + } + + fn get_target_function_by_role(role_index: usize, team: &TeamQuantization, c: &CharacterCommonData, w: &WeaponCommonData) -> Box { + unimplemented!() + } +} \ No newline at end of file diff --git a/mona_core/src/character/characters/hydro/mod.rs b/mona_core/src/character/characters/hydro/mod.rs index 982009d1..8441a9f0 100644 --- a/mona_core/src/character/characters/hydro/mod.rs +++ b/mona_core/src/character/characters/hydro/mod.rs @@ -9,6 +9,7 @@ pub mod nilou; pub mod candace; pub mod neuvillette; pub mod furina; +pub mod sigewinne; pub use barbara::Barbara; pub use mona::Mona; @@ -21,3 +22,4 @@ pub use nilou::Nilou; pub use candace::Candace; pub use neuvillette::Neuvillette; pub use furina::Furina; +pub use sigewinne::Sigewinne; diff --git a/mona_core/src/character/characters/hydro/sigewinne.rs b/mona_core/src/character/characters/hydro/sigewinne.rs new file mode 100644 index 00000000..f3675223 --- /dev/null +++ b/mona_core/src/character/characters/hydro/sigewinne.rs @@ -0,0 +1,292 @@ +use crate::attribute::{Attribute, AttributeName, AttributeCommon}; +use crate::character::{CharacterConfig, CharacterName, CharacterStaticData}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::character_sub_stat::CharacterSubStatFamily; +use crate::character::macros::{damage_enum, damage_ratio, skill_map, skill_type}; +use crate::character::skill_config::CharacterSkillConfig; +use crate::character::traits::{CharacterSkillMap, CharacterSkillMapItem, CharacterTrait}; +use crate::common::{ChangeAttribute, Element, SkillType, StatName, WeaponType}; +use crate::common::i18n::{locale, hit_n_dmg, plunging_dmg, charged_dmg}; +use crate::common::item_config_type::{ItemConfig, ItemConfigType}; +use crate::damage::damage_builder::DamageBuilder; +use crate::damage::DamageContext; +use crate::target_functions::TargetFunction; +use crate::team::TeamQuantization; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct SigewinneSkillType { + pub normal_dmg1: [f64; 15], + pub normal_dmg2: [f64; 15], + pub normal_dmg3: [f64; 15], + pub charged_dmg1: [f64; 15], + pub charged_dmg2: [f64; 15], + pub charged_dmg3: [f64; 15], + pub plunging_dmg1: [f64; 15], + pub plunging_dmg2: [f64; 15], + pub plunging_dmg3: [f64; 15], + + pub e_dmg1: [f64; 15], + pub e_heal1: [f64; 15], + pub e_heal1_fixed: [f64; 15], + pub e_heal2: f64, + pub e_dmg2: [f64; 15], + + pub q_dmg1: [f64; 15], +} + +pub const SIGEWINNE_SKILL: SigewinneSkillType = SigewinneSkillType { + normal_dmg1: [0.5261, 0.569, 0.6118, 0.673, 0.7158, 0.7647, 0.832, 0.8993, 0.9666, 1.04, 1.1135, 1.1869, 1.2603, 1.3337, 1.4071], + normal_dmg2: [0.5107, 0.5523, 0.5939, 0.6532, 0.6948, 0.7423, 0.8076, 0.873, 0.9383, 1.0095, 1.0808, 1.1521, 1.2233, 1.2946, 1.3659], + normal_dmg3: [0.7829, 0.8466, 0.9104, 1.0014, 1.0651, 1.138, 1.2381, 1.3382, 1.4384, 1.5476, 1.6569, 1.7661, 1.8753, 1.9846, 2.0938], + charged_dmg1: [0.4386, 0.4743, 0.51, 0.561, 0.5967, 0.6375, 0.6936, 0.7497, 0.8058, 0.867, 0.9282, 0.9894, 1.0506, 1.1118, 1.173], + charged_dmg2: [1.1408, 1.2264, 1.426, 1.55, 1.5116, 1.5971, 1.7112, 1.8253, 1.9394, 2.0534, 2.1675, 2.2816, 2.4242, 2.5668, 2.7094], + charged_dmg3: [0.2282, 0.2453, 0.2852, 0.31, 0.3023, 0.3194, 0.3422, 0.3651, 0.3879, 0.4107, 0.4335, 0.4563, 0.4848, 0.5134, 0.5419], + plunging_dmg1: [0.5683, 0.6145, 0.6608, 0.7269, 0.7731, 0.826, 0.8987, 0.9714, 1.0441, 1.1234, 1.2027, 1.282, 1.3612, 1.4405, 1.5198], + plunging_dmg2: [1.1363, 1.2288, 1.3213, 1.4535, 1.5459, 1.6517, 1.797, 1.9423, 2.0877, 2.2462, 2.4048, 2.5634, 2.7219, 2.8805, 3.039], + plunging_dmg3: [1.4193, 1.5349, 1.6504, 1.8154, 1.931, 2.063, 2.2445, 2.4261, 2.6076, 2.8057, 3.0037, 3.2018, 3.3998, 3.5979, 3.7959], + e_dmg1: [0.0228, 0.0245, 0.0262, 0.0285, 0.0302, 0.0319, 0.0342, 0.0365, 0.0388, 0.041, 0.0433, 0.0456, 0.0485, 0.0513, 0.0542], + e_heal1: [0.028, 0.0301, 0.0322, 0.035, 0.0371, 0.0392, 0.042, 0.0448, 0.0476, 0.0504, 0.0532, 0.056, 0.0595, 0.063, 0.0665], + e_heal1_fixed: [269.63, 296.6, 325.81, 357.27, 390.98, 426.94, 465.14, 505.59, 548.29, 593.23, 640.43, 689.87, 741.55, 795.49, 851.67], + e_heal2: 0.5, + e_dmg2: [0.0068, 0.0074, 0.0079, 0.0086, 0.0091, 0.0096, 0.0103, 0.0109, 0.0116, 0.0123, 0.013, 0.0137, 0.0145, 0.0154, 0.0162], + q_dmg1: [0.1177, 0.1265, 0.1354, 0.1471, 0.156, 0.1648, 0.1766, 0.1883, 0.2001, 0.2119, 0.2236, 0.2354, 0.2501, 0.2648, 0.2796], +}; + +damage_enum!( + SigewinneDamageEnum + Normal1 + Normal2 + Normal3 + Charged1 + Charged2 + Charged3 + Plunging1 + Plunging2 + Plunging3 + E1 + E12 + E13 + EHeal1 + EHeal12 + EHeal13 + EHeal2 + E2 + Q1 +); + +impl SigewinneDamageEnum { + pub fn get_skill_type(&self) -> SkillType { + use SigewinneDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 => SkillType::NormalAttack, + Charged1 | Charged2 | Charged3 => SkillType::ChargedAttack, + Plunging1 => SkillType::PlungingAttackInAction, + Plunging2 | Plunging3 => SkillType::PlungingAttackOnGround, + E1 | E12 | E13 | EHeal1 | EHeal12 | EHeal13 | EHeal2 | E2 => SkillType::ElementalSkill, + Q1 => SkillType::ElementalBurst + } + } + + pub fn get_element(&self) -> Element { + use SigewinneDamageEnum::*; + match *self { + Normal1 | Normal2 | Normal3 | Charged1 | Plunging1 | Plunging2 | Plunging3 => Element::Physical, + Charged2 | Charged3 | E1 | E12 | E13 | EHeal1 | EHeal12 | EHeal13 | EHeal2 | E2 | Q1 => Element::Hydro + } + } + + pub fn is_heal(&self) -> bool { + use SigewinneDamageEnum::*; + match *self { + EHeal1 | EHeal12 | EHeal13 | EHeal2 => true, + _ => false + } + } +} + +pub struct SigewinneEffect { + pub c6_rate: f64, + pub constellation: usize, +} + +impl ChangeAttribute for SigewinneEffect { + fn change_attribute(&self, attribute: &mut A) { + let r = self.c6_rate; + if self.constellation >= 6 { + attribute.add_edge1( + AttributeName::HP, + AttributeName::CriticalElementalBurst, + Box::new(move |hp, _| { + ((hp / 1000.0).floor() * 0.004).min(0.2) + }), + Box::new(|_x, _y, _grad| (0.0, 0.0)), + "C6「最光辉的精灵,可否为我祷告」" + ); + attribute.add_edge1( + AttributeName::HP, + AttributeName::CriticalDamageElementalBurst, + Box::new(move |hp, _| { + ((hp / 1000.0).floor() * 0.022).min(1.1) + }), + Box::new(|_x, _y, _grad| (0.0, 0.0)), + "C6「最光辉的精灵,可否为我祷告」" + ); + } + } +} + +pub struct Sigewinne; + +impl CharacterTrait for Sigewinne { + const STATIC_DATA: CharacterStaticData = CharacterStaticData { + name: CharacterName::Sigewinne, + internal_name: "Sigewinne", + name_locale: locale!( + zh_cn: "希格雯", + en: "Sigewinne" + ), + element: Element::Hydro, + hp: [1039, 2695, 3586, 5366, 5999, 6902, 7747, 8659, 9292, 10213, 10846, 11777, 12410, 13348], + atk: [15, 39, 52, 77, 87, 100, 112, 125, 134, 147, 156, 170, 179, 193], + def: [39, 101, 134, 201, 225, 258, 290, 324, 348, 382, 406, 441, 464, 500], + sub_stat: CharacterSubStatFamily::HP288, + weapon_type: WeaponType::Bow, + star: 5, + skill_name1: locale!( + zh_cn: "普通攻击·靶向治疗", + en: "Normal Attack: Targeted Treatment" + ), + skill_name2: locale!( + zh_cn: "弹跳水疗法", + en: "Rebound Hydrotherapy" + ), + skill_name3: locale!( + zh_cn: "过饱和心意注射", + en: "Super Saturated Syringing" + ), + }; + type SkillType = SigewinneSkillType; + const SKILL: Self::SkillType = SIGEWINNE_SKILL; + type DamageEnumType = SigewinneDamageEnum; + type RoleEnum = (); + + #[cfg(not(target_family = "wasm"))] + const SKILL_MAP: CharacterSkillMap = CharacterSkillMap { + skill1: skill_map!( + SigewinneDamageEnum + Normal1 hit_n_dmg!(1) + Normal2 hit_n_dmg!(2) + Normal3 hit_n_dmg!(3) + Charged1 locale!(zh_cn: "瞄准射击", en: "Aimed Shot") + Charged2 locale!(zh_cn: "满蓄力瞄准射击", en: "Fully-Charged Aimed Shot") + Charged3 locale!(zh_cn: "小小关心气泡伤害", en: "Mini-Stration Bubble DMG") + Plunging1 plunging_dmg!(1) + Plunging2 plunging_dmg!(2) + Plunging3 plunging_dmg!(3) + ), + skill2: skill_map!( + SigewinneDamageEnum + E1 locale!(zh_cn: "激愈水球伤害", en: "Bolstering Bubblebalm DMG") + E12 locale!(zh_cn: "激愈水球伤害-一级", en: "Bolstering Bubblebalm DMG-tier1") + E13 locale!(zh_cn: "激愈水球伤害-二级", en: "Bolstering Bubblebalm DMG-tier2") + EHeal1 locale!(zh_cn: "激愈水球治疗量", en: "Bolstering Bubblebalm Healing") + EHeal12 locale!(zh_cn: "激愈水球治疗量-一级", en: "Bolstering Bubblebalm Healing-tier1") + EHeal13 locale!(zh_cn: "激愈水球治疗量-二级", en: "Bolstering Bubblebalm Healing-tier2") + EHeal2 locale!(zh_cn: "弹跳结束治疗量", en: "Final Bounce Healing") + E2 locale!(zh_cn: "流涌之刃伤害", en: "Surging Blade DMG") + ), + skill3: skill_map!( + SigewinneDamageEnum + Q1 locale!(zh_cn: "技能伤害", en: "Skill DMG") + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig { + name: "c6_rate", + title: locale!( + zh_cn: "C6「最光辉的精灵,可否为我祷告」比例", + en: "C6 Rate", + ), + config: ItemConfigType::Float { min: 0.0, max: 1.0, default: 0.0 } + } + ]); + + fn damage_internal(context: &DamageContext<'_, D::AttributeType>, s: usize, config: &CharacterSkillConfig, fumo: Option) -> D::Result { + let s: SigewinneDamageEnum = num::FromPrimitive::from_usize(s).unwrap(); + let (s1, s2, s3) = context.character_common_data.get_3_skill(); + + use SigewinneDamageEnum::*; + let is_heal = s.is_heal(); + let mut builder = D::new(); + let skill_type = s.get_skill_type(); + if is_heal { + let ratio = match s { + EHeal1 => SIGEWINNE_SKILL.e_heal1[s2], + SigewinneDamageEnum::EHeal12 => SIGEWINNE_SKILL.e_heal1[s2] * 1.05, + EHeal13 => SIGEWINNE_SKILL.e_heal1[s2] * 1.1, + EHeal2 => SIGEWINNE_SKILL.e_heal2, + _ => 0.0 + }; + let fixed = match s { + EHeal1 => SIGEWINNE_SKILL.e_heal1_fixed[s2], + SigewinneDamageEnum::EHeal12 => SIGEWINNE_SKILL.e_heal1_fixed[s2] * 1.05, + EHeal13 => SIGEWINNE_SKILL.e_heal1_fixed[s2] * 1.1, + _ => 0.0 + }; + builder.add_hp_ratio("技能倍率", ratio); + if fixed > 0.0 { + builder.add_extra_damage("技能倍率", fixed); + } + builder.heal(&context.attribute) + } else { + let ratio = match s { + Normal1 => SIGEWINNE_SKILL.normal_dmg1[s1], + Normal2 => SIGEWINNE_SKILL.normal_dmg2[s1], + Normal3 => SIGEWINNE_SKILL.normal_dmg3[s1], + Charged1 => SIGEWINNE_SKILL.charged_dmg1[s1], + Charged2 => SIGEWINNE_SKILL.charged_dmg2[s1], + Charged3 => SIGEWINNE_SKILL.charged_dmg3[s1], + Plunging1 => SIGEWINNE_SKILL.plunging_dmg1[s1], + Plunging2 => SIGEWINNE_SKILL.plunging_dmg2[s1], + Plunging3 => SIGEWINNE_SKILL.plunging_dmg3[s1], + E1 => SIGEWINNE_SKILL.e_dmg1[s2], + E12 => SIGEWINNE_SKILL.e_dmg1[s2] * 1.05, + E13 => SIGEWINNE_SKILL.e_dmg1[s2] * 1.1, + E2 => SIGEWINNE_SKILL.e_dmg2[s2], + Q1 => SIGEWINNE_SKILL.q_dmg1[s3], + _ => 0.0 + }; + if skill_type == SkillType::NormalAttack { + builder.add_atk_ratio("技能倍率", ratio); + } else { + builder.add_hp_ratio("技能倍率", ratio); + } + builder.damage( + &context.attribute, + &context.enemy, + s.get_element(), + skill_type, + context.character_common_data.level, + fumo + ) + } + } + + fn new_effect(common_data: &CharacterCommonData, config: &CharacterConfig) -> Option>> { + match *config { + CharacterConfig::Sigewinne { c6_rate } => { + Some(Box::new(SigewinneEffect { + c6_rate, + constellation: common_data.constellation as usize, + })) + }, + _ => None + } + } + + fn get_target_function_by_role(role_index: usize, team: &TeamQuantization, c: &CharacterCommonData, w: &WeaponCommonData) -> Box { + unimplemented!() + } +} diff --git a/mona_core/src/character/skill_config.rs b/mona_core/src/character/skill_config.rs index 7bb5fea9..82a731cc 100644 --- a/mona_core/src/character/skill_config.rs +++ b/mona_core/src/character/skill_config.rs @@ -47,5 +47,6 @@ pub enum CharacterSkillConfig { Navia { shard_count: usize, strike11: bool, after_e: bool }, Gaming { pyro: bool }, Arlecchino { bond_of_life: f64 }, + Clorinde { bond_of_life: f64 }, NoConfig, } diff --git a/mona_core/src/target_functions/target_function_name.rs b/mona_core/src/target_functions/target_function_name.rs index 328a0a0f..3c1f8e61 100644 --- a/mona_core/src/target_functions/target_function_name.rs +++ b/mona_core/src/target_functions/target_function_name.rs @@ -98,4 +98,7 @@ pub enum TargetFunctionName { XianyunDefault, ChioriDefault, ArlecchinoDefault, + ClorindeDefault, + SigewinneDefault, + SethosDefault, } diff --git a/mona_core/src/target_functions/target_functions/electro/clorinde_default.rs b/mona_core/src/target_functions/target_functions/electro/clorinde_default.rs new file mode 100644 index 00000000..0638a419 --- /dev/null +++ b/mona_core/src/target_functions/target_functions/electro/clorinde_default.rs @@ -0,0 +1,68 @@ +use crate::artifacts::Artifact; +use crate::artifacts::effect_config::ArtifactEffectConfig; +use crate::attribute::SimpleAttributeGraph2; +use crate::character::{Character, CharacterName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::characters::Clorinde; +use crate::character::prelude::CharacterTrait; +use crate::character::skill_config::CharacterSkillConfig; +use crate::common::i18n::locale; +use crate::damage::{DamageContext, SimpleDamageBuilder}; +use crate::enemies::Enemy; +use crate::target_functions::target_function::TargetFunctionMetaTrait; +use crate::target_functions::target_function_meta::{TargetFunctionFor, TargetFunctionMeta, TargetFunctionMetaImage}; +use crate::target_functions::target_function_opt_config::TargetFunctionOptConfig; +use crate::target_functions::{TargetFunction, TargetFunctionConfig, TargetFunctionName}; +use crate::team::TeamQuantization; +use crate::weapon::Weapon; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct ClorindeDefaultTargetFunction; + +impl TargetFunction for ClorindeDefaultTargetFunction { + fn get_target_function_opt_config(&self) -> TargetFunctionOptConfig { + unimplemented!() + } + + fn get_default_artifact_config(&self, team_config: &TeamQuantization) -> ArtifactEffectConfig { + Default::default() + } + + fn target(&self, attribute: &SimpleAttributeGraph2, character: &Character, weapon: &Weapon, artifacts: &[&Artifact], enemy: &Enemy) -> f64 { + let context: DamageContext<'_, SimpleAttributeGraph2> = DamageContext { + character_common_data: &character.common_data, + attribute, + enemy + }; + + type S = ::DamageEnumType; + let skill_config = CharacterSkillConfig::Clorinde { bond_of_life: 1.0 }; + let dmg_e = Clorinde::damage::( + &context, S::E11, &skill_config, None + ); + + dmg_e.normal.expectation + } +} + +impl TargetFunctionMetaTrait for ClorindeDefaultTargetFunction { + #[cfg(not(target_family = "wasm"))] + const META_DATA: TargetFunctionMeta = TargetFunctionMeta { + name: TargetFunctionName::ClorindeDefault, + name_locale: locale!( + zh_cn: "克洛琳德-「秉烛狝影」", + en: "Clorinde-Candlebearer, Shadowhunter" + ), + description: locale!( + zh_cn: "最大化驰猎伤害", + en: "Maximize Swift Hunt DMG" + ), + tags: "", + four: TargetFunctionFor::SomeWho(CharacterName::Clorinde), + image: TargetFunctionMetaImage::Avatar, + }; + + fn create(character: &CharacterCommonData, weapon: &WeaponCommonData, config: &TargetFunctionConfig) -> Box { + Box::new(ClorindeDefaultTargetFunction) + } +} diff --git a/mona_core/src/target_functions/target_functions/electro/mod.rs b/mona_core/src/target_functions/target_functions/electro/mod.rs index 4aa3f877..4ac9884f 100644 --- a/mona_core/src/target_functions/target_functions/electro/mod.rs +++ b/mona_core/src/target_functions/target_functions/electro/mod.rs @@ -9,6 +9,8 @@ pub mod razor_default; pub mod yae_miko_default; pub mod kuki_shinobu_default; pub mod cyno_default; +pub mod clorinde_default; +pub mod sethos_default; pub use beidou_default::BeidouDefaultTargetFunction; pub use fischl_default::FischlDefaultTargetFunction; @@ -21,3 +23,5 @@ pub use razor_default::RazorDefaultTargetFunction; pub use yae_miko_default::YaeMikoDefaultTargetFunction; pub use kuki_shinobu_default::KukiShinobuDefaultTargetFunction; pub use cyno_default::CynoDefaultTargetFunction; +pub use clorinde_default::ClorindeDefaultTargetFunction; +pub use sethos_default::SethosDefaultTargetFunction; diff --git a/mona_core/src/target_functions/target_functions/electro/sethos_default.rs b/mona_core/src/target_functions/target_functions/electro/sethos_default.rs new file mode 100644 index 00000000..22052847 --- /dev/null +++ b/mona_core/src/target_functions/target_functions/electro/sethos_default.rs @@ -0,0 +1,70 @@ +use crate::artifacts::Artifact; +use crate::artifacts::effect_config::ArtifactEffectConfig; +use crate::attribute::SimpleAttributeGraph2; +use crate::character::{Character, CharacterName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::characters::Sethos; +use crate::character::skill_config::CharacterSkillConfig; +use crate::character::traits::CharacterTrait; +use crate::common::i18n::locale; +use crate::damage::{DamageContext, SimpleDamageBuilder}; +use crate::enemies::Enemy; +use crate::target_functions::target_function::TargetFunctionMetaTrait; +use crate::target_functions::target_function_meta::{TargetFunctionFor, TargetFunctionMeta, TargetFunctionMetaImage}; +use crate::target_functions::target_function_opt_config::TargetFunctionOptConfig; +use crate::target_functions::{TargetFunction, TargetFunctionConfig, TargetFunctionName}; +use crate::team::TeamQuantization; +use crate::weapon::Weapon; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct SethosDefaultTargetFunction; + +impl TargetFunction for SethosDefaultTargetFunction { + fn get_target_function_opt_config(&self) -> TargetFunctionOptConfig { + unimplemented!() + } + + fn get_default_artifact_config(&self, team_config: &TeamQuantization) -> ArtifactEffectConfig { + Default::default() + } + + fn target(&self, attribute: &SimpleAttributeGraph2, character: &Character, weapon: &Weapon, artifacts: &[&Artifact], enemy: &Enemy) -> f64 { + let context: DamageContext<'_, SimpleAttributeGraph2> = DamageContext { + character_common_data: &character.common_data, + attribute, + enemy + }; + + type S = ::DamageEnumType; + let damage = Sethos::damage::( + &context, + S::Charged3, + &CharacterSkillConfig::NoConfig, + None + ); + + damage.normal.expectation + } +} + +impl TargetFunctionMetaTrait for SethosDefaultTargetFunction { + #[cfg(not(target_family = "wasm"))] + const META_DATA: TargetFunctionMeta = TargetFunctionMeta { + name: TargetFunctionName::SethosDefault, + name_locale: locale!( + zh_cn: "赛索斯-「衡明知度」", + en: "Sethos-Wisdom's Measure" + ), + description: locale!( + zh_cn: "最大化贯影箭伤害", + en: "Maximize Shadowpiercing Shot DMG" + ), + tags: "", + four: TargetFunctionFor::SomeWho(CharacterName::Sethos), + image: TargetFunctionMetaImage::Avatar, + }; + + fn create(character: &CharacterCommonData, weapon: &WeaponCommonData, config: &TargetFunctionConfig) -> Box { + Box::new(SethosDefaultTargetFunction) + } +} diff --git a/mona_core/src/target_functions/target_functions/hydro/mod.rs b/mona_core/src/target_functions/target_functions/hydro/mod.rs index 0e7e55af..fa7dbe4e 100644 --- a/mona_core/src/target_functions/target_functions/hydro/mod.rs +++ b/mona_core/src/target_functions/target_functions/hydro/mod.rs @@ -8,6 +8,7 @@ pub mod yelan_default; pub mod nilou_default; pub mod neuvillette_default; pub mod furina_default; +pub mod sigewinne_default; pub use barbara_default::BarbaraDefaultTargetFunction; pub use mona_default::MonaDefaultTargetFunction; @@ -19,3 +20,4 @@ pub use yelan_default::YelanDefaultTargetFunction; pub use nilou_default::NilouDefaultTargetFunction; pub use neuvillette_default::NeuvilletteDefaultTargetFunction; pub use furina_default::FurinaDefaultTargetFunction; +pub use sigewinne_default::SigewinneDefaultTargetFunction; diff --git a/mona_core/src/target_functions/target_functions/hydro/sigewinne_default.rs b/mona_core/src/target_functions/target_functions/hydro/sigewinne_default.rs new file mode 100644 index 00000000..bb56851c --- /dev/null +++ b/mona_core/src/target_functions/target_functions/hydro/sigewinne_default.rs @@ -0,0 +1,70 @@ +use crate::artifacts::Artifact; +use crate::artifacts::effect_config::ArtifactEffectConfig; +use crate::attribute::SimpleAttributeGraph2; +use crate::character::{Character, CharacterName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::character::characters::Sigewinne; +use crate::character::prelude::CharacterTrait; +use crate::character::skill_config::CharacterSkillConfig; +use crate::common::i18n::locale; +use crate::damage::{DamageContext, SimpleDamageBuilder}; +use crate::enemies::Enemy; +use crate::target_functions::target_function::TargetFunctionMetaTrait; +use crate::target_functions::target_function_meta::{TargetFunctionFor, TargetFunctionMeta, TargetFunctionMetaImage}; +use crate::target_functions::target_function_opt_config::TargetFunctionOptConfig; +use crate::target_functions::{TargetFunction, TargetFunctionConfig, TargetFunctionName}; +use crate::team::TeamQuantization; +use crate::weapon::Weapon; +use crate::weapon::weapon_common_data::WeaponCommonData; + +pub struct SigewinneDefaultTargetFunction; + +impl TargetFunction for SigewinneDefaultTargetFunction { + fn get_target_function_opt_config(&self) -> TargetFunctionOptConfig { + unimplemented!() + } + + fn get_default_artifact_config(&self, team_config: &TeamQuantization) -> ArtifactEffectConfig { + Default::default() + } + + fn target(&self, attribute: &SimpleAttributeGraph2, character: &Character, weapon: &Weapon, artifacts: &[&Artifact], enemy: &Enemy) -> f64 { + let context: DamageContext<'_, SimpleAttributeGraph2> = DamageContext { + character_common_data: &character.common_data, + attribute, + enemy + }; + + type S = ::DamageEnumType; + let damage = Sigewinne::damage::( + &context, + S::Q1, + &CharacterSkillConfig::NoConfig, + None + ); + + damage.normal.expectation + } +} + +impl TargetFunctionMetaTrait for SigewinneDefaultTargetFunction { + #[cfg(not(target_family = "wasm"))] + const META_DATA: TargetFunctionMeta = TargetFunctionMeta { + name: TargetFunctionName::SigewinneDefault, + name_locale: locale!( + zh_cn: "希格雯-「龙女妙变」", + en: "Sigewinne-Wondrous Dragonheir" + ), + description: locale!( + zh_cn: "最大化Q伤害", + en: "Maximize Q DMG" + ), + tags: "", + four: TargetFunctionFor::SomeWho(CharacterName::Sigewinne), + image: TargetFunctionMetaImage::Avatar, + }; + + fn create(character: &CharacterCommonData, weapon: &WeaponCommonData, config: &TargetFunctionConfig) -> Box { + Box::new(SigewinneDefaultTargetFunction) + } +} diff --git a/mona_core/src/weapon/weapon_config.rs b/mona_core/src/weapon/weapon_config.rs index 18329b03..3fc327df 100644 --- a/mona_core/src/weapon/weapon_config.rs +++ b/mona_core/src/weapon/weapon_config.rs @@ -31,6 +31,7 @@ pub enum WeaponConfig { TheDockhandsAssistant { stack: f64 }, SplendorOfTranquilWaters { stack1: f64, stack2: f64 }, UrakuMisugiri { rate: f64 }, + Absolution { stack: f64 }, // claymore WolfsGravestone { rate: f64 }, @@ -128,6 +129,8 @@ pub enum WeaponConfig { ScionOfTheBlazingSun { rate: f64 }, SongOfStillness { rate: f64 }, RangeGauge { stack: f64 }, + Cloudforged { stack: f64 }, + SilvershowerHeartstrings { stack: f64, stack3_rate: f64 }, } impl Default for WeaponConfig { diff --git a/mona_core/src/weapon/weapon_name.rs b/mona_core/src/weapon/weapon_name.rs index 51c71afa..cd0104a7 100644 --- a/mona_core/src/weapon/weapon_name.rs +++ b/mona_core/src/weapon/weapon_name.rs @@ -55,6 +55,7 @@ pub enum WeaponName { SwordOfNarzissenkreuz, SplendorOfTranquilWaters, UrakuMisugiri, + Absolution, // claymore WolfsGravestone, @@ -203,4 +204,6 @@ pub enum WeaponName { ScionOfTheBlazingSun, SongOfStillness, RangeGauge, + Cloudforged, + SilvershowerHeartstrings, } diff --git a/mona_core/src/weapon/weapons/bows/cloudforged.rs b/mona_core/src/weapon/weapons/bows/cloudforged.rs new file mode 100644 index 00000000..817f7342 --- /dev/null +++ b/mona_core/src/weapon/weapons/bows/cloudforged.rs @@ -0,0 +1,59 @@ +use crate::attribute::{Attribute, AttributeName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::common::i18n::locale; +use crate::common::item_config_type::ItemConfig; +use crate::common::WeaponType; +use crate::weapon::weapon_common_data::WeaponCommonData; +use crate::weapon::weapon_effect::WeaponEffect; +use crate::weapon::weapon_static_data::WeaponStaticData; +use crate::weapon::weapon_trait::WeaponTrait; +use crate::weapon::{WeaponConfig, WeaponName}; +use crate::weapon::weapon_base_atk::WeaponBaseATKFamily; +use crate::weapon::weapon_sub_stat::WeaponSubStatFamily; + +pub struct CloudforgedEffect { + pub stack: f64, +} + +impl WeaponEffect for CloudforgedEffect { + fn apply(&self, data: &WeaponCommonData, attribute: &mut A) { + let refine = data.refine as f64; + attribute.set_value_by(AttributeName::ElementalMastery, "筑云被动", 30.0 + refine * 10.0); + } +} + +pub struct Cloudforged; + +impl WeaponTrait for Cloudforged { + const META_DATA: WeaponStaticData = WeaponStaticData { + name: WeaponName::Cloudforged, + internal_name: "Cloudforged", + weapon_type: WeaponType::Bow, + weapon_sub_stat: Some(WeaponSubStatFamily::EM36), + weapon_base: WeaponBaseATKFamily::ATK510, + star: 4, + #[cfg(not(target_family = "wasm"))] + effect: Some(locale!( + zh_cn: "元素能量减少后,装备者的元素精通提升40-50-60-70-80点。该效果持续18秒,至多叠加2层。", + en: "After Elemental Energy is decreased, the equipping character's Elemental Mastery will increase by 40-50-60-70-80 for 18s. Max 2 stacks." + )), + #[cfg(not(target_family = "wasm"))] + name_locale: locale!( + zh_cn: "筑云", + en: "Cloudforged", + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig::STACK02 + ]); + + fn get_effect(character: &CharacterCommonData, config: &WeaponConfig) -> Option>> { + let stack = match *config { + WeaponConfig::Cloudforged { stack } => stack, + _ => 0.0 + }; + Some(Box::new(CloudforgedEffect { stack })) + } +} diff --git a/mona_core/src/weapon/weapons/bows/mod.rs b/mona_core/src/weapon/weapons/bows/mod.rs index aa686079..05965acf 100644 --- a/mona_core/src/weapon/weapons/bows/mod.rs +++ b/mona_core/src/weapon/weapons/bows/mod.rs @@ -35,6 +35,8 @@ pub use the_first_great_magic::TheFirstGreatMagic; pub use scion_of_the_blazing_sun::ScionOfTheBlazingSun; pub use song_of_stillness::SongOfStillness; pub use range_gauge::RangeGauge; +pub use cloudforged::Cloudforged; +pub use silvershower_heartstrings::SilvershowerHeartstrings; pub mod polar_star; pub mod thundering_pulse; @@ -73,3 +75,5 @@ pub mod the_first_great_magic; pub mod scion_of_the_blazing_sun; pub mod song_of_stillness; pub mod range_gauge; +pub mod cloudforged; +pub mod silvershower_heartstrings; diff --git a/mona_core/src/weapon/weapons/bows/silvershower_heartstrings.rs b/mona_core/src/weapon/weapons/bows/silvershower_heartstrings.rs new file mode 100644 index 00000000..518424d6 --- /dev/null +++ b/mona_core/src/weapon/weapons/bows/silvershower_heartstrings.rs @@ -0,0 +1,91 @@ +use crate::attribute::{Attribute, AttributeCommon, AttributeName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::common::i18n::locale; +use crate::common::item_config_type::{ItemConfig, ItemConfigType}; +use crate::common::WeaponType; +use crate::weapon::weapon_common_data::WeaponCommonData; +use crate::weapon::weapon_effect::WeaponEffect; +use crate::weapon::weapon_static_data::WeaponStaticData; +use crate::weapon::weapon_trait::WeaponTrait; +use crate::weapon::{WeaponConfig, WeaponName}; +use crate::weapon::weapon_base_atk::WeaponBaseATKFamily; +use crate::weapon::weapon_sub_stat::WeaponSubStatFamily; + +pub struct SilvershowerHeartstringsEffect { + pub stack3_rate: f64, + pub stack: f64, +} + +impl WeaponEffect for SilvershowerHeartstringsEffect { + fn apply(&self, data: &WeaponCommonData, attribute: &mut A) { + let refine = data.refine as f64; + let stack1 = 0.09 + refine * 0.03; + let stack2 = 0.18 + refine * 0.06; + let stack3 = 0.3 + refine * 0.1; + + let value = if self.stack < 1.0 { + self.stack * stack1 + } else if self.stack < 2.0 { + stack1 + (stack2 - stack1) * (self.stack - 1.0) + } else { + stack2 + (stack3 - stack2) * (self.stack - 2.0) + }; + attribute.add_hp_percentage("白雨心弦被动", value); + + attribute.set_value_by(AttributeName::CriticalElementalBurst, "白雨心弦被动", 0.21 + refine * 0.07); + } +} + +pub struct SilvershowerHeartstrings; + +impl WeaponTrait for SilvershowerHeartstrings { + const META_DATA: WeaponStaticData = WeaponStaticData { + name: WeaponName::SilvershowerHeartstrings, + internal_name: "SilvershowerHeartstrings", + weapon_type: WeaponType::Bow, + weapon_sub_stat: Some(WeaponSubStatFamily::HP144), + weapon_base: WeaponBaseATKFamily::ATK542, + star: 5, + #[cfg(not(target_family = "wasm"))] + effect: Some(locale!( + zh_cn: "装备者能获得「疗护」效果,持有1/2/3层疗护时,生命值上限提升12%-15%-18%-21%-24%/24%-30%-36%-42%-48%/40%-50%-60%-70%-80%。在下列情况下,装备者将各获得1层疗护:施放元素战技时,持续25秒;生命之契的数值增加时,持续25秒;进行治疗时,持续20秒,装备者处于队伍后台时依然能触发。每层疗护的持续时间独立计算。此外,处于3层疗护状态下时,元素爆发的暴击率提升28%-35%-42%-49%-56%,该效果将在疗护不足3层4秒后移除。", + en: "The equipping character can gain the Remedy effect. When they possess 1/2/3 Remedy stacks, Max HP will increase by 12%-15%-18%-21%-24%/24%-30%-36%-42%-48%/40%-50%-60%-70%-80%. 1 stack may be gained when the following conditions are met: 1 stack for 25s when using an Elemental Skill; 1 stack for 25s when the value of a Bond of Life value increased; 1 stack for 20s for performing healing. Stacks can still be triggered when the equipping character is not on the field. Each stack's duration is counted independently. In addition, when 3 stacks are active, Elemental Burst CRIT Rate will be increased by 28%-35%-42%-49%-56%. This effect will be canceled 4s after falling under 3 stacks." + )), + #[cfg(not(target_family = "wasm"))] + name_locale: locale!( + zh_cn: "白雨心弦", + en: "Silvershower Heartstrings", + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig { + name: "stack", + title: ItemConfig::DEFAULT_STACK_TITLE, + config: ItemConfigType::Float { min: 0.0, max: 3.0, default: 3.0 }, + }, + ItemConfig { + name: "stack3_rate", + title: locale!( + zh_cn: "3层效果比例", + en: "Stack-3 Portion" + ), + config: ItemConfigType::Float { min: 0.0, max: 1.0, default: 1.0 }, + } + ]); + + fn get_effect(character: &CharacterCommonData, config: &WeaponConfig) -> Option>> { + let (stack, stack3_rate) = match *config { + WeaponConfig::SilvershowerHeartstrings { stack, stack3_rate } => (stack, stack3_rate), + _ => (0.0, 0.0) + }; + if stack > 0.0 && stack3_rate > 0.0 { + Some(Box::new(SilvershowerHeartstringsEffect { + stack, stack3_rate + })) + } else { + None + } + } +} diff --git a/mona_core/src/weapon/weapons/swords/absolution.rs b/mona_core/src/weapon/weapons/swords/absolution.rs new file mode 100644 index 00000000..69045f97 --- /dev/null +++ b/mona_core/src/weapon/weapons/swords/absolution.rs @@ -0,0 +1,62 @@ +use crate::attribute::{Attribute, AttributeName}; +use crate::character::character_common_data::CharacterCommonData; +use crate::common::i18n::locale; +use crate::common::item_config_type::ItemConfig; +use crate::common::WeaponType; +use crate::weapon::weapon_common_data::WeaponCommonData; +use crate::weapon::weapon_effect::WeaponEffect; +use crate::weapon::weapon_static_data::WeaponStaticData; +use crate::weapon::weapon_trait::WeaponTrait; +use crate::weapon::{WeaponConfig, WeaponName}; +use crate::weapon::weapon_base_atk::WeaponBaseATKFamily; +use crate::weapon::weapon_sub_stat::WeaponSubStatFamily; + +pub struct AbsolutionEffect { + pub stack: f64, +} + +impl WeaponEffect for AbsolutionEffect { + fn apply(&self, data: &WeaponCommonData, attribute: &mut A) { + let refine = data.refine as f64; + attribute.set_value_by(AttributeName::CriticalDamageBase, "赦罪被动", 0.15 + refine * 0.05); + attribute.set_value_by(AttributeName::BonusBase, "赦罪被动", self.stack * (0.12 + 0.04 * refine)); + } +} + +pub struct Absolution; + +impl WeaponTrait for Absolution { + const META_DATA: WeaponStaticData = WeaponStaticData { + name: WeaponName::Absolution, + internal_name: "Absolution", + weapon_type: WeaponType::Sword, + weapon_sub_stat: Some(WeaponSubStatFamily::CriticalDamage96), + weapon_base: WeaponBaseATKFamily::ATK674, + star: 5, + #[cfg(not(target_family = "wasm"))] + effect: Some(locale!( + zh_cn: "暴击伤害提升20%-25%-30%-35%-40%;生命之契的数值增加时,装备者造成的伤害提升16%-20%-24%-28%-32%。该效果持续6秒,至多叠加3次。", + en: "CRIT DMG increased by 20%-25%-30%-35%-40%. Increasing the value of a Bond of Life increases the DMG the equipping character deals by 16%-20%-24%-28%-32% for 6s. Max 3 stacks." + )), + #[cfg(not(target_family = "wasm"))] + name_locale: locale!( + zh_cn: "赦罪", + en: "Absolution" + ), + }; + + #[cfg(not(target_family = "wasm"))] + const CONFIG_DATA: Option<&'static [ItemConfig]> = Some(&[ + ItemConfig::STACK03 + ]); + + fn get_effect(character: &CharacterCommonData, config: &WeaponConfig) -> Option>> { + let stack = match *config { + WeaponConfig::Absolution { stack } => stack, + _ => 0.0 + }; + Some(Box::new(AbsolutionEffect { + stack + })) + } +} diff --git a/mona_core/src/weapon/weapons/swords/mod.rs b/mona_core/src/weapon/weapons/swords/mod.rs index 8cc55333..d41fe066 100644 --- a/mona_core/src/weapon/weapons/swords/mod.rs +++ b/mona_core/src/weapon/weapons/swords/mod.rs @@ -40,6 +40,7 @@ pub use the_dockhands_assistant::TheDockhandsAssistant; pub use sword_of_narzissenkreuz::SwordOfNarzissenkreuz; pub use splendor_of_tranquil_waters::SplendorOfTranquilWaters; pub use uraku_misugiri::UrakuMisugiri; +pub use absolution::Absolution; pub mod mistsplitter_reforged; pub mod aquila_favonia; @@ -83,3 +84,4 @@ pub mod the_dockhands_assistant; pub mod sword_of_narzissenkreuz; pub mod splendor_of_tranquil_waters; pub mod uraku_misugiri; +pub mod absolution; diff --git a/package.json b/package.json index 60183ee5..48ed5dc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "genshin_artifacts", - "version": "5.23.0", + "version": "5.24.0", "private": true, "scripts": { "serve": "cross-env ENV_FILE=.env.development.yaml vue-cli-service serve", diff --git a/src/images/characters/Clorinde_splash.png b/src/images/characters/Clorinde_splash.png new file mode 100644 index 00000000..26048ddc Binary files /dev/null and b/src/images/characters/Clorinde_splash.png differ diff --git a/src/images/characters/Sethos_splash.png b/src/images/characters/Sethos_splash.png new file mode 100644 index 00000000..4a31bfcd Binary files /dev/null and b/src/images/characters/Sethos_splash.png differ diff --git a/src/images/characters/Sigewinne_splash.png b/src/images/characters/Sigewinne_splash.png new file mode 100644 index 00000000..6c4b31a4 Binary files /dev/null and b/src/images/characters/Sigewinne_splash.png differ