This commit is contained in:
Sam 2023-06-03 20:30:10 -04:00
parent dd616f85a9
commit 9fa556b165
5 changed files with 629 additions and 131 deletions

View File

@ -306,9 +306,9 @@ common-abilities-axe-bloodfeast = Bloodfeast
common-abilities-axe-fierce_raze = Fierce Raze common-abilities-axe-fierce_raze = Fierce Raze
.desc = .desc =
A rapid flurry of strikes on your foe A rapid flurry of strikes on your foe
common-abilities-axe-dueal_fierce_raze = Fierce Raze common-abilities-axe-dual_fierce_raze = Fierce Raze
.desc = .desc =
A rapid flurry of strikes on yoru foe using both of your axes A rapid flurry of strikes on your foe using both of your axes
common-abilities-axe-furor = Furor common-abilities-axe-furor = Furor
.desc = .desc =
As your fury rises, your movement and attacks quicken As your fury rises, your movement and attacks quicken

View File

@ -8,7 +8,7 @@ use common::{
ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance, MAX_ABILITIES}, ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance, MAX_ABILITIES},
buff::BuffKind, buff::BuffKind,
item::tool::AbilityContext, item::tool::AbilityContext,
skills::{BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill}, skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
AbilityInput, Agent, CharacterAbility, CharacterState, ControlAction, ControlEvent, AbilityInput, Agent, CharacterAbility, CharacterState, ControlAction, ControlEvent,
Controller, InputKind, Controller, InputKind,
}, },
@ -327,18 +327,6 @@ impl<'a> AgentData<'a> {
} }
} }
pub fn handle_axe_attack(
&self,
_agent: &mut Agent,
_controller: &mut Controller,
_attack_data: &AttackData,
_tgt_data: &TargetData,
_read_data: &ReadData,
_rng: &mut impl Rng,
) {
// TODO
}
pub fn handle_hammer_attack( pub fn handle_hammer_attack(
&self, &self,
agent: &mut Agent, agent: &mut Agent,
@ -738,7 +726,10 @@ impl<'a> AgentData<'a> {
agent.action_state.int_counters[IntCounters::Tactics as usize], agent.action_state.int_counters[IntCounters::Tactics as usize],
) { ) {
SwordTactics::Unskilled => { SwordTactics::Unskilled => {
let desired_energy = 15.0; let ability_preferences = AbilityPreferences {
desired_energy: 15.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -749,7 +740,7 @@ impl<'a> AgentData<'a> {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -760,14 +751,17 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::Basic => { SwordTactics::Basic => {
let desired_energy = 25.0; let ability_preferences = AbilityPreferences {
desired_energy: 25.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
continue_current_input(input, &mut next_input); continue_current_input(input, &mut next_input);
} else { } else {
let attempt_ability = InputKind::Ability(rng.gen_range(0..5)); let attempt_ability = InputKind::Ability(rng.gen_range(0..5));
if could_use_input(attempt_ability, desired_energy) { if could_use_input(attempt_ability, ability_preferences) {
next_input = Some(attempt_ability); next_input = Some(attempt_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -776,7 +770,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -787,7 +781,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::HeavySimple => { SwordTactics::HeavySimple => {
let desired_energy = 35.0; let ability_preferences = AbilityPreferences {
desired_energy: 35.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -796,16 +793,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(3..5)); let stance_ability = InputKind::Ability(rng.gen_range(3..5));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Heavy))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Heavy))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -814,7 +811,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -825,7 +822,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::AgileSimple => { SwordTactics::AgileSimple => {
let desired_energy = 35.0; let ability_preferences = AbilityPreferences {
desired_energy: 35.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -834,16 +834,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(3..5)); let stance_ability = InputKind::Ability(rng.gen_range(3..5));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Agile))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Agile))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -852,7 +852,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -863,7 +863,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::DefensiveSimple => { SwordTactics::DefensiveSimple => {
let desired_energy = 35.0; let ability_preferences = AbilityPreferences {
desired_energy: 35.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -872,18 +875,18 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(3..5)); let stance_ability = InputKind::Ability(rng.gen_range(3..5));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Defensive))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Defensive))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(InputKind::Ability(3), desired_energy) { } else if could_use_input(InputKind::Ability(3), ability_preferences) {
next_input = Some(InputKind::Ability(3)); next_input = Some(InputKind::Ability(3));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -892,7 +895,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -903,7 +906,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::CripplingSimple => { SwordTactics::CripplingSimple => {
let desired_energy = 35.0; let ability_preferences = AbilityPreferences {
desired_energy: 35.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -912,16 +918,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(3..5)); let stance_ability = InputKind::Ability(rng.gen_range(3..5));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Crippling))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Crippling))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -930,7 +936,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -941,7 +947,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::CleavingSimple => { SwordTactics::CleavingSimple => {
let desired_energy = 35.0; let ability_preferences = AbilityPreferences {
desired_energy: 35.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -950,16 +959,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(3..5)); let stance_ability = InputKind::Ability(rng.gen_range(3..5));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Cleaving))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Cleaving))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -968,7 +977,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -979,7 +988,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::HeavyAdvanced => { SwordTactics::HeavyAdvanced => {
let desired_energy = 50.0; let ability_preferences = AbilityPreferences {
desired_energy: 50.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -988,16 +1000,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(1..3)); let stance_ability = InputKind::Ability(rng.gen_range(1..3));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Heavy))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Heavy))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -1006,7 +1018,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -1017,7 +1029,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::AgileAdvanced => { SwordTactics::AgileAdvanced => {
let desired_energy = 50.0; let ability_preferences = AbilityPreferences {
desired_energy: 50.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -1026,16 +1041,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(1..3)); let stance_ability = InputKind::Ability(rng.gen_range(1..3));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Agile))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Agile))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -1044,7 +1059,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -1055,7 +1070,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::DefensiveAdvanced => { SwordTactics::DefensiveAdvanced => {
let desired_energy = 50.0; let ability_preferences = AbilityPreferences {
desired_energy: 50.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -1064,18 +1082,18 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(1..3)); let stance_ability = InputKind::Ability(rng.gen_range(1..3));
let random_ability = InputKind::Ability(rng.gen_range(1..4)); let random_ability = InputKind::Ability(rng.gen_range(1..4));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Defensive))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Defensive))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if could_use_input(InputKind::Ability(4), desired_energy) } else if could_use_input(InputKind::Ability(4), ability_preferences)
&& rng.gen_bool(2.0 * read_data.dt.0 as f64) && rng.gen_bool(2.0 * read_data.dt.0 as f64)
{ {
next_input = Some(InputKind::Ability(4)); next_input = Some(InputKind::Ability(4));
@ -1086,7 +1104,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -1097,7 +1115,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::CripplingAdvanced => { SwordTactics::CripplingAdvanced => {
let desired_energy = 50.0; let ability_preferences = AbilityPreferences {
desired_energy: 50.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -1106,16 +1127,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(1..3)); let stance_ability = InputKind::Ability(rng.gen_range(1..3));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Crippling))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Crippling))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -1124,7 +1145,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -1135,7 +1156,10 @@ impl<'a> AgentData<'a> {
} }
}, },
SwordTactics::CleavingAdvanced => { SwordTactics::CleavingAdvanced => {
let desired_energy = 50.0; let ability_preferences = AbilityPreferences {
desired_energy: 50.0,
combo_scaling_buildup: 0,
};
let current_input = self.char_state.ability_info().map(|ai| ai.input); let current_input = self.char_state.ability_info().map(|ai| ai.input);
let mut next_input = None; let mut next_input = None;
if let Some(input) = current_input { if let Some(input) = current_input {
@ -1144,16 +1168,16 @@ impl<'a> AgentData<'a> {
let stance_ability = InputKind::Ability(rng.gen_range(1..3)); let stance_ability = InputKind::Ability(rng.gen_range(1..3));
let random_ability = InputKind::Ability(rng.gen_range(1..5)); let random_ability = InputKind::Ability(rng.gen_range(1..5));
if !matches!(self.stance, Some(Stance::Sword(SwordStance::Cleaving))) { if !matches!(self.stance, Some(Stance::Sword(SwordStance::Cleaving))) {
if could_use_input(stance_ability, desired_energy) { if could_use_input(stance_ability, ability_preferences) {
next_input = Some(stance_ability); next_input = Some(stance_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
} else { } else {
next_input = Some(InputKind::Secondary); next_input = Some(InputKind::Secondary);
} }
} else if could_use_input(InputKind::Ability(0), desired_energy) { } else if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0)); next_input = Some(InputKind::Ability(0));
} else if could_use_input(random_ability, desired_energy) { } else if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability); next_input = Some(random_ability);
} else if rng.gen_bool(0.5) { } else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary); next_input = Some(InputKind::Primary);
@ -1162,7 +1186,7 @@ impl<'a> AgentData<'a> {
} }
}; };
if let Some(input) = next_input { if let Some(input) = next_input {
if could_use_input(input, desired_energy) { if could_use_input(input, ability_preferences) {
controller.push_basic_input(input); controller.push_basic_input(input);
false false
} else { } else {
@ -1189,6 +1213,322 @@ impl<'a> AgentData<'a> {
} }
} }
pub fn handle_axe_attack(
&self,
agent: &mut Agent,
controller: &mut Controller,
attack_data: &AttackData,
tgt_data: &TargetData,
read_data: &ReadData,
rng: &mut impl Rng,
) {
if !agent.action_state.initialized {
agent.action_state.initialized = true;
let available_tactics = {
let mut tactics = Vec::new();
let try_tactic = |skill, tactic, tactics: &mut Vec<AxeTactics>| {
if self.skill_set.has_skill(Skill::Axe(skill)) {
tactics.push(tactic);
}
};
try_tactic(AxeSkill::Execute, AxeTactics::SavageAdvanced, &mut tactics);
try_tactic(
AxeSkill::Lacerate,
AxeTactics::MercilessAdvanced,
&mut tactics,
);
try_tactic(AxeSkill::Bulkhead, AxeTactics::RivingAdvanced, &mut tactics);
if tactics.is_empty() {
try_tactic(
AxeSkill::RisingTide,
AxeTactics::SavageIntermediate,
&mut tactics,
);
try_tactic(
AxeSkill::FierceRaze,
AxeTactics::MercilessIntermediate,
&mut tactics,
);
try_tactic(
AxeSkill::Plunder,
AxeTactics::RivingIntermediate,
&mut tactics,
);
}
if tactics.is_empty() {
try_tactic(
AxeSkill::BrutalSwing,
AxeTactics::SavageSimple,
&mut tactics,
);
try_tactic(AxeSkill::Rake, AxeTactics::MercilessSimple, &mut tactics);
try_tactic(AxeSkill::SkullBash, AxeTactics::RivingSimple, &mut tactics);
}
if tactics.is_empty() {
tactics.push(AxeTactics::Unskilled);
}
tactics
};
let tactic = available_tactics
.choose(rng)
.copied()
.unwrap_or(AxeTactics::Unskilled);
agent.action_state.int_counters[IntCounters::Tactic as usize] = tactic as u8;
let auxiliary_key = ActiveAbilities::active_auxiliary_key(Some(self.inventory));
let set_axe_ability = |controller: &mut Controller, slot, skill| {
controller.push_event(ControlEvent::ChangeAbility {
slot,
auxiliary_key,
new_ability: AuxiliaryAbility::MainWeapon(skill),
});
};
match tactic {
AxeTactics::Unskilled => {},
AxeTactics::SavageSimple => {
// Brutal swing
set_axe_ability(controller, 0, 0);
},
AxeTactics::MercilessSimple => {
// Rake
set_axe_ability(controller, 0, 6);
},
AxeTactics::RivingSimple => {
// Skull bash
set_axe_ability(controller, 0, 12);
},
AxeTactics::SavageIntermediate => {
// Brutal swing
set_axe_ability(controller, 0, 0);
// Berserk
set_axe_ability(controller, 1, 1);
// Rising tide
set_axe_ability(controller, 2, 2);
},
AxeTactics::MercilessIntermediate => {
// Rake
set_axe_ability(controller, 0, 6);
// Bloodfeast
set_axe_ability(controller, 1, 7);
// Fierce raze
set_axe_ability(controller, 2, 8);
},
AxeTactics::RivingIntermediate => {
// Skull bash
set_axe_ability(controller, 0, 12);
// Sunder
set_axe_ability(controller, 1, 13);
// Plunder
set_axe_ability(controller, 2, 14);
},
AxeTactics::SavageAdvanced => {
// Berserk
set_axe_ability(controller, 0, 1);
// Rising tide
set_axe_ability(controller, 1, 2);
// Savage sense
set_axe_ability(controller, 2, 3);
// Adrenaline rush
set_axe_ability(controller, 3, 4);
// Execute/maelstrom
set_axe_ability(controller, 4, 5);
},
AxeTactics::MercilessAdvanced => {
// Bloodfeast
set_axe_ability(controller, 0, 7);
// Fierce raze
set_axe_ability(controller, 1, 8);
// Furor
set_axe_ability(controller, 2, 9);
// Fracture
set_axe_ability(controller, 3, 10);
// Lacerate/riptide
set_axe_ability(controller, 4, 11);
},
AxeTactics::RivingAdvanced => {
// Sunder
set_axe_ability(controller, 0, 13);
// Plunder
set_axe_ability(controller, 1, 14);
// Defiance
set_axe_ability(controller, 2, 15);
// Keelhaul
set_axe_ability(controller, 3, 16);
// Bulkhead/capsize
set_axe_ability(controller, 4, 17);
},
}
agent.action_state.int_counters[IntCounters::ActionMode as usize] =
ActionMode::Reckless as u8;
}
enum IntCounters {
Tactic = 0,
ActionMode = 1,
}
enum Timers {
GuardedCycle = 0,
PosTimeOut = 1,
}
enum Conditions {
GuardedDefend = 0,
RollingBreakThrough = 1,
}
enum FloatCounters {
GuardedTimer = 0,
}
enum Positions {
GuardedCover = 0,
Flee = 1,
}
let attempt_attack = handle_attack_aggression(
self,
agent,
controller,
attack_data,
tgt_data,
read_data,
rng,
Timers::PosTimeOut as usize,
Timers::GuardedCycle as usize,
FloatCounters::GuardedTimer as usize,
IntCounters::ActionMode as usize,
Conditions::GuardedDefend as usize,
Conditions::RollingBreakThrough as usize,
Positions::GuardedCover as usize,
Positions::Flee as usize,
);
let attack_failed = if attempt_attack {
let primary = self.extract_ability(AbilityInput::Primary);
let secondary = self.extract_ability(AbilityInput::Secondary);
let abilities = [
self.extract_ability(AbilityInput::Auxiliary(0)),
self.extract_ability(AbilityInput::Auxiliary(1)),
self.extract_ability(AbilityInput::Auxiliary(2)),
self.extract_ability(AbilityInput::Auxiliary(3)),
self.extract_ability(AbilityInput::Auxiliary(4)),
];
let could_use_input = |input, desired_energy| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, desired_energy)
}),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, desired_energy)
}),
InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| {
a.could_use(attack_data, self, tgt_data, read_data, desired_energy)
}),
_ => false,
};
let continue_current_input = |current_input, next_input: &mut Option<InputKind>| {
if matches!(current_input, InputKind::Secondary) {
let charging =
matches!(self.char_state.stage_section(), Some(StageSection::Charge));
let charged = self
.char_state
.durations()
.and_then(|durs| durs.charge)
.zip(self.char_state.timer())
.map_or(false, |(dur, timer)| timer > dur);
if !(charging && charged) {
*next_input = Some(InputKind::Secondary);
}
} else {
*next_input = Some(current_input);
}
};
let current_input = self.char_state.ability_info().map(|ai| ai.input);
let ability_preferences = AbilityPreferences {
desired_energy: 40.0,
combo_scaling_buildup: 15,
};
let mut next_input = None;
if let Some(input) = current_input {
continue_current_input(input, &mut next_input);
} else {
match AxeTactics::from_u8(
agent.action_state.int_counters[IntCounters::Tactic as usize],
) {
AxeTactics::Unskilled => {
if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary);
} else {
next_input = Some(InputKind::Secondary);
}
},
AxeTactics::SavageSimple
| AxeTactics::MercilessSimple
| AxeTactics::RivingSimple => {
if could_use_input(InputKind::Ability(0), ability_preferences) {
next_input = Some(InputKind::Ability(0));
} else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary);
} else {
next_input = Some(InputKind::Secondary);
}
},
AxeTactics::SavageIntermediate
| AxeTactics::MercilessIntermediate
| AxeTactics::RivingIntermediate => {
let random_ability = InputKind::Ability(rng.gen_range(0..3));
if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability);
} else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary);
} else {
next_input = Some(InputKind::Secondary);
}
},
AxeTactics::SavageAdvanced
| AxeTactics::MercilessAdvanced
| AxeTactics::RivingAdvanced => {
let random_ability = InputKind::Ability(rng.gen_range(0..5));
if could_use_input(random_ability, ability_preferences) {
next_input = Some(random_ability);
} else if rng.gen_bool(0.5) {
next_input = Some(InputKind::Primary);
} else {
next_input = Some(InputKind::Secondary);
}
},
}
}
if let Some(input) = next_input {
if could_use_input(input, ability_preferences) {
controller.push_basic_input(input);
false
} else {
true
}
} else {
true
}
} else {
false
};
if attack_failed && attack_data.dist_sqrd > 1.5_f32.powi(2) {
self.path_toward_target(
agent,
controller,
tgt_data.pos.0,
read_data,
Path::Separate,
None,
);
}
}
pub fn handle_bow_attack( pub fn handle_bow_attack(
&self, &self,
agent: &mut Agent, agent: &mut Agent,
@ -4767,10 +5107,22 @@ impl<'a> AgentData<'a> {
let secondary = self.extract_ability(AbilityInput::Secondary); let secondary = self.extract_ability(AbilityInput::Secondary);
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| { InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, 0.0) s.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };
@ -4823,10 +5175,22 @@ impl<'a> AgentData<'a> {
let secondary = self.extract_ability(AbilityInput::Secondary); let secondary = self.extract_ability(AbilityInput::Secondary);
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| { InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, 0.0) s.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };
@ -4868,7 +5232,13 @@ impl<'a> AgentData<'a> {
let primary = self.extract_ability(AbilityInput::Primary); let primary = self.extract_ability(AbilityInput::Primary);
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };
@ -4916,13 +5286,31 @@ impl<'a> AgentData<'a> {
]; ];
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| { InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, 0.0) s.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| { InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| {
a.could_use(attack_data, self, tgt_data, read_data, 0.0) a.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };
@ -4984,13 +5372,31 @@ impl<'a> AgentData<'a> {
]; ];
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| { InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, 0.0) s.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| { InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| {
a.could_use(attack_data, self, tgt_data, read_data, 0.0) a.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };
@ -5077,13 +5483,31 @@ impl<'a> AgentData<'a> {
]; ];
let could_use_input = |input| match input { let could_use_input = |input| match input {
InputKind::Primary => primary.as_ref().map_or(false, |p| { InputKind::Primary => primary.as_ref().map_or(false, |p| {
p.could_use(attack_data, self, tgt_data, read_data, 0.0) p.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Secondary => secondary.as_ref().map_or(false, |s| { InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
s.could_use(attack_data, self, tgt_data, read_data, 0.0) s.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| { InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| {
a.could_use(attack_data, self, tgt_data, read_data, 0.0) a.could_use(
attack_data,
self,
tgt_data,
read_data,
AbilityPreferences::default(),
)
}), }),
_ => false, _ => false,
}; };

View File

@ -6,7 +6,10 @@ use common::{
character_state::AttackFilters, character_state::AttackFilters,
group, group,
inventory::{ inventory::{
item::{tool::ToolKind, ItemKind, MaterialStatManifest}, item::{
tool::{AbilityMap, ToolKind},
ItemKind, MaterialStatManifest,
},
slot::EquipSlot, slot::EquipSlot,
}, },
ActiveAbilities, Alignment, Body, CharacterState, Combo, Energy, Health, Inventory, ActiveAbilities, Alignment, Body, CharacterState, Combo, Energy, Health, Inventory,
@ -246,7 +249,7 @@ pub enum Tactic {
AdletElder, AdletElder,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Debug)]
pub enum SwordTactics { pub enum SwordTactics {
Unskilled = 0, Unskilled = 0,
Basic = 1, Basic = 1,
@ -283,6 +286,39 @@ impl SwordTactics {
} }
} }
#[derive(Copy, Clone, Debug)]
pub enum AxeTactics {
Unskilled = 0,
SavageSimple = 1,
MercilessSimple = 2,
RivingSimple = 3,
SavageIntermediate = 4,
MercilessIntermediate = 5,
RivingIntermediate = 6,
SavageAdvanced = 7,
MercilessAdvanced = 8,
RivingAdvanced = 9,
}
impl AxeTactics {
pub fn from_u8(x: u8) -> Self {
use AxeTactics::*;
match x {
0 => Unskilled,
1 => SavageSimple,
2 => MercilessSimple,
3 => RivingSimple,
4 => SavageIntermediate,
5 => MercilessIntermediate,
6 => RivingIntermediate,
7 => SavageAdvanced,
8 => MercilessAdvanced,
9 => RivingAdvanced,
_ => Unskilled,
}
}
}
#[derive(SystemData)] #[derive(SystemData)]
pub struct ReadData<'a> { pub struct ReadData<'a> {
pub entities: Entities<'a>, pub entities: Entities<'a>,
@ -323,6 +359,7 @@ pub struct ReadData<'a> {
pub poises: ReadStorage<'a, Poise>, pub poises: ReadStorage<'a, Poise>,
pub stances: ReadStorage<'a, Stance>, pub stances: ReadStorage<'a, Stance>,
pub presences: ReadStorage<'a, Presence>, pub presences: ReadStorage<'a, Presence>,
pub ability_map: ReadExpect<'a, AbilityMap>,
} }
impl<'a> ReadData<'a> { impl<'a> ReadData<'a> {
@ -353,10 +390,13 @@ pub enum AbilityData {
angle: f32, angle: f32,
energy: f32, energy: f32,
combo: u32, combo: u32,
combo_scales: bool,
}, },
SelfBuff { SelfBuff {
buff: BuffKind, buff: BuffKind,
energy: f32, energy: f32,
combo: u32,
combo_scales: bool,
}, },
DiveMelee { DiveMelee {
range: f32, range: f32,
@ -420,6 +460,12 @@ pub enum AbilityData {
}, },
} }
#[derive(Copy, Clone, Debug, Default)]
pub struct AbilityPreferences {
pub desired_energy: f32,
pub combo_scaling_buildup: u32,
}
impl AbilityData { impl AbilityData {
pub fn from_ability(ability: &CharacterAbility) -> Option<Self> { pub fn from_ability(ability: &CharacterAbility) -> Option<Self> {
use CharacterAbility::*; use CharacterAbility::*;
@ -456,20 +502,26 @@ impl AbilityData {
energy_cost, energy_cost,
melee_constructor, melee_constructor,
minimum_combo, minimum_combo,
scaling,
.. ..
} => Self::FinisherMelee { } => Self::FinisherMelee {
energy: *energy_cost, energy: *energy_cost,
range: melee_constructor.range, range: melee_constructor.range,
angle: melee_constructor.angle, angle: melee_constructor.angle,
combo: *minimum_combo, combo: *minimum_combo,
combo_scales: scaling.is_some(),
}, },
SelfBuff { SelfBuff {
buff_kind, buff_kind,
energy_cost, energy_cost,
combo_cost,
combo_scaling,
.. ..
} => Self::SelfBuff { } => Self::SelfBuff {
buff: *buff_kind, buff: *buff_kind,
energy: *energy_cost, energy: *energy_cost,
combo: *combo_cost,
combo_scales: combo_scaling.is_some(),
}, },
DiveMelee { DiveMelee {
energy_cost, energy_cost,
@ -595,7 +647,7 @@ impl AbilityData {
agent_data: &AgentData, agent_data: &AgentData,
tgt_data: &TargetData, tgt_data: &TargetData,
read_data: &ReadData, read_data: &ReadData,
desired_energy: f32, ability_preferences: AbilityPreferences,
) -> bool { ) -> bool {
let melee_check = |range: f32, angle, forced_movement: Option<ForcedMovement>| { let melee_check = |range: f32, angle, forced_movement: Option<ForcedMovement>| {
let (range_inc, min_mult) = forced_movement.map_or((0.0, 0.0), |fm| match fm { let (range_inc, min_mult) = forced_movement.map_or((0.0, 0.0), |fm| match fm {
@ -621,9 +673,19 @@ impl AbilityData {
}; };
let energy_check = |energy: f32| { let energy_check = |energy: f32| {
agent_data.energy.current() >= energy agent_data.energy.current() >= energy
&& (energy < f32::EPSILON || agent_data.energy.current() >= desired_energy) && (energy < f32::EPSILON
|| agent_data.energy.current() >= ability_preferences.desired_energy)
};
let combo_check = |combo, scales| {
let additional_combo = if scales {
ability_preferences.combo_scaling_buildup
} else {
0
};
agent_data
.combo
.map_or(false, |c| c.counter() >= combo + additional_combo)
}; };
let combo_check = |combo| agent_data.combo.map_or(false, |c| c.counter() >= combo);
let attack_kind_check = |attacks: AttackFilters| { let attack_kind_check = |attacks: AttackFilters| {
tgt_data tgt_data
.char_state .char_state
@ -673,9 +735,20 @@ impl AbilityData {
angle, angle,
energy, energy,
combo, combo,
} => melee_check(*range, *angle, None) && energy_check(*energy) && combo_check(*combo), combo_scales,
SelfBuff { buff, energy } => { } => {
melee_check(*range, *angle, None)
&& energy_check(*energy)
&& combo_check(*combo, *combo_scales)
},
SelfBuff {
buff,
energy,
combo,
combo_scales,
} => {
energy_check(*energy) energy_check(*energy)
&& combo_check(*combo, *combo_scales)
&& agent_data && agent_data
.buffs .buffs
.map_or(false, |buffs| !buffs.contains(*buff)) .map_or(false, |buffs| !buffs.contains(*buff))
@ -716,7 +789,7 @@ impl AbilityData {
} => { } => {
melee_check(*range, *angle, None) melee_check(*range, *angle, None)
&& energy_check(*energy_per_strike * *strikes as f32) && energy_check(*energy_per_strike * *strikes as f32)
&& combo_check(*combo) && combo_check(*combo, false)
}, },
ChargedMelee { ChargedMelee {
range, range,

View File

@ -1061,43 +1061,6 @@ impl Animation for ComboAnimation {
next.belt.orientation.rotate_z(move2 * -0.6); next.belt.orientation.rotate_z(move2 * -0.6);
next.control.position += Vec3::new(move2 * -6.0, move2 * -20.0, move2 * -4.0); next.control.position += Vec3::new(move2 * -6.0, move2 * -20.0, move2 * -4.0);
}, },
Some("common.abilities.axe.fracture") => {
let (move1, move2) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0),
Some(StageSection::Action) => (1.0, anim_time),
Some(StageSection::Recover) => (1.0, 1.0),
_ => (0.0, 0.0),
};
let move1 = move1 * multi_strike_pullback;
let move2 = move2 * multi_strike_pullback;
next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2);
next.hand_l.orientation =
Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4);
next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2);
next.hand_r.orientation =
Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5);
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5 + move1 * -PI / 2.0 + move2 * -0.5);
next.control.orientation.rotate_x(move1 * 0.0);
next.chest.orientation.rotate_x(move1 * -0.5);
next.chest.orientation.rotate_z(move1 * 0.7);
next.head.orientation.rotate_z(move1 * -0.3);
next.belt.orientation.rotate_z(move1 * -0.1);
next.shorts.orientation.rotate_z(move1 * -0.4);
next.chest.orientation.rotate_z(move2 * -1.8);
next.head.orientation.rotate_z(move2 * 0.9);
next.shorts.orientation.rotate_z(move2 * 1.3);
next.belt.orientation.rotate_z(move2 * 0.6);
next.control.orientation.rotate_x(move2 * -0.9);
next.control.orientation.rotate_z(move2 * -3.5);
next.control.position += Vec3::new(move2 * 14.0, move2 * 6.0, 0.0);
},
Some("common.abilities.axe.skull_bash") => { Some("common.abilities.axe.skull_bash") => {
let (move1, move2) = match stage_section { let (move1, move2) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0), Some(StageSection::Buildup) => (anim_time, 0.0),

View File

@ -402,6 +402,44 @@ impl Animation for FinisherMeleeAnimation {
next.control.position += Vec3::new(move2 * 12.0, move2 * -6.0, 0.0); next.control.position += Vec3::new(move2 * 12.0, move2 * -6.0, 0.0);
next.torso.orientation.rotate_z(move2_raw * -TAU); next.torso.orientation.rotate_z(move2_raw * -TAU);
}, },
Some("common.abilities.axe.fracture") => {
let (move1, move2, move3) = match stage_section {
Some(StageSection::Buildup) => (anim_time, 0.0, 0.0),
Some(StageSection::Action) => (1.0, anim_time, 0.0),
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
_ => (0.0, 0.0, 0.0),
};
let pullback = 1.0 - move3;
let move1 = move1 * pullback;
let move2 = move2 * pullback;
next.hand_l.position = Vec3::new(s_a.ahl.0, s_a.ahl.1, s_a.ahl.2);
next.hand_l.orientation =
Quaternion::rotation_x(s_a.ahl.3) * Quaternion::rotation_y(s_a.ahl.4);
next.hand_r.position = Vec3::new(s_a.ahr.0, s_a.ahr.1, s_a.ahr.2);
next.hand_r.orientation =
Quaternion::rotation_x(s_a.ahr.3) * Quaternion::rotation_z(s_a.ahr.5);
next.control.position = Vec3::new(s_a.ac.0, s_a.ac.1, s_a.ac.2);
next.control.orientation = Quaternion::rotation_x(s_a.ac.3)
* Quaternion::rotation_y(s_a.ac.4)
* Quaternion::rotation_z(s_a.ac.5 + move1 * -PI / 2.0 + move2 * -0.5);
next.control.orientation.rotate_x(move1 * 0.0);
next.chest.orientation.rotate_x(move1 * -0.5);
next.chest.orientation.rotate_z(move1 * 0.7);
next.head.orientation.rotate_z(move1 * -0.3);
next.belt.orientation.rotate_z(move1 * -0.1);
next.shorts.orientation.rotate_z(move1 * -0.4);
next.chest.orientation.rotate_z(move2 * -1.8);
next.head.orientation.rotate_z(move2 * 0.9);
next.shorts.orientation.rotate_z(move2 * 1.3);
next.belt.orientation.rotate_z(move2 * 0.6);
next.control.orientation.rotate_x(move2 * -0.9);
next.control.orientation.rotate_z(move2 * -3.5);
next.control.position += Vec3::new(move2 * 14.0, move2 * 6.0, 0.0);
},
_ => {}, _ => {},
} }