Merge branch 'sam/mindflayer-balancing' into 'master'

Mindflayer balance tweaks.

See merge request veloren/veloren!2031
This commit is contained in:
Samuel Keiffer 2021-03-29 21:05:49 +00:00
commit 12ec46c572
6 changed files with 44 additions and 26 deletions

View File

@ -1,5 +1,5 @@
Blink( Blink(
buildup_duration: 0.5, buildup_duration: 0.75,
recover_duration: 0.25, recover_duration: 0.25,
max_range: 100.0, max_range: 100.0,
) )

View File

@ -2,10 +2,10 @@ SpinMelee(
buildup_duration: 0.5, buildup_duration: 0.5,
swing_duration: 0.2, swing_duration: 0.2,
recover_duration: 0.6, recover_duration: 0.6,
base_damage: 70.0, base_damage: 80.0,
base_poise_damage: 0.0, base_poise_damage: 1.0,
knockback: ( strength: 8.0, direction: Towards), knockback: ( strength: 7.0, direction: Towards),
range: 17.5, range: 16.0,
damage_effect: Some(Lifesteal(1.0)), damage_effect: Some(Lifesteal(1.0)),
energy_cost: 0.0, energy_cost: 0.0,
is_infinite: true, is_infinite: true,

View File

@ -1364,7 +1364,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
specifier: *specifier, specifier: *specifier,
}, },
timer: Duration::default(), timer: Duration::default(),
spins_remaining: *num_spins - 1, consecutive_spins: 1,
stage_section: StageSection::Buildup, stage_section: StageSection::Buildup,
exhausted: false, exhausted: false,
}), }),

View File

@ -60,8 +60,8 @@ pub struct Data {
pub static_data: StaticData, pub static_data: StaticData,
/// Timer for each stage /// Timer for each stage
pub timer: Duration, pub timer: Duration,
/// How many spins it can do before ending /// How many spins it has done
pub spins_remaining: u32, pub consecutive_spins: u32,
/// What section the character stage is in /// What section the character stage is in
pub stage_section: StageSection, pub stage_section: StageSection,
/// Whether the state can deal damage /// Whether the state can deal damage
@ -187,18 +187,13 @@ impl CharacterBehavior for Data {
..*self ..*self
}); });
} else if update.energy.current() as f32 >= self.static_data.energy_cost } else if update.energy.current() as f32 >= self.static_data.energy_cost
&& (self.spins_remaining != 0 && (self.consecutive_spins < self.static_data.num_spins
|| (self.static_data.is_infinite || (self.static_data.is_infinite
&& input_is_pressed(data, self.static_data.ability_info.input))) && input_is_pressed(data, self.static_data.ability_info.input)))
{ {
let new_spins_remaining = if self.static_data.is_infinite {
self.spins_remaining
} else {
self.spins_remaining - 1
};
update.character = CharacterState::SpinMelee(Data { update.character = CharacterState::SpinMelee(Data {
timer: Duration::default(), timer: Duration::default(),
spins_remaining: new_spins_remaining, consecutive_spins: self.consecutive_spins + 1,
exhausted: false, exhausted: false,
..*self ..*self
}); });

View File

@ -22,6 +22,7 @@ use common::{
path::TraversalConfig, path::TraversalConfig,
resources::{DeltaTime, Time, TimeOfDay}, resources::{DeltaTime, Time, TimeOfDay},
rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent}, rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent},
states::utils::StageSection,
terrain::{Block, TerrainGrid}, terrain::{Block, TerrainGrid},
time::DayPeriod, time::DayPeriod,
trade::{TradeAction, TradePhase, TradeResult}, trade::{TradeAction, TradePhase, TradeResult},
@ -39,7 +40,7 @@ use specs::{
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World, Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World,
Write, WriteExpect, WriteStorage, Write, WriteExpect, WriteStorage,
}; };
use std::{f32::consts::PI, sync::Arc}; use std::{f32::consts::PI, sync::Arc, time::Duration};
use vek::*; use vek::*;
struct AgentData<'a> { struct AgentData<'a> {
@ -2370,7 +2371,7 @@ impl<'a> AgentData<'a> {
} }
}, },
Tactic::Mindflayer => { Tactic::Mindflayer => {
const MINDFLAYER_ATTACK_DIST: f32 = 17.5; const MINDFLAYER_ATTACK_DIST: f32 = 16.0;
const MINION_SUMMON_THRESHOLD: f32 = 0.20; const MINION_SUMMON_THRESHOLD: f32 = 0.20;
let health_fraction = self.health.map_or(0.5, |h| h.fraction()); let health_fraction = self.health.map_or(0.5, |h| h.fraction());
// Extreme hack to set action_timer at start of combat // Extreme hack to set action_timer at start of combat
@ -2382,10 +2383,11 @@ impl<'a> AgentData<'a> {
let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2);
if agent.action_timer > health_fraction { if agent.action_timer > health_fraction {
// Summon minions at particular thresholds of health // Summon minions at particular thresholds of health
if !self.char_state.is_attack() { controller
controller .actions
.actions .push(ControlAction::basic_input(InputKind::Ability(1)));
.push(ControlAction::basic_input(InputKind::Ability(1))); if matches!(self.char_state, CharacterState::BasicSummon(c) if matches!(c.stage_section, StageSection::Recover))
{
agent.action_timer -= MINION_SUMMON_THRESHOLD; agent.action_timer -= MINION_SUMMON_THRESHOLD;
} }
} else if mindflayer_is_far { } else if mindflayer_is_far {
@ -2401,13 +2403,16 @@ impl<'a> AgentData<'a> {
}); });
} else { } else {
// If close to target, use either primary or secondary ability // If close to target, use either primary or secondary ability
if matches!(self.char_state, CharacterState::BasicBeam(_)) { if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(10) && !matches!(c.stage_section, StageSection::Recover))
// If already using primary, keep using primary {
// If already using primary, keep using primary until 10 consecutive seconds
controller controller
.actions .actions
.push(ControlAction::basic_input(InputKind::Primary)); .push(ControlAction::basic_input(InputKind::Primary));
} else if matches!(self.char_state, CharacterState::SpinMelee(_)) { } else if matches!(self.char_state, CharacterState::SpinMelee(c) if c.consecutive_spins < 50 && !matches!(c.stage_section, StageSection::Recover))
// If already using secondary, keep using secondary {
// If already using secondary, keep using secondary until 10 consecutive
// seconds
controller controller
.actions .actions
.push(ControlAction::basic_input(InputKind::Secondary)); .push(ControlAction::basic_input(InputKind::Secondary));
@ -2423,6 +2428,23 @@ impl<'a> AgentData<'a> {
.push(ControlAction::basic_input(InputKind::Secondary)); .push(ControlAction::basic_input(InputKind::Secondary));
} }
} }
// Move towards target
if let Some((bearing, speed)) = agent.chaser.chase(
&*terrain,
self.pos.0,
self.vel.0,
tgt_pos.0,
TraversalConfig {
min_tgt_dist: 1.25,
..self.traversal_config
},
) {
controller.inputs.move_dir =
bearing.xy().try_normalized().unwrap_or_else(Vec2::zero) * speed;
self.jump_if(controller, bearing.z > 1.5);
controller.inputs.move_z = bearing.z;
}
}, },
} }
} }

View File

@ -548,6 +548,7 @@ impl Floor {
.map(|density| dynamic_rng.gen_range(0..density.recip() as usize) == 0) .map(|density| dynamic_rng.gen_range(0..density.recip() as usize) == 0)
.unwrap_or(false) .unwrap_or(false)
&& !tile_is_pillar && !tile_is_pillar
&& !(room.boss && room.difficulty == 5)
{ {
// Bad // Bad
let chosen = match room.difficulty { let chosen = match room.difficulty {
@ -833,7 +834,7 @@ impl Floor {
"common.loot_tables.loot_table_miniboss", "common.loot_tables.loot_table_miniboss",
), ),
5 => Lottery::<String>::load_expect( 5 => Lottery::<String>::load_expect(
match dynamic_rng.gen_range(0..4) { match dynamic_rng.gen_range(0..3) {
0 => "common.loot_tables.mindflayer", 0 => "common.loot_tables.mindflayer",
_ => "common.loot_tables.loot_table_miniboss", _ => "common.loot_tables.loot_table_miniboss",
}, },