use crate::cat::unit::{Battle, TalentGroup};
use crate::common::data::img015;
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum AttrUnit {
None,
Percent,
Frames,
Range,
}
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum Identity {
SingleAttack, AreaAttack, TargetRed, TargetFloat, TargetDark, TargetMetal, TargetAngel,
TargetAlien, TargetZombie, TargetRelic, TargetAku, TargetTraitless, TargetWitch, TargetEva,
AttackOnly, StrongAgainst, MassiveDamage, InsaneDamage, Resist, InsanelyTough, Metal,
BaseDestroyer, DoubleBounty, ZombieKiller, Soulstrike, ColossusSlayer, SageSlayer,
BehemothSlayer, WitchKiller, EvaKiller, WaveBlock, CounterSurge, Kamikaze, Stop, MultiHit,
LongDistance, OmniStrike, Conjure, MetalKiller, WaveAttack, MiniWave, SurgeAttack,
MiniSurge, Explosion, SavageBlow, CriticalHit, Strengthen, Survive, BarrierBreaker,
ShieldPiercer, Dodge, Weaken, Freeze, Slow, Knockback, Curse, Warp, Unknown,
ImmuneWave, ImmuneSurge, ImmuneExplosion, ImmuneWeaken, ImmuneFreeze, ImmuneSlow,
ImmuneKnockback, ImmuneCurse, ImmuneToxic, ImmuneWarp, ImmuneBossWave, ResistWeaken,
ResistFreeze, ResistSlow, ResistKnockback, ResistWave, ResistWarp, ResistCurse,
ResistToxic, ResistSurge, CostDown, RecoverSpeedUp, MoveSpeedUp, AttackBuff,
HealthBuff, TbaDown, ImproveKnockbacks
}
pub struct Ability {
pub identity: Identity,
pub talent_id: u8,
pub icon_id: Option<usize>,
pub name: &'static str,
pub description: &'static str,
pub schema: &'static [(&'static str, AttrUnit)],
pub attributes: fn(&Battle) -> Vec<(&'static str, i32, AttrUnit)>,
pub apply_talent: Option<fn(&mut Battle, val1: i32, val2: i32, group: &TalentGroup)>,
}
fn get_dur_val(v1: i32, v2: i32) -> i32 {
if v1 != 0 { v1 } else { v2 }
}
pub fn get_talent(id: u8) -> Option<&'static Ability> {
REGISTRY.iter().find(|ability| ability.talent_id == id)
}
pub static REGISTRY: &[Ability] = &[
Ability {
identity: Identity::SingleAttack,
talent_id: 0,
icon_id: Some(img015::ICON_SINGLE_ATTACK),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.area_attack == 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::AreaAttack,
talent_id: 0,
icon_id: Some(img015::ICON_AREA_ATTACK),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.area_attack == 1 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::TargetRed,
talent_id: 33,
icon_id: Some(img015::ICON_TRAIT_RED),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_red > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_red = 1),
},
Ability {
identity: Identity::TargetFloat,
talent_id: 34,
icon_id: Some(img015::ICON_TRAIT_FLOATING),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_floating > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_floating = 1),
},
Ability {
identity: Identity::TargetDark,
talent_id: 35,
icon_id: Some(img015::ICON_TRAIT_BLACK),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_dark > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_dark = 1),
},
Ability {
identity: Identity::TargetMetal,
talent_id: 36,
icon_id: Some(img015::ICON_TRAIT_METAL),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_metal > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_metal = 1),
},
Ability {
identity: Identity::TargetAngel,
talent_id: 37,
icon_id: Some(img015::ICON_TRAIT_ANGEL),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_angel > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_angel = 1),
},
Ability {
identity: Identity::TargetAlien,
talent_id: 38,
icon_id: Some(img015::ICON_TRAIT_ALIEN),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_alien > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_alien = 1),
},
Ability {
identity: Identity::TargetZombie,
talent_id: 39,
icon_id: Some(img015::ICON_TRAIT_ZOMBIE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_zombie > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_zombie = 1),
},
Ability {
identity: Identity::TargetRelic,
talent_id: 40,
icon_id: Some(img015::ICON_TRAIT_RELIC),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_relic > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_relic = 1),
},
Ability {
identity: Identity::TargetAku,
talent_id: 57,
icon_id: Some(img015::ICON_TRAIT_AKU),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_aku > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_aku = 1),
},
Ability {
identity: Identity::TargetTraitless,
talent_id: 41,
icon_id: Some(img015::ICON_TRAIT_TRAITLESS),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_traitless > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_traitless = 1),
},
Ability {
identity: Identity::TargetWitch,
talent_id: 0,
icon_id: Some(img015::ICON_WITCH),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_witch > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_witch = 1),
},
Ability {
identity: Identity::TargetEva,
talent_id: 0,
icon_id: Some(img015::ICON_EVA),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.target_eva > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.target_eva = 1),
},
Ability {
identity: Identity::AttackOnly,
talent_id: 4,
icon_id: Some(img015::ICON_ATTACK_ONLY),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.attack_only > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.attack_only = 1),
},
Ability {
identity: Identity::StrongAgainst,
talent_id: 5,
icon_id: Some(img015::ICON_STRONG_AGAINST),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.strong_against > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.strong_against = 1),
},
Ability {
identity: Identity::MassiveDamage,
talent_id: 7,
icon_id: Some(img015::ICON_MASSIVE_DAMAGE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.massive_damage > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.massive_damage = 1),
},
Ability {
identity: Identity::InsaneDamage,
talent_id: 7,
icon_id: Some(img015::ICON_INSANE_DAMAGE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.insane_damage > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::Resist,
talent_id: 6,
icon_id: Some(img015::ICON_RESIST),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.resist > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.resist = 1),
},
Ability {
identity: Identity::InsanelyTough,
talent_id: 6,
icon_id: Some(img015::ICON_INSANELY_TOUGH),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.insanely_tough > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::Metal,
talent_id: 43,
icon_id: Some(img015::ICON_METAL),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.metal > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.metal = 1),
},
Ability {
identity: Identity::BaseDestroyer,
talent_id: 12,
icon_id: Some(img015::ICON_BASE_DESTROYER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.base_destroyer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.base_destroyer = 1),
},
Ability {
identity: Identity::DoubleBounty,
talent_id: 16,
icon_id: Some(img015::ICON_DOUBLE_BOUNTY),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.double_bounty > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.double_bounty = 1),
},
Ability {
identity: Identity::ZombieKiller,
talent_id: 14,
icon_id: Some(img015::ICON_ZOMBIE_KILLER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.zombie_killer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.zombie_killer = 1),
},
Ability {
identity: Identity::Soulstrike,
talent_id: 59,
icon_id: Some(img015::ICON_SOULSTRIKE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.soulstrike == 2 || (stats.soulstrike > 0 && stats.zombie_killer > 0) { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.soulstrike = 2),
},
Ability {
identity: Identity::ColossusSlayer,
talent_id: 63,
icon_id: Some(img015::ICON_COLOSSUS_SLAYER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.colossus_slayer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.colossus_slayer = 1),
},
Ability {
identity: Identity::SageSlayer,
talent_id: 66,
icon_id: Some(img015::ICON_SAGE_SLAYER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.sage_slayer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.sage_slayer = 1),
},
Ability {
identity: Identity::BehemothSlayer,
talent_id: 64,
icon_id: Some(img015::ICON_BEHEMOTH_SLAYER),
name: "",
description: "",
schema: &[
("Dodge Chance", AttrUnit::Percent),
("Dodge Duration", AttrUnit::Frames)
],
attributes: |stats| {
if stats.behemoth_slayer > 0 {
if stats.behemoth_dodge_chance > 0 {
vec![
("Active", 1, AttrUnit::None),
("Dodge Chance", stats.behemoth_dodge_chance, AttrUnit::Percent),
("Dodge Duration", stats.behemoth_dodge_duration, AttrUnit::Frames),
]
} else {
vec![("Active", 1, AttrUnit::None)]
}
} else {
vec![]
}
},
apply_talent: Some(|stats, chance, duration, _| {
stats.behemoth_slayer = 1;
stats.behemoth_dodge_chance = if chance > 0 { chance } else { 5 };
stats.behemoth_dodge_duration = if duration > 0 { duration } else { 30 };
}),
},
Ability {
identity: Identity::WitchKiller,
talent_id: 0,
icon_id: Some(img015::ICON_WITCH_KILLER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.witch_killer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.witch_killer = 1),
},
Ability {
identity: Identity::EvaKiller,
talent_id: 0,
icon_id: Some(img015::ICON_EVA_KILLER),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.eva_killer > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.eva_killer = 1),
},
Ability {
identity: Identity::WaveBlock,
talent_id: 0,
icon_id: Some(img015::ICON_WAVE_BLOCK),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.wave_block > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats, _, _, _| stats.wave_block = 1),
},
Ability {
identity: Identity::CounterSurge,
talent_id: 68,
icon_id: Some(img015::ICON_COUNTER_SURGE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.counter_surge > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.counter_surge = 1),
},
Ability {
identity: Identity::Kamikaze,
talent_id: 0,
icon_id: None,
name: "",
description: "",
schema: &[("Attacks", AttrUnit::None)],
attributes: |stats| {
if stats.attack_count_total > -1 && stats.attack_count_state == 2 {
vec![("Attacks", stats.attack_count_total, AttrUnit::None)]
} else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::Stop,
talent_id: 0,
icon_id: None,
name: "",
description: "",
schema: &[("Attacks", AttrUnit::None)],
attributes: |stats| {
if stats.attack_count_total > -1 && stats.attack_count_state == 0 {
vec![("Attacks", stats.attack_count_total, AttrUnit::None)]
} else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::MultiHit,
talent_id: 0,
icon_id: None,
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.attack_2 > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::LongDistance,
talent_id: 0,
icon_id: Some(img015::ICON_LONG_DISTANCE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
let has_omni = (stats.long_distance_1_span < 0 || (stats.long_distance_1_span == 0 && stats.long_distance_1_anchor != 0)) ||
(stats.long_distance_2_flag > 0 && (stats.long_distance_2_span < 0 || (stats.long_distance_2_span == 0 && stats.long_distance_2_anchor != 0))) ||
(stats.long_distance_3_flag > 0 && (stats.long_distance_3_span < 0 || (stats.long_distance_3_span == 0 && stats.long_distance_3_anchor != 0)));
let has_ld = (stats.long_distance_1_span > 0) ||
(stats.long_distance_2_flag > 0 && stats.long_distance_2_span > 0) ||
(stats.long_distance_3_flag > 0 && stats.long_distance_3_span > 0);
if has_ld && !has_omni { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::OmniStrike,
talent_id: 0,
icon_id: Some(img015::ICON_OMNI_STRIKE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
let has_omni = (stats.long_distance_1_span < 0 || (stats.long_distance_1_span == 0 && stats.long_distance_1_anchor != 0)) ||
(stats.long_distance_2_flag > 0 && (stats.long_distance_2_span < 0 || (stats.long_distance_2_span == 0 && stats.long_distance_2_anchor != 0))) ||
(stats.long_distance_3_flag > 0 && (stats.long_distance_3_span < 0 || (stats.long_distance_3_span == 0 && stats.long_distance_3_anchor != 0)));
if has_omni { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::Conjure,
talent_id: 0,
icon_id: Some(img015::ICON_CONJURE),
name: "",
description: "",
schema: &[("Spirit ID", AttrUnit::None)],
attributes: |stats| {
if stats.conjure_unit_id > -1 { vec![("Spirit ID", stats.conjure_unit_id, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::MetalKiller,
talent_id: 0,
icon_id: Some(img015::ICON_METAL_KILLER),
name: "",
description: "",
schema: &[("Damage", AttrUnit::Percent)],
attributes: |stats| {
if stats.metal_killer_percent > 0 { vec![("Damage", stats.metal_killer_percent, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, percent, _, _| stats.metal_killer_percent = percent),
},
Ability {
identity: Identity::WaveAttack,
talent_id: 17,
icon_id: Some(img015::ICON_WAVE),
name: "",
description: "",
schema: &[
("Chance", AttrUnit::Percent),
("Level", AttrUnit::None),
],
attributes: |stats| {
if stats.mini_wave_flag == 0 && stats.wave_chance > 0 {
let maximum_reach = (332.5 + ((stats.wave_level - 1) as f32 * 200.0)).round() as i32;
vec![
("Chance", stats.wave_chance, AttrUnit::Percent),
("Level", stats.wave_level, AttrUnit::None),
("Max Reach", maximum_reach, AttrUnit::Range),
]
} else { vec![] }
},
apply_talent: Some(|stats, chance, level, _| { stats.wave_chance += chance; stats.wave_level = level; }),
},
Ability {
identity: Identity::MiniWave,
talent_id: 62,
icon_id: Some(img015::ICON_MINI_WAVE),
name: "",
description: "",
schema: &[
("Chance", AttrUnit::Percent),
("Level", AttrUnit::None),
],
attributes: |stats| {
if stats.mini_wave_flag > 0 && stats.wave_chance > 0 {
let maximum_reach = (332.5 + ((stats.wave_level - 1) as f32 * 200.0)).round() as i32;
vec![
("Chance", stats.wave_chance, AttrUnit::Percent),
("Level", stats.wave_level, AttrUnit::None),
("Max Reach", maximum_reach, AttrUnit::Range),
]
} else { vec![] }
},
apply_talent: Some(|stats, chance, level, _| { stats.mini_wave_flag = 1; stats.wave_chance += chance; stats.wave_level = level; }),
},
Ability {
identity: Identity::SurgeAttack,
talent_id: 56,
icon_id: Some(img015::ICON_SURGE),
name: "",
description: "",
schema: &[
("Chance", AttrUnit::Percent),
("Level", AttrUnit::None),
("Min Range", AttrUnit::Range),
("Max Range", AttrUnit::Range),
],
attributes: |stats| {
if stats.mini_surge_flag == 0 && stats.surge_chance > 0 {
vec![
("Chance", stats.surge_chance, AttrUnit::Percent),
("Level", stats.surge_level, AttrUnit::None),
("Min Range", stats.surge_spawn_anchor, AttrUnit::Range),
("Max Range", stats.surge_spawn_anchor + stats.surge_spawn_span, AttrUnit::Range),
("Width", stats.surge_spawn_span, AttrUnit::Range),
]
} else { vec![] }
},
apply_talent: Some(|stats, chance, level, group_data| {
stats.surge_chance += chance; stats.surge_level = level;
stats.surge_spawn_anchor = group_data.min_3 as i32 / 4;
stats.surge_spawn_span = group_data.min_4 as i32 / 4;
}),
},
Ability {
identity: Identity::MiniSurge,
talent_id: 65,
icon_id: Some(img015::ICON_MINI_SURGE),
name: "",
description: "",
schema: &[
("Chance", AttrUnit::Percent),
("Level", AttrUnit::None),
("Min Range", AttrUnit::Range),
("Max Range", AttrUnit::Range),
],
attributes: |stats| {
if stats.mini_surge_flag > 0 && stats.surge_chance > 0 {
vec![
("Chance", stats.surge_chance, AttrUnit::Percent),
("Level", stats.surge_level, AttrUnit::None),
("Min Range", stats.surge_spawn_anchor, AttrUnit::Range),
("Max Range", stats.surge_spawn_anchor + stats.surge_spawn_span, AttrUnit::Range),
("Width", stats.surge_spawn_span, AttrUnit::Range),
]
} else { vec![] }
},
apply_talent: Some(|stats, chance, level, group_data| {
stats.mini_surge_flag = 1; stats.surge_chance += chance; stats.surge_level = level;
stats.surge_spawn_anchor = group_data.min_3 as i32 / 4;
stats.surge_spawn_span = group_data.min_4 as i32 / 4;
}),
},
Ability {
identity: Identity::Explosion,
talent_id: 67,
icon_id: Some(img015::ICON_EXPLOSION),
name: "",
description: "",
schema: &[
("Chance", AttrUnit::Percent),
("Min Range", AttrUnit::Range),
("Max Range", AttrUnit::Range),
],
attributes: |stats| {
if stats.explosion_chance > 0 {
vec![
("Chance", stats.explosion_chance, AttrUnit::Percent),
("Min Range", stats.explosion_spawn_anchor, AttrUnit::Range),
("Max Range", stats.explosion_spawn_anchor + stats.explosion_spawn_span, AttrUnit::Range),
("Width", stats.explosion_spawn_span, AttrUnit::Range),
]
} else { vec![] }
},
apply_talent: Some(|stats, chance, _, group_data| {
stats.explosion_chance += chance;
stats.explosion_spawn_anchor = group_data.min_2 as i32 / 4;
stats.explosion_spawn_span = group_data.min_3 as i32 / 4;
}),
},
Ability {
identity: Identity::SavageBlow,
talent_id: 50,
icon_id: Some(img015::ICON_SAVAGE_BLOW),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Boost", AttrUnit::Percent)],
attributes: |stats| {
if stats.savage_blow_chance > 0 { vec![("Chance", stats.savage_blow_chance, AttrUnit::Percent), ("Boost", stats.savage_blow_boost, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, boost, _| { stats.savage_blow_chance += chance; if boost > 0 { stats.savage_blow_boost = boost; } }),
},
Ability {
identity: Identity::CriticalHit,
talent_id: 13,
icon_id: Some(img015::ICON_CRITICAL_HIT),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent)],
attributes: |stats| {
if stats.critical_chance > 0 { vec![("Chance", stats.critical_chance, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, _, _| stats.critical_chance += chance),
},
Ability {
identity: Identity::Strengthen,
talent_id: 10,
icon_id: Some(img015::ICON_STRENGTHEN),
name: "",
description: "",
schema: &[("HP", AttrUnit::Percent), ("Boost", AttrUnit::Percent)],
attributes: |stats| {
if stats.strengthen_threshold > 0 { vec![("HP", stats.strengthen_threshold, AttrUnit::Percent), ("Boost", stats.strengthen_boost, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, threshold, boost, _| {
if stats.strengthen_boost == 0 {
stats.strengthen_threshold = 100 - threshold;
stats.strengthen_boost = boost;
} else {
stats.strengthen_boost += if threshold != 0 { threshold } else { boost };
}
}),
},
Ability {
identity: Identity::Survive,
talent_id: 11,
icon_id: Some(img015::ICON_SURVIVE),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent)],
attributes: |stats| {
if stats.survive > 0 { vec![("Chance", stats.survive, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, _, _| stats.survive += chance),
},
Ability {
identity: Identity::BarrierBreaker,
talent_id: 15,
icon_id: Some(img015::ICON_BARRIER_BREAKER),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent)],
attributes: |stats| {
if stats.barrier_breaker_chance > 0 { vec![("Chance", stats.barrier_breaker_chance, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, _, _| stats.barrier_breaker_chance += chance),
},
Ability {
identity: Identity::ShieldPiercer,
talent_id: 58,
icon_id: Some(img015::ICON_SHIELD_PIERCER),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent)],
attributes: |stats| {
if stats.shield_pierce_chance > 0 { vec![("Chance", stats.shield_pierce_chance, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, _, _| stats.shield_pierce_chance += chance),
},
Ability {
identity: Identity::Dodge,
talent_id: 51,
icon_id: Some(img015::ICON_DODGE),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Duration", AttrUnit::Frames)],
attributes: |stats| {
if stats.dodge_chance > 0 { vec![("Chance", stats.dodge_chance, AttrUnit::Percent), ("Duration", stats.dodge_duration, AttrUnit::Frames)] } else { vec![] }
},
apply_talent: Some(|stats, chance, duration, _| { stats.dodge_chance += chance; stats.dodge_duration += duration; }),
},
Ability {
identity: Identity::Weaken,
talent_id: 1,
icon_id: Some(img015::ICON_WEAKEN),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Reduced To", AttrUnit::Percent), ("Duration", AttrUnit::Frames)],
attributes: |stats| {
if stats.weaken_chance > 0 { vec![("Chance", stats.weaken_chance, AttrUnit::Percent), ("Reduced To", stats.weaken_to, AttrUnit::Percent), ("Duration", stats.weaken_duration, AttrUnit::Frames)] } else { vec![] }
},
apply_talent: Some(|stats, chance, duration, group_data| {
if stats.weaken_chance == 0 {
stats.weaken_chance = chance; stats.weaken_duration = duration; stats.weaken_to = (100 - group_data.min_3) as i32;
} else if group_data.text_id == 42 { stats.weaken_duration += get_dur_val(chance, duration); }
else { stats.weaken_chance += chance; stats.weaken_duration += duration; }
}),
},
Ability {
identity: Identity::Freeze,
talent_id: 2,
icon_id: Some(img015::ICON_FREEZE),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Duration", AttrUnit::Frames)],
attributes: |stats| {
if stats.freeze_chance > 0 { vec![("Chance", stats.freeze_chance, AttrUnit::Percent), ("Duration", stats.freeze_duration, AttrUnit::Frames)] } else { vec![] }
},
apply_talent: Some(|stats, chance, duration, group_data| {
if stats.freeze_chance == 0 { stats.freeze_chance = chance; stats.freeze_duration = duration; }
else if group_data.text_id == 74 { stats.freeze_chance += chance; }
else { stats.freeze_duration += get_dur_val(chance, duration); }
}),
},
Ability {
identity: Identity::Slow,
talent_id: 3,
icon_id: Some(img015::ICON_SLOW),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Duration", AttrUnit::Frames)],
attributes: |stats| {
if stats.slow_chance > 0 { vec![("Chance", stats.slow_chance, AttrUnit::Percent), ("Duration", stats.slow_duration, AttrUnit::Frames)] } else { vec![] }
},
apply_talent: Some(|stats, chance, duration, group_data| {
if stats.slow_chance == 0 { stats.slow_chance = chance; stats.slow_duration = duration; }
else if group_data.text_id == 63 { stats.slow_chance += chance; }
else { stats.slow_duration += get_dur_val(chance, duration); }
}),
},
Ability {
identity: Identity::Knockback,
talent_id: 8,
icon_id: Some(img015::ICON_KNOCKBACK),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent)],
attributes: |stats| {
if stats.knockback_chance > 0 { vec![("Chance", stats.knockback_chance, AttrUnit::Percent)] } else { vec![] }
},
apply_talent: Some(|stats, chance, _, _| stats.knockback_chance += chance),
},
Ability {
identity: Identity::Curse,
talent_id: 60,
icon_id: Some(img015::ICON_CURSE),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Duration", AttrUnit::Frames)],
attributes: |stats| {
if stats.curse_chance > 0 { vec![("Chance", stats.curse_chance, AttrUnit::Percent), ("Duration", stats.curse_duration, AttrUnit::Frames)] } else { vec![] }
},
apply_talent: Some(|stats, chance, duration, group_data| {
if stats.curse_chance == 0 { stats.curse_chance = chance; stats.curse_duration = duration; }
else if group_data.text_id == 93 { stats.curse_duration += get_dur_val(chance, duration); }
else { stats.curse_chance += chance; }
}),
},
Ability {
identity: Identity::Warp,
talent_id: 9,
icon_id: Some(img015::ICON_WARP),
name: "",
description: "",
schema: &[("Chance", AttrUnit::Percent), ("Duration", AttrUnit::Frames), ("Min Distance", AttrUnit::Range), ("Max Distance", AttrUnit::Range)],
attributes: |stats| {
if stats.warp_chance > 0 {
vec![("Chance", stats.warp_chance, AttrUnit::Percent), ("Duration", stats.warp_duration, AttrUnit::Frames), ("Min Distance", stats.warp_distance_minimum, AttrUnit::Range), ("Max Distance", stats.warp_distance_maximum, AttrUnit::Range)]
} else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::Unknown,
talent_id: 0,
icon_id: None,
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.has_unknown_abilities > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: None,
},
Ability {
identity: Identity::ImmuneWave,
talent_id: 48,
icon_id: Some(img015::ICON_IMMUNE_WAVE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.wave_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.wave_immune = 1),
},
Ability {
identity: Identity::ImmuneSurge,
talent_id: 55,
icon_id: Some(img015::ICON_IMMUNE_SURGE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.surge_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.surge_immune = 1),
},
Ability {
identity: Identity::ImmuneExplosion,
talent_id: 69,
icon_id: Some(img015::ICON_IMMUNE_EXPLOSION),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.explosion_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.explosion_immune = 1),
},
Ability {
identity: Identity::ImmuneWeaken,
talent_id: 44,
icon_id: Some(img015::ICON_IMMUNE_WEAKEN),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.weaken_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.weaken_immune = 1),
},
Ability {
identity: Identity::ImmuneFreeze,
talent_id: 45,
icon_id: Some(img015::ICON_IMMUNE_FREEZE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.freeze_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.freeze_immune = 1),
},
Ability {
identity: Identity::ImmuneSlow,
talent_id: 46,
icon_id: Some(img015::ICON_IMMUNE_SLOW),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.slow_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.slow_immune = 1),
},
Ability {
identity: Identity::ImmuneKnockback,
talent_id: 47,
icon_id: Some(img015::ICON_IMMUNE_KNOCKBACK),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.knockback_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.knockback_immune = 1),
},
Ability {
identity: Identity::ImmuneCurse,
talent_id: 29,
icon_id: Some(img015::ICON_IMMUNE_CURSE),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.curse_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.curse_immune = 1),
},
Ability {
identity: Identity::ImmuneToxic,
talent_id: 53,
icon_id: Some(img015::ICON_IMMUNE_TOXIC),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.toxic_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.toxic_immune = 1),
},
Ability {
identity: Identity::ImmuneWarp,
talent_id: 49,
icon_id: Some(img015::ICON_IMMUNE_WARP),
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.warp_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.warp_immune = 1),
},
Ability {
identity: Identity::ImmuneBossWave,
talent_id: 0,
icon_id: None,
name: "",
description: "",
schema: &[],
attributes: |stats| {
if stats.boss_wave_immune > 0 { vec![("Active", 1, AttrUnit::None)] } else { vec![] }
},
apply_talent: Some(|stats,_,_,_| stats.boss_wave_immune = 1),
},
Ability {
identity: Identity::ResistWeaken,
talent_id: 18,
icon_id: Some(img015::ICON_RESIST_WEAKEN),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistFreeze,
talent_id: 19,
icon_id: Some(img015::ICON_RESIST_FREEZE),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistSlow,
talent_id: 20,
icon_id: Some(img015::ICON_RESIST_SLOW),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistKnockback,
talent_id: 21,
icon_id: Some(img015::ICON_RESIST_KNOCKBACK),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistWave,
talent_id: 22,
icon_id: Some(img015::ICON_RESIST_WAVE),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistWarp,
talent_id: 24,
icon_id: Some(img015::ICON_RESIST_WARP),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistCurse,
talent_id: 30,
icon_id: Some(img015::ICON_RESIST_CURSE),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistToxic,
talent_id: 52,
icon_id: Some(img015::ICON_RESIST_TOXIC),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::ResistSurge,
talent_id: 54,
icon_id: Some(img015::ICON_SURGE_RESIST),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|_,_,_,_| {}),
},
Ability {
identity: Identity::CostDown,
talent_id: 25,
icon_id: Some(img015::ICON_COST_DOWN),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, reduction, _, _| stats.eoc1_cost = stats.eoc1_cost.saturating_sub(reduction)),
},
Ability {
identity: Identity::RecoverSpeedUp,
talent_id: 26,
icon_id: Some(img015::ICON_RECOVER_SPEED_UP),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, frames, _, _| stats.cooldown = stats.cooldown.saturating_sub(frames)),
},
Ability {
identity: Identity::MoveSpeedUp,
talent_id: 27,
icon_id: Some(img015::ICON_MOVE_SPEED),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, speed, _, _| stats.speed += speed),
},
Ability {
identity: Identity::AttackBuff,
talent_id: 31,
icon_id: Some(img015::ICON_ATTACK_BUFF),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, percent, _, _| {
let percentage_factor = (100 + percent) as f32 / 100.0;
stats.attack_1 = (stats.attack_1 as f32 * percentage_factor).round() as i32;
stats.attack_2 = (stats.attack_2 as f32 * percentage_factor).round() as i32;
stats.attack_3 = (stats.attack_3 as f32 * percentage_factor).round() as i32;
}),
},
Ability {
identity: Identity::HealthBuff,
talent_id: 32,
icon_id: Some(img015::ICON_HEALTH_BUFF),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, percent, _, _| {
let percentage_factor = (100 + percent) as f32 / 100.0;
stats.hitpoints = (stats.hitpoints as f32 * percentage_factor).round() as i32;
}),
},
Ability {
identity: Identity::TbaDown,
talent_id: 61,
icon_id: Some(img015::ICON_TBA_DOWN),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, percent, _, _| {
let time_reduction = (stats.time_between_attacks as f32 * percent as f32 / 100.0).round() as i32;
stats.time_between_attacks = stats.time_between_attacks.saturating_sub(time_reduction);
}),
},
Ability {
identity: Identity::ImproveKnockbacks,
talent_id: 28,
icon_id: Some(img015::ICON_IMPROVE_KNOCKBACK_COUNT),
name: "",
description: "",
schema: &[],
attributes: |_| vec![],
apply_talent: Some(|stats, count, _, _| stats.knockbacks += count),
},
];