diff --git a/server/agent/src/attack.rs b/server/agent/src/attack.rs index 9c01c7c51c..0576874b02 100644 --- a/server/agent/src/attack.rs +++ b/server/agent/src/attack.rs @@ -40,6 +40,8 @@ fn projectile_multi_angle(projectile_spread: f32, num_projectiles: u32) -> f32 { (180.0 / PI) * projectile_spread * (num_projectiles - 1) as f32 } +fn rng_from_span(rng: &mut impl Rng, span: [f32; 2]) -> f32 { rng.gen_range(span[0]..=span[1]) } + impl<'a> AgentData<'a> { // Intended for any agent that has one attack, that attack is a melee attack, // and the agent is able to freely walk around @@ -138,7 +140,7 @@ impl<'a> AgentData<'a> { // Behaviour parameters const STRAFE_DIST: f32 = 4.5; const STRAFE_SPEED_MULT: f32 = 0.75; - const STRATE_SPIRAL_MULT: f32 = 0.8; // how quickly they close gap while strafing + const STRAFE_SPIRAL_MULT: f32 = 0.8; // how quickly they close gap while strafing const BACKSTAB_SPEED_MULT: f32 = 0.3; // Handle movement of agent @@ -179,7 +181,7 @@ impl<'a> AgentData<'a> { .find(|move_dir| target_ori.xy().dot(**move_dir) < 0.0) { controller.inputs.move_dir = - STRAFE_SPEED_MULT * (*move_dir - STRATE_SPIRAL_MULT * target_ori.xy()); + STRAFE_SPEED_MULT * (*move_dir - STRAFE_SPIRAL_MULT * target_ori.xy()); } } else { // Aim for a point a given distance behind the target to prevent sideways @@ -4775,7 +4777,7 @@ impl<'a> AgentData<'a> { // Inputs: // Primary: scythe // Secondary: firebreath - // Abilities: + // Auxiliary // 0: explosivepumpkin // 1: ensaringvines_sparse // 2: ensaringvines_dense @@ -4800,25 +4802,16 @@ impl<'a> AgentData<'a> { const FAR_PUMPKIN_COOLDOWN_SPAN: [f32; 2] = [3.0, 5.0]; // allows for pathing to player between throws // conditions - enum ActionStateConditions { - HasSummonedFirstVines, - HasSummonedSecondVines, - } - + const HAS_SUMMONED_FIRST_VINES: usize = 0; + const HAS_SUMMONED_SECOND_VINES: usize = 1; // timers - enum ActionStateTimers { - Firebreath, - Mixup, - FarPumpkin, - } - - // //counters - #[allow(clippy::enum_variant_names)] - enum ActionStateCounters { - CloseMixupCooldown, - MidMixupCooldown, - FarPumpkinCooldown, - } + const FIREBREATH: usize = 0; + const MIXUP: usize = 1; + const FAR_PUMPKIN: usize = 2; + //counters + const CLOSE_MIXUP_COOLDOWN: usize = 0; + const MID_MIXUP_COOLDOWN: usize = 1; + const FAR_PUMPKIN_COOLDOWN: usize = 2; // line of sight check let line_of_sight_with_target = || { @@ -4834,82 +4827,59 @@ impl<'a> AgentData<'a> { }; // --- dynamic --- - // attack data (with fallback values) - let scythe_range; - let scythe_angle; - match self - .extract_ability(AbilityInput::Primary) - .unwrap_or_default() - { - AbilityData::BasicMelee { range, angle, .. } => { - scythe_range = range; - scythe_angle = angle; - }, - _ => { - scythe_range = 4.5; - scythe_angle = 50.0; - }, + // attack data + let (scythe_range, scythe_angle) = { + if let Some(AbilityData::BasicMelee { range, angle, .. }) = + self.extract_ability(AbilityInput::Primary) + { + (range, angle) + } else { + (0.0, 0.0) + } }; - - let firebreath_range; - let firebreath_angle; - match self - .extract_ability(AbilityInput::Secondary) - .unwrap_or_default() - { - AbilityData::BasicBeam { range, angle, .. } => { - firebreath_range = range; - firebreath_angle = angle; - }, - _ => { - firebreath_range = 20.0; - firebreath_angle = 15.0; - }, + let (firebreath_range, firebreath_angle) = { + if let Some(AbilityData::BasicBeam { range, angle, .. }) = + self.extract_ability(AbilityInput::Secondary) + { + (range, angle) + } else { + (0.0, 0.0) + } }; - - let pumpkin_speed = match self - .extract_ability(AbilityInput::Auxiliary(0)) - .unwrap_or_default() - { - AbilityData::BasicRanged { + let pumpkin_speed = { + if let Some(AbilityData::BasicRanged { projectile_speed, .. - } => projectile_speed, - _ => 30.0, + }) = self.extract_ability(AbilityInput::Auxiliary(0)) + { + projectile_speed + } else { + 0.0 + } }; + // calculated attack data let pumpkin_max_range = - projectile_flat_range(pumpkin_speed, self.body.map_or(5.4, |b| b.height())); + projectile_flat_range(pumpkin_speed, self.body.map_or(0.0, |b| b.height())); // character state info - let mut is_using_firebreath = false; - let mut is_using_pumpkin = false; - let mut is_in_summon_recovery = false; - let mut firebreath_timer = Duration::from_secs(0); - match self.char_state { - CharacterState::BasicBeam(data) => { - is_using_firebreath = true; - firebreath_timer = data.timer; - }, - CharacterState::BasicRanged(_) => { - is_using_pumpkin = true; - }, - CharacterState::SpriteSummon(data) - if matches!(data.stage_section, StageSection::Recover) => - { - is_in_summon_recovery = true; - }, - _ => {}, - } + let is_using_firebreath = matches!(self.char_state, CharacterState::BasicBeam(_)); + let is_using_pumpkin = matches!(self.char_state, CharacterState::BasicRanged(_)); + let is_in_summon_recovery = matches!(self.char_state, CharacterState::SpriteSummon(data) if matches!(data.stage_section, StageSection::Recover)); + let firebreath_timer = if let CharacterState::BasicBeam(data) = self.char_state { + data.timer + } else { + Default::default() + }; let is_using_mixup = is_using_firebreath || is_using_pumpkin; // initialise randomised cooldowns if !agent.combat_state.initialized { agent.combat_state.initialized = true; - agent.combat_state.counters[ActionStateCounters::CloseMixupCooldown as usize] = - rng.gen_range(CLOSE_MIXUP_COOLDOWN_SPAN[0]..=CLOSE_MIXUP_COOLDOWN_SPAN[1]); - agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize] = - rng.gen_range(MID_MIXUP_COOLDOWN_SPAN[0]..=MID_MIXUP_COOLDOWN_SPAN[1]); - agent.combat_state.counters[ActionStateCounters::FarPumpkinCooldown as usize] = - rng.gen_range(FAR_PUMPKIN_COOLDOWN_SPAN[0]..=FAR_PUMPKIN_COOLDOWN_SPAN[1]); + agent.combat_state.counters[CLOSE_MIXUP_COOLDOWN] = + rng_from_span(rng, CLOSE_MIXUP_COOLDOWN_SPAN); + agent.combat_state.counters[MID_MIXUP_COOLDOWN] = + rng_from_span(rng, MID_MIXUP_COOLDOWN_SPAN); + agent.combat_state.counters[FAR_PUMPKIN_COOLDOWN] = + rng_from_span(rng, FAR_PUMPKIN_COOLDOWN_SPAN); } // === main === @@ -4917,25 +4887,25 @@ impl<'a> AgentData<'a> { // --- timers --- if is_in_summon_recovery { // reset all timers when done summoning - agent.combat_state.timers[ActionStateTimers::Firebreath as usize] = 0.0; - agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0; - agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] = 0.0; + agent.combat_state.timers[FIREBREATH] = 0.0; + agent.combat_state.timers[MIXUP] = 0.0; + agent.combat_state.timers[FAR_PUMPKIN] = 0.0; } else { // handle state timers if is_using_firebreath { - agent.combat_state.timers[ActionStateTimers::Firebreath as usize] = 0.0; + agent.combat_state.timers[FIREBREATH] = 0.0; } else { - agent.combat_state.timers[ActionStateTimers::Firebreath as usize] += read_data.dt.0; + agent.combat_state.timers[FIREBREATH] += read_data.dt.0; } if is_using_mixup { - agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0; + agent.combat_state.timers[MIXUP] = 0.0; } else { - agent.combat_state.timers[ActionStateTimers::Mixup as usize] += read_data.dt.0; + agent.combat_state.timers[MIXUP] += read_data.dt.0; } if is_using_pumpkin { - agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] = 0.0; + agent.combat_state.timers[FAR_PUMPKIN] = 0.0; } else { - agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] += read_data.dt.0; + agent.combat_state.timers[FAR_PUMPKIN] += read_data.dt.0; } } @@ -4943,25 +4913,24 @@ impl<'a> AgentData<'a> { let health_fraction = self.health.map_or(0.5, |h| h.fraction()); // second vine summon if health_fraction < SECOND_VINE_CREATION_THRESHOLD - && !agent.combat_state.conditions - [ActionStateConditions::HasSummonedSecondVines as usize] + && !agent.combat_state.conditions[HAS_SUMMONED_SECOND_VINES] { + // use the dense vine summon controller.push_basic_input(InputKind::Ability(2)); // wait till recovery before finishing if is_in_summon_recovery { - agent.combat_state.conditions - [ActionStateConditions::HasSummonedSecondVines as usize] = true; + agent.combat_state.conditions[HAS_SUMMONED_SECOND_VINES] = true; } } // first vine summon else if health_fraction < FIRST_VINE_CREATION_THRESHOLD - && !agent.combat_state.conditions[ActionStateConditions::HasSummonedFirstVines as usize] + && !agent.combat_state.conditions[HAS_SUMMONED_FIRST_VINES] { + // use the sparse vine summon controller.push_basic_input(InputKind::Ability(1)); // wait till recovery before finishing if is_in_summon_recovery { - agent.combat_state.conditions - [ActionStateConditions::HasSummonedFirstVines as usize] = true; + agent.combat_state.conditions[HAS_SUMMONED_FIRST_VINES] = true; } } // close range @@ -4977,14 +4946,12 @@ impl<'a> AgentData<'a> { // in scythe angle if attack_data.angle < scythe_angle * SCYTHE_AIM_FACTOR { // on timer, randomly mixup attacks - if agent.combat_state.timers[ActionStateTimers::Mixup as usize] - > agent.combat_state.counters[ActionStateCounters::CloseMixupCooldown as usize] + if agent.combat_state.timers[MIXUP] + > agent.combat_state.counters[CLOSE_MIXUP_COOLDOWN] // for now, no line of sight check for consitency in attacks { // if on firebreath cooldown, throw pumpkin - if agent.combat_state.timers[ActionStateTimers::Firebreath as usize] - < FIREBREATH_COOLDOWN - { + if agent.combat_state.timers[FIREBREATH] < FIREBREATH_COOLDOWN { controller.push_basic_input(InputKind::Ability(0)); } // otherwise, randomise between firebreath and pumpkin @@ -4995,9 +4962,8 @@ impl<'a> AgentData<'a> { } // reset mixup cooldown if actually being used if is_using_mixup { - agent.combat_state.counters - [ActionStateCounters::CloseMixupCooldown as usize] = rng - .gen_range(CLOSE_MIXUP_COOLDOWN_SPAN[0]..=CLOSE_MIXUP_COOLDOWN_SPAN[1]); + agent.combat_state.counters[CLOSE_MIXUP_COOLDOWN] = + rng_from_span(rng, CLOSE_MIXUP_COOLDOWN_SPAN); } } // default to using scythe melee @@ -5017,35 +4983,34 @@ impl<'a> AgentData<'a> { // start using firebreath if close enough, in angle, and off cooldown else if attack_data.dist_sqrd < (firebreath_range * FIREBREATH_RANGE_FACTOR).powi(2) && attack_data.angle < firebreath_angle * FIREBREATH_AIM_FACTOR - && agent.combat_state.timers[ActionStateTimers::Firebreath as usize] - > FIREBREATH_COOLDOWN + && agent.combat_state.timers[FIREBREATH] > FIREBREATH_COOLDOWN { controller.push_basic_input(InputKind::Secondary); } // on mixup timer, throw a pumpkin - else if agent.combat_state.timers[ActionStateTimers::Mixup as usize] - > agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize] + else if agent.combat_state.timers[MIXUP] + > agent.combat_state.counters[MID_MIXUP_COOLDOWN] { controller.push_basic_input(InputKind::Ability(0)); // reset mixup cooldown if pumpkin is actually being used if is_using_pumpkin { - agent.combat_state.counters[ActionStateCounters::MidMixupCooldown as usize] = - rng.gen_range(MID_MIXUP_COOLDOWN_SPAN[0]..=MID_MIXUP_COOLDOWN_SPAN[1]); + agent.combat_state.counters[MID_MIXUP_COOLDOWN] = + rng_from_span(rng, MID_MIXUP_COOLDOWN_SPAN); } } } // long range (with line of sight) else if attack_data.dist_sqrd < (pumpkin_max_range * PUMPKIN_RANGE_FACTOR).powi(2) - && agent.combat_state.timers[ActionStateTimers::FarPumpkin as usize] - > agent.combat_state.counters[ActionStateCounters::FarPumpkinCooldown as usize] + && agent.combat_state.timers[FAR_PUMPKIN] + > agent.combat_state.counters[FAR_PUMPKIN_COOLDOWN] && line_of_sight_with_target() { // throw pumpkin controller.push_basic_input(InputKind::Ability(0)); // reset pumpkin cooldown if actually being used if is_using_pumpkin { - agent.combat_state.counters[ActionStateCounters::FarPumpkinCooldown as usize] = - rng.gen_range(FAR_PUMPKIN_COOLDOWN_SPAN[0]..=FAR_PUMPKIN_COOLDOWN_SPAN[1]); + agent.combat_state.counters[FAR_PUMPKIN_COOLDOWN] = + rng_from_span(rng, FAR_PUMPKIN_COOLDOWN_SPAN); } } @@ -5999,7 +5964,7 @@ impl<'a> AgentData<'a> { // Inputs: // Primary: strike // Secondary: spin - // Abilities: + // Auxiliary // 0: shockwave // === setup === @@ -6019,55 +5984,41 @@ impl<'a> AgentData<'a> { const MIXUP_RELAX_FACTOR: f32 = 0.3; // timers - enum ActionStateTimers { - Spin, - Shockwave, - Mixup, - } + const SPIN: usize = 0; + const SHOCKWAVE: usize = 1; + const MIXUP: usize = 2; // --- dynamic --- // behaviour parameters - let shockwave_min_range = self.body.map_or(8.0, |b| b.height() * 1.1); + let shockwave_min_range = self.body.map_or(0.0, |b| b.height() * 1.1); - // attack data (with fallback values) - let strike_range; - let strike_angle; - match self - .extract_ability(AbilityInput::Primary) - .unwrap_or_default() - { - AbilityData::BasicMelee { range, angle, .. } => { - strike_range = range; - strike_angle = angle; - }, - _ => { - strike_range = 4.0; - strike_angle = 55.0; - }, + // attack data + let (strike_range, strike_angle) = { + if let Some(AbilityData::BasicMelee { range, angle, .. }) = + self.extract_ability(AbilityInput::Primary) + { + (range, angle) + } else { + (0.0, 0.0) + } }; - - let spin_range = match self - .extract_ability(AbilityInput::Secondary) - .unwrap_or_default() - { - AbilityData::BasicMelee { range, .. } => range, - _ => 5.0, + let spin_range = { + if let Some(AbilityData::BasicMelee { range, .. }) = + self.extract_ability(AbilityInput::Secondary) + { + range + } else { + 0.0 + } }; - - let shockwave_max_range; - let shockwave_angle; - match self - .extract_ability(AbilityInput::Auxiliary(0)) - .unwrap_or_default() - { - AbilityData::Shockwave { angle, range, .. } => { - shockwave_max_range = range; - shockwave_angle = angle; - }, - _ => { - shockwave_max_range = 15.0 * 1.9; - shockwave_angle = 90.0; - }, + let (shockwave_max_range, shockwave_angle) = { + if let Some(AbilityData::Shockwave { range, angle, .. }) = + self.extract_ability(AbilityInput::Auxiliary(0)) + { + (range, angle) + } else { + (0.0, 0.0) + } }; // re-used checks (makes separating timers and attacks easier) @@ -6084,44 +6035,40 @@ impl<'a> AgentData<'a> { let current_input = self.char_state.ability_info().map(|ai| ai.input); if matches!(current_input, Some(InputKind::Secondary)) { // reset when spinning - agent.combat_state.timers[ActionStateTimers::Spin as usize] = 0.0; - agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0; + agent.combat_state.timers[SPIN] = 0.0; + agent.combat_state.timers[MIXUP] = 0.0; } else if is_in_spin_range && !(is_in_strike_range && is_in_strike_angle) { // increment within spin range and not in strike range + angle - agent.combat_state.timers[ActionStateTimers::Spin as usize] += read_data.dt.0; + agent.combat_state.timers[SPIN] += read_data.dt.0; } else { // relax towards zero otherwise - agent.combat_state.timers[ActionStateTimers::Spin as usize] = - (agent.combat_state.timers[ActionStateTimers::Spin as usize] - - read_data.dt.0 * SPIN_RELAX_FACTOR) - .max(0.0); + agent.combat_state.timers[SPIN] = + (agent.combat_state.timers[SPIN] - read_data.dt.0 * SPIN_RELAX_FACTOR).max(0.0); } // shockwave if matches!(self.char_state, CharacterState::Shockwave(_)) { // reset when using shockwave - agent.combat_state.timers[ActionStateTimers::Shockwave as usize] = 0.0; - agent.combat_state.timers[ActionStateTimers::Mixup as usize] = 0.0; + agent.combat_state.timers[SHOCKWAVE] = 0.0; + agent.combat_state.timers[MIXUP] = 0.0; } else { // increment otherwise - agent.combat_state.timers[ActionStateTimers::Shockwave as usize] += read_data.dt.0; + agent.combat_state.timers[SHOCKWAVE] += read_data.dt.0; } // mixup if is_in_strike_range && is_in_strike_angle { // increment within strike range and angle - agent.combat_state.timers[ActionStateTimers::Mixup as usize] += read_data.dt.0; + agent.combat_state.timers[MIXUP] += read_data.dt.0; } else { // relax towards zero otherwise - agent.combat_state.timers[ActionStateTimers::Mixup as usize] = - (agent.combat_state.timers[ActionStateTimers::Mixup as usize] - - read_data.dt.0 * MIXUP_RELAX_FACTOR) - .max(0.0); + agent.combat_state.timers[MIXUP] = + (agent.combat_state.timers[MIXUP] - read_data.dt.0 * MIXUP_RELAX_FACTOR).max(0.0); } // --- attacks --- // strike range and angle if is_in_strike_range && is_in_strike_angle { // on timer, randomly mixup between all attacks - if agent.combat_state.timers[ActionStateTimers::Mixup as usize] > MIXUP_COOLDOWN { + if agent.combat_state.timers[MIXUP] > MIXUP_COOLDOWN { let randomise: u8 = rng.gen_range(1..=3); match randomise { 1 => controller.push_basic_input(InputKind::Ability(0)), // shockwave @@ -6137,7 +6084,7 @@ impl<'a> AgentData<'a> { // spin range (or out of angle in strike range) else if is_in_spin_range || (is_in_strike_range && !is_in_strike_angle) { // on timer, use spin attack to try and hit evasive target - if agent.combat_state.timers[ActionStateTimers::Spin as usize] > SPIN_COOLDOWN { + if agent.combat_state.timers[SPIN] > SPIN_COOLDOWN { controller.push_basic_input(InputKind::Secondary); } // otherwise, close angle (no action required) @@ -6148,8 +6095,7 @@ impl<'a> AgentData<'a> { && attack_data.angle < shockwave_angle * SHOCKWAVE_AIM_FACTOR { // on timer, use shockwave - if agent.combat_state.timers[ActionStateTimers::Shockwave as usize] > SHOCKWAVE_COOLDOWN - { + if agent.combat_state.timers[SHOCKWAVE] > SHOCKWAVE_COOLDOWN { controller.push_basic_input(InputKind::Ability(0)); } // otherwise, close gap and/or angle (no action required) @@ -6193,7 +6139,7 @@ impl<'a> AgentData<'a> { // Inputs // Primary: flamestrike // Secondary: firebarrage - // Abilities + // Auxiliary // 0: fireshockwave // 1: redtotem // 2: greentotem @@ -6215,20 +6161,12 @@ impl<'a> AgentData<'a> { const HEAVY_ATTACK_FAST_CHARGE_FACTOR: f32 = 5.0; // conditions - enum ActionStateConditions { - HasSummonedFirstTotem, - } - + const HAS_SUMMONED_FIRST_TOTEM: usize = 0; // timers - enum ActionStateTimers { - SummonTotem, - HeavyAttack, - } - + const SUMMON_TOTEM: usize = 0; + const HEAVY_ATTACK: usize = 1; // counters - enum ActionStateCounters { - HeavyAttackCooldown, - } + const HEAVY_ATTACK_COOLDOWN: usize = 0; // line of sight check let line_of_sight_with_target = || { @@ -6244,58 +6182,44 @@ impl<'a> AgentData<'a> { }; // --- dynamic --- - // attack data (with fallback values) - let strike_range; - let strike_angle; - match self - .extract_ability(AbilityInput::Primary) - .unwrap_or_default() - { - AbilityData::BasicMelee { range, angle, .. } => { - strike_range = range; - strike_angle = angle; - }, - _ => { - strike_range = 3.0; - strike_angle = 40.0; - }, + // attack data + let (strike_range, strike_angle) = { + if let Some(AbilityData::BasicMelee { range, angle, .. }) = + self.extract_ability(AbilityInput::Primary) + { + (range, angle) + } else { + (0.0, 0.0) + } }; - - let barrage_speed; - let barrage_spread; - let barrage_count; - match self - .extract_ability(AbilityInput::Secondary) - .unwrap_or_default() - { - AbilityData::BasicRanged { + let (barrage_speed, barrage_spread, barrage_count) = { + if let Some(AbilityData::BasicRanged { projectile_speed, projectile_spread, num_projectiles, .. - } => { - barrage_speed = projectile_speed; - barrage_spread = projectile_spread; - barrage_count = num_projectiles; - }, - _ => { - barrage_speed = 25.0; - barrage_spread = 0.125; - barrage_count = 5; - }, + }) = self.extract_ability(AbilityInput::Secondary) + { + (projectile_speed, projectile_spread, num_projectiles) + } else { + (0.0, 0.0, 0) + } }; + let shockwave_range = { + if let Some(AbilityData::Shockwave { range, .. }) = + self.extract_ability(AbilityInput::Auxiliary(0)) + { + range + } else { + 0.0 + } + }; + + // calculated attack data let barrage_max_range = projectile_flat_range(barrage_speed, self.body.map_or(2.0, |b| b.height())); let barrange_angle = projectile_multi_angle(barrage_spread, barrage_count); - let shockwave_range = match self - .extract_ability(AbilityInput::Auxiliary(0)) - .unwrap_or_default() - { - AbilityData::Shockwave { range, .. } => range, - _ => 12.0 * 1.0, - }; - // re-used checks let is_in_strike_range = attack_data.dist_sqrd < (attack_data.body_dist + strike_range * STRIKE_RANGE_FACTOR).powi(2); @@ -6304,8 +6228,8 @@ impl<'a> AgentData<'a> { // initialise randomised cooldowns if !agent.combat_state.initialized { agent.combat_state.initialized = true; - agent.combat_state.counters[ActionStateCounters::HeavyAttackCooldown as usize] = - rng.gen_range(HEAVY_ATTACK_COOLDOWN_SPAN[0]..=HEAVY_ATTACK_COOLDOWN_SPAN[1]); + agent.combat_state.counters[HEAVY_ATTACK_COOLDOWN] = + rng_from_span(rng, HEAVY_ATTACK_COOLDOWN_SPAN); } // === main === @@ -6315,53 +6239,49 @@ impl<'a> AgentData<'a> { match self.char_state { CharacterState::BasicSummon(s) if s.stage_section == StageSection::Recover => { // reset when finished summoning - agent.combat_state.timers[ActionStateTimers::SummonTotem as usize] = 0.0; - agent.combat_state.conditions - [ActionStateConditions::HasSummonedFirstTotem as usize] = true; + agent.combat_state.timers[SUMMON_TOTEM] = 0.0; + agent.combat_state.conditions[HAS_SUMMONED_FIRST_TOTEM] = true; }, CharacterState::Shockwave(_) | CharacterState::BasicRanged(_) => { // reset heavy attack on either ability - agent.combat_state.counters[ActionStateTimers::HeavyAttack as usize] = 0.0; - agent.combat_state.counters[ActionStateCounters::HeavyAttackCooldown as usize] = - rng.gen_range(HEAVY_ATTACK_COOLDOWN_SPAN[0]..=HEAVY_ATTACK_COOLDOWN_SPAN[1]); + agent.combat_state.counters[HEAVY_ATTACK] = 0.0; + agent.combat_state.counters[HEAVY_ATTACK_COOLDOWN] = + rng_from_span(rng, HEAVY_ATTACK_COOLDOWN_SPAN); }, _ => {}, } // totem (always increment) - agent.combat_state.timers[ActionStateTimers::SummonTotem as usize] += read_data.dt.0; + agent.combat_state.timers[SUMMON_TOTEM] += read_data.dt.0; // heavy attack (increment at different rates) if is_in_strike_range { // recharge at standard rate in strike range and angle if is_in_strike_angle { - agent.combat_state.counters[ActionStateTimers::HeavyAttack as usize] += - read_data.dt.0; + agent.combat_state.counters[HEAVY_ATTACK] += read_data.dt.0; } else { // If not in angle, charge heavy attack faster - agent.combat_state.counters[ActionStateTimers::HeavyAttack as usize] += + agent.combat_state.counters[HEAVY_ATTACK] += read_data.dt.0 * HEAVY_ATTACK_FAST_CHARGE_FACTOR; } } else { // If not in range, charge heavy attack faster - agent.combat_state.counters[ActionStateTimers::HeavyAttack as usize] += + agent.combat_state.counters[HEAVY_ATTACK] += read_data.dt.0 * HEAVY_ATTACK_CHARGE_FACTOR; } // --- attacks --- // start by summoning green totem - if !agent.combat_state.conditions[ActionStateConditions::HasSummonedFirstTotem as usize] { + if !agent.combat_state.conditions[HAS_SUMMONED_FIRST_TOTEM] { controller.push_basic_input(InputKind::Ability(2)); } // on timer, summon a new random totem - else if agent.combat_state.timers[ActionStateTimers::SummonTotem as usize] - > TOTEM_COOLDOWN - { + else if agent.combat_state.timers[SUMMON_TOTEM] > TOTEM_COOLDOWN { controller.push_basic_input(InputKind::Ability(rng.gen_range(1..=3))); } // on timer and in range, use a heavy attack // assumes: barrange_max_range * BARRAGE_RANGE_FACTOR > shockwave_range * // SHOCKWAVE_RANGE_FACTOR - else if agent.combat_state.counters[ActionStateTimers::HeavyAttack as usize] - > agent.combat_state.counters[ActionStateCounters::HeavyAttackCooldown as usize] + else if agent.combat_state.counters[HEAVY_ATTACK] + > agent.combat_state.counters[HEAVY_ATTACK_COOLDOWN] && attack_data.dist_sqrd < (barrage_max_range * BARRAGE_RANGE_FACTOR).powi(2) { // has line of sight diff --git a/server/agent/src/data.rs b/server/agent/src/data.rs index 14b3aec60d..7e5f218e85 100755 --- a/server/agent/src/data.rs +++ b/server/agent/src/data.rs @@ -438,10 +438,8 @@ pub enum Path { Partial, } -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug)] pub enum AbilityData { - #[default] - Default, ComboMelee { range: f32, angle: f32, @@ -826,7 +824,6 @@ impl AbilityData { }; use AbilityData::*; match self { - Default => false, ComboMelee { range, angle,