refinements to woodgolem; ori & small updates to harvester; some formatting

This commit is contained in:
horblegorble 2024-06-21 17:28:58 +10:00
parent 9187c37ab1
commit a838dcf545
7 changed files with 98 additions and 53 deletions

View File

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

View File

@ -12,8 +12,8 @@ BasicMelee(
energy_regen: 0.0, energy_regen: 0.0,
), ),
range: 4.5, range: 4.5,
angle: 60.0, angle: 50.0,
multi_target: Some(Normal), multi_target: Some(Normal),
), ),
ori_modifier: 1.0, ori_modifier: 0.5,
) )

View File

@ -11,7 +11,7 @@ BasicMelee(
knockback: 20, knockback: 20,
energy_regen: 0, energy_regen: 0,
), ),
range: 6.0, range: 5.0,
angle: 360, angle: 360,
), ),
ori_modifier: 0.75, ori_modifier: 0.75,

View File

@ -11,7 +11,7 @@ BasicMelee(
knockback: 15.0, knockback: 15.0,
energy_regen: 0.0, energy_regen: 0.0,
), ),
range: 4.5, range: 4.0,
angle: 55.0, angle: 55.0,
), ),
ori_modifier: 0.7, ori_modifier: 0.7,

View File

@ -226,7 +226,10 @@ impl Body {
Body::Dragon(_) => 1.0, Body::Dragon(_) => 1.0,
Body::BirdLarge(_) => 7.0, Body::BirdLarge(_) => 7.0,
Body::FishSmall(_) => 7.0, Body::FishSmall(_) => 7.0,
Body::BipedLarge(_) => 2.7, Body::BipedLarge(biped_large) => match biped_large.species {
biped_large::Species::Harvester => 2.0,
_ => 2.7,
},
Body::BipedSmall(_) => 3.5, Body::BipedSmall(_) => 3.5,
Body::Object(_) => 2.0, Body::Object(_) => 2.0,
Body::ItemDrop(_) => 2.0, Body::ItemDrop(_) => 2.0,

View File

@ -685,6 +685,21 @@ impl<'a> AgentData<'a> {
} }
} }
// same as look_toward, using &TargetData instead of EcsEntity
pub fn look_toward_data(&self, controller: &mut Controller, tgt_data: &TargetData) {
let tgt_pos = tgt_data.pos;
let eye_offset = self.body.map_or(0.0, |b| b.eye_height(self.scale));
let tgt_eye_offset = tgt_data
.body
.map_or(0.0, |b| b.eye_height(tgt_data.scale.map_or(1.0, |s| s.0)));
if let Some(dir) = Dir::from_unnormalized(
Vec3::new(tgt_pos.0.x, tgt_pos.0.y, tgt_pos.0.z + tgt_eye_offset)
- Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
) {
controller.inputs.look_dir = dir;
}
}
pub fn flee( pub fn flee(
&self, &self,
agent: &mut Agent, agent: &mut Agent,

View File

@ -4770,16 +4770,22 @@ impl<'a> AgentData<'a> {
// --- setup --- // --- setup ---
// hard-coded attack values // hard-coded attack values
const SCYTHE_RANGE: f32 = 5.0; const SCYTHE_RANGE: f32 = 4.5;
const SCYTHE_AIM_ANGLE: f32 = 50.0 * 0.7;
const FIREBREATH_RANGE: f32 = 20.0;
// behaviour parameters // behaviour parameters
const SCYTHE_RANGE_FACTOR: f32 = 0.75; // start attack while suitably in range
const FIREBREATH_RANGE_FACTOR: f32 = 0.7; // ^
const PATH_RANGE_FACTOR: f32 = 0.4; // get comfortably in range, but give player room to breathe
const FIRST_VINE_CREATION_THRESHOLD: f32 = 0.60; const FIRST_VINE_CREATION_THRESHOLD: f32 = 0.60;
const SECOND_VINE_CREATION_THRESHOLD: f32 = 0.30; const SECOND_VINE_CREATION_THRESHOLD: f32 = 0.30;
const MAX_PUMPKIN_RANGE: f32 = 50.0; const MAX_PUMPKIN_RANGE: f32 = 50.0;
const FIREBREATH_RANGE: f32 = 20.0; const FIREBREATH_AIM_ANGLE: f32 = 30.0;
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.0; const FIREBREATH_COOLDOWN: f32 = 3.5;
const CLOSE_MIXUP_COOLDOWN: f32 = 2.5; // variation in attacks at close range 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
// conditions // conditions
@ -4808,25 +4814,29 @@ impl<'a> AgentData<'a> {
) )
}; };
// --- main --- // === main ===
// handle timers // --- timers ---
match self.char_state { match self.char_state {
CharacterState::BasicBeam(_) => { CharacterState::BasicBeam(_) => {
// 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; agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] = 0.0;
}, },
CharacterState::BasicRanged(_) => { CharacterState::BasicRanged(_) => {
// 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; agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] = 0.0;
}, },
_ => { _ => {
// 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::CloseMixup as usize] += read_data.dt.0;
}, },
} }
// --- attacks ---
// vine summoning // vine summoning
let health_fraction = self.health.map_or(0.5, |h| h.fraction()); let health_fraction = self.health.map_or(0.5, |h| h.fraction());
@ -4853,17 +4863,19 @@ impl<'a> AgentData<'a> {
} }
} }
// close range // close range
// 0.75 multiplier tuned to start melee attack while suitably in range else if attack_data.dist_sqrd
else if attack_data.dist_sqrd < (attack_data.body_dist + 0.75 * SCYTHE_RANGE).powi(2) { < (attack_data.body_dist + SCYTHE_RANGE * SCYTHE_RANGE_FACTOR).powi(2)
{
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIREBREATH_SHORT_TIME)) if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIREBREATH_SHORT_TIME))
{ {
// 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::CloseMixup as usize]
> CLOSE_MIXUP_COOLDOWN > CLOSE_MIXUP_COOLDOWN
&& 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
{ {
// mix up close range attacks // mix up close range attacks when in angle
if agent.combat_state.timers[ActionStateTimers::Firebreath as usize] if agent.combat_state.timers[ActionStateTimers::Firebreath as usize]
< FIREBREATH_COOLDOWN < FIREBREATH_COOLDOWN
{ {
@ -4873,31 +4885,37 @@ impl<'a> AgentData<'a> {
let randomise = rng.gen_range(1..=3); let randomise = rng.gen_range(1..=3);
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::Ability(0)), // pumpkin 2 => controller.push_basic_input(InputKind::Primary), // scythe
_ => controller.push_basic_input(InputKind::Primary), // scythe _ => controller.push_basic_input(InputKind::Ability(0)), // pumpkin
} }
} }
} else if attack_data.angle < 60.0 { } 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 (with line of sight)
else if attack_data.dist_sqrd < FIREBREATH_RANGE.powi(2) && line_of_sight_with_target() { else if attack_data.dist_sqrd < FIREBREATH_RANGE.powi(2)
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs_f32(FIREBREATH_TIME)) && 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))
{
controller.push_basic_input(InputKind::Secondary); controller.push_basic_input(InputKind::Secondary);
} else if attack_data.angle < 30.0 }
&& agent.combat_state.timers[ActionStateTimers::Firebreath as usize] // start using firebreath if close enough, in angle, and off cooldown
else if // attack_data.dist_sqrd < FIREBREATH_RANGE * FIREBREATH_RANGE_FACTOR
// && attack_data.angle < FIREBREATH_AIM_ANGLE
// &&
agent.combat_state.timers[ActionStateTimers::Firebreath as usize]
> FIREBREATH_COOLDOWN > FIREBREATH_COOLDOWN
{ {
// start using firebreath
controller.push_basic_input(InputKind::Secondary); controller.push_basic_input(InputKind::Secondary);
} else if agent.combat_state.timers[ActionStateTimers::CloseMixup as usize] }
> CLOSE_MIXUP_COOLDOWN // on mixup timer, throw a pumpkin
else if agent.combat_state.timers[ActionStateTimers::CloseMixup as usize]
> MID_MIXUP_COOLDOWN
{ {
// throw pumpkin
controller.push_basic_input(InputKind::Ability(0)); controller.push_basic_input(InputKind::Ability(0));
} }
} }
@ -4911,9 +4929,11 @@ impl<'a> AgentData<'a> {
controller.push_basic_input(InputKind::Ability(0)); controller.push_basic_input(InputKind::Ability(0));
} }
// --- movement ---
// closing gap // closing gap
// 0.4 multiplier tuned to get comfortably in melee range if attack_data.dist_sqrd
if attack_data.dist_sqrd > (attack_data.body_dist + 0.4 * SCYTHE_RANGE).powi(2) { > (attack_data.body_dist + SCYTHE_RANGE * PATH_RANGE_FACTOR).powi(2)
{
self.path_toward_target( self.path_toward_target(
agent, agent,
controller, controller,
@ -4923,6 +4943,14 @@ impl<'a> AgentData<'a> {
None, None,
); );
} }
// closing angle
else if attack_data.angle > 0.0 {
controller.inputs.move_dir = (tgt_data.pos.0 - self.pos.0)
.xy()
.try_normalized()
.unwrap_or_else(Vec2::zero)
* 0.001; // scaled way down to minimise position change and keep close rotation consistent
}
} }
pub fn handle_frostgigas_attack( pub fn handle_frostgigas_attack(
@ -5855,17 +5883,21 @@ impl<'a> AgentData<'a> {
// === setup === // === setup ===
// hard-coded attack vlues // hard-coded attack vlues (some scaled for usage)
const STRIKE_RANGE: f32 = 4.5; const STRIKE_RANGE: f32 = 4.0;
const STRIKE_AIM_ANGLE: f32 = 55.0 * 0.7; const STRIKE_AIM_ANGLE: f32 = 55.0 * 0.7;
const SPIN_RANGE: f32 = 6.0; const SPIN_RANGE: f32 = 5.0;
const SHOCKWAVE_AIM_ANGLE: f32 = 45.0 * 0.7; const SHOCKWAVE_AIM_ANGLE: f32 = 45.0 * 0.7;
const SHOCKWAVE_MAX_RANGE: f32 = 30.0 * 0.6;
// behaviour parameters // behaviour parameters
const ATTACK_RANGE_FACTOR: f32 = 0.6; // start attack while suitably in range
const PATH_RANGE_FACTOR: f32 = 0.3; // get comfortably in range, but give player room to breathe
const SPIN_COOLDOWN: f32 = 1.5; const SPIN_COOLDOWN: f32 = 1.5;
const SHOCKWAVE_COOLDOWN: f32 = 4.5; const SPIN_RELAX_FACTOR: f32 = 0.2;
const SHOCKWAVE_COOLDOWN: f32 = 5.0;
const SHOCKWAVE_MIN_RANGE: f32 = 8.0; const SHOCKWAVE_MIN_RANGE: f32 = 8.0;
const SHOCKWAVE_MAX_RANGE: f32 = 25.0; const MIXUP_COOLDOWN: f32 = 2.5;
const MIXUP_COOLDOWN: f32 = 3.0; const MIXUP_RELAX_FACTOR: f32 = 0.3;
// timers // timers
enum ActionStateTimers { enum ActionStateTimers {
@ -5874,14 +5906,14 @@ impl<'a> AgentData<'a> {
Mixup, Mixup,
} }
// re-used comparisons // re-used comparisons (makes separating timers and attacks easier)
// hard-coded multiplier tuned to start attack while suitably in range let is_in_spin_range = attack_data.dist_sqrd
let is_in_spin_range = < (attack_data.body_dist + SPIN_RANGE * ATTACK_RANGE_FACTOR).powi(2);
attack_data.dist_sqrd < (attack_data.body_dist + (0.85 * SPIN_RANGE).powi(2)); let is_in_strike_range = attack_data.dist_sqrd
let is_in_strike_range = < (attack_data.body_dist + STRIKE_RANGE * ATTACK_RANGE_FACTOR).powi(2);
attack_data.dist_sqrd < (attack_data.body_dist + (0.85 * STRIKE_RANGE).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 ---
@ -5898,7 +5930,7 @@ impl<'a> AgentData<'a> {
// relax towards zero otherwise // relax towards zero otherwise
agent.combat_state.timers[ActionStateTimers::Spin as usize] = agent.combat_state.timers[ActionStateTimers::Spin as usize] =
(agent.combat_state.timers[ActionStateTimers::Spin as usize] (agent.combat_state.timers[ActionStateTimers::Spin as usize]
- 0.2 * read_data.dt.0) - SPIN_RELAX_FACTOR * read_data.dt.0)
.max(0.0); .max(0.0);
} }
// shockwave // shockwave
@ -5918,13 +5950,13 @@ impl<'a> AgentData<'a> {
// relax towards zero otherwise // relax towards zero otherwise
agent.combat_state.timers[ActionStateTimers::Mixup as usize] = agent.combat_state.timers[ActionStateTimers::Mixup as usize] =
(agent.combat_state.timers[ActionStateTimers::Mixup as usize] (agent.combat_state.timers[ActionStateTimers::Mixup as usize]
- 0.5 * read_data.dt.0) - MIXUP_RELAX_FACTOR * read_data.dt.0)
.max(0.0); .max(0.0);
} }
// --- attacks --- // --- attacks ---
// strike range // strike range and in angle
if is_in_strike_range { 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 = rng.gen_range(1..=3);
@ -5933,7 +5965,7 @@ impl<'a> AgentData<'a> {
2 => controller.push_basic_input(InputKind::Primary), // strike 2 => controller.push_basic_input(InputKind::Primary), // strike
_ => controller.push_basic_input(InputKind::Secondary), // spin _ => controller.push_basic_input(InputKind::Secondary), // spin
} }
} else if is_in_strike_angle { } else {
// use strike // use strike
controller.push_basic_input(InputKind::Primary); controller.push_basic_input(InputKind::Primary);
} }
@ -5957,9 +5989,9 @@ impl<'a> AgentData<'a> {
// --- movement --- // --- movement ---
// closing gap // closing gap
// hard-coded multiplier tuned to get comfortably in range, while giving player if attack_data.dist_sqrd
// some room to breathe > (attack_data.body_dist + STRIKE_RANGE * PATH_RANGE_FACTOR).powi(2)
if attack_data.dist_sqrd > (attack_data.body_dist + (0.75 * STRIKE_RANGE).powi(2)) { {
self.path_toward_target( self.path_toward_target(
agent, agent,
controller, controller,
@ -5976,12 +6008,7 @@ impl<'a> AgentData<'a> {
.xy() .xy()
.try_normalized() .try_normalized()
.unwrap_or_else(Vec2::zero) .unwrap_or_else(Vec2::zero)
* 0.001; * 0.001; // scaled way down to minimise position change and keep close rotation consistent
// // an attempt modifying look direciton, rather than using
// movement: let delta = (tgt_data.pos.0 -
// self.pos.0).try_normalized().unwrap_or_else(Vec3::zero);
// controller.inputs.look_dir =
// controller.inputs.look_dir.slerped_to(Dir::new(delta), 0.8);
} }
} }