Mindflayer balance tweaks.

This commit is contained in:
Sam 2021-03-29 10:44:46 -04:00
parent 206efcfc3a
commit 71ba9b6a54
6 changed files with 44 additions and 26 deletions

View File

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

View File

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

View File

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

View File

@ -60,8 +60,8 @@ pub struct Data {
pub static_data: StaticData,
/// Timer for each stage
pub timer: Duration,
/// How many spins it can do before ending
pub spins_remaining: u32,
/// How many spins it has done
pub consecutive_spins: u32,
/// What section the character stage is in
pub stage_section: StageSection,
/// Whether the state can deal damage
@ -187,18 +187,13 @@ impl CharacterBehavior for Data {
..*self
});
} 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
&& 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 {
timer: Duration::default(),
spins_remaining: new_spins_remaining,
consecutive_spins: self.consecutive_spins + 1,
exhausted: false,
..*self
});

View File

@ -20,6 +20,7 @@ use common::{
path::TraversalConfig,
resources::{DeltaTime, Time, TimeOfDay},
rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent},
states::utils::StageSection,
terrain::{Block, TerrainGrid},
time::DayPeriod,
trade::{TradeAction, TradePhase, TradeResult},
@ -37,7 +38,7 @@ use specs::{
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World,
Write, WriteExpect, WriteStorage,
};
use std::{f32::consts::PI, sync::Arc};
use std::{f32::consts::PI, sync::Arc, time::Duration};
use vek::*;
struct AgentData<'a> {
@ -2202,7 +2203,7 @@ impl<'a> AgentData<'a> {
}
},
Tactic::Mindflayer => {
const MINDFLAYER_ATTACK_DIST: f32 = 17.5;
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());
// Extreme hack to set action_timer at start of combat
@ -2214,10 +2215,11 @@ impl<'a> AgentData<'a> {
let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2);
if agent.action_timer > health_fraction {
// Summon minions at particular thresholds of health
if !self.char_state.is_attack() {
controller
.actions
.push(ControlAction::basic_input(InputKind::Ability(1)));
controller
.actions
.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;
}
} else if mindflayer_is_far {
@ -2233,13 +2235,16 @@ impl<'a> AgentData<'a> {
});
} else {
// If close to target, use either primary or secondary ability
if matches!(self.char_state, CharacterState::BasicBeam(_)) {
// If already using primary, keep using primary
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 until 10 consecutive seconds
controller
.actions
.push(ControlAction::basic_input(InputKind::Primary));
} else if matches!(self.char_state, CharacterState::SpinMelee(_)) {
// If already using secondary, keep using secondary
} 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 until 10 consecutive
// seconds
controller
.actions
.push(ControlAction::basic_input(InputKind::Secondary));
@ -2255,6 +2260,23 @@ impl<'a> AgentData<'a> {
.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)
.unwrap_or(false)
&& !tile_is_pillar
&& (!room.boss || room.difficulty != 5)
{
// Bad
let chosen = match room.difficulty {
@ -833,7 +834,7 @@ impl Floor {
"common.loot_tables.loot_table_miniboss",
),
5 => Lottery::<String>::load_expect(
match dynamic_rng.gen_range(0..4) {
match dynamic_rng.gen_range(0..3) {
0 => "common.loot_tables.mindflayer",
_ => "common.loot_tables.loot_table_miniboss",
},