mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'sam/yeti' into 'master'
Yeti Rework See merge request veloren/veloren!2359
This commit is contained in:
commit
85b8d4e7c0
@ -120,6 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Optimized rendering of quads (most of the graphics in the game) using an index buffer, decreasing the number of vertices that need to be processed by 33%.
|
||||
- Moved the rest of screenshot work into the background. Screenshoting no longer induces large pauses.
|
||||
- Reworked tidal warrior to have unique attacks
|
||||
- Reworked yeti to have unique attacks
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -237,6 +237,14 @@
|
||||
(None, "common.abilities.custom.claygolem.rocket"),
|
||||
],
|
||||
),
|
||||
Custom("Yeti"): (
|
||||
primary: "common.abilities.custom.yeti.strike",
|
||||
secondary: "common.abilities.custom.yeti.icespikes",
|
||||
abilities: [
|
||||
(None, "common.abilities.custom.yeti.frostbreath"),
|
||||
(None, "common.abilities.custom.yeti.snowball"),
|
||||
],
|
||||
),
|
||||
Custom("Bird Large Breathe"): (
|
||||
primary: "common.abilities.custom.birdlargebreathe.firebomb",
|
||||
secondary: "common.abilities.custom.birdlargebreathe.triplestrike",
|
||||
|
19
assets/common/abilities/custom/yeti/frostbreath.ron
Normal file
19
assets/common/abilities/custom/yeti/frostbreath.ron
Normal file
@ -0,0 +1,19 @@
|
||||
BasicBeam(
|
||||
buildup_duration: 0.4,
|
||||
recover_duration: 0.25,
|
||||
beam_duration: 0.25,
|
||||
damage: 50,
|
||||
tick_rate: 1.0,
|
||||
range: 15.0,
|
||||
max_angle: 30.0,
|
||||
damage_effect: Some(Buff((
|
||||
kind: Frozen,
|
||||
dur_secs: 3.0,
|
||||
strength: Value(1.5),
|
||||
chance: 1.0,
|
||||
))),
|
||||
energy_regen: 0,
|
||||
energy_drain: 0,
|
||||
orientation_behavior: Normal,
|
||||
specifier: Frost,
|
||||
)
|
17
assets/common/abilities/custom/yeti/icespikes.ron
Normal file
17
assets/common/abilities/custom/yeti/icespikes.ron
Normal file
@ -0,0 +1,17 @@
|
||||
Shockwave(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.6,
|
||||
swing_duration: 0.12,
|
||||
recover_duration: 0.3,
|
||||
damage: 100,
|
||||
poise_damage: 10,
|
||||
knockback: (strength: 25.0, direction: Up),
|
||||
shockwave_angle: 90.0,
|
||||
shockwave_vertical_angle: 15.0,
|
||||
shockwave_speed: 50.0,
|
||||
shockwave_duration: 0.5,
|
||||
requires_ground: true,
|
||||
move_efficiency: 0.5,
|
||||
damage_kind: Piercing,
|
||||
specifier: IceSpikes,
|
||||
)
|
13
assets/common/abilities/custom/yeti/snowball.ron
Normal file
13
assets/common/abilities/custom/yeti/snowball.ron
Normal file
@ -0,0 +1,13 @@
|
||||
BasicRanged(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.5,
|
||||
recover_duration: 0.4,
|
||||
projectile: Snowball(
|
||||
damage: 200.0,
|
||||
radius: 5.0,
|
||||
),
|
||||
projectile_body: Object(Snowball),
|
||||
projectile_speed: 60.0,
|
||||
num_projectiles: 1,
|
||||
projectile_spread: 0.0,
|
||||
)
|
13
assets/common/abilities/custom/yeti/strike.ron
Normal file
13
assets/common/abilities/custom/yeti/strike.ron
Normal file
@ -0,0 +1,13 @@
|
||||
BasicMelee(
|
||||
energy_cost: 0,
|
||||
buildup_duration: 0.6,
|
||||
swing_duration: 0.1,
|
||||
recover_duration: 0.5,
|
||||
base_damage: 100,
|
||||
base_poise_damage: 50,
|
||||
knockback: ( strength: 40.0, direction: Away),
|
||||
range: 4.0,
|
||||
max_angle: 20.0,
|
||||
damage_effect: None,
|
||||
damage_kind: Crushing,
|
||||
)
|
@ -2,11 +2,11 @@ ItemDef(
|
||||
name: "Yeti Hammer",
|
||||
description: "Placeholder",
|
||||
kind: Tool((
|
||||
kind: Hammer,
|
||||
kind: Natural,
|
||||
hands: Two,
|
||||
stats: Direct((
|
||||
equip_time_secs: 0.0,
|
||||
power: 2.0,
|
||||
equip_time_secs: 0.5,
|
||||
power: 1.0,
|
||||
poise_strength: 1.0,
|
||||
speed: 1.0,
|
||||
crit_chance: 0.046875,
|
||||
@ -15,5 +15,5 @@ ItemDef(
|
||||
)),
|
||||
quality: Low,
|
||||
tags: [],
|
||||
ability_spec: Some(Custom("Hammer Simple")),
|
||||
ability_spec: Some(Custom("Yeti")),
|
||||
)
|
@ -69,6 +69,7 @@ const int BIG_SHRAPNEL = 27;
|
||||
const int LASER = 28;
|
||||
const int BUBBLES = 29;
|
||||
const int WATER = 30;
|
||||
const int ICE_SPIKES = 31;
|
||||
|
||||
// meters per second squared (acceleration)
|
||||
const float earth_gravity = 9.807;
|
||||
@ -144,6 +145,12 @@ vec3 perp_axis2(vec3 axis1, vec3 axis2) {
|
||||
return normalize(vec3(axis1.y * axis2.z - axis1.z * axis2.y, axis1.z * axis2.x - axis1.x * axis2.z, axis1.x * axis2.y - axis1.y * axis2.x));
|
||||
}
|
||||
|
||||
// Line is the axis of the spiral, it goes from the start position to the end position
|
||||
// Radius is the distance from the axis the particle is
|
||||
// Time function is some value that ideally goes from 0 to 1. When it is 0, it is as
|
||||
// the point (0, 0, 0), when it is 1, it is at the point provided by the coordinates of line
|
||||
// Frequency increases the frequency of rotation
|
||||
// Offset is an offset to the angle of the rotation
|
||||
vec3 spiral_motion(vec3 line, float radius, float time_function, float frequency, float offset) {
|
||||
vec3 axis2 = perp_axis1(line);
|
||||
vec3 axis3 = perp_axis2(line, axis2);
|
||||
@ -420,10 +427,11 @@ void main() {
|
||||
break;
|
||||
case ICE:
|
||||
f_reflect = 0.0; // Ice doesn't reflect to look like magic
|
||||
float ice_color = 1.9 + rand5 * 0.3;
|
||||
attr = Attr(
|
||||
inst_dir * ((rand0+1.0)/2 + 0.4) * slow_end(2.0) + 0.3 * grav_vel(earth_gravity),
|
||||
vec3((3 * (1 - slow_start(0.1)))),
|
||||
vec4(0.2, 1.6 + rand5 * 0.3 - 0.4 * percent(), 3, 1),
|
||||
vec3((5 * (1 - slow_start(.1)))),
|
||||
vec4(0.8 * ice_color, 0.9 * ice_color, ice_color, 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
@ -513,6 +521,16 @@ void main() {
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 5 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case ICE_SPIKES:
|
||||
f_reflect = 0.0; // Ice doesn't reflect to look like magic
|
||||
ice_color = 1.7 + rand5 * 0.2;
|
||||
attr = Attr(
|
||||
vec3(0.0),
|
||||
vec3(11.0, 11.0, 11.0 * length(inst_dir) * 2.0 * (0.5 - abs(0.5 - slow_end(0.5)))) / 3,
|
||||
vec4(0.8 * ice_color, 0.9 * ice_color, ice_color, 1),
|
||||
spin_in_axis(vec3(1,0,0),0)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
|
@ -719,4 +719,14 @@
|
||||
central: ("armor.empty"),
|
||||
)
|
||||
),
|
||||
Snowball: (
|
||||
bone0: (
|
||||
offset: (-12.5, -12.5, 0.0),
|
||||
central: ("weapon.projectile.snowball"),
|
||||
),
|
||||
bone1: (
|
||||
offset: (0.0, 0.0, 0.0),
|
||||
central: ("armor.empty"),
|
||||
)
|
||||
),
|
||||
})
|
||||
|
BIN
assets/voxygen/voxel/weapon/projectile/snowball.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/weapon/projectile/snowball.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -54,4 +54,5 @@ pub enum FrontendSpecifier {
|
||||
Cultist,
|
||||
ClayGolem,
|
||||
Bubbles,
|
||||
Frost,
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ impl Body {
|
||||
biped_large::Species::Dullahan => 3000,
|
||||
biped_large::Species::Mindflayer => 12500,
|
||||
biped_large::Species::Tidalwarrior => 16000,
|
||||
biped_large::Species::Yeti => 4000,
|
||||
biped_large::Species::Yeti => 12000,
|
||||
biped_large::Species::Minotaur => 30000,
|
||||
biped_large::Species::Harvester => 3000,
|
||||
biped_large::Species::Blueoni => 2400,
|
||||
@ -586,7 +586,7 @@ impl Body {
|
||||
biped_large::Species::Wendigo => 80,
|
||||
biped_large::Species::Troll => 60,
|
||||
biped_large::Species::Dullahan => 120,
|
||||
biped_large::Species::Yeti => 80,
|
||||
biped_large::Species::Yeti => 0,
|
||||
biped_large::Species::Harvester => 80,
|
||||
// Boss enemies have their health set, not adjusted by level.
|
||||
biped_large::Species::Mindflayer => 0,
|
||||
@ -650,6 +650,7 @@ impl Body {
|
||||
biped_large::Species::Mindflayer => 4.8,
|
||||
biped_large::Species::Minotaur => 3.2,
|
||||
biped_large::Species::Tidalwarrior => 2.25,
|
||||
biped_large::Species::Yeti => 2.0,
|
||||
_ => 1.0,
|
||||
},
|
||||
Body::Golem(g) => match g.species {
|
||||
|
@ -84,6 +84,7 @@ make_case_elim!(
|
||||
ClayRocket = 69,
|
||||
HaniwaSentry = 70,
|
||||
SeaLantern = 71,
|
||||
Snowball = 72,
|
||||
}
|
||||
);
|
||||
|
||||
@ -94,7 +95,7 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
pub const ALL_OBJECTS: [Body; 72] = [
|
||||
pub const ALL_OBJECTS: [Body; 73] = [
|
||||
Body::Arrow,
|
||||
Body::Bomb,
|
||||
Body::Scarecrow,
|
||||
@ -167,6 +168,7 @@ pub const ALL_OBJECTS: [Body; 72] = [
|
||||
Body::ClayRocket,
|
||||
Body::HaniwaSentry,
|
||||
Body::SeaLantern,
|
||||
Body::Snowball,
|
||||
];
|
||||
|
||||
impl From<Body> for super::Body {
|
||||
@ -248,6 +250,7 @@ impl Body {
|
||||
Body::ClayRocket => "clay_rocket",
|
||||
Body::HaniwaSentry => "haniwa_sentry",
|
||||
Body::SeaLantern => "sea_lantern",
|
||||
Body::Snowball => "snowball",
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +273,7 @@ impl Body {
|
||||
Body::Crate => 300.0, // let's say it's a lot of wood and maybe some contents
|
||||
Body::Scarecrow => 900.0,
|
||||
Body::TrainingDummy => 2000.0,
|
||||
Body::Snowball => 0.9 * WATER_DENSITY,
|
||||
// let them sink
|
||||
_ => 1.1 * WATER_DENSITY,
|
||||
};
|
||||
@ -340,6 +344,7 @@ impl Body {
|
||||
Body::ClayRocket => 50.0,
|
||||
Body::HaniwaSentry => 300.0,
|
||||
Body::SeaLantern => 1000.0,
|
||||
Body::Snowball => 7360.0, // 2.5 m diamter
|
||||
};
|
||||
|
||||
Mass(m)
|
||||
@ -354,6 +359,7 @@ impl Body {
|
||||
Body::Crossbow => Vec3::new(3.0, 3.0, 1.5),
|
||||
Body::HaniwaSentry => Vec3::new(0.8, 0.8, 1.4),
|
||||
Body::SeaLantern => Vec3::new(0.5, 0.5, 1.0),
|
||||
Body::Snowball => Vec3::broadcast(2.5),
|
||||
_ => Vec3::broadcast(0.5),
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ pub struct Projectile {
|
||||
/// Whether projectile collides with entities in the same group as its
|
||||
/// owner
|
||||
pub ignore_group: bool,
|
||||
/// Whether the projectile is sticky
|
||||
pub is_sticky: bool,
|
||||
/// Whether the projectile should use a point collider
|
||||
pub is_point: bool,
|
||||
}
|
||||
|
||||
impl Component for Projectile {
|
||||
@ -64,6 +68,10 @@ pub enum ProjectileConstructor {
|
||||
radius: f32,
|
||||
knockback: f32,
|
||||
},
|
||||
Snowball {
|
||||
damage: f32,
|
||||
radius: f32,
|
||||
},
|
||||
}
|
||||
|
||||
impl ProjectileConstructor {
|
||||
@ -113,6 +121,8 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(15),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
}
|
||||
},
|
||||
Fireball {
|
||||
@ -149,6 +159,8 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
}
|
||||
},
|
||||
Frostball { damage, radius } => {
|
||||
@ -167,7 +179,7 @@ impl ProjectileConstructor {
|
||||
let explosion = Explosion {
|
||||
effects: vec![RadiusEffect::Attack(attack)],
|
||||
radius,
|
||||
reagent: Some(Reagent::Blue),
|
||||
reagent: Some(Reagent::White),
|
||||
};
|
||||
Projectile {
|
||||
hit_solid: vec![Effect::Explode(explosion.clone()), Effect::Vanish],
|
||||
@ -175,6 +187,8 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
}
|
||||
},
|
||||
NecroticSphere { damage, radius } => {
|
||||
@ -201,6 +215,8 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
}
|
||||
},
|
||||
Possess => Projectile {
|
||||
@ -209,6 +225,8 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: false,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
},
|
||||
ClayRocket {
|
||||
damage,
|
||||
@ -249,6 +267,35 @@ impl ProjectileConstructor {
|
||||
time_left: Duration::from_secs(10),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
}
|
||||
},
|
||||
Snowball { damage, radius } => {
|
||||
let damage = AttackDamage::new(
|
||||
Damage {
|
||||
source: DamageSource::Explosion,
|
||||
kind: DamageKind::Energy,
|
||||
value: damage,
|
||||
},
|
||||
Some(GroupTarget::OutOfGroup),
|
||||
);
|
||||
let attack = Attack::default()
|
||||
.with_damage(damage)
|
||||
.with_crit(crit_chance, crit_mult);
|
||||
let explosion = Explosion {
|
||||
effects: vec![RadiusEffect::Attack(attack)],
|
||||
radius,
|
||||
reagent: Some(Reagent::White),
|
||||
};
|
||||
Projectile {
|
||||
hit_solid: vec![],
|
||||
hit_entity: vec![Effect::Explode(explosion), Effect::Vanish],
|
||||
time_left: Duration::from_secs(120),
|
||||
owner,
|
||||
ignore_group: true,
|
||||
is_sticky: false,
|
||||
is_point: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -300,6 +347,13 @@ impl ProjectileConstructor {
|
||||
*damage *= power;
|
||||
*radius *= range;
|
||||
},
|
||||
Snowball {
|
||||
ref mut damage,
|
||||
ref mut radius,
|
||||
} => {
|
||||
*damage *= power;
|
||||
*radius *= range;
|
||||
},
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -50,4 +50,5 @@ pub enum FrontendSpecifier {
|
||||
Ground,
|
||||
Fire,
|
||||
Water,
|
||||
IceSpikes,
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ impl CharacterBehavior for Data {
|
||||
- self.timer.as_secs_f32()
|
||||
/ self.static_data.movement_duration.as_secs_f32())
|
||||
/ 2.0
|
||||
+ 0.5),
|
||||
+ 0.25),
|
||||
});
|
||||
|
||||
if self.timer < self.static_data.movement_duration {
|
||||
|
@ -285,17 +285,29 @@ impl StateExt for State {
|
||||
body: comp::Body,
|
||||
projectile: comp::Projectile,
|
||||
) -> EcsEntityBuilder {
|
||||
self.ecs_mut()
|
||||
let mut projectile_base = self
|
||||
.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(vel)
|
||||
.with(comp::Ori::from_unnormalized_vec(vel.0).unwrap_or_default())
|
||||
.with(body.mass())
|
||||
.with(body.density())
|
||||
.with(comp::Collider::Point)
|
||||
.with(body)
|
||||
.with(projectile)
|
||||
.with(comp::Sticky)
|
||||
.with(body.density());
|
||||
|
||||
if projectile.is_sticky {
|
||||
projectile_base = projectile_base.with(comp::Sticky)
|
||||
}
|
||||
if projectile.is_point {
|
||||
projectile_base = projectile_base.with(comp::Collider::Point)
|
||||
} else {
|
||||
projectile_base = projectile_base.with(comp::Collider::Box {
|
||||
radius: body.radius(),
|
||||
z_min: 0.0,
|
||||
z_max: body.height(),
|
||||
})
|
||||
}
|
||||
|
||||
projectile_base.with(projectile).with(body)
|
||||
}
|
||||
|
||||
fn create_shockwave(
|
||||
|
@ -119,6 +119,7 @@ pub enum Tactic {
|
||||
Minotaur,
|
||||
ClayGolem,
|
||||
TidalWarrior,
|
||||
Yeti,
|
||||
}
|
||||
|
||||
#[derive(SystemData)]
|
||||
@ -1609,6 +1610,7 @@ impl<'a> AgentData<'a> {
|
||||
"Clay Golem" => Tactic::ClayGolem,
|
||||
"Tidal Warrior" => Tactic::TidalWarrior,
|
||||
"Tidal Totem" => Tactic::RadialTurret,
|
||||
"Yeti" => Tactic::Yeti,
|
||||
_ => Tactic::Melee,
|
||||
},
|
||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||
@ -1697,6 +1699,18 @@ impl<'a> AgentData<'a> {
|
||||
),
|
||||
)
|
||||
},
|
||||
Tactic::Yeti if matches!(self.char_state, CharacterState::BasicRanged(_)) => {
|
||||
const SNOWBALL_SPEED: f32 = 60.0;
|
||||
aim_projectile(
|
||||
SNOWBALL_SPEED,
|
||||
Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
|
||||
Vec3::new(
|
||||
tgt_data.pos.0.x,
|
||||
tgt_data.pos.0.y,
|
||||
tgt_data.pos.0.z + tgt_eye_offset,
|
||||
),
|
||||
)
|
||||
},
|
||||
_ => Dir::from_unnormalized(
|
||||
Vec3::new(
|
||||
tgt_data.pos.0.x,
|
||||
@ -1865,6 +1879,9 @@ impl<'a> AgentData<'a> {
|
||||
&tgt_data,
|
||||
&read_data,
|
||||
),
|
||||
Tactic::Yeti => {
|
||||
self.handle_yeti_attack(agent, controller, &attack_data, &tgt_data, &read_data)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -3476,6 +3493,65 @@ impl<'a> AgentData<'a> {
|
||||
self.path_toward_target(agent, controller, tgt_data, read_data, false, None);
|
||||
}
|
||||
|
||||
fn handle_yeti_attack(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
controller: &mut Controller,
|
||||
attack_data: &AttackData,
|
||||
tgt_data: &TargetData,
|
||||
read_data: &ReadData,
|
||||
) {
|
||||
const ICE_SPIKES_RANGE: f32 = 20.0;
|
||||
const ICE_BREATH_RANGE: f32 = 15.0;
|
||||
const ICE_BREATH_TIMER: f32 = 10.0;
|
||||
const SNOWBALL_MAX_RANGE: f32 = 50.0;
|
||||
|
||||
agent.action_state.counter += read_data.dt.0;
|
||||
|
||||
if attack_data.dist_sqrd < ICE_BREATH_RANGE.powi(2) && attack_data.angle < 60.0 {
|
||||
if matches!(self.char_state, CharacterState::BasicBeam(c) if c.timer < Duration::from_secs(1))
|
||||
{
|
||||
// Keep using ice breath until a second has passed
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||
} else if agent.action_state.counter > ICE_BREATH_TIMER {
|
||||
// Use ice breath if timer has gone for long enough
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(0)));
|
||||
|
||||
if matches!(self.char_state, CharacterState::BasicBeam(_)) {
|
||||
// Resets action counter when using beam
|
||||
agent.action_state.counter = 0.0;
|
||||
}
|
||||
} else if attack_data.in_min_range() {
|
||||
// Basic attack if on top of them
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Primary));
|
||||
} else {
|
||||
// Use ice spikes if too far for other abilities
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||
}
|
||||
} else if attack_data.dist_sqrd < ICE_SPIKES_RANGE.powi(2) && attack_data.angle < 60.0 {
|
||||
// Use ice spikes if in range
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Secondary));
|
||||
} else if attack_data.dist_sqrd < SNOWBALL_MAX_RANGE.powi(2) && attack_data.angle < 60.0 {
|
||||
// Otherwise, chuck all the snowballs
|
||||
controller
|
||||
.actions
|
||||
.push(ControlAction::basic_input(InputKind::Ability(1)));
|
||||
}
|
||||
|
||||
// Always attempt to path towards target
|
||||
self.path_toward_target(agent, controller, tgt_data, read_data, false, None);
|
||||
}
|
||||
|
||||
fn follow(
|
||||
&self,
|
||||
agent: &mut Agent,
|
||||
|
@ -132,6 +132,8 @@ impl<'a> System<'a> for Sys {
|
||||
time_left: Duration::from_secs(60),
|
||||
owner: *owner,
|
||||
ignore_group: true,
|
||||
is_sticky: true,
|
||||
is_point: true,
|
||||
},
|
||||
speed,
|
||||
object: Some(Object::Firework {
|
||||
|
@ -297,6 +297,35 @@ impl Animation for AlphaAnimation {
|
||||
next.head.orientation =
|
||||
Quaternion::rotation_x(move1 * -0.6 + move2 * 0.4)
|
||||
},
|
||||
"Yeti" => {
|
||||
next.control_l.position = Vec3::new(-1.0, 2.0, 12.0 + move2 * -10.0);
|
||||
next.control_r.position = Vec3::new(1.0, 2.0, -2.0);
|
||||
|
||||
next.control.position = Vec3::new(
|
||||
4.0 + move1 * -12.0 + move2 * 20.0,
|
||||
(s_a.grip.0 / 1.0) + move1 * -3.0 + move2 * 5.0,
|
||||
(-s_a.grip.0 / 0.8) + move1 * -2.0 + move2 * 8.0,
|
||||
);
|
||||
next.head.orientation = Quaternion::rotation_x(move1 * -0.25)
|
||||
* Quaternion::rotation_z(move1 * -0.2 + move2 * 0.6);
|
||||
next.upper_torso.orientation =
|
||||
Quaternion::rotation_z(move1 * 0.2 + move2 * -0.4);
|
||||
next.lower_torso.orientation =
|
||||
Quaternion::rotation_z(move1 * -0.2 + move2 * 0.2);
|
||||
|
||||
next.control_l.orientation =
|
||||
Quaternion::rotation_x(PI / 2.0 + move2 * 0.8)
|
||||
* Quaternion::rotation_y(-0.0);
|
||||
next.control_r.orientation =
|
||||
Quaternion::rotation_x(PI / 2.0 + 0.2 + move2 * 0.8)
|
||||
* Quaternion::rotation_y(0.0)
|
||||
* Quaternion::rotation_z(0.0);
|
||||
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(-1.0 + move1 * -0.5 + move2 * -0.3)
|
||||
* Quaternion::rotation_y(-1.8 + move1 * -0.8 + move2 * 3.0)
|
||||
* Quaternion::rotation_z(move1 * -0.8 + move2 * -0.8);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -73,17 +73,12 @@ impl Animation for BeamAnimation {
|
||||
|
||||
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
||||
let (move1base, move2shake, _move2base, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (
|
||||
(anim_time.powf(0.25)).min(1.0),
|
||||
(anim_time * 15.0 + PI).sin(),
|
||||
(anim_time * 10.0 + PI).sin(),
|
||||
0.0,
|
||||
),
|
||||
let (move1base, move2shake, move2base, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => ((anim_time.powf(0.25)).min(1.0), 0.0, 0.0, 0.0),
|
||||
Some(StageSection::Cast) => (
|
||||
1.0,
|
||||
(anim_time * 15.0 + PI).sin(),
|
||||
anim_time.powf(0.25),
|
||||
(anim_time.powf(0.1)).min(1.0),
|
||||
0.0,
|
||||
),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, 1.0, anim_time),
|
||||
@ -91,6 +86,7 @@ impl Animation for BeamAnimation {
|
||||
};
|
||||
let pullback = 1.0 - move3;
|
||||
let move1 = move1base * pullback;
|
||||
let move2 = move2base * pullback;
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Sceptre) | Some(ToolKind::Staff) => {
|
||||
next.control_l.position = Vec3::new(-1.0, 3.0, 12.0);
|
||||
@ -128,8 +124,6 @@ impl Animation for BeamAnimation {
|
||||
);
|
||||
next.shoulder_r.orientation =
|
||||
Quaternion::rotation_x(move1 * 0.2 + 0.3 + 0.6 * speednorm + (footrotl * -0.2));
|
||||
next.torso.orientation = Quaternion::rotation_x(move1 * -0.1);
|
||||
next.torso.position = Vec3::new(0.0, 0.0, move1 * 1.0);
|
||||
},
|
||||
Some(ToolKind::Natural) => {
|
||||
if let Some(AbilitySpec::Custom(spec)) = active_tool_spec {
|
||||
@ -177,6 +171,50 @@ impl Animation for BeamAnimation {
|
||||
next.shoulder_r.orientation = Quaternion::rotation_z(move1 * 0.3);
|
||||
};
|
||||
},
|
||||
"Yeti" => {
|
||||
next.second.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.head.orientation = Quaternion::rotation_x(
|
||||
move1 * 0.5 + move2 * -0.5 + move2shake * -0.02,
|
||||
);
|
||||
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
||||
next.jaw.orientation =
|
||||
Quaternion::rotation_x(move2 * -0.5 + move2shake * -0.1);
|
||||
next.control_l.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_r.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||
|
||||
next.weapon_l.position = Vec3::new(-12.0, -1.0, -15.0);
|
||||
next.weapon_r.position = Vec3::new(12.0, -1.0, -15.0);
|
||||
|
||||
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
|
||||
next.arm_control_r.orientation =
|
||||
Quaternion::rotation_x(move1 * 1.1 + move2 * -1.6)
|
||||
* Quaternion::rotation_y(move1 * 1.4 + move2 * -1.8);
|
||||
|
||||
next.shoulder_l.orientation =
|
||||
Quaternion::rotation_x(move1 * 1.4 + move2 * -1.8);
|
||||
|
||||
next.shoulder_r.orientation =
|
||||
Quaternion::rotation_x(move1 * 1.4 + move2 * -1.8);
|
||||
|
||||
next.upper_torso.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.upper_torso.0,
|
||||
s_a.upper_torso.1 + move1 * -1.9 + move2 * 1.2,
|
||||
);
|
||||
next.upper_torso.orientation = Quaternion::rotation_x(
|
||||
move1 * 0.8 + move2 * -1.1 + move2shake * -0.02,
|
||||
);
|
||||
next.lower_torso.position =
|
||||
Vec3::new(0.0, s_a.lower_torso.0, s_a.lower_torso.1);
|
||||
next.lower_torso.orientation = Quaternion::rotation_x(
|
||||
move1 * -0.8 + move2 * 1.1 + move2shake * 0.02,
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,22 @@ use super::{
|
||||
super::{vek::*, Animation},
|
||||
BipedLargeSkeleton, SkeletonAttr,
|
||||
};
|
||||
use common::{comp::item::ToolKind, states::utils::StageSection};
|
||||
use common::{
|
||||
comp::item::{AbilitySpec, ToolKind},
|
||||
states::utils::StageSection,
|
||||
};
|
||||
|
||||
pub struct ShockwaveAnimation;
|
||||
|
||||
type ShockwaveAnimationDependency<'a> = (
|
||||
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||
(Option<ToolKind>, Option<&'a AbilitySpec>),
|
||||
f32,
|
||||
f32,
|
||||
Option<StageSection>,
|
||||
);
|
||||
impl Animation for ShockwaveAnimation {
|
||||
type Dependency<'a> = (
|
||||
Option<ToolKind>,
|
||||
Option<ToolKind>,
|
||||
f32,
|
||||
f32,
|
||||
Option<StageSection>,
|
||||
);
|
||||
type Dependency<'a> = ShockwaveAnimationDependency<'a>;
|
||||
type Skeleton = BipedLargeSkeleton;
|
||||
|
||||
#[cfg(feature = "use-dyn-lib")]
|
||||
@ -23,7 +27,13 @@ impl Animation for ShockwaveAnimation {
|
||||
#[allow(clippy::single_match)] // TODO: Pending review in #587
|
||||
fn update_skeleton_inner<'a>(
|
||||
skeleton: &Self::Skeleton,
|
||||
(_active_tool_kind, _second_tool_kind, _global_time, velocity, stage_section): Self::Dependency<'a>,
|
||||
(
|
||||
(active_tool_kind, active_tool_spec),
|
||||
_second_tool_kind,
|
||||
_global_time,
|
||||
velocity,
|
||||
stage_section,
|
||||
): Self::Dependency<'a>,
|
||||
anim_time: f32,
|
||||
rate: &mut f32,
|
||||
s_a: &SkeletonAttr,
|
||||
@ -31,71 +41,162 @@ impl Animation for ShockwaveAnimation {
|
||||
*rate = 1.0;
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let (movement1, movement2, movement3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time, 0.0, 0.0),
|
||||
Some(StageSection::Swing) => (1.0, anim_time, 0.0),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, anim_time),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
let (move1, move1pow, move2, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time, anim_time.powf(0.25) as f32, 0.0, 0.0),
|
||||
Some(StageSection::Swing) => (1.0, 1.0, anim_time, 0.0),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, 1.0, anim_time),
|
||||
_ => (0.0, 0.0, 0.0, 0.0),
|
||||
};
|
||||
|
||||
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||
let pullback = 1.0 - move3;
|
||||
let move1pow = move1pow * pullback;
|
||||
let move2 = move2 * pullback;
|
||||
|
||||
next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.sthl.3) * Quaternion::rotation_y(s_a.sthl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.sthr.0, s_a.sthr.1, s_a.sthr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.sthr.3) * Quaternion::rotation_y(s_a.sthr.4);
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_y(0.0);
|
||||
next.main.orientation = Quaternion::rotation_x(0.0);
|
||||
|
||||
next.control.position = Vec3::new(s_a.stc.0, s_a.stc.1, s_a.stc.2);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(s_a.stc.3) * Quaternion::rotation_y(s_a.stc.4);
|
||||
next.hand_l.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||
next.hand_r.position = Vec3::new(0.0, 0.0, s_a.grip.0);
|
||||
|
||||
let twist = movement1 * 0.8;
|
||||
next.hand_l.orientation = Quaternion::rotation_x(0.0);
|
||||
next.hand_r.orientation = Quaternion::rotation_x(0.0);
|
||||
|
||||
next.control.position = Vec3::new(
|
||||
s_a.stc.0 + movement1 * 5.0 + movement3 * -5.0,
|
||||
s_a.stc.1 + movement1 * 13.0 + movement3 * -3.0,
|
||||
s_a.stc.2 + movement1 * 10.0 + movement2 * -2.0 + movement3 * -8.0,
|
||||
);
|
||||
next.control.orientation = Quaternion::rotation_x(
|
||||
s_a.stc.3 + movement1 * 0.8 + movement2 * 0.3 + movement3 * -1.1,
|
||||
) * Quaternion::rotation_y(
|
||||
s_a.stc.4 + movement1 * -0.15 + movement2 * 0.3 + movement3 * -0.45,
|
||||
) * Quaternion::rotation_z(movement1 * 0.8 + movement2 * -0.8);
|
||||
match active_tool_kind {
|
||||
Some(ToolKind::Sceptre) => {
|
||||
next.head.position = Vec3::new(0.0, s_a.head.0, s_a.head.1);
|
||||
|
||||
next.head.orientation = Quaternion::rotation_x(movement1 * 0.4 + movement3 * -0.4)
|
||||
* Quaternion::rotation_z(twist * 0.2 + movement2 * -0.8 + movement3 * 0.6);
|
||||
next.hand_l.position = Vec3::new(s_a.sthl.0, s_a.sthl.1, s_a.sthl.2);
|
||||
next.hand_l.orientation =
|
||||
Quaternion::rotation_x(s_a.sthl.3) * Quaternion::rotation_y(s_a.sthl.4);
|
||||
next.hand_r.position = Vec3::new(s_a.sthr.0, s_a.sthr.1, s_a.sthr.2);
|
||||
next.hand_r.orientation =
|
||||
Quaternion::rotation_x(s_a.sthr.3) * Quaternion::rotation_y(s_a.sthr.4);
|
||||
next.main.position = Vec3::new(0.0, 0.0, 0.0);
|
||||
next.main.orientation = Quaternion::rotation_y(0.0);
|
||||
|
||||
next.upper_torso.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.upper_torso.0,
|
||||
s_a.upper_torso.1 + movement1 * 2.0 + movement2 * -4.0 + movement3 * 2.0,
|
||||
);
|
||||
next.upper_torso.orientation = Quaternion::rotation_x(movement2 * -0.8 + movement3 * 0.8)
|
||||
* Quaternion::rotation_z(twist * -0.2 + movement2 * -0.1 + movement3 * 0.3);
|
||||
next.control.position = Vec3::new(s_a.stc.0, s_a.stc.1, s_a.stc.2);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(s_a.stc.3) * Quaternion::rotation_y(s_a.stc.4);
|
||||
|
||||
next.lower_torso.orientation = Quaternion::rotation_x(movement2 * 0.3 + movement3 * -0.3)
|
||||
* Quaternion::rotation_z(twist + movement2 * -0.8);
|
||||
let twist = move1 * 0.8;
|
||||
|
||||
if velocity < 0.5 {
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0,
|
||||
s_a.foot.1 + movement1 * -7.0 + movement2 * 7.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_l.orientation = Quaternion::rotation_x(movement1 * -0.8 + movement2 * 0.8)
|
||||
* Quaternion::rotation_z(movement1 * 0.3 + movement2 * -0.3);
|
||||
next.control.position = Vec3::new(
|
||||
s_a.stc.0 + move1 * 5.0 + move3 * -5.0,
|
||||
s_a.stc.1 + move1 * 13.0 + move3 * -3.0,
|
||||
s_a.stc.2 + move1 * 10.0 + move2 * -2.0 + move3 * -8.0,
|
||||
);
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(s_a.stc.3 + move1 * 0.8 + move2 * 0.3 + move3 * -1.1)
|
||||
* Quaternion::rotation_y(
|
||||
s_a.stc.4 + move1 * -0.15 + move2 * 0.3 + move3 * -0.45,
|
||||
)
|
||||
* Quaternion::rotation_z(move1 * 0.8 + move2 * -0.8);
|
||||
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0,
|
||||
s_a.foot.1 + movement1 * 5.0 + movement2 * -5.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_r.orientation = Quaternion::rotation_y(movement1 * -0.3 + movement2 * 0.3)
|
||||
* Quaternion::rotation_z(movement1 * 0.4 + movement2 * -0.4);
|
||||
next.head.orientation = Quaternion::rotation_x(move1 * 0.4 + move3 * -0.4)
|
||||
* Quaternion::rotation_z(twist * 0.2 + move2 * -0.8 + move3 * 0.6);
|
||||
|
||||
next.upper_torso.position = Vec3::new(
|
||||
0.0,
|
||||
s_a.upper_torso.0,
|
||||
s_a.upper_torso.1 + move1 * 2.0 + move2 * -4.0 + move3 * 2.0,
|
||||
);
|
||||
next.upper_torso.orientation = Quaternion::rotation_x(move2 * -0.8 + move3 * 0.8)
|
||||
* Quaternion::rotation_z(twist * -0.2 + move2 * -0.1 + move3 * 0.3);
|
||||
|
||||
next.lower_torso.orientation = Quaternion::rotation_x(move2 * 0.3 + move3 * -0.3)
|
||||
* Quaternion::rotation_z(twist + move2 * -0.8);
|
||||
|
||||
if velocity < 0.5 {
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0,
|
||||
s_a.foot.1 + move1 * -7.0 + move2 * 7.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_l.orientation = Quaternion::rotation_x(move1 * -0.8 + move2 * 0.8)
|
||||
* Quaternion::rotation_z(move1 * 0.3 + move2 * -0.3);
|
||||
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0,
|
||||
s_a.foot.1 + move1 * 5.0 + move2 * -5.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_r.orientation = Quaternion::rotation_y(move1 * -0.3 + move2 * 0.3)
|
||||
* Quaternion::rotation_z(move1 * 0.4 + move2 * -0.4);
|
||||
}
|
||||
},
|
||||
Some(ToolKind::Natural) => {
|
||||
if let Some(AbilitySpec::Custom(spec)) = active_tool_spec {
|
||||
match spec.as_str() {
|
||||
"Yeti" => {
|
||||
next.second.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.head.orientation =
|
||||
Quaternion::rotation_x(move1pow * 0.8 + move2 * -1.2);
|
||||
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
||||
next.jaw.orientation = Quaternion::rotation_x(move2 * -0.3);
|
||||
next.control_l.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_r.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||
next.weapon_l.position =
|
||||
Vec3::new(-12.0 + (move1pow * 20.0).min(10.0), -1.0, -15.0);
|
||||
next.weapon_r.position =
|
||||
Vec3::new(12.0 + (move1pow * -20.0).max(-10.0), -1.0, -15.0);
|
||||
|
||||
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1)
|
||||
* Quaternion::rotation_z(move1pow * -1.0);
|
||||
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1)
|
||||
* Quaternion::rotation_z(move1pow * 1.0);
|
||||
|
||||
next.shoulder_l.orientation =
|
||||
Quaternion::rotation_x(-0.3 + move1pow * 2.8 + move2 * -2.8);
|
||||
|
||||
next.shoulder_r.orientation =
|
||||
Quaternion::rotation_x(-0.3 + move1pow * 2.8 + move2 * -2.8);
|
||||
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(move1pow * 2.5 + move2 * -2.0);
|
||||
|
||||
let twist = move1 * 0.6 + move3 * -0.6;
|
||||
next.upper_torso.position =
|
||||
Vec3::new(0.0, s_a.upper_torso.0, s_a.upper_torso.1);
|
||||
next.upper_torso.orientation =
|
||||
Quaternion::rotation_x(move1pow * 0.8 + move2 * -1.1)
|
||||
* Quaternion::rotation_z(
|
||||
twist * -0.2 + move1 * -0.1 + move2 * 0.3,
|
||||
);
|
||||
|
||||
next.lower_torso.orientation =
|
||||
Quaternion::rotation_x(move1pow * -0.8 + move2 * 1.1)
|
||||
* Quaternion::rotation_z(twist);
|
||||
|
||||
next.foot_l.position = Vec3::new(
|
||||
-s_a.foot.0,
|
||||
s_a.foot.1 + move1pow * -7.0 + move2 * 7.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_l.orientation =
|
||||
Quaternion::rotation_x(move1pow * -0.8 + move2 * 0.8)
|
||||
* Quaternion::rotation_z(move1pow * 0.3 + move2 * -0.3);
|
||||
|
||||
next.foot_r.position = Vec3::new(
|
||||
s_a.foot.0,
|
||||
s_a.foot.1 + move1pow * 5.0 + move2 * -5.0,
|
||||
s_a.foot.2,
|
||||
);
|
||||
next.foot_r.orientation =
|
||||
Quaternion::rotation_y(move1pow * -0.3 + move2 * 0.3)
|
||||
* Quaternion::rotation_z(move1pow * 0.4 + move2 * -0.4);
|
||||
|
||||
next.main.orientation =
|
||||
Quaternion::rotation_y(move1 * 0.4 + move2 * -0.6)
|
||||
* Quaternion::rotation_x(move2 * -0.4);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
next
|
||||
}
|
||||
|
@ -219,6 +219,49 @@ impl Animation for ShootAnimation {
|
||||
* Quaternion::rotation_z(move1 * -0.5);
|
||||
next.head.orientation = Quaternion::rotation_x(move1 * -0.3);
|
||||
},
|
||||
"Yeti" => {
|
||||
let (move1, move2, move3) = match stage_section {
|
||||
Some(StageSection::Buildup) => (anim_time.powf(0.25), 0.0, 0.0),
|
||||
Some(StageSection::Swing) => (1.0, anim_time, 0.0),
|
||||
Some(StageSection::Recover) => (1.0, 1.0, anim_time.powi(4)),
|
||||
_ => (0.0, 0.0, 0.0),
|
||||
};
|
||||
next.second.scale = Vec3::one() * 0.0;
|
||||
|
||||
next.head.orientation = Quaternion::rotation_x(move1 * 0.4);
|
||||
next.jaw.position = Vec3::new(0.0, s_a.jaw.0, s_a.jaw.1);
|
||||
next.jaw.orientation = Quaternion::rotation_x(move2 * -0.3);
|
||||
next.control_l.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_r.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||
next.weapon_l.position = Vec3::new(-12.0, -1.0, -15.0);
|
||||
next.weapon_r.position = Vec3::new(12.0, -1.0, -15.0);
|
||||
|
||||
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
|
||||
let twist = move1 * 0.8 + move3 * -0.8;
|
||||
next.upper_torso.position =
|
||||
Vec3::new(0.0, s_a.upper_torso.0, s_a.upper_torso.1);
|
||||
next.upper_torso.orientation =
|
||||
Quaternion::rotation_x(move1 * 0.8 + move2 * -1.1)
|
||||
* Quaternion::rotation_z(
|
||||
twist * -0.2 + move1 * -0.1 + move2 * 0.3,
|
||||
);
|
||||
|
||||
next.lower_torso.orientation =
|
||||
Quaternion::rotation_x(move1 * -0.8 + move2 * 1.1)
|
||||
* Quaternion::rotation_z(twist);
|
||||
|
||||
next.arm_control_r.orientation =
|
||||
Quaternion::rotation_x(move1 * PI / 2.0)
|
||||
* Quaternion::rotation_y(move1 * -PI / 2.0 + move2 * 2.5);
|
||||
//* Quaternion::rotation_y(move1 * -PI/2.0)
|
||||
//* Quaternion::rotation_z(move1 * -PI/2.0);
|
||||
next.arm_control_r.position =
|
||||
Vec3::new(0.0, move1 * 10.0 + move2 * -10.0, 0.0);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -450,6 +450,25 @@ impl Animation for WieldAnimation {
|
||||
|
||||
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3);
|
||||
},
|
||||
"Yeti" => {
|
||||
next.second.scale = Vec3::one() * 0.0;
|
||||
next.control_l.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.control_r.position = Vec3::new(-0.5, 4.0, 1.0);
|
||||
next.weapon_l.position = Vec3::new(-12.0, -1.0, -15.0);
|
||||
next.weapon_r.position = Vec3::new(12.0, -1.0, -15.0);
|
||||
|
||||
next.weapon_l.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
next.weapon_r.orientation = Quaternion::rotation_x(-1.57 - 0.1);
|
||||
|
||||
next.control_l.orientation = Quaternion::rotation_x(1.57);
|
||||
next.control_r.orientation = Quaternion::rotation_x(1.57);
|
||||
|
||||
next.control.orientation =
|
||||
Quaternion::rotation_x(0.0) * Quaternion::rotation_y(0.0);
|
||||
next.shoulder_l.orientation = Quaternion::rotation_x(-0.3);
|
||||
|
||||
next.shoulder_r.orientation = Quaternion::rotation_x(-0.3);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +403,9 @@ impl SfxMgr {
|
||||
audio.emit_sfx(sfx_trigger_item, *pos, None, false);
|
||||
}
|
||||
},
|
||||
beam::FrontendSpecifier::ClayGolem | beam::FrontendSpecifier::Bubbles => {},
|
||||
beam::FrontendSpecifier::ClayGolem
|
||||
| beam::FrontendSpecifier::Bubbles
|
||||
| beam::FrontendSpecifier::Frost => {},
|
||||
},
|
||||
Outcome::BreakBlock { pos, .. } => {
|
||||
let sfx_trigger_item = triggers.get_key_value(&SfxEvent::BreakBlock);
|
||||
|
@ -81,6 +81,7 @@ pub enum ParticleMode {
|
||||
Laser = 28,
|
||||
Bubbles = 29,
|
||||
Water = 30,
|
||||
IceSpikes = 31,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
|
@ -4161,8 +4161,8 @@ impl FigureMgr {
|
||||
anim::biped_large::ShockwaveAnimation::update_skeleton(
|
||||
&target_base,
|
||||
(
|
||||
active_tool_kind,
|
||||
second_tool_kind,
|
||||
(active_tool_kind, active_tool_spec),
|
||||
(second_tool_kind, second_tool_spec),
|
||||
time,
|
||||
rel_vel.magnitude(),
|
||||
Some(s.stage_section),
|
||||
@ -4775,7 +4775,7 @@ impl FigureMgr {
|
||||
.join()
|
||||
// Don't render dead entities
|
||||
.filter(|(_, _, _, health, _, _)| health.map_or(true, |h| !h.is_dead))
|
||||
// Don't render player
|
||||
// Don't render player
|
||||
.filter(|(entity, _, _, _, _, _)| *entity != player_entity)
|
||||
{
|
||||
if let Some((bound, model, col_lights)) = self.get_model_for_render(
|
||||
|
@ -100,7 +100,7 @@ impl ParticleMgr {
|
||||
},
|
||||
);
|
||||
},
|
||||
Some(Reagent::Blue) => {
|
||||
Some(Reagent::White) => {
|
||||
self.particles.resize_with(
|
||||
self.particles.len() + (75.0 * power.abs()) as usize,
|
||||
|| {
|
||||
@ -855,6 +855,31 @@ impl ParticleMgr {
|
||||
},
|
||||
);
|
||||
},
|
||||
beam::FrontendSpecifier::Frost => {
|
||||
let mut rng = thread_rng();
|
||||
let (from, to) = (Vec3::<f32>::unit_z(), *ori.look_dir());
|
||||
let m = Mat3::<f32>::rotation_from_to_3d(from, to);
|
||||
self.particles.resize_with(
|
||||
self.particles.len() + usize::from(beam_tick_count) / 4,
|
||||
|| {
|
||||
let phi: f32 = rng.gen_range(0.0..beam.properties.angle);
|
||||
let theta: f32 = rng.gen_range(0.0..2.0 * PI);
|
||||
let offset_z = Vec3::new(
|
||||
phi.sin() * theta.cos(),
|
||||
phi.sin() * theta.sin(),
|
||||
phi.cos(),
|
||||
);
|
||||
let random_ori = offset_z * m * Vec3::new(-1.0, -1.0, 1.0);
|
||||
Particle::new_directed(
|
||||
beam.properties.duration,
|
||||
time,
|
||||
ParticleMode::Ice,
|
||||
pos.0,
|
||||
pos.0 + random_ori * range,
|
||||
)
|
||||
},
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1131,12 +1156,14 @@ impl ParticleMgr {
|
||||
let elapsed = time - shockwave.creation.unwrap_or(time);
|
||||
let speed = shockwave.properties.speed;
|
||||
|
||||
let percent = elapsed as f32 / shockwave.properties.duration.as_secs_f32();
|
||||
|
||||
let distance = speed * elapsed as f32;
|
||||
|
||||
let radians = shockwave.properties.angle.to_radians();
|
||||
|
||||
let ori_vec = ori.look_vec();
|
||||
let theta = ori_vec.y.atan2(ori_vec.x);
|
||||
let theta = ori_vec.y.atan2(ori_vec.x) - radians / 2.0;
|
||||
let dtheta = radians / distance;
|
||||
|
||||
// Number of particles derived from arc length (for new particles at least, old
|
||||
@ -1162,8 +1189,7 @@ impl ParticleMgr {
|
||||
self.particles.reserve(new_particle_count as usize);
|
||||
|
||||
for d in 0..(new_particle_count as i32) {
|
||||
let arc_position =
|
||||
theta - radians / 2.0 + dtheta * d as f32 / particle_count_factor;
|
||||
let arc_position = theta + dtheta * d as f32 / particle_count_factor;
|
||||
|
||||
let position = pos.0
|
||||
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
||||
@ -1183,7 +1209,7 @@ impl ParticleMgr {
|
||||
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(2));
|
||||
for _ in 0..heartbeats {
|
||||
for d in 0..3 * distance as i32 {
|
||||
let arc_position = theta - radians / 2.0 + dtheta * d as f32 / 3.0;
|
||||
let arc_position = theta + dtheta * d as f32 / 3.0;
|
||||
|
||||
let position = pos.0
|
||||
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
||||
@ -1198,8 +1224,8 @@ impl ParticleMgr {
|
||||
}
|
||||
},
|
||||
FrontendSpecifier::Water => {
|
||||
// 4 particles per unit length of arc
|
||||
let particles_per_length = (arc_length) as usize;
|
||||
// 1 particle per unit length of arc
|
||||
let particles_per_length = arc_length as usize;
|
||||
let dtheta = radians / particles_per_length as f32;
|
||||
// Scales number of desired heartbeats from speed - thicker arc = higher speed =
|
||||
// lower duration = more particles
|
||||
@ -1232,6 +1258,67 @@ impl ParticleMgr {
|
||||
}
|
||||
}
|
||||
},
|
||||
FrontendSpecifier::IceSpikes => {
|
||||
// 1 / 3 the size of terrain voxel
|
||||
let scale = 1.0 / 3.0;
|
||||
let scaled_distance = distance / scale;
|
||||
let scaled_speed = speed / scale;
|
||||
|
||||
// 1 particle per scaled unit length of arc
|
||||
let particles_per_length = (0.25 * arc_length / scale) as usize;
|
||||
let dtheta = radians / particles_per_length as f32;
|
||||
// Scales number of desired heartbeats from speed - thicker arc = higher speed =
|
||||
// lower duration = more particles
|
||||
let heartbeats = self
|
||||
.scheduler
|
||||
.heartbeats(Duration::from_secs_f32(3.0 / scaled_speed));
|
||||
|
||||
// Reserves capacity for new particles
|
||||
let new_particle_count = particles_per_length * heartbeats as usize;
|
||||
self.particles.reserve(new_particle_count);
|
||||
|
||||
// Used to make taller the further out spikes are
|
||||
let height_scale = 0.5 + 1.5 * percent;
|
||||
|
||||
for i in 0..particles_per_length {
|
||||
let angle = theta + dtheta * i as f32;
|
||||
let direction = Vec3::new(angle.cos(), angle.sin(), 0.0);
|
||||
for j in 0..heartbeats {
|
||||
// Sub tick dt
|
||||
let dt = (j as f32 / heartbeats as f32) * dt;
|
||||
let scaled_distance = scaled_distance + scaled_speed * dt;
|
||||
let pos1 = pos.0 + (scaled_distance * direction).floor() * scale;
|
||||
let time = time + dt as f64;
|
||||
|
||||
let get_positions = |a| {
|
||||
let pos1 = match a {
|
||||
2 => pos1 + Vec3::unit_x() * scale,
|
||||
3 => pos1 - Vec3::unit_x() * scale,
|
||||
4 => pos1 + Vec3::unit_y() * scale,
|
||||
5 => pos1 - Vec3::unit_y() * scale,
|
||||
_ => pos1,
|
||||
};
|
||||
let pos2 = if a == 1 {
|
||||
pos1 + Vec3::unit_z() * 5.0 * height_scale
|
||||
} else {
|
||||
pos1 + Vec3::unit_z() * 1.0 * height_scale
|
||||
};
|
||||
(pos1, pos2)
|
||||
};
|
||||
|
||||
for a in 1..=5 {
|
||||
let (pos1, pos2) = get_positions(a);
|
||||
self.particles.push(Particle::new_directed(
|
||||
Duration::from_secs_f32(0.5),
|
||||
time,
|
||||
ParticleMode::IceSpikes,
|
||||
pos1,
|
||||
pos2,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user