mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Simple AI for each of the stances.
This commit is contained in:
parent
43d7e9357a
commit
1edd064611
@ -795,7 +795,7 @@ impl<'a> AgentData<'a> {
|
|||||||
e
|
e
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
controller.events.reserve(32);
|
||||||
attack_fn(self, agent, controller, tgt_data, read_data);
|
attack_fn(self, agent, controller, tgt_data, read_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{consts::MAX_PATH_DIST, data::*, util::entities_have_line_of_sight};
|
use crate::{consts::MAX_PATH_DIST, data::*, util::entities_have_line_of_sight};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
ability::{ActiveAbilities, AuxiliaryAbility},
|
ability::{ActiveAbilities, AuxiliaryAbility, Stance, SwordStance},
|
||||||
buff::BuffKind,
|
buff::BuffKind,
|
||||||
item::tool::AbilityContext,
|
item::tool::AbilityContext,
|
||||||
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
|
skills::{AxeSkill, BowSkill, HammerSkill, SceptreSkill, Skill, StaffSkill, SwordSkill},
|
||||||
@ -510,6 +510,7 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !agent.action_state.initialized {
|
if !agent.action_state.initialized {
|
||||||
|
agent.action_state.initialized = true;
|
||||||
let available_tactics = {
|
let available_tactics = {
|
||||||
let mut tactics = Vec::new();
|
let mut tactics = Vec::new();
|
||||||
let try_tactic = |skill, tactic, tactics: &mut Vec<SwordTactics>| {
|
let try_tactic = |skill, tactic, tactics: &mut Vec<SwordTactics>| {
|
||||||
@ -542,33 +543,33 @@ impl<'a> AgentData<'a> {
|
|||||||
// SwordTactics::CleavingAdvanced,
|
// SwordTactics::CleavingAdvanced,
|
||||||
// &mut tactics,
|
// &mut tactics,
|
||||||
// );
|
// );
|
||||||
// if tactics.is_empty() {
|
if tactics.is_empty() {
|
||||||
// try_tactic(
|
try_tactic(
|
||||||
// SwordSkill::HeavyWindmillSlash,
|
SwordSkill::HeavyWindmillSlash,
|
||||||
// SwordTactics::HeavySimple,
|
SwordTactics::HeavySimple,
|
||||||
// &mut tactics,
|
&mut tactics,
|
||||||
// );
|
);
|
||||||
// try_tactic(
|
try_tactic(
|
||||||
// SwordSkill::AgileQuickDraw,
|
SwordSkill::AgileQuickDraw,
|
||||||
// SwordTactics::AgileSimple,
|
SwordTactics::AgileSimple,
|
||||||
// &mut tactics,
|
&mut tactics,
|
||||||
// );
|
);
|
||||||
// try_tactic(
|
try_tactic(
|
||||||
// SwordSkill::DefensiveDisengage,
|
SwordSkill::DefensiveDisengage,
|
||||||
// SwordTactics::DefensiveSimple,
|
SwordTactics::DefensiveSimple,
|
||||||
// &mut tactics,
|
&mut tactics,
|
||||||
// );
|
);
|
||||||
// try_tactic(
|
try_tactic(
|
||||||
// SwordSkill::CripplingGouge,
|
SwordSkill::CripplingGouge,
|
||||||
// SwordTactics::CripplingSimple,
|
SwordTactics::CripplingSimple,
|
||||||
// &mut tactics,
|
&mut tactics,
|
||||||
// );
|
);
|
||||||
// try_tactic(
|
try_tactic(
|
||||||
// SwordSkill::CleavingWhirlwindSlice,
|
SwordSkill::CleavingWhirlwindSlice,
|
||||||
// SwordTactics::CleavingSimple,
|
SwordTactics::CleavingSimple,
|
||||||
// &mut tactics,
|
&mut tactics,
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
if tactics.is_empty() {
|
if tactics.is_empty() {
|
||||||
try_tactic(SwordSkill::CrescentSlash, SwordTactics::Basic, &mut tactics);
|
try_tactic(SwordSkill::CrescentSlash, SwordTactics::Basic, &mut tactics);
|
||||||
}
|
}
|
||||||
@ -586,147 +587,147 @@ impl<'a> AgentData<'a> {
|
|||||||
agent.action_state.int_counters[IntCounters::Tactics as usize] = tactic as u8;
|
agent.action_state.int_counters[IntCounters::Tactics as usize] = tactic as u8;
|
||||||
|
|
||||||
let auxiliary_key = ActiveAbilities::active_auxiliary_key(Some(self.inventory));
|
let auxiliary_key = ActiveAbilities::active_auxiliary_key(Some(self.inventory));
|
||||||
let mut set_sword_ability = |slot, skill| {
|
let mut set_sword_ability = |controller: &mut Controller, slot, skill| {
|
||||||
controller.push_event(ControlEvent::ChangeAbility {
|
controller.push_event(ControlEvent::ChangeAbility {
|
||||||
slot,
|
slot,
|
||||||
auxiliary_key,
|
auxiliary_key,
|
||||||
new_ability: AuxiliaryAbility::MainWeapon(skill),
|
new_ability: AuxiliaryAbility::MainWeapon(skill),
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
match tactic {
|
match tactic {
|
||||||
SwordTactics::Unskilled => {},
|
SwordTactics::Unskilled => {},
|
||||||
SwordTactics::Basic => {
|
SwordTactics::Basic => {
|
||||||
// Crescent slash
|
// Crescent slash
|
||||||
set_sword_ability(0, 0);
|
set_sword_ability(controller, 0, 0);
|
||||||
// Fell strike
|
// Fell strike
|
||||||
set_sword_ability(1, 1);
|
set_sword_ability(controller, 1, 1);
|
||||||
// Skewer
|
// Skewer
|
||||||
set_sword_ability(2, 2);
|
set_sword_ability(controller, 2, 2);
|
||||||
// Cascade
|
// Cascade
|
||||||
set_sword_ability(3, 3);
|
set_sword_ability(controller, 3, 3);
|
||||||
// Cross cut
|
// Cross cut
|
||||||
set_sword_ability(4, 4);
|
set_sword_ability(controller, 4, 4);
|
||||||
},
|
},
|
||||||
SwordTactics::HeavySimple => {
|
SwordTactics::HeavySimple => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Crescent slash
|
// Crescent slash
|
||||||
set_sword_ability(1, 0);
|
set_sword_ability(controller, 1, 0);
|
||||||
// Cascade
|
// Cascade
|
||||||
set_sword_ability(2, 3);
|
set_sword_ability(controller, 2, 3);
|
||||||
// Windmill slash
|
// Windmill slash
|
||||||
set_sword_ability(3, 6);
|
set_sword_ability(controller, 3, 6);
|
||||||
// Pommel strike
|
// Pommel strike
|
||||||
set_sword_ability(4, 7);
|
set_sword_ability(controller, 4, 7);
|
||||||
},
|
},
|
||||||
SwordTactics::AgileSimple => {
|
SwordTactics::AgileSimple => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Skewer
|
// Skewer
|
||||||
set_sword_ability(1, 2);
|
set_sword_ability(controller, 1, 2);
|
||||||
// Cross cut
|
// Cross cut
|
||||||
set_sword_ability(2, 4);
|
set_sword_ability(controller, 2, 4);
|
||||||
// Quick draw
|
// Quick draw
|
||||||
set_sword_ability(3, 8);
|
set_sword_ability(controller, 3, 8);
|
||||||
// Feint
|
// Feint
|
||||||
set_sword_ability(4, 9);
|
set_sword_ability(controller, 4, 9);
|
||||||
},
|
},
|
||||||
SwordTactics::DefensiveSimple => {
|
SwordTactics::DefensiveSimple => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Crescent slash
|
// Crescent slash
|
||||||
set_sword_ability(1, 0);
|
set_sword_ability(controller, 1, 0);
|
||||||
// Fell strike
|
// Fell strike
|
||||||
set_sword_ability(2, 1);
|
set_sword_ability(controller, 2, 1);
|
||||||
// Riposte
|
// Riposte
|
||||||
set_sword_ability(3, 10);
|
set_sword_ability(controller, 3, 10);
|
||||||
// Disengage
|
// Disengage
|
||||||
set_sword_ability(4, 11);
|
set_sword_ability(controller, 4, 11);
|
||||||
},
|
},
|
||||||
SwordTactics::CripplingSimple => {
|
SwordTactics::CripplingSimple => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Fell strike
|
// Fell strike
|
||||||
set_sword_ability(1, 1);
|
set_sword_ability(controller, 1, 1);
|
||||||
// Skewer
|
// Skewer
|
||||||
set_sword_ability(2, 2);
|
set_sword_ability(controller, 2, 2);
|
||||||
// Gouge
|
// Gouge
|
||||||
set_sword_ability(3, 12);
|
set_sword_ability(controller, 3, 12);
|
||||||
// Hamstring
|
// Hamstring
|
||||||
set_sword_ability(4, 13);
|
set_sword_ability(controller, 4, 13);
|
||||||
},
|
},
|
||||||
SwordTactics::CleavingSimple => {
|
SwordTactics::CleavingSimple => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Cascade
|
// Cascade
|
||||||
set_sword_ability(1, 3);
|
set_sword_ability(controller, 1, 3);
|
||||||
// Cross cut
|
// Cross cut
|
||||||
set_sword_ability(2, 4);
|
set_sword_ability(controller, 2, 4);
|
||||||
// Whirlwind slice
|
// Whirlwind slice
|
||||||
set_sword_ability(3, 14);
|
set_sword_ability(controller, 3, 14);
|
||||||
// Earth splitter
|
// Earth splitter
|
||||||
set_sword_ability(4, 15);
|
set_sword_ability(controller, 4, 15);
|
||||||
},
|
},
|
||||||
SwordTactics::HeavyAdvanced => {
|
SwordTactics::HeavyAdvanced => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Windmill slash
|
// Windmill slash
|
||||||
set_sword_ability(1, 6);
|
set_sword_ability(controller, 1, 6);
|
||||||
// Pommel strike
|
// Pommel strike
|
||||||
set_sword_ability(2, 7);
|
set_sword_ability(controller, 2, 7);
|
||||||
// Fortitude
|
// Fortitude
|
||||||
set_sword_ability(3, 16);
|
set_sword_ability(controller, 3, 16);
|
||||||
// Pillar Thrust
|
// Pillar Thrust
|
||||||
set_sword_ability(4, 17);
|
set_sword_ability(controller, 4, 17);
|
||||||
},
|
},
|
||||||
SwordTactics::AgileAdvanced => {
|
SwordTactics::AgileAdvanced => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Quick draw
|
// Quick draw
|
||||||
set_sword_ability(1, 8);
|
set_sword_ability(controller, 1, 8);
|
||||||
// Feint
|
// Feint
|
||||||
set_sword_ability(2, 9);
|
set_sword_ability(controller, 2, 9);
|
||||||
// Dancing edge
|
// Dancing edge
|
||||||
set_sword_ability(3, 18);
|
set_sword_ability(controller, 3, 18);
|
||||||
// Flurry
|
// Flurry
|
||||||
set_sword_ability(4, 19);
|
set_sword_ability(controller, 4, 19);
|
||||||
},
|
},
|
||||||
SwordTactics::DefensiveAdvanced => {
|
SwordTactics::DefensiveAdvanced => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Riposte
|
// Riposte
|
||||||
set_sword_ability(1, 10);
|
set_sword_ability(controller, 1, 10);
|
||||||
// Disengage
|
// Disengage
|
||||||
set_sword_ability(2, 11);
|
set_sword_ability(controller, 2, 11);
|
||||||
// Stalwart sword
|
// Stalwart sword
|
||||||
set_sword_ability(3, 20);
|
set_sword_ability(controller, 3, 20);
|
||||||
// Deflect
|
// Deflect
|
||||||
set_sword_ability(4, 21);
|
set_sword_ability(controller, 4, 21);
|
||||||
},
|
},
|
||||||
SwordTactics::CripplingAdvanced => {
|
SwordTactics::CripplingAdvanced => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Gouge
|
// Gouge
|
||||||
set_sword_ability(1, 12);
|
set_sword_ability(controller, 1, 12);
|
||||||
// Hamstring
|
// Hamstring
|
||||||
set_sword_ability(2, 13);
|
set_sword_ability(controller, 2, 13);
|
||||||
// Eviscerate
|
// Eviscerate
|
||||||
set_sword_ability(3, 22);
|
set_sword_ability(controller, 3, 22);
|
||||||
// Bloody gash
|
// Bloody gash
|
||||||
set_sword_ability(4, 23);
|
set_sword_ability(controller, 4, 23);
|
||||||
},
|
},
|
||||||
SwordTactics::CleavingAdvanced => {
|
SwordTactics::CleavingAdvanced => {
|
||||||
// Finisher
|
// Finisher
|
||||||
set_sword_ability(0, 5);
|
set_sword_ability(controller, 0, 5);
|
||||||
// Whirlwind slice
|
// Whirlwind slice
|
||||||
set_sword_ability(1, 14);
|
set_sword_ability(controller, 1, 14);
|
||||||
// Earth splitter
|
// Earth splitter
|
||||||
set_sword_ability(2, 15);
|
set_sword_ability(controller, 2, 15);
|
||||||
// Blade fever
|
// Blade fever
|
||||||
set_sword_ability(3, 24);
|
set_sword_ability(controller, 3, 24);
|
||||||
// Sky splitter
|
// Sky splitter
|
||||||
set_sword_ability(4, 25);
|
set_sword_ability(controller, 4, 25);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1047,15 +1048,15 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let could_use_input = |input, misc_data| match input {
|
let could_use_input = |input, misc_data| match input {
|
||||||
InputKind::Primary => primary
|
InputKind::Primary => primary.as_ref().map_or(false, |p| {
|
||||||
.as_ref()
|
p.could_use(attack_data, self, misc_data, tgt_data)
|
||||||
.map_or(false, |p| p.could_use(attack_data, self, misc_data)),
|
}),
|
||||||
InputKind::Secondary => secondary
|
InputKind::Secondary => secondary.as_ref().map_or(false, |s| {
|
||||||
.as_ref()
|
s.could_use(attack_data, self, misc_data, tgt_data)
|
||||||
.map_or(false, |s| s.could_use(attack_data, self, misc_data)),
|
}),
|
||||||
InputKind::Ability(x) => abilities[x]
|
InputKind::Ability(x) => abilities[x].as_ref().map_or(false, |a| {
|
||||||
.as_ref()
|
a.could_use(attack_data, self, misc_data, tgt_data)
|
||||||
.map_or(false, |a| a.could_use(attack_data, self, misc_data)),
|
}),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
match SwordTactics::from_u8(
|
match SwordTactics::from_u8(
|
||||||
@ -1148,11 +1149,298 @@ impl<'a> AgentData<'a> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SwordTactics::HeavySimple => true,
|
SwordTactics::HeavySimple => {
|
||||||
SwordTactics::AgileSimple => true,
|
let misc_data = MiscData {
|
||||||
SwordTactics::DefensiveSimple => true,
|
desired_energy: 25.0,
|
||||||
SwordTactics::CripplingSimple => true,
|
};
|
||||||
SwordTactics::CleavingSimple => true,
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
|
let mut next_input = None;
|
||||||
|
if let Some(input) = current_input {
|
||||||
|
if let 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(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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, &misc_data) {
|
||||||
|
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), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(0));
|
||||||
|
} else if could_use_input(random_ability, &misc_data) {
|
||||||
|
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, &misc_data) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SwordTactics::AgileSimple => {
|
||||||
|
let misc_data = MiscData {
|
||||||
|
desired_energy: 25.0,
|
||||||
|
};
|
||||||
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
|
let mut next_input = None;
|
||||||
|
if let Some(input) = current_input {
|
||||||
|
if let 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(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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, &misc_data) {
|
||||||
|
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), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(0));
|
||||||
|
} else if could_use_input(random_ability, &misc_data) {
|
||||||
|
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, &misc_data) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SwordTactics::DefensiveSimple => {
|
||||||
|
let misc_data = MiscData {
|
||||||
|
desired_energy: 25.0,
|
||||||
|
};
|
||||||
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
|
let mut next_input = None;
|
||||||
|
if let Some(input) = current_input {
|
||||||
|
if let 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(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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, &misc_data) {
|
||||||
|
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), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(0));
|
||||||
|
} else if could_use_input(InputKind::Ability(3), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(3));
|
||||||
|
} else if could_use_input(random_ability, &misc_data) {
|
||||||
|
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, &misc_data) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SwordTactics::CripplingSimple => {
|
||||||
|
let misc_data = MiscData {
|
||||||
|
desired_energy: 25.0,
|
||||||
|
};
|
||||||
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
|
let mut next_input = None;
|
||||||
|
if let Some(input) = current_input {
|
||||||
|
if let 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(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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, &misc_data) {
|
||||||
|
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), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(0));
|
||||||
|
} else if could_use_input(random_ability, &misc_data) {
|
||||||
|
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, &misc_data) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SwordTactics::CleavingSimple => {
|
||||||
|
let misc_data = MiscData {
|
||||||
|
desired_energy: 25.0,
|
||||||
|
};
|
||||||
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
|
let mut next_input = None;
|
||||||
|
if let Some(input) = current_input {
|
||||||
|
if let 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(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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, &misc_data) {
|
||||||
|
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), &misc_data) {
|
||||||
|
next_input = Some(InputKind::Ability(0));
|
||||||
|
} else if could_use_input(random_ability, &misc_data) {
|
||||||
|
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, &misc_data) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
SwordTactics::HeavyAdvanced => true,
|
SwordTactics::HeavyAdvanced => true,
|
||||||
SwordTactics::AgileAdvanced => true,
|
SwordTactics::AgileAdvanced => true,
|
||||||
SwordTactics::DefensiveAdvanced => true,
|
SwordTactics::DefensiveAdvanced => true,
|
||||||
|
@ -13,7 +13,7 @@ use common::{
|
|||||||
path::TraversalConfig,
|
path::TraversalConfig,
|
||||||
resources::{DeltaTime, Time, TimeOfDay},
|
resources::{DeltaTime, Time, TimeOfDay},
|
||||||
rtsim::RtSimEntity,
|
rtsim::RtSimEntity,
|
||||||
states::utils::ForcedMovement,
|
states::utils::{ForcedMovement, StageSection},
|
||||||
terrain::TerrainGrid,
|
terrain::TerrainGrid,
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
};
|
};
|
||||||
@ -195,6 +195,7 @@ pub enum Path {
|
|||||||
Partial,
|
Partial,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum AbilityData {
|
pub enum AbilityData {
|
||||||
ComboMelee {
|
ComboMelee {
|
||||||
range: f32,
|
range: f32,
|
||||||
@ -239,6 +240,11 @@ pub enum AbilityData {
|
|||||||
energy_drain: f32,
|
energy_drain: f32,
|
||||||
charge_dur: f32,
|
charge_dur: f32,
|
||||||
},
|
},
|
||||||
|
RiposteMelee {
|
||||||
|
range: f32,
|
||||||
|
angle: f32,
|
||||||
|
energy: f32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MiscData {
|
pub struct MiscData {
|
||||||
@ -346,6 +352,15 @@ impl AbilityData {
|
|||||||
range: melee_constructor.range,
|
range: melee_constructor.range,
|
||||||
angle: melee_constructor.angle,
|
angle: melee_constructor.angle,
|
||||||
},
|
},
|
||||||
|
RiposteMelee {
|
||||||
|
energy_cost,
|
||||||
|
melee_constructor,
|
||||||
|
..
|
||||||
|
} => Self::RiposteMelee {
|
||||||
|
energy: *energy_cost,
|
||||||
|
range: melee_constructor.range,
|
||||||
|
angle: melee_constructor.angle,
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(inner)
|
Some(inner)
|
||||||
@ -356,6 +371,7 @@ impl AbilityData {
|
|||||||
attack_data: &AttackData,
|
attack_data: &AttackData,
|
||||||
agent_data: &AgentData,
|
agent_data: &AgentData,
|
||||||
misc_data: &MiscData,
|
misc_data: &MiscData,
|
||||||
|
tgt_data: &TargetData,
|
||||||
) -> 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 = forced_movement.map_or(0.0, |fm| match fm {
|
let range_inc = forced_movement.map_or(0.0, |fm| match fm {
|
||||||
@ -442,6 +458,25 @@ impl AbilityData {
|
|||||||
melee_check(*range, *angle, None)
|
melee_check(*range, *angle, None)
|
||||||
&& energy_check(*initial_energy + *energy_drain * *charge_dur)
|
&& energy_check(*initial_energy + *energy_drain * *charge_dur)
|
||||||
},
|
},
|
||||||
|
RiposteMelee {
|
||||||
|
energy,
|
||||||
|
range,
|
||||||
|
angle,
|
||||||
|
} => {
|
||||||
|
melee_check(*range, *angle, None)
|
||||||
|
&& energy_check(*energy)
|
||||||
|
&& tgt_data.char_state.map_or(false, |cs| {
|
||||||
|
cs.is_melee_attack()
|
||||||
|
&& matches!(
|
||||||
|
cs.stage_section(),
|
||||||
|
Some(
|
||||||
|
StageSection::Buildup
|
||||||
|
| StageSection::Charge
|
||||||
|
| StageSection::Movement
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user