mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Reaching stance AI
This commit is contained in:
parent
9b4dcbfdde
commit
eb67cc2cf7
@ -14,7 +14,7 @@ DashMelee(
|
||||
energy_regen: 0,
|
||||
)),
|
||||
range: 4,
|
||||
angle: 45.0,
|
||||
angle: 15.0,
|
||||
),
|
||||
energy_drain: 20,
|
||||
forward_speed: 3,
|
||||
|
@ -8,8 +8,8 @@ ComboMelee2(
|
||||
knockback: 0,
|
||||
energy_regen: 5,
|
||||
),
|
||||
range: 3.0,
|
||||
angle: 45.0,
|
||||
range: 4.0,
|
||||
angle: 10.0,
|
||||
),
|
||||
buildup_duration: 0.3,
|
||||
swing_duration: 0.1,
|
||||
@ -25,8 +25,8 @@ ComboMelee2(
|
||||
knockback: 0,
|
||||
energy_regen: 8,
|
||||
),
|
||||
range: 3.0,
|
||||
angle: 45.0,
|
||||
range: 5.0,
|
||||
angle: 7.5,
|
||||
),
|
||||
buildup_duration: 0.3,
|
||||
swing_duration: 0.1,
|
||||
@ -36,7 +36,7 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: true,
|
||||
energy_cost_per_strike: 15,
|
||||
energy_cost_per_strike: 5,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
|
@ -3,13 +3,13 @@ RapidMelee(
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.5,
|
||||
melee_constructor: (
|
||||
kind: Slash(
|
||||
damage: 6,
|
||||
kind: Stab(
|
||||
damage: 8,
|
||||
poise: 0,
|
||||
knockback: 0,
|
||||
energy_regen: 5,
|
||||
),
|
||||
range: 3.5,
|
||||
range: 4.5,
|
||||
angle: 10.0,
|
||||
),
|
||||
energy_cost: 10,
|
||||
|
@ -25,7 +25,7 @@ ComboMelee2(
|
||||
),
|
||||
],
|
||||
is_stance: false,
|
||||
energy_cost_per_strike: 20,
|
||||
energy_cost_per_strike: 10,
|
||||
meta: (
|
||||
kind: Some(Sword(Reaching)),
|
||||
),
|
||||
|
@ -503,6 +503,53 @@ impl<'a> AgentData<'a> {
|
||||
&& agent_data.energy.current() >= self.energy
|
||||
}
|
||||
}
|
||||
struct DashMeleeData {
|
||||
range: f32,
|
||||
angle: f32,
|
||||
initial_energy: f32,
|
||||
energy_drain: f32,
|
||||
speed: f32,
|
||||
charge_dur: f32,
|
||||
}
|
||||
impl DashMeleeData {
|
||||
// TODO: Maybe figure out better way of pulling in base accel from body and
|
||||
// accounting for friction?
|
||||
const BASE_SPEED: f32 = 3.0;
|
||||
const ORI_RATE: f32 = 30.0;
|
||||
|
||||
fn could_use(&self, attack_data: &AttackData, agent_data: &AgentData) -> bool {
|
||||
let charge_dur = self.charge_dur(agent_data);
|
||||
let charge_dist = charge_dur * self.speed * Self::BASE_SPEED;
|
||||
let attack_dist = charge_dist + self.range;
|
||||
let ori_gap = Self::ORI_RATE * charge_dur;
|
||||
attack_data.dist_sqrd < attack_dist.powi(2)
|
||||
&& attack_data.angle < self.angle + ori_gap
|
||||
&& agent_data.energy.current() > self.initial_energy
|
||||
}
|
||||
|
||||
fn use_desirable(&self, attack_data: &AttackData, agent_data: &AgentData) -> bool {
|
||||
let charge_dist = self.charge_dur(agent_data) * self.speed * Self::BASE_SPEED;
|
||||
attack_data.dist_sqrd / charge_dist.powi(2) > 0.75_f32.powi(2)
|
||||
}
|
||||
|
||||
fn charge_dur(&self, agent_data: &AgentData) -> f32 {
|
||||
((agent_data.energy.current() - self.initial_energy) / self.energy_drain)
|
||||
.clamp(0.0, self.charge_dur)
|
||||
}
|
||||
}
|
||||
struct RapidMeleeData {
|
||||
range: f32,
|
||||
angle: f32,
|
||||
energy: f32,
|
||||
strikes: u32,
|
||||
}
|
||||
impl RapidMeleeData {
|
||||
fn could_use(&self, attack_data: &AttackData, agent_data: &AgentData) -> bool {
|
||||
attack_data.dist_sqrd < self.range.powi(2)
|
||||
&& attack_data.angle < self.angle
|
||||
&& agent_data.energy.current() > self.energy * self.strikes as f32
|
||||
}
|
||||
}
|
||||
use ability::SwordStance;
|
||||
let stance = |stance| match stance {
|
||||
1 => SwordStance::Offensive,
|
||||
@ -527,9 +574,8 @@ impl<'a> AgentData<'a> {
|
||||
// Hack to make cleaving stance come up less often because agents cannot use it
|
||||
// effectively due to only considering a single target
|
||||
// Remove when agents properly consider multiple targets
|
||||
// 4 + rng.gen_range(0..13) / 3
|
||||
4 + rng.gen_range(0..13) / 3
|
||||
// rng.gen_range(4..9)
|
||||
6
|
||||
} else if self
|
||||
.skill_set
|
||||
.has_skill(Skill::Sword(SwordSkill::OffensiveFinisher))
|
||||
@ -732,6 +778,10 @@ impl<'a> AgentData<'a> {
|
||||
buff: BuffKind::ProtectingWard,
|
||||
energy: 40.0,
|
||||
};
|
||||
const MOBILITY_AGILITY: SelfBuffData = SelfBuffData {
|
||||
buff: BuffKind::Hastened,
|
||||
energy: 40.0,
|
||||
};
|
||||
|
||||
match stance(agent.action_state.int_counter) {
|
||||
SwordStance::Balanced => {
|
||||
@ -941,10 +991,6 @@ impl<'a> AgentData<'a> {
|
||||
angle: 35.0,
|
||||
energy: 10.0,
|
||||
};
|
||||
const MOBILITY_AGILITY: SelfBuffData = SelfBuffData {
|
||||
buff: BuffKind::Hastened,
|
||||
energy: 40.0,
|
||||
};
|
||||
const DESIRED_ENERGY: f32 = 50.0;
|
||||
|
||||
let mut try_roll = || {
|
||||
@ -1452,7 +1498,93 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
SwordStance::Reaching => {
|
||||
fallback_tactics(agent, controller);
|
||||
const REACHING_COMBO: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 0.0,
|
||||
max_range: 4.5,
|
||||
angle: 6.0,
|
||||
energy: 5.0,
|
||||
};
|
||||
const REACHING_CHARGE: DashMeleeData = DashMeleeData {
|
||||
range: 3.5,
|
||||
angle: 12.5,
|
||||
initial_energy: 10.0,
|
||||
energy_drain: 20.0,
|
||||
speed: 3.0,
|
||||
charge_dur: 1.0,
|
||||
};
|
||||
const REACHING_FLURRY: RapidMeleeData = RapidMeleeData {
|
||||
range: 4.0,
|
||||
angle: 7.5,
|
||||
energy: 10.0,
|
||||
strikes: 6,
|
||||
};
|
||||
const REACHING_SKEWER: ComboMeleeData = ComboMeleeData {
|
||||
min_range: 1.0,
|
||||
max_range: 7.5,
|
||||
angle: 7.5,
|
||||
energy: 10.0,
|
||||
};
|
||||
const DESIRED_ENERGY: f32 = 50.0;
|
||||
|
||||
if self.energy.current() < DESIRED_ENERGY {
|
||||
fallback_tactics(agent, controller);
|
||||
} else if MOBILITY_AGILITY.could_use(self) && MOBILITY_AGILITY.use_desirable(self) {
|
||||
if in_stance(SwordStance::Reaching) {
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
} else {
|
||||
controller.push_basic_input(InputKind::Ability(4));
|
||||
}
|
||||
} else if !in_stance(SwordStance::Reaching) {
|
||||
controller.push_basic_input(InputKind::Ability(0));
|
||||
} else if matches!(self.char_state, CharacterState::DashMelee(s) if s.stage_section != StageSection::Recover)
|
||||
|| (REACHING_CHARGE.could_use(attack_data, self)
|
||||
&& REACHING_CHARGE.use_desirable(attack_data, self))
|
||||
{
|
||||
controller.push_basic_input(InputKind::Ability(1));
|
||||
advance(
|
||||
agent,
|
||||
controller,
|
||||
REACHING_CHARGE.range,
|
||||
REACHING_CHARGE.angle,
|
||||
);
|
||||
} else if REACHING_FLURRY.could_use(attack_data, self)
|
||||
&& matches!(
|
||||
tgt_data.char_state.and_then(|cs| cs.stage_section()),
|
||||
Some(StageSection::Buildup)
|
||||
)
|
||||
&& rng.gen::<f32>() < 0.5
|
||||
{
|
||||
controller.push_basic_input(InputKind::Ability(2));
|
||||
advance(
|
||||
agent,
|
||||
controller,
|
||||
REACHING_FLURRY.range,
|
||||
REACHING_FLURRY.angle,
|
||||
);
|
||||
} else if REACHING_SKEWER.could_use(attack_data, self) && rng.gen::<f32>() < 0.33 {
|
||||
controller.push_basic_input(InputKind::Ability(3));
|
||||
advance(
|
||||
agent,
|
||||
controller,
|
||||
REACHING_SKEWER.max_range,
|
||||
REACHING_SKEWER.angle,
|
||||
);
|
||||
} else if REACHING_COMBO.could_use(attack_data, self) {
|
||||
controller.push_basic_input(InputKind::Primary);
|
||||
advance(
|
||||
agent,
|
||||
controller,
|
||||
REACHING_COMBO.max_range,
|
||||
REACHING_COMBO.angle,
|
||||
);
|
||||
} else {
|
||||
advance(
|
||||
agent,
|
||||
controller,
|
||||
REACHING_COMBO.max_range,
|
||||
REACHING_COMBO.angle,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user