mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Axe AI
This commit is contained in:
parent
dd616f85a9
commit
9fa556b165
@ -306,9 +306,9 @@ common-abilities-axe-bloodfeast = Bloodfeast
|
||||
common-abilities-axe-fierce_raze = Fierce Raze
|
||||
.desc =
|
||||
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 =
|
||||
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
|
||||
.desc =
|
||||
As your fury rises, your movement and attacks quicken
|
||||
|
@ -8,7 +8,7 @@ use common::{
|
||||
ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance, MAX_ABILITIES},
|
||||
buff::BuffKind,
|
||||
item::tool::AbilityContext,
|
||||
skills::{BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
|
||||
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
|
||||
AbilityInput, Agent, CharacterAbility, CharacterState, ControlAction, ControlEvent,
|
||||
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(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
@ -738,7 +726,10 @@ impl<'a> AgentData<'a> {
|
||||
agent.action_state.int_counters[IntCounters::Tactics as usize],
|
||||
) {
|
||||
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 mut next_input = None;
|
||||
if let Some(input) = current_input {
|
||||
@ -749,7 +740,7 @@ impl<'a> AgentData<'a> {
|
||||
next_input = Some(InputKind::Secondary);
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -760,14 +751,17 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
if let Some(input) = current_input {
|
||||
continue_current_input(input, &mut next_input);
|
||||
} else {
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
@ -776,7 +770,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -787,7 +781,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -814,7 +811,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -825,7 +822,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -852,7 +852,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -863,7 +863,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} 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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -892,7 +895,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -903,7 +906,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -930,7 +936,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -941,7 +947,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -968,7 +977,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -979,7 +988,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -1006,7 +1018,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -1017,7 +1029,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -1044,7 +1059,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -1055,7 +1070,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..4));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else if could_use_input(random_ability, ability_preferences) {
|
||||
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)
|
||||
{
|
||||
next_input = Some(InputKind::Ability(4));
|
||||
@ -1086,7 +1104,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -1097,7 +1115,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -1124,7 +1145,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} else {
|
||||
@ -1135,7 +1156,10 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
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 mut next_input = None;
|
||||
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 random_ability = InputKind::Ability(rng.gen_range(1..5));
|
||||
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);
|
||||
} else if rng.gen_bool(0.5) {
|
||||
next_input = Some(InputKind::Primary);
|
||||
} else {
|
||||
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));
|
||||
} else if could_use_input(random_ability, desired_energy) {
|
||||
} else 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);
|
||||
@ -1162,7 +1186,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
};
|
||||
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);
|
||||
false
|
||||
} 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(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
@ -4767,10 +5107,22 @@ impl<'a> AgentData<'a> {
|
||||
let secondary = self.extract_ability(AbilityInput::Secondary);
|
||||
let could_use_input = |input| match input {
|
||||
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| {
|
||||
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,
|
||||
};
|
||||
@ -4823,10 +5175,22 @@ impl<'a> AgentData<'a> {
|
||||
let secondary = self.extract_ability(AbilityInput::Secondary);
|
||||
let could_use_input = |input| match input {
|
||||
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| {
|
||||
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,
|
||||
};
|
||||
@ -4868,7 +5232,13 @@ impl<'a> AgentData<'a> {
|
||||
let primary = self.extract_ability(AbilityInput::Primary);
|
||||
let could_use_input = |input| match input {
|
||||
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,
|
||||
};
|
||||
@ -4916,13 +5286,31 @@ impl<'a> AgentData<'a> {
|
||||
];
|
||||
let could_use_input = |input| match input {
|
||||
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| {
|
||||
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| {
|
||||
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,
|
||||
};
|
||||
@ -4984,13 +5372,31 @@ impl<'a> AgentData<'a> {
|
||||
];
|
||||
let could_use_input = |input| match input {
|
||||
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| {
|
||||
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| {
|
||||
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,
|
||||
};
|
||||
@ -5077,13 +5483,31 @@ impl<'a> AgentData<'a> {
|
||||
];
|
||||
let could_use_input = |input| match input {
|
||||
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| {
|
||||
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| {
|
||||
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,
|
||||
};
|
||||
|
@ -6,7 +6,10 @@ use common::{
|
||||
character_state::AttackFilters,
|
||||
group,
|
||||
inventory::{
|
||||
item::{tool::ToolKind, ItemKind, MaterialStatManifest},
|
||||
item::{
|
||||
tool::{AbilityMap, ToolKind},
|
||||
ItemKind, MaterialStatManifest,
|
||||
},
|
||||
slot::EquipSlot,
|
||||
},
|
||||
ActiveAbilities, Alignment, Body, CharacterState, Combo, Energy, Health, Inventory,
|
||||
@ -246,7 +249,7 @@ pub enum Tactic {
|
||||
AdletElder,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum SwordTactics {
|
||||
Unskilled = 0,
|
||||
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)]
|
||||
pub struct ReadData<'a> {
|
||||
pub entities: Entities<'a>,
|
||||
@ -323,6 +359,7 @@ pub struct ReadData<'a> {
|
||||
pub poises: ReadStorage<'a, Poise>,
|
||||
pub stances: ReadStorage<'a, Stance>,
|
||||
pub presences: ReadStorage<'a, Presence>,
|
||||
pub ability_map: ReadExpect<'a, AbilityMap>,
|
||||
}
|
||||
|
||||
impl<'a> ReadData<'a> {
|
||||
@ -353,10 +390,13 @@ pub enum AbilityData {
|
||||
angle: f32,
|
||||
energy: f32,
|
||||
combo: u32,
|
||||
combo_scales: bool,
|
||||
},
|
||||
SelfBuff {
|
||||
buff: BuffKind,
|
||||
energy: f32,
|
||||
combo: u32,
|
||||
combo_scales: bool,
|
||||
},
|
||||
DiveMelee {
|
||||
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 {
|
||||
pub fn from_ability(ability: &CharacterAbility) -> Option<Self> {
|
||||
use CharacterAbility::*;
|
||||
@ -456,20 +502,26 @@ impl AbilityData {
|
||||
energy_cost,
|
||||
melee_constructor,
|
||||
minimum_combo,
|
||||
scaling,
|
||||
..
|
||||
} => Self::FinisherMelee {
|
||||
energy: *energy_cost,
|
||||
range: melee_constructor.range,
|
||||
angle: melee_constructor.angle,
|
||||
combo: *minimum_combo,
|
||||
combo_scales: scaling.is_some(),
|
||||
},
|
||||
SelfBuff {
|
||||
buff_kind,
|
||||
energy_cost,
|
||||
combo_cost,
|
||||
combo_scaling,
|
||||
..
|
||||
} => Self::SelfBuff {
|
||||
buff: *buff_kind,
|
||||
energy: *energy_cost,
|
||||
combo: *combo_cost,
|
||||
combo_scales: combo_scaling.is_some(),
|
||||
},
|
||||
DiveMelee {
|
||||
energy_cost,
|
||||
@ -595,7 +647,7 @@ impl AbilityData {
|
||||
agent_data: &AgentData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
desired_energy: f32,
|
||||
ability_preferences: AbilityPreferences,
|
||||
) -> bool {
|
||||
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 {
|
||||
@ -621,9 +673,19 @@ impl AbilityData {
|
||||
};
|
||||
let energy_check = |energy: f32| {
|
||||
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| {
|
||||
tgt_data
|
||||
.char_state
|
||||
@ -673,9 +735,20 @@ impl AbilityData {
|
||||
angle,
|
||||
energy,
|
||||
combo,
|
||||
} => melee_check(*range, *angle, None) && energy_check(*energy) && combo_check(*combo),
|
||||
SelfBuff { buff, energy } => {
|
||||
combo_scales,
|
||||
} => {
|
||||
melee_check(*range, *angle, None)
|
||||
&& energy_check(*energy)
|
||||
&& combo_check(*combo, *combo_scales)
|
||||
},
|
||||
SelfBuff {
|
||||
buff,
|
||||
energy,
|
||||
combo,
|
||||
combo_scales,
|
||||
} => {
|
||||
energy_check(*energy)
|
||||
&& combo_check(*combo, *combo_scales)
|
||||
&& agent_data
|
||||
.buffs
|
||||
.map_or(false, |buffs| !buffs.contains(*buff))
|
||||
@ -716,7 +789,7 @@ impl AbilityData {
|
||||
} => {
|
||||
melee_check(*range, *angle, None)
|
||||
&& energy_check(*energy_per_strike * *strikes as f32)
|
||||
&& combo_check(*combo)
|
||||
&& combo_check(*combo, false)
|
||||
},
|
||||
ChargedMelee {
|
||||
range,
|
||||
|
@ -1061,43 +1061,6 @@ impl Animation for ComboAnimation {
|
||||
next.belt.orientation.rotate_z(move2 * -0.6);
|
||||
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") => {
|
||||
let (move1, move2) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time, 0.0),
|
||||
|
@ -402,6 +402,44 @@ impl Animation for FinisherMeleeAnimation {
|
||||
next.control.position += Vec3::new(move2 * 12.0, move2 * -6.0, 0.0);
|
||||
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);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user