mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Unskilled sword AI
This commit is contained in:
parent
387ea16598
commit
c4154b0160
@ -517,61 +517,61 @@ impl<'a> AgentData<'a> {
|
|||||||
tactics.push(tactic);
|
tactics.push(tactic);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try_tactic(
|
// try_tactic(
|
||||||
SwordSkill::HeavyFortitude,
|
// SwordSkill::HeavyFortitude,
|
||||||
SwordTactics::HeavyAdvanced,
|
// SwordTactics::HeavyAdvanced,
|
||||||
&mut tactics,
|
// &mut tactics,
|
||||||
);
|
// );
|
||||||
try_tactic(
|
// try_tactic(
|
||||||
SwordSkill::AgileDancingEdge,
|
// SwordSkill::AgileDancingEdge,
|
||||||
SwordTactics::AgileAdvanced,
|
// SwordTactics::AgileAdvanced,
|
||||||
&mut tactics,
|
// &mut tactics,
|
||||||
);
|
// );
|
||||||
try_tactic(
|
// try_tactic(
|
||||||
SwordSkill::DefensiveStalwartSword,
|
// SwordSkill::DefensiveStalwartSword,
|
||||||
SwordTactics::DefensiveAdvanced,
|
// SwordTactics::DefensiveAdvanced,
|
||||||
&mut tactics,
|
// &mut tactics,
|
||||||
);
|
// );
|
||||||
try_tactic(
|
// try_tactic(
|
||||||
SwordSkill::CripplingEviscerate,
|
// SwordSkill::CripplingEviscerate,
|
||||||
SwordTactics::CripplingAdvanced,
|
// SwordTactics::CripplingAdvanced,
|
||||||
&mut tactics,
|
// &mut tactics,
|
||||||
);
|
// );
|
||||||
try_tactic(
|
// try_tactic(
|
||||||
SwordSkill::CleavingBladeFever,
|
// SwordSkill::CleavingBladeFever,
|
||||||
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);
|
||||||
}
|
// }
|
||||||
if tactics.is_empty() {
|
if tactics.is_empty() {
|
||||||
tactics.push(SwordTactics::Unskilled);
|
tactics.push(SwordTactics::Unskilled);
|
||||||
}
|
}
|
||||||
@ -753,10 +753,10 @@ impl<'a> AgentData<'a> {
|
|||||||
|
|
||||||
if let Some(health) = self.health {
|
if let Some(health) = self.health {
|
||||||
agent.action_state.int_counters[IntCounters::ActionMode as usize] =
|
agent.action_state.int_counters[IntCounters::ActionMode as usize] =
|
||||||
if health.fraction() < 0.25 {
|
if health.fraction() < 0.2 {
|
||||||
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
agent.action_state.positions[Positions::GuardedCover as usize] = None;
|
||||||
ActionMode::Fleeing as u8
|
ActionMode::Fleeing as u8
|
||||||
} else if health.fraction() < 0.75 {
|
} else if health.fraction() < 0.9 {
|
||||||
agent.action_state.positions[Positions::Flee as usize] = None;
|
agent.action_state.positions[Positions::Flee as usize] = None;
|
||||||
ActionMode::Guarded as u8
|
ActionMode::Guarded as u8
|
||||||
} else {
|
} else {
|
||||||
@ -769,6 +769,7 @@ impl<'a> AgentData<'a> {
|
|||||||
enum IntCounters {
|
enum IntCounters {
|
||||||
Tactics = 0,
|
Tactics = 0,
|
||||||
ActionMode = 1,
|
ActionMode = 1,
|
||||||
|
NextInput = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Timers {
|
enum Timers {
|
||||||
@ -779,6 +780,7 @@ impl<'a> AgentData<'a> {
|
|||||||
enum Conditions {
|
enum Conditions {
|
||||||
GuardedAttack = 0,
|
GuardedAttack = 0,
|
||||||
RollingBreakThrough = 1,
|
RollingBreakThrough = 1,
|
||||||
|
TacticMisc = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FloatCounters {
|
enum FloatCounters {
|
||||||
@ -990,7 +992,7 @@ impl<'a> AgentData<'a> {
|
|||||||
- 1.0;
|
- 1.0;
|
||||||
agent.action_state.conditions
|
agent.action_state.conditions
|
||||||
[Conditions::RollingBreakThrough as usize] = true;
|
[Conditions::RollingBreakThrough as usize] = true;
|
||||||
Some(self.pos.0 - rand_dir * actual_dist)
|
Some(self.pos.0 - rand_dir * dist)
|
||||||
} else {
|
} else {
|
||||||
Some(self.pos.0 + rand_dir * actual_dist)
|
Some(self.pos.0 + rand_dir * actual_dist)
|
||||||
}
|
}
|
||||||
@ -1027,23 +1029,85 @@ impl<'a> AgentData<'a> {
|
|||||||
extract_ability(AbilityInput::Auxiliary(3)),
|
extract_ability(AbilityInput::Auxiliary(3)),
|
||||||
extract_ability(AbilityInput::Auxiliary(4)),
|
extract_ability(AbilityInput::Auxiliary(4)),
|
||||||
];
|
];
|
||||||
|
fn input_from_u8(x: u8) -> Option<InputKind> {
|
||||||
|
let input = match x {
|
||||||
|
x @ 0..5 => InputKind::Ability(x as usize),
|
||||||
|
6 => InputKind::Primary,
|
||||||
|
7 => InputKind::Secondary,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(input)
|
||||||
|
}
|
||||||
|
fn input_to_u8(input: InputKind) -> u8 {
|
||||||
|
match input {
|
||||||
|
InputKind::Ability(x) => x as u8,
|
||||||
|
InputKind::Primary => 6,
|
||||||
|
InputKind::Secondary => 7,
|
||||||
|
_ => 255,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let could_use_input = |input| match input {
|
||||||
|
InputKind::Primary => primary.map_or(false, |p| p.could_use(attack_data, self)),
|
||||||
|
InputKind::Secondary => secondary.map_or(false, |s| s.could_use(attack_data, self)),
|
||||||
|
InputKind::Ability(x) => abilities[x]
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |a| a.could_use(attack_data, self)),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
match SwordTactics::from_u8(
|
match SwordTactics::from_u8(
|
||||||
agent.action_state.int_counters[IntCounters::Tactics as usize],
|
agent.action_state.int_counters[IntCounters::Tactics as usize],
|
||||||
) {
|
) {
|
||||||
SwordTactics::Unskilled => {},
|
SwordTactics::Unskilled => {
|
||||||
SwordTactics::Basic => {},
|
let current_input = self.char_state.ability_info().map(|ai| ai.input);
|
||||||
SwordTactics::HeavySimple => {},
|
let mut next_input = None;
|
||||||
SwordTactics::AgileSimple => {},
|
if let Some(input) = current_input {
|
||||||
SwordTactics::DefensiveSimple => {},
|
if let input = InputKind::Secondary {
|
||||||
SwordTactics::CripplingSimple => {},
|
let charging = matches!(
|
||||||
SwordTactics::CleavingSimple => {},
|
self.char_state.stage_section(),
|
||||||
SwordTactics::HeavyAdvanced => {},
|
Some(StageSection::Charge)
|
||||||
SwordTactics::AgileAdvanced => {},
|
);
|
||||||
SwordTactics::DefensiveAdvanced => {},
|
let charged = self
|
||||||
SwordTactics::CripplingAdvanced => {},
|
.char_state
|
||||||
SwordTactics::CleavingAdvanced => {},
|
.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 {
|
||||||
|
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) {
|
||||||
|
controller.push_basic_input(input);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SwordTactics::Basic => true,
|
||||||
|
SwordTactics::HeavySimple => true,
|
||||||
|
SwordTactics::AgileSimple => true,
|
||||||
|
SwordTactics::DefensiveSimple => true,
|
||||||
|
SwordTactics::CripplingSimple => true,
|
||||||
|
SwordTactics::CleavingSimple => true,
|
||||||
|
SwordTactics::HeavyAdvanced => true,
|
||||||
|
SwordTactics::AgileAdvanced => true,
|
||||||
|
SwordTactics::DefensiveAdvanced => true,
|
||||||
|
SwordTactics::CripplingAdvanced => true,
|
||||||
|
SwordTactics::CleavingAdvanced => true,
|
||||||
}
|
}
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
@ -230,6 +230,13 @@ pub enum AbilityData {
|
|||||||
strikes: u32,
|
strikes: u32,
|
||||||
combo: u32,
|
combo: u32,
|
||||||
},
|
},
|
||||||
|
ChargedMelee {
|
||||||
|
range: f32,
|
||||||
|
angle: f32,
|
||||||
|
initial_energy: f32,
|
||||||
|
energy_drain: f32,
|
||||||
|
charge_dur: f32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbilityData {
|
impl AbilityData {
|
||||||
@ -310,6 +317,19 @@ impl AbilityData {
|
|||||||
strikes: max_strikes.unwrap_or(100),
|
strikes: max_strikes.unwrap_or(100),
|
||||||
combo: *minimum_combo,
|
combo: *minimum_combo,
|
||||||
},
|
},
|
||||||
|
ChargedMelee {
|
||||||
|
energy_cost,
|
||||||
|
energy_drain,
|
||||||
|
charge_duration,
|
||||||
|
melee_constructor,
|
||||||
|
..
|
||||||
|
} => Self::ChargedMelee {
|
||||||
|
initial_energy: *energy_cost,
|
||||||
|
energy_drain: *energy_drain,
|
||||||
|
charge_dur: *charge_duration,
|
||||||
|
range: melee_constructor.range,
|
||||||
|
angle: melee_constructor.angle,
|
||||||
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(inner)
|
Some(inner)
|
||||||
@ -379,6 +399,16 @@ impl AbilityData {
|
|||||||
&& energy_check(*energy_per_strike * *strikes as f32)
|
&& energy_check(*energy_per_strike * *strikes as f32)
|
||||||
&& combo_check(*combo)
|
&& combo_check(*combo)
|
||||||
},
|
},
|
||||||
|
ChargedMelee {
|
||||||
|
range,
|
||||||
|
angle,
|
||||||
|
initial_energy,
|
||||||
|
energy_drain,
|
||||||
|
charge_dur,
|
||||||
|
} => {
|
||||||
|
melee_check(*range, *angle)
|
||||||
|
&& energy_check(*initial_energy + *energy_drain * *charge_dur)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#![feature(exclusive_range_pattern)]
|
||||||
|
|
||||||
#[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
|
#[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
|
||||||
compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
|
compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user