mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added totem ability, totem ai, totem ability set, particles for totem abilities, and totem voxel model.
This commit is contained in:
parent
ac2f097d80
commit
5bf99eac11
@ -116,6 +116,11 @@
|
|||||||
(None, "common.abilities.custom.tidalwarrior.totem"),
|
(None, "common.abilities.custom.tidalwarrior.totem"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Custom("Tidal Totem"): (
|
||||||
|
primary: "common.abilities.custom.tidalwarrior.totem_wave",
|
||||||
|
secondary: "common.abilities.custom.tidalwarrior.totem_wave",
|
||||||
|
abilities: [],
|
||||||
|
),
|
||||||
Custom("Quad Med Quick"): (
|
Custom("Quad Med Quick"): (
|
||||||
primary: "common.abilities.custom.quadmedquick.triplestrike",
|
primary: "common.abilities.custom.quadmedquick.triplestrike",
|
||||||
secondary: "common.abilities.custom.quadmedquick.dash",
|
secondary: "common.abilities.custom.quadmedquick.dash",
|
||||||
|
@ -13,4 +13,5 @@ Shockwave(
|
|||||||
requires_ground: false,
|
requires_ground: false,
|
||||||
move_efficiency: 0.1,
|
move_efficiency: 0.1,
|
||||||
damage_kind: Energy,
|
damage_kind: Energy,
|
||||||
|
specifier: Fire,
|
||||||
)
|
)
|
||||||
|
@ -13,4 +13,5 @@ Shockwave(
|
|||||||
requires_ground: true,
|
requires_ground: true,
|
||||||
move_efficiency: 0.0,
|
move_efficiency: 0.0,
|
||||||
damage_kind: Crushing,
|
damage_kind: Crushing,
|
||||||
|
specifier: Ground,
|
||||||
)
|
)
|
@ -13,4 +13,5 @@ Shockwave(
|
|||||||
requires_ground: true,
|
requires_ground: true,
|
||||||
move_efficiency: 0.05,
|
move_efficiency: 0.05,
|
||||||
damage_kind: Crushing,
|
damage_kind: Crushing,
|
||||||
|
specifier: Ground,
|
||||||
)
|
)
|
||||||
|
@ -2,12 +2,11 @@ BasicSummon(
|
|||||||
buildup_duration: 0.5,
|
buildup_duration: 0.5,
|
||||||
cast_duration: 1.0,
|
cast_duration: 1.0,
|
||||||
recover_duration: 0.5,
|
recover_duration: 0.5,
|
||||||
summon_amount: 6,
|
summon_amount: 1,
|
||||||
summon_info: (
|
summon_info: (
|
||||||
// If this is still HaniwaSentry, code reviewers open a comment. I'll know what to do.
|
body: Object(SeaLantern),
|
||||||
body: Object(HaniwaSentry),
|
|
||||||
scale: None,
|
scale: None,
|
||||||
health_scaling: 20,
|
health_scaling: 0,
|
||||||
loadout_config: None,
|
loadout_config: None,
|
||||||
skillset_config: None,
|
skillset_config: None,
|
||||||
),
|
),
|
||||||
|
17
assets/common/abilities/custom/tidalwarrior/totem_wave.ron
Normal file
17
assets/common/abilities/custom/tidalwarrior/totem_wave.ron
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Shockwave(
|
||||||
|
energy_cost: 0,
|
||||||
|
buildup_duration: 1.4,
|
||||||
|
swing_duration: 0.1,
|
||||||
|
recover_duration: 0.5,
|
||||||
|
damage: 10,
|
||||||
|
poise_damage: 0,
|
||||||
|
knockback: ( strength: 100.0, direction: Up),
|
||||||
|
shockwave_angle: 360.0,
|
||||||
|
shockwave_vertical_angle: 30.0,
|
||||||
|
shockwave_speed: 10.0,
|
||||||
|
shockwave_duration: 5.0,
|
||||||
|
requires_ground: true,
|
||||||
|
move_efficiency: 0.0,
|
||||||
|
damage_kind: Crushing,
|
||||||
|
specifier: Water,
|
||||||
|
)
|
@ -13,4 +13,5 @@ Shockwave(
|
|||||||
requires_ground: false,
|
requires_ground: false,
|
||||||
move_efficiency: 0.1,
|
move_efficiency: 0.1,
|
||||||
damage_kind: Energy,
|
damage_kind: Energy,
|
||||||
|
specifier: Fire,
|
||||||
)
|
)
|
||||||
|
19
assets/common/items/npc_weapons/unique/tidal_totem.ron
Normal file
19
assets/common/items/npc_weapons/unique/tidal_totem.ron
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
ItemDef(
|
||||||
|
name: "Tidal Totem",
|
||||||
|
description: "Yeet",
|
||||||
|
kind: Tool((
|
||||||
|
kind: Natural,
|
||||||
|
hands: Two,
|
||||||
|
stats: Direct((
|
||||||
|
equip_time_secs: 0.01,
|
||||||
|
power: 1.0,
|
||||||
|
poise_strength: 1.0,
|
||||||
|
speed: 1.0,
|
||||||
|
crit_chance: 0.0625,
|
||||||
|
crit_mult: 1.9142857,
|
||||||
|
)),
|
||||||
|
)),
|
||||||
|
quality: Low,
|
||||||
|
tags: [],
|
||||||
|
ability_spec: Some(Custom("Tidal Totem")),
|
||||||
|
)
|
@ -68,6 +68,7 @@ const int ENRAGED = 26;
|
|||||||
const int BIG_SHRAPNEL = 27;
|
const int BIG_SHRAPNEL = 27;
|
||||||
const int LASER = 28;
|
const int LASER = 28;
|
||||||
const int BUBBLES = 29;
|
const int BUBBLES = 29;
|
||||||
|
const int WATER = 30;
|
||||||
|
|
||||||
// meters per second squared (acceleration)
|
// meters per second squared (acceleration)
|
||||||
const float earth_gravity = 9.807;
|
const float earth_gravity = 9.807;
|
||||||
@ -501,6 +502,17 @@ void main() {
|
|||||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case WATER:
|
||||||
|
f_reflect = 0.0; // Magic water doesn't reflect light, it emits it
|
||||||
|
blue_color = 1.25 + 0.2 * rand3 + 1.75 * max(floor(rand4 + 0.15), 0.0);
|
||||||
|
size = 8.0 * (1 - slow_start(0.1)) * slow_end(0.15);
|
||||||
|
attr = Attr(
|
||||||
|
(inst_dir * slow_end(0.2)) + vec3(rand0, rand1, rand2) * 0.5,
|
||||||
|
vec3(size),
|
||||||
|
vec4(0.5 * blue_color, 0.9 * blue_color, blue_color, 1),
|
||||||
|
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 5 + 3 * rand9)
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
attr = Attr(
|
attr = Attr(
|
||||||
linear_motion(
|
linear_motion(
|
||||||
|
BIN
assets/voxygen/voxel/object/sea_lantern.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/object/sea_lantern.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -709,4 +709,14 @@
|
|||||||
central: ("object.haniwa_sentry.bone1"),
|
central: ("object.haniwa_sentry.bone1"),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
SeaLantern: (
|
||||||
|
bone0: (
|
||||||
|
offset: (-4.5, -4.5, 0.0),
|
||||||
|
central: ("object.sea_lantern"),
|
||||||
|
),
|
||||||
|
bone1: (
|
||||||
|
offset: (0.0, 0.0, 0.0),
|
||||||
|
central: ("armor.empty"),
|
||||||
|
)
|
||||||
|
),
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
assets::{self, Asset},
|
assets::{self, Asset},
|
||||||
combat::{self, CombatEffect, DamageKind, Knockback},
|
combat::{self, CombatEffect, DamageKind, Knockback},
|
||||||
comp::{
|
comp::{
|
||||||
aura, beam, buff, inventory::item::tool::ToolKind, projectile::ProjectileConstructor,
|
self, aura, beam, buff, inventory::item::tool::ToolKind, projectile::ProjectileConstructor,
|
||||||
skills, Body, CharacterState, EnergySource, LightEmitter, StateUpdate,
|
skills, Body, CharacterState, EnergySource, LightEmitter, StateUpdate,
|
||||||
},
|
},
|
||||||
states::{
|
states::{
|
||||||
@ -233,6 +233,7 @@ pub enum CharacterAbility {
|
|||||||
requires_ground: bool,
|
requires_ground: bool,
|
||||||
move_efficiency: f32,
|
move_efficiency: f32,
|
||||||
damage_kind: DamageKind,
|
damage_kind: DamageKind,
|
||||||
|
specifier: comp::shockwave::FrontendSpecifier,
|
||||||
},
|
},
|
||||||
BasicBeam {
|
BasicBeam {
|
||||||
buildup_duration: f32,
|
buildup_duration: f32,
|
||||||
@ -1596,6 +1597,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
requires_ground,
|
requires_ground,
|
||||||
move_efficiency,
|
move_efficiency,
|
||||||
damage_kind,
|
damage_kind,
|
||||||
|
specifier,
|
||||||
} => CharacterState::Shockwave(shockwave::Data {
|
} => CharacterState::Shockwave(shockwave::Data {
|
||||||
static_data: shockwave::StaticData {
|
static_data: shockwave::StaticData {
|
||||||
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
buildup_duration: Duration::from_secs_f32(*buildup_duration),
|
||||||
@ -1612,6 +1614,7 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState {
|
|||||||
move_efficiency: *move_efficiency,
|
move_efficiency: *move_efficiency,
|
||||||
ability_info,
|
ability_info,
|
||||||
damage_kind: *damage_kind,
|
damage_kind: *damage_kind,
|
||||||
|
specifier: *specifier,
|
||||||
},
|
},
|
||||||
timer: Duration::default(),
|
timer: Duration::default(),
|
||||||
stage_section: StageSection::Buildup,
|
stage_section: StageSection::Buildup,
|
||||||
|
@ -491,6 +491,7 @@ impl Body {
|
|||||||
object::Body::TrainingDummy => 10000,
|
object::Body::TrainingDummy => 10000,
|
||||||
object::Body::Crossbow => 800,
|
object::Body::Crossbow => 800,
|
||||||
object::Body::HaniwaSentry => 600,
|
object::Body::HaniwaSentry => 600,
|
||||||
|
object::Body::SeaLantern => 1000,
|
||||||
_ => 10000,
|
_ => 10000,
|
||||||
},
|
},
|
||||||
Body::Golem(golem) => match golem.species {
|
Body::Golem(golem) => match golem.species {
|
||||||
|
@ -83,6 +83,7 @@ make_case_elim!(
|
|||||||
SilverOre = 68,
|
SilverOre = 68,
|
||||||
ClayRocket = 69,
|
ClayRocket = 69,
|
||||||
HaniwaSentry = 70,
|
HaniwaSentry = 70,
|
||||||
|
SeaLantern = 71,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ impl Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ALL_OBJECTS: [Body; 71] = [
|
pub const ALL_OBJECTS: [Body; 72] = [
|
||||||
Body::Arrow,
|
Body::Arrow,
|
||||||
Body::Bomb,
|
Body::Bomb,
|
||||||
Body::Scarecrow,
|
Body::Scarecrow,
|
||||||
@ -165,6 +166,7 @@ pub const ALL_OBJECTS: [Body; 71] = [
|
|||||||
Body::GoldOre,
|
Body::GoldOre,
|
||||||
Body::ClayRocket,
|
Body::ClayRocket,
|
||||||
Body::HaniwaSentry,
|
Body::HaniwaSentry,
|
||||||
|
Body::SeaLantern,
|
||||||
];
|
];
|
||||||
|
|
||||||
impl From<Body> for super::Body {
|
impl From<Body> for super::Body {
|
||||||
@ -245,6 +247,7 @@ impl Body {
|
|||||||
Body::GoldOre => "gold_ore",
|
Body::GoldOre => "gold_ore",
|
||||||
Body::ClayRocket => "clay_rocket",
|
Body::ClayRocket => "clay_rocket",
|
||||||
Body::HaniwaSentry => "haniwa_sentry",
|
Body::HaniwaSentry => "haniwa_sentry",
|
||||||
|
Body::SeaLantern => "sea_lantern",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +339,7 @@ impl Body {
|
|||||||
Body::GoldOre => 1000.0,
|
Body::GoldOre => 1000.0,
|
||||||
Body::ClayRocket => 50.0,
|
Body::ClayRocket => 50.0,
|
||||||
Body::HaniwaSentry => 300.0,
|
Body::HaniwaSentry => 300.0,
|
||||||
|
Body::SeaLantern => 1000.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
Mass(m)
|
Mass(m)
|
||||||
|
@ -308,6 +308,9 @@ pub fn default_main_tool(body: &Body) -> Option<Item> {
|
|||||||
object::Body::HaniwaSentry => Some(Item::new_from_asset_expect(
|
object::Body::HaniwaSentry => Some(Item::new_from_asset_expect(
|
||||||
"common.items.npc_weapons.unique.haniwa_sentry",
|
"common.items.npc_weapons.unique.haniwa_sentry",
|
||||||
)),
|
)),
|
||||||
|
object::Body::SeaLantern => Some(Item::new_from_asset_expect(
|
||||||
|
"common.items.npc_weapons.unique.tidal_totem",
|
||||||
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
Body::BipedSmall(biped_small) => match (biped_small.species, biped_small.body_type) {
|
Body::BipedSmall(biped_small) => match (biped_small.species, biped_small.body_type) {
|
||||||
|
@ -13,6 +13,7 @@ pub struct Properties {
|
|||||||
pub requires_ground: bool,
|
pub requires_ground: bool,
|
||||||
pub duration: Duration,
|
pub duration: Duration,
|
||||||
pub owner: Option<Uid>,
|
pub owner: Option<Uid>,
|
||||||
|
pub specifier: FrontendSpecifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@ -43,3 +44,10 @@ pub struct ShockwaveHitEntities {
|
|||||||
impl Component for ShockwaveHitEntities {
|
impl Component for ShockwaveHitEntities {
|
||||||
type Storage = IdvStorage<Self>;
|
type Storage = IdvStorage<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub enum FrontendSpecifier {
|
||||||
|
Ground,
|
||||||
|
Fire,
|
||||||
|
Water,
|
||||||
|
}
|
||||||
|
@ -44,6 +44,8 @@ pub struct StaticData {
|
|||||||
pub ability_info: AbilityInfo,
|
pub ability_info: AbilityInfo,
|
||||||
/// What kind of damage the attack does
|
/// What kind of damage the attack does
|
||||||
pub damage_kind: DamageKind,
|
pub damage_kind: DamageKind,
|
||||||
|
/// Used to specify the shockwave to the frontend
|
||||||
|
pub specifier: shockwave::FrontendSpecifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@ -108,6 +110,7 @@ impl CharacterBehavior for Data {
|
|||||||
attack,
|
attack,
|
||||||
requires_ground: self.static_data.requires_ground,
|
requires_ground: self.static_data.requires_ground,
|
||||||
owner: Some(*data.uid),
|
owner: Some(*data.uid),
|
||||||
|
specifier: self.static_data.specifier,
|
||||||
};
|
};
|
||||||
update.server_events.push_front(ServerEvent::Shockwave {
|
update.server_events.push_front(ServerEvent::Shockwave {
|
||||||
properties,
|
properties,
|
||||||
|
@ -112,6 +112,7 @@ pub enum Tactic {
|
|||||||
Turret,
|
Turret,
|
||||||
FixedTurret,
|
FixedTurret,
|
||||||
RotatingTurret,
|
RotatingTurret,
|
||||||
|
RadialTurret,
|
||||||
Mindflayer,
|
Mindflayer,
|
||||||
BirdLargeBreathe,
|
BirdLargeBreathe,
|
||||||
BirdLargeFire,
|
BirdLargeFire,
|
||||||
@ -1607,6 +1608,7 @@ impl<'a> AgentData<'a> {
|
|||||||
"Minotaur" => Tactic::Minotaur,
|
"Minotaur" => Tactic::Minotaur,
|
||||||
"Clay Golem" => Tactic::ClayGolem,
|
"Clay Golem" => Tactic::ClayGolem,
|
||||||
"Tidal Warrior" => Tactic::TidalWarrior,
|
"Tidal Warrior" => Tactic::TidalWarrior,
|
||||||
|
"Tidal Totem" => Tactic::RadialTurret,
|
||||||
_ => Tactic::Melee,
|
_ => Tactic::Melee,
|
||||||
},
|
},
|
||||||
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
AbilitySpec::Tool(tool_kind) => tool_tactic(*tool_kind),
|
||||||
@ -1856,6 +1858,13 @@ impl<'a> AgentData<'a> {
|
|||||||
&tgt_data,
|
&tgt_data,
|
||||||
&read_data,
|
&read_data,
|
||||||
),
|
),
|
||||||
|
Tactic::RadialTurret => self.handle_radial_turret_attack(
|
||||||
|
agent,
|
||||||
|
controller,
|
||||||
|
&attack_data,
|
||||||
|
&tgt_data,
|
||||||
|
&read_data,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2860,6 +2869,26 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_radial_turret_attack(
|
||||||
|
&self,
|
||||||
|
_agent: &mut Agent,
|
||||||
|
controller: &mut Controller,
|
||||||
|
attack_data: &AttackData,
|
||||||
|
tgt_data: &TargetData,
|
||||||
|
read_data: &ReadData,
|
||||||
|
) {
|
||||||
|
if can_see_tgt(
|
||||||
|
&*read_data.terrain,
|
||||||
|
self.pos,
|
||||||
|
tgt_data.pos,
|
||||||
|
attack_data.dist_sqrd,
|
||||||
|
) {
|
||||||
|
controller
|
||||||
|
.actions
|
||||||
|
.push(ControlAction::basic_input(InputKind::Primary));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_mindflayer_attack(
|
fn handle_mindflayer_attack(
|
||||||
&self,
|
&self,
|
||||||
agent: &mut Agent,
|
agent: &mut Agent,
|
||||||
|
@ -80,6 +80,7 @@ pub enum ParticleMode {
|
|||||||
BigShrapnel = 27,
|
BigShrapnel = 27,
|
||||||
Laser = 28,
|
Laser = 28,
|
||||||
Bubbles = 29,
|
Bubbles = 29,
|
||||||
|
Water = 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParticleMode {
|
impl ParticleMode {
|
||||||
|
@ -9,8 +9,8 @@ use crate::{
|
|||||||
use common::{
|
use common::{
|
||||||
assets::{AssetExt, DotVoxAsset},
|
assets::{AssetExt, DotVoxAsset},
|
||||||
comp::{
|
comp::{
|
||||||
self, aura, beam, body, buff, item::Reagent, object, BeamSegment, Body, CharacterState,
|
self, aura, beam, body, buff, item::Reagent, object, shockwave, BeamSegment, Body,
|
||||||
Ori, Pos, Shockwave, Vel,
|
CharacterState, Ori, Pos, Shockwave, Vel,
|
||||||
},
|
},
|
||||||
figure::Segment,
|
figure::Segment,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -1118,6 +1118,7 @@ impl ParticleMgr {
|
|||||||
let state = scene_data.state;
|
let state = scene_data.state;
|
||||||
let ecs = state.ecs();
|
let ecs = state.ecs();
|
||||||
let time = state.get_time();
|
let time = state.get_time();
|
||||||
|
let dt = scene_data.state.ecs().fetch::<DeltaTime>().0;
|
||||||
|
|
||||||
for (_entity, pos, ori, shockwave) in (
|
for (_entity, pos, ori, shockwave) in (
|
||||||
&ecs.entities(),
|
&ecs.entities(),
|
||||||
@ -1127,9 +1128,10 @@ impl ParticleMgr {
|
|||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
let elapsed = time - shockwave.creation.unwrap_or_default();
|
let elapsed = time - shockwave.creation.unwrap_or(time);
|
||||||
|
let speed = shockwave.properties.speed;
|
||||||
|
|
||||||
let distance = shockwave.properties.speed * elapsed as f32;
|
let distance = speed * elapsed as f32;
|
||||||
|
|
||||||
let radians = shockwave.properties.angle.to_radians();
|
let radians = shockwave.properties.angle.to_radians();
|
||||||
|
|
||||||
@ -1137,55 +1139,99 @@ impl ParticleMgr {
|
|||||||
let theta = ori_vec.y.atan2(ori_vec.x);
|
let theta = ori_vec.y.atan2(ori_vec.x);
|
||||||
let dtheta = radians / distance;
|
let dtheta = radians / distance;
|
||||||
|
|
||||||
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(2));
|
// Number of particles derived from arc length (for new particles at least, old
|
||||||
|
// can be converted later)
|
||||||
|
let arc_length = distance * radians;
|
||||||
|
|
||||||
for heartbeat in 0..heartbeats {
|
use shockwave::FrontendSpecifier;
|
||||||
if shockwave.properties.requires_ground {
|
match shockwave.properties.specifier {
|
||||||
// 1 / 3 the size of terrain voxel
|
FrontendSpecifier::Ground => {
|
||||||
let scale = 1.0 / 3.0;
|
let heartbeats = self.scheduler.heartbeats(Duration::from_millis(2));
|
||||||
|
for heartbeat in 0..heartbeats {
|
||||||
|
// 1 / 3 the size of terrain voxel
|
||||||
|
let scale = 1.0 / 3.0;
|
||||||
|
|
||||||
let scaled_speed = shockwave.properties.speed * scale;
|
let scaled_speed = speed * scale;
|
||||||
|
|
||||||
let sub_tick_interpolation = scaled_speed * 1000.0 * heartbeat as f32;
|
let sub_tick_interpolation = scaled_speed * 1000.0 * heartbeat as f32;
|
||||||
|
|
||||||
let distance =
|
let distance = speed * (elapsed as f32 - sub_tick_interpolation);
|
||||||
shockwave.properties.speed * (elapsed as f32 - sub_tick_interpolation);
|
|
||||||
|
|
||||||
let particle_count_factor = radians / (3.0 * scale);
|
let particle_count_factor = radians / (3.0 * scale);
|
||||||
let new_particle_count = distance * particle_count_factor;
|
let new_particle_count = distance * particle_count_factor;
|
||||||
self.particles.reserve(new_particle_count as usize);
|
self.particles.reserve(new_particle_count as usize);
|
||||||
|
|
||||||
for d in 0..(new_particle_count as i32) {
|
for d in 0..(new_particle_count as i32) {
|
||||||
let arc_position =
|
let arc_position =
|
||||||
theta - radians / 2.0 + dtheta * d as f32 / particle_count_factor;
|
theta - radians / 2.0 + dtheta * d as f32 / particle_count_factor;
|
||||||
|
|
||||||
let position = pos.0
|
let position = pos.0
|
||||||
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
||||||
|
|
||||||
let position_snapped = ((position / scale).floor() + 0.5) * scale;
|
let position_snapped = ((position / scale).floor() + 0.5) * scale;
|
||||||
|
|
||||||
self.particles.push(Particle::new(
|
self.particles.push(Particle::new(
|
||||||
Duration::from_millis(250),
|
Duration::from_millis(250),
|
||||||
time,
|
time,
|
||||||
ParticleMode::GroundShockwave,
|
ParticleMode::GroundShockwave,
|
||||||
position_snapped,
|
position_snapped,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
for d in 0..3 * distance as i32 {
|
FrontendSpecifier::Fire => {
|
||||||
let arc_position = theta - radians / 2.0 + dtheta * d as f32 / 3.0;
|
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 position = pos.0
|
let position = pos.0
|
||||||
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
+ distance * Vec3::new(arc_position.cos(), arc_position.sin(), 0.0);
|
||||||
|
|
||||||
self.particles.push(Particle::new(
|
self.particles.push(Particle::new(
|
||||||
Duration::from_secs_f32((distance + 10.0) / 50.0),
|
Duration::from_secs_f32((distance + 10.0) / 50.0),
|
||||||
time,
|
time,
|
||||||
ParticleMode::FireShockwave,
|
ParticleMode::FireShockwave,
|
||||||
position,
|
position,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
FrontendSpecifier::Water => {
|
||||||
|
// 4 particles 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
|
||||||
|
let heartbeats = self
|
||||||
|
.scheduler
|
||||||
|
.heartbeats(Duration::from_secs_f32(1.0 / speed));
|
||||||
|
|
||||||
|
// Reserves capacity for new particles
|
||||||
|
let new_particle_count = particles_per_length * heartbeats as usize;
|
||||||
|
self.particles.reserve(new_particle_count);
|
||||||
|
|
||||||
|
for i in 0..particles_per_length {
|
||||||
|
let angle = 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 distance = distance + speed * dt;
|
||||||
|
let pos1 = pos.0 + distance * direction - Vec3::unit_z();
|
||||||
|
let pos2 = pos1 + (Vec3::unit_z() + direction) * 3.0;
|
||||||
|
let time = time + dt as f64;
|
||||||
|
|
||||||
|
self.particles.push(Particle::new_directed(
|
||||||
|
Duration::from_secs_f32(0.5),
|
||||||
|
time,
|
||||||
|
ParticleMode::Water,
|
||||||
|
pos1,
|
||||||
|
pos2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user