Add a new particle mode for potion sickness.

This commit is contained in:
Avi Weinstock 2023-01-18 19:11:55 -05:00
parent dc6e61983c
commit aba6f6654e
4 changed files with 75 additions and 25 deletions

View File

@ -78,6 +78,7 @@ const int BLACK_SMOKE = 37;
const int LIGHTNING = 38; const int LIGHTNING = 38;
const int STEAM = 39; const int STEAM = 39;
const int BARRELORGAN = 40; const int BARRELORGAN = 40;
const int POTION_SICKNESS = 41;
// meters per second squared (acceleration) // meters per second squared (acceleration)
const float earth_gravity = 9.807; const float earth_gravity = 9.807;
@ -95,6 +96,12 @@ vec3 linear_motion(vec3 init_offs, vec3 vel) {
return init_offs + vel * lifetime; return init_offs + vel * lifetime;
} }
vec3 quadratic_bezier_motion(vec3 start, vec3 ctrl0, vec3 end) {
float t = lifetime;
float u = 1 - lifetime;
return u*u*start + t*u*ctrl0 + t*t*end;
}
vec3 grav_vel(float grav) { vec3 grav_vel(float grav) {
return vec3(0, 0, -grav * lifetime); return vec3(0, 0, -grav * lifetime);
} }
@ -637,6 +644,18 @@ void main() {
spin_in_axis(vec3(1,0,0),0) spin_in_axis(vec3(1,0,0),0)
); );
break; break;
case POTION_SICKNESS:
attr = Attr(
quadratic_bezier_motion(
vec3(0.0),
vec3(inst_dir.xy, 0.0),
inst_dir
),
vec3((2.0 * (1 - slow_start(0.8)))),
vec4(0.075, 0.625, 0, 1),
spin_in_axis(vec3(1,0,0),0)
);
break;
default: default:
attr = Attr( attr = Attr(
linear_motion( linear_motion(

View File

@ -436,6 +436,13 @@ impl Buff {
source, source,
} }
} }
/// Calculate how much time has elapsed since the buff was applied (if the
/// buff has a finite duration, otherwise insufficient information
/// exists to track that)
pub fn elapsed(&self) -> Option<Duration> {
self.data.duration.zip_with(self.time, |x, y| x - y)
}
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]

View File

@ -92,6 +92,7 @@ pub enum ParticleMode {
Lightning = 38, Lightning = 38,
Steam = 39, Steam = 39,
BarrelOrgan = 40, BarrelOrgan = 40,
PotionSickness = 41,
} }
impl ParticleMode { impl ParticleMode {

View File

@ -1148,11 +1148,12 @@ impl ParticleMgr {
let time = state.get_time(); let time = state.get_time();
let mut rng = thread_rng(); let mut rng = thread_rng();
for (interp, pos, buffs, body) in ( for (interp, pos, buffs, body, ori) in (
ecs.read_storage::<Interpolated>().maybe(), ecs.read_storage::<Interpolated>().maybe(),
&ecs.read_storage::<Pos>(), &ecs.read_storage::<Pos>(),
&ecs.read_storage::<comp::Buffs>(), &ecs.read_storage::<comp::Buffs>(),
&ecs.read_storage::<Body>(), &ecs.read_storage::<Body>(),
&ecs.read_storage::<Ori>(),
) )
.join() .join()
{ {
@ -1161,28 +1162,10 @@ impl ParticleMgr {
for (buff_kind, buff_ids) in buffs.kinds.iter() { for (buff_kind, buff_ids) in buffs.kinds.iter() {
use buff::BuffKind; use buff::BuffKind;
match buff_kind { match buff_kind {
BuffKind::Cursed | BuffKind::Burning | BuffKind::PotionSickness => { BuffKind::Cursed | BuffKind::Burning => {
let mut multiplicity = if buff_kind.stacks() {
buff_ids.len()
} else {
1
};
if let BuffKind::PotionSickness = buff_kind {
// Only show particles for potion sickness at the beginning
if buff_ids
.iter()
.filter_map(|id| buffs.buffs.get(id))
.all(|buff| buff.delay.is_none())
{
multiplicity = 0;
}
}
self.particles.resize_with( self.particles.resize_with(
self.particles.len() self.particles.len()
+ multiplicity + usize::from(self.scheduler.heartbeats(Duration::from_millis(15))),
* usize::from(
self.scheduler.heartbeats(Duration::from_millis(15)),
),
|| { || {
let start_pos = pos let start_pos = pos
+ Vec3::unit_z() * body.height() * 0.25 + Vec3::unit_z() * body.height() * 0.25
@ -1198,10 +1181,10 @@ impl ParticleMgr {
Particle::new_directed( Particle::new_directed(
Duration::from_secs(1), Duration::from_secs(1),
time, time,
match buff_kind { if matches!(buff_kind, BuffKind::Cursed) {
BuffKind::Cursed => ParticleMode::CultistFlame, ParticleMode::CultistFlame
BuffKind::PotionSickness => ParticleMode::Blood, } else {
_ => ParticleMode::FlameThrower, ParticleMode::FlameThrower
}, },
start_pos, start_pos,
end_pos, end_pos,
@ -1209,6 +1192,46 @@ impl ParticleMgr {
}, },
); );
}, },
BuffKind::PotionSickness => {
let mut multiplicity = 0;
// Only show particles for potion sickness at the beginning, after the
// drinking animation finishes
if buff_ids
.iter()
.filter_map(|id| buffs.buffs.get(id))
.any(|buff| {
matches!(buff.elapsed(), Some(dur) if Duration::from_secs(1) <= dur && dur <= Duration::from_secs_f32(1.5))
})
{
multiplicity = 1;
}
self.particles.resize_with(
self.particles.len()
+ multiplicity
* usize::from(
self.scheduler.heartbeats(Duration::from_millis(25)),
),
|| {
let start_pos = pos + Vec3::unit_z() * body.eye_height();
let (radius, theta) =
(rng.gen_range(0.0f32..1.0).sqrt(), rng.gen_range(0.0..TAU));
let end_pos = pos
+ *ori.look_dir()
+ Vec3::<f32>::new(
radius * theta.cos(),
radius * theta.sin(),
0.0,
) * 0.25;
Particle::new_directed(
Duration::from_secs(1),
time,
ParticleMode::PotionSickness,
start_pos,
end_pos,
)
},
);
},
BuffKind::Frenzied => { BuffKind::Frenzied => {
self.particles.resize_with( self.particles.resize_with(
self.particles.len() self.particles.len()