mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'aweinstock/mindflayerfixes-202105' into 'master'
Mindflayer AI improvments See merge request veloren/veloren!2285
This commit is contained in:
commit
a86c3af42b
@ -125,6 +125,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Wolf AI will no longer circle into walls and will instead use the power of raycasts to stop early
|
||||
- Squirrels are no longer immune to arrows at some angles.
|
||||
- /spawn command's auto-complete now works for species names
|
||||
- Mindflayer AI now correctly summons husks at certain HP thresholds.
|
||||
|
||||
## [0.9.0] - 2021-03-20
|
||||
|
||||
|
@ -204,6 +204,7 @@
|
||||
secondary: "common.abilities.custom.mindflayer.necroticvortex",
|
||||
abilities: [
|
||||
(None, "common.abilities.custom.mindflayer.dimensionaldoor"),
|
||||
(None, "common.abilities.custom.mindflayer.necroticsphere"),
|
||||
(None, "common.abilities.custom.mindflayer.summonminions"),
|
||||
],
|
||||
),
|
||||
|
12
assets/common/abilities/custom/mindflayer/necroticsphere.ron
Normal file
12
assets/common/abilities/custom/mindflayer/necroticsphere.ron
Normal file
@ -0,0 +1,12 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.75,
|
||||
recover_duration: 0.4,
|
||||
projectile: NecroticSphere(
|
||||
damage: 300.0,
|
||||
radius: 5.0,
|
||||
),
|
||||
projectile_body: Object(FireworkPurple),
|
||||
projectile_speed: 100.0,
|
||||
)
|
||||
|
@ -8,9 +8,5 @@ BasicRanged(
|
||||
energy_regen: 50,
|
||||
),
|
||||
projectile_body: Object(BoltFire),
|
||||
/*projectile_light: Some(LightEmitter {
|
||||
col: (1.0, 0.75, 0.11).into(),
|
||||
..Default::default()
|
||||
}),*/
|
||||
projectile_speed: 60.0,
|
||||
)
|
||||
|
@ -281,6 +281,7 @@ pub struct ActionState {
|
||||
pub timer: f32,
|
||||
pub counter: f32,
|
||||
pub condition: bool,
|
||||
pub int_counter: u8,
|
||||
}
|
||||
|
||||
impl Agent {
|
||||
|
@ -54,6 +54,10 @@ pub enum ProjectileConstructor {
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
},
|
||||
NecroticSphere {
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
},
|
||||
Possess,
|
||||
}
|
||||
|
||||
@ -168,6 +172,32 @@ impl ProjectileConstructor {
|
||||
ignore_group: true,
|
||||
}
|
||||
},
|
||||
NecroticSphere { damage, radius } => {
|
||||
let damage = AttackDamage::new(
|
||||
Damage {
|
||||
source: DamageSource::Explosion,
|
||||
kind: DamageKind::Energy,
|
||||
value: damage,
|
||||
},
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
);
|
||||
let attack = Attack::default()
|
||||
.with_damage(damage)
|
||||
.with_crit(crit_chance, crit_mult)
|
||||
.with_combo_increment();
|
||||
let explosion = Explosion {
|
||||
effects: vec![RadiusEffect::Attack(attack)],
|
||||
radius,
|
||||
reagent: Some(Reagent::Purple),
|
||||
};
|
||||
Projectile {
|
||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||
hit_entity: vec![Effect::Explode(explosion), Effect::Vanish],
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
}
|
||||
},
|
||||
Possess => Projectile {
|
||||
hit_solid: vec![Effect::Stick],
|
||||
hit_entity: vec![Effect::Stick, Effect::Possess],
|
||||
@ -207,6 +237,14 @@ impl ProjectileConstructor {
|
||||
*damage *= power;
|
||||
*radius *= range;
|
||||
},
|
||||
NecroticSphere {
|
||||
ref mut damage,
|
||||
ref mut radius,
|
||||
..
|
||||
} => {
|
||||
*damage *= power;
|
||||
*radius *= range;
|
||||
},
|
||||
Possess => {},
|
||||
}
|
||||
self
|
||||
|
@ -581,9 +581,9 @@ fn handle_ability(data: &JoinData, update: &mut StateUpdate, input: InputKind) {
|
||||
InputKind::Primary => Some(abilities.primary.clone()),
|
||||
InputKind::Secondary => Some(abilities.secondary.clone()),
|
||||
InputKind::Ability(0) => abilities.abilities.get(0).cloned().and_then(unlocked),
|
||||
InputKind::Ability(_) => abilities
|
||||
InputKind::Ability(i) => abilities
|
||||
.abilities
|
||||
.get(skill_index)
|
||||
.get(if i < 2 { skill_index } else { i })
|
||||
.cloned()
|
||||
.and_then(unlocked),
|
||||
InputKind::Roll | InputKind::Jump | InputKind::Fly | InputKind::Block => None,
|
||||
|
@ -22,6 +22,8 @@ common-net = { package = "veloren-common-net", path = "../common/net" }
|
||||
world = { package = "veloren-world", path = "../world" }
|
||||
network = { package = "veloren-network", path = "../network", features = ["metrics", "compression"], default-features = false }
|
||||
|
||||
# inline_tweak = "1.0.8"
|
||||
|
||||
specs = { git = "https://github.com/amethyst/specs.git", features = ["shred-derive"], rev = "5a9b71035007be0e3574f35184acac1cd4530496" }
|
||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "b65fb220e94f5d3c9bc30074a076149763795556" }
|
||||
|
||||
|
@ -2997,8 +2997,9 @@ impl<'a> AgentData<'a> {
|
||||
const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
|
||||
const MINION_SUMMON_THRESHOLD: f32 = 0.20;
|
||||
let health_fraction = self.health.map_or(0.5, |h| h.fraction());
|
||||
// Sets counter at start of combat
|
||||
if agent.action_state.condition {
|
||||
// Sets counter at start of combat, using `condition` to keep track of whether
|
||||
// it was already intitialized
|
||||
if !agent.action_state.condition {
|
||||
agent.action_state.counter = 1.0 - MINION_SUMMON_THRESHOLD;
|
||||
agent.action_state.condition = true;
|
||||
}
|
||||
@ -3007,22 +3008,41 @@ impl<'a> AgentData<'a> {
|
||||
// Summon minions at particular thresholds of health
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||
.push(ControlAction::basic_input(InputKind::Ability(2)));
|
||||
|
||||
if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
|
||||
{
|
||||
agent.action_state.counter -= MINION_SUMMON_THRESHOLD;
|
||||
}
|
||||
} else if mindflayer_is_far {
|
||||
// If too far from target, blink to them.
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target_entity: agent
|
||||
.target
|
||||
.as_ref()
|
||||
.and_then(|t| read_data.uids.get(t.target))
|
||||
.copied(),
|
||||
select_pos: None,
|
||||
});
|
||||
// If too far from target, throw a random number of necrotic spheres at them and
|
||||
// then blink to them.
|
||||
let num_fireballs = &mut agent.action_state.int_counter;
|
||||
if *num_fireballs == 0 {
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(0),
|
||||
target_entity: agent
|
||||
.target
|
||||
.as_ref()
|
||||
.and_then(|t| read_data.uids.get(t.target))
|
||||
.copied(),
|
||||
select_pos: None,
|
||||
});
|
||||
if matches!(self.char_state, CharacterState::Blink(_)) {
|
||||
*num_fireballs = rand::random::<u8>() % 4;
|
||||
}
|
||||
} else if matches!(self.char_state, CharacterState::Wielding) {
|
||||
*num_fireballs -= 1;
|
||||
controller.actions.push(ControlAction::StartInput {
|
||||
input: InputKind::Ability(1),
|
||||
target_entity: agent
|
||||
.target
|
||||
.as_ref()
|
||||
.and_then(|t| read_data.uids.get(t.target))
|
||||
.copied(),
|
||||
select_pos: None,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If close to target, use either primary or secondary ability
|
||||
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(10) && !matches!(c.stage_section, StageSection::Recover))
|
||||
|
@ -117,6 +117,23 @@ impl ParticleMgr {
|
||||
},
|
||||
);
|
||||
},
|
||||
Some(Reagent::Purple) => {
|
||||
self.particles.resize_with(
|
||||
self.particles.len() + (75.0 * power.abs()) as usize,
|
||||
|| {
|
||||
Particle::new_directed(
|
||||
Duration::from_millis(500),
|
||||
time,
|
||||
ParticleMode::CultistFlame,
|
||||
*pos,
|
||||
*pos + Vec3::<f32>::zero()
|
||||
.map(|_| rng.gen_range(-1.0..1.0))
|
||||
.normalized()
|
||||
* *radius,
|
||||
)
|
||||
},
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user