randomised mixup cooldowns for harvester; small adjustment to firebreath ori

This commit is contained in:
horblegorble
2024-06-22 17:40:15 +10:00
parent a838dcf545
commit 60f4be1116
2 changed files with 62 additions and 29 deletions

View File

@ -14,6 +14,6 @@ BasicBeam(
))), ))),
energy_regen: 0, energy_regen: 0,
energy_drain: 0, energy_drain: 0,
ori_rate: 0.6, ori_rate: 0.7,
specifier: Flamethrower, specifier: Flamethrower,
) )

View File

@ -27,6 +27,8 @@ use rand::{prelude::SliceRandom, Rng};
use std::{f32::consts::PI, time::Duration}; use std::{f32::consts::PI, time::Duration};
use vek::*; use vek::*;
fn midpoint(min_max: [f32; 2]) -> f32 { return min_max[0] + (min_max[1] - min_max[0]) / 2.0 }
impl<'a> AgentData<'a> { impl<'a> AgentData<'a> {
// Intended for any agent that has one attack, that attack is a melee attack, // Intended for any agent that has one attack, that attack is a melee attack,
// and the agent is able to freely walk around // and the agent is able to freely walk around
@ -4784,23 +4786,36 @@ impl<'a> AgentData<'a> {
const FIREBREATH_TIME: f32 = 4.0; const FIREBREATH_TIME: f32 = 4.0;
const FIREBREATH_SHORT_TIME: f32 = 2.5; // cutoff sooner at close range const FIREBREATH_SHORT_TIME: f32 = 2.5; // cutoff sooner at close range
const FIREBREATH_COOLDOWN: f32 = 3.5; const FIREBREATH_COOLDOWN: f32 = 3.5;
const CLOSE_MIXUP_COOLDOWN: f32 = 2.5; // variation in attacks at close range
const MID_MIXUP_COOLDOWN: f32 = 3.0; // ^ mid
const FAR_PUMPKIN_COOLDOWN: f32 = 1.0; // allows for pathing to player between throws const FAR_PUMPKIN_COOLDOWN: f32 = 1.0; // allows for pathing to player between throws
// const CLOSE_MIXUP_COOLDOWN: f32 = 2.5; // variation in attacks at close range
// const MID_MIXUP_COOLDOWN: f32 = 3.0; // ^ mid
const CLOSE_MIXUP_COOLDOWN_SPAN: [f32; 2] = [1.5, 7.0];
const MID_MIXUP_COOLDOWN_SPAN: [f32; 2] = [2.0, 6.0];
// notes on cooldown values:
// - scalar values are from the end of an attack
// - span values are from the beginning of an attack
// conditions // conditions
enum ActionStateConditions { enum ActionStateConditions {
HasSummonedFirstVines = 0, FirstVines = 0,
HasSummonedSecondVines, SecondVines,
MixupInit,
} }
// timers // timers
enum ActionStateTimers { enum ActionStateTimers {
Firebreath = 0, Firebreath = 0,
CloseMixup, Mixup,
FarPumpkin, FarPumpkin,
} }
// //counters
enum ActionStateCounters {
CloseMixupCooldown = 0,
MidMixupCooldown,
}
// line of sight check // line of sight check
let line_of_sight_with_target = || { let line_of_sight_with_target = || {
entities_have_line_of_sight( entities_have_line_of_sight(
@ -4816,23 +4831,31 @@ impl<'a> AgentData<'a> {
// === main === // === main ===
// initialise mixup cooldowns
if !agent.combat_state.conditions[ActionStateConditions::MixupInit as usize] {
agent.combat_state.counters[ActionStateCounters::CloseMixupCooldown as usize] =
midpoint(CLOSE_MIXUP_COOLDOWN_SPAN);
agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize] =
midpoint(MID_MIXUP_COOLDOWN_SPAN);
agent.combat_state.conditions[ActionStateConditions::MixupInit as usize] = true;
}
// --- timers --- // --- timers ---
// mixup timer reset is handled within attack logic
match self.char_state { match self.char_state {
CharacterState::BasicBeam(_) => { CharacterState::BasicBeam(_) => {
// reset when using firebreath // reset when using firebreath
agent.combat_state.timers[ActionStateTimers::Firebreath as usize] = 0.0; agent.combat_state.timers[ActionStateTimers::Firebreath as usize] = 0.0;
agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] = 0.0;
}, },
CharacterState::BasicRanged(_) => { CharacterState::BasicRanged(_) => {
// reset when using explodingpumpkin // reset when using explodingpumpkin
agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] = 0.0; agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] = 0.0;
agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] = 0.0;
}, },
_ => { _ => {
// increment otherwise // increment otherwise
agent.combat_state.timers[ActionStateTimers::Firebreath as usize] += read_data.dt.0; agent.combat_state.timers[ActionStateTimers::Firebreath as usize] += read_data.dt.0;
agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] += read_data.dt.0; agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] += read_data.dt.0;
agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] += read_data.dt.0; agent.combat_state.timers[ActionStateTimers::Mixup as usize] += read_data.dt.0;
}, },
} }
@ -4842,24 +4865,24 @@ impl<'a> AgentData<'a> {
if health_fraction < SECOND_VINE_CREATION_THRESHOLD if health_fraction < SECOND_VINE_CREATION_THRESHOLD
&& !agent.combat_state.conditions && !agent.combat_state.conditions
[ActionStateConditions::HasSummonedSecondVines as usize] [ActionStateConditions::SecondVines as usize]
{ {
// second vines summon // second vines summon
controller.push_basic_input(InputKind::Ability(2)); controller.push_basic_input(InputKind::Ability(2));
if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover)) if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover))
{ {
agent.combat_state.conditions agent.combat_state.conditions
[ActionStateConditions::HasSummonedSecondVines as usize] = true; [ActionStateConditions::SecondVines as usize] = true;
} }
} else if health_fraction < FIRST_VINE_CREATION_THRESHOLD } else if health_fraction < FIRST_VINE_CREATION_THRESHOLD
&& !agent.combat_state.conditions[ActionStateConditions::HasSummonedFirstVines as usize] && !agent.combat_state.conditions[ActionStateConditions::FirstVines as usize]
{ {
// first vines summon // first vines summon
controller.push_basic_input(InputKind::Ability(1)); controller.push_basic_input(InputKind::Ability(1));
if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover)) if matches!(self.char_state, CharacterState::SpriteSummon(c) if matches!(c.stage_section, StageSection::Recover))
{ {
agent.combat_state.conditions agent.combat_state.conditions
[ActionStateConditions::HasSummonedFirstVines as usize] = true; [ActionStateConditions::FirstVines as usize] = true;
} }
} }
// close range // close range
@ -4870,8 +4893,8 @@ impl<'a> AgentData<'a> {
{ {
// keep using firebreath under short time limit // keep using firebreath under short time limit
controller.push_basic_input(InputKind::Secondary); controller.push_basic_input(InputKind::Secondary);
} else if agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] } else if agent.combat_state.timers[ActionStateTimers::Mixup as usize]
> CLOSE_MIXUP_COOLDOWN > agent.combat_state.counters[ActionStateCounters::CloseMixupCooldown as usize]
&& attack_data.angle < SCYTHE_AIM_ANGLE && attack_data.angle < SCYTHE_AIM_ANGLE
// for now, no line of sight check for consitency in attacks // for now, no line of sight check for consitency in attacks
{ {
@ -4882,41 +4905,52 @@ impl<'a> AgentData<'a> {
// if on firebreath cooldown, throw pumpkin // if on firebreath cooldown, throw pumpkin
controller.push_basic_input(InputKind::Ability(0)); controller.push_basic_input(InputKind::Ability(0));
} else { } else {
let randomise = rng.gen_range(1..=3); let randomise: u8 = rng.gen_range(1..=2);
match randomise { match randomise {
1 => controller.push_basic_input(InputKind::Secondary), // firebreath 1 => controller.push_basic_input(InputKind::Secondary), // firebreath
2 => controller.push_basic_input(InputKind::Primary), // scythe
_ => controller.push_basic_input(InputKind::Ability(0)), // pumpkin _ => controller.push_basic_input(InputKind::Ability(0)), // pumpkin
} }
} }
// check if a mixup attack is being used
if matches!(self.char_state, CharacterState::BasicBeam(_) | CharacterState::BasicRanged(_) ) {
// reset mixup timer and setup new close mixup cooldown
agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0;
agent.combat_state.counters[ActionStateCounters::CloseMixupCooldown as usize] =
rng.gen_range(CLOSE_MIXUP_COOLDOWN_SPAN[0]..=CLOSE_MIXUP_COOLDOWN_SPAN[1]);
}
} else if attack_data.angle < SCYTHE_AIM_ANGLE { } else if attack_data.angle < SCYTHE_AIM_ANGLE {
// scythe melee // scythe melee
controller.push_basic_input(InputKind::Primary); controller.push_basic_input(InputKind::Primary);
} }
} }
// mid range (with line of sight) // mid range (line of sight not needed for 'suppressing' attacks)
else if attack_data.dist_sqrd < FIREBREATH_RANGE.powi(2) else if attack_data.dist_sqrd < FIREBREATH_RANGE.powi(2) {
&& line_of_sight_with_target()
{
// keep using firebreath under full time limit // keep using firebreath under full time limit
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIREBREATH_TIME)) if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIREBREATH_TIME))
{ {
controller.push_basic_input(InputKind::Secondary); controller.push_basic_input(InputKind::Secondary);
} }
// start using firebreath if close enough, in angle, and off cooldown // start using firebreath if close enough, in angle, and off cooldown
else if // attack_data.dist_sqrd < FIREBREATH_RANGE * FIREBREATH_RANGE_FACTOR else if attack_data.dist_sqrd < (FIREBREATH_RANGE * FIREBREATH_RANGE_FACTOR).powi(2)
// && attack_data.angle < FIREBREATH_AIM_ANGLE && attack_data.angle < FIREBREATH_AIM_ANGLE
// && && agent.combat_state.timers[ActionStateTimers::Firebreath as usize]
agent.combat_state.timers[ActionStateTimers::Firebreath as usize]
> FIREBREATH_COOLDOWN > FIREBREATH_COOLDOWN
{ {
controller.push_basic_input(InputKind::Secondary); controller.push_basic_input(InputKind::Secondary);
} }
// on mixup timer, throw a pumpkin // on mixup timer, throw a pumpkin
else if agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] else if agent.combat_state.timers[ActionStateTimers::Mixup as usize]
> MID_MIXUP_COOLDOWN > agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize]
{ {
controller.push_basic_input(InputKind::Ability(0)); controller.push_basic_input(InputKind::Ability(0));
// check if pumpkin is being used
if matches!(self.char_state, CharacterState::BasicRanged(_) ) {
// reset mixup timer and setup new mid mixup cooldown
agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0;
agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize] =
rng.gen_range(MID_MIXUP_COOLDOWN_SPAN[0]..=MID_MIXUP_COOLDOWN_SPAN[1]);
}
} }
} }
// long range (with line of sight) // long range (with line of sight)
@ -5913,7 +5947,6 @@ impl<'a> AgentData<'a> {
< (attack_data.body_dist + STRIKE_RANGE * ATTACK_RANGE_FACTOR).powi(2); < (attack_data.body_dist + STRIKE_RANGE * ATTACK_RANGE_FACTOR).powi(2);
let is_in_strike_angle = attack_data.angle < STRIKE_AIM_ANGLE; let is_in_strike_angle = attack_data.angle < STRIKE_AIM_ANGLE;
// === main === // === main ===
// --- timers --- // --- timers ---
@ -5959,7 +5992,7 @@ impl<'a> AgentData<'a> {
if is_in_strike_range && is_in_strike_angle { if is_in_strike_range && is_in_strike_angle {
if agent.combat_state.timers[ActionStateTimers::Mixup as usize] > MIXUP_COOLDOWN { if agent.combat_state.timers[ActionStateTimers::Mixup as usize] > MIXUP_COOLDOWN {
// randomly mix up // randomly mix up
let randomise = rng.gen_range(1..=3); let randomise: u8 = rng.gen_range(1..=3);
match randomise { match randomise {
1 => controller.push_basic_input(InputKind::Ability(0)), // shockwave 1 => controller.push_basic_input(InputKind::Ability(0)), // shockwave
2 => controller.push_basic_input(InputKind::Primary), // strike 2 => controller.push_basic_input(InputKind::Primary), // strike