use std::{num::NonZeroU8, time::Duration};
use falling_tetromino_engine::{Game, InGameTime, TileID};
use crate::tui_settings::{
graphics_settings::{
MaybeOverride::{self, Keep, Override},
TileTexture, UnwrapTileFromStr,
},
Palette, SlotMachine,
};
#[derive(PartialEq, PartialOrd, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum LineClearEffect {
Inline(LineClearInlineEffect),
Particle(LineClearParticleEffect),
}
#[derive(PartialEq, PartialOrd, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct LineClearInlineEffect {
#[serde(rename = "anim_idcs")]
pub anim_indices: [usize; 2 * Game::WIDTH],
#[serde(rename = "anim_lastidx")]
pub anim_lastidx: usize,
#[serde(rename = "col_anim")]
pub color_animation: Vec<MaybeOverride<TileID>>,
}
#[derive(PartialEq, PartialOrd, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct LineClearParticleEffect {
#[serde(rename = "dur_override")]
pub duration_override: MaybeOverride<InGameTime>,
#[serde(rename = "anim")]
pub animation: Vec<(MaybeOverride<TileTexture>, MaybeOverride<TileID>)>,
#[serde(rename = "accel")]
pub acceleration: (f32, f32),
#[serde(rename = "mm_base")]
pub momentum_base: (f32, f32),
#[serde(rename = "mm_rand")]
pub momentum_rand: (f32, f32),
#[serde(rename = "mm_xpos")]
pub momentum_xpos: f32,
}
pub fn default_line_clear_effect_slots() -> SlotMachine<LineClearEffect> {
let slots = vec![
("None".to_owned(), LineClearEffect::none()),
("Instant".to_owned(), LineClearEffect::instant()),
("Blink".to_owned(), LineClearEffect::blink()),
("Flash white".to_owned(), LineClearEffect::flash_white()),
("Left to right".to_owned(), LineClearEffect::left_to_right()),
("Clear inward".to_owned(), LineClearEffect::inward()),
("Burn outward".to_owned(), LineClearEffect::burn_outward()),
("Pop".to_owned(), LineClearEffect::pop()),
("Pop (higher)".to_owned(), LineClearEffect::pop_high()),
(
"Confetti (gratuitous)".to_owned(),
LineClearEffect::confetti(),
),
("Stardust".to_owned(), LineClearEffect::stardust()),
("Blast".to_owned(), LineClearEffect::blast()),
("Sparks".to_owned(), LineClearEffect::sparks()),
("Sparks ASCII".to_owned(), LineClearEffect::sparks_ascii()),
];
SlotMachine::with_unmodifiable_slots(slots, "Lineclear".to_owned())
}
impl LineClearEffect {
pub fn none() -> Self {
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::ZERO),
animation: Vec::new(),
acceleration: (0.0, 0.0),
momentum_base: (0.0, 0.0),
momentum_rand: (0.0, 0.0),
momentum_xpos: 0.0,
})
}
pub fn instant() -> Self {
LineClearEffect::Inline(LineClearInlineEffect {
anim_indices: [0; 2 * Game::WIDTH],
anim_lastidx: 1,
color_animation: Vec::new(),
})
}
pub fn left_to_right() -> Self {
LineClearEffect::Inline(LineClearInlineEffect {
anim_indices: [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
],
anim_lastidx: 19,
color_animation: vec![Override(Palette::WHITE)],
})
}
pub fn inward() -> Self {
LineClearEffect::Inline(LineClearInlineEffect {
anim_indices: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
anim_lastidx: 9,
color_animation: vec![Override(Palette::WHITE)],
})
}
pub fn burn_outward() -> Self {
let color_animation = [255, 255, 1, 6, 4]
.map(|n| Override(NonZeroU8::new(n).unwrap()))
.into();
LineClearEffect::Inline(LineClearInlineEffect {
anim_indices: [
18, 8, 16, 6, 14, 4, 12, 2, 10, 0, 1, 11, 3, 13, 5, 15, 7, 17, 9, 19,
],
anim_lastidx: 19,
color_animation,
})
}
pub fn flash_white() -> Self {
LineClearEffect::Inline(LineClearInlineEffect {
anim_indices: [1; 2 * Game::WIDTH],
anim_lastidx: 0,
color_animation: vec![Override(Palette::WHITE), Keep, Override(Palette::WHITE)],
})
}
pub fn blink() -> Self {
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Keep,
animation: [Keep, Override(" ".tile()), Keep, Override(" ".tile())]
.map(|t| (t, Keep))
.into(),
acceleration: (0.0, 0.0),
momentum_base: (0.0, 0.0),
momentum_rand: (0.0, 0.0),
momentum_xpos: 0.0,
})
}
pub fn pop() -> Self {
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(1000)),
animation: vec![(Keep, Keep)],
acceleration: (0.0, -200.0),
momentum_base: (0.0, 30.0),
momentum_rand: (10.0, 5.0),
momentum_xpos: 75.0,
})
}
pub fn pop_high() -> Self {
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(1000)),
animation: vec![(Keep, Keep)],
acceleration: (0.0, -200.0),
momentum_base: (0.0, 45.0),
momentum_rand: (50.0, 5.0),
momentum_xpos: 0.0,
})
}
pub fn confetti() -> Self {
let color_animation = [255, 1, 6, 4, 5, 7, 2, 3, 1, 6, 4, 5, 7, 2, 3]
.map(|n| Override(NonZeroU8::new(n).unwrap()));
let animation = color_animation
.into_iter()
.map(|recolor| (Keep, recolor))
.collect();
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(1000)),
animation,
acceleration: (0.0, -200.0),
momentum_base: (0.0, 55.0),
momentum_rand: (55.0, 25.0),
momentum_xpos: 45.0,
})
}
pub fn blast() -> Self {
let color_animation = [255, 1, 6, 4, 5].map(|n| Override(NonZeroU8::new(n).unwrap()));
let animation = color_animation
.into_iter()
.map(|recolor| (Keep, recolor))
.collect();
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(500)),
animation,
acceleration: (0.0, 10.0),
momentum_base: (0.0, -45.0),
momentum_rand: (50.0, 10.0),
momentum_xpos: 50.0,
})
}
pub fn stardust() -> Self {
let color_animation = [255, 3, 2, 2, 7, 5].map(|n| Override(NonZeroU8::new(n).unwrap()));
let animation = color_animation.map(|recolor| (Keep, recolor)).into();
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(450)),
animation,
acceleration: (650.0, 80.0),
momentum_base: (0.0, 0.0),
momentum_rand: (70.0, 10.0),
momentum_xpos: 100.0,
})
}
pub fn sparks() -> Self {
let color_animation = [255, 2, 1, 6, 4, 5].map(|n| Override(NonZeroU8::new(n).unwrap()));
let animation = color_animation.map(|recolor| (Keep, recolor)).into();
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(400)),
animation,
acceleration: (0.0, 0.0),
momentum_base: (0.0, 0.0),
momentum_rand: (60.0, 60.0),
momentum_xpos: 100.0,
})
}
pub fn sparks_ascii() -> Self {
let tile_animation =
["@@", "$$", "##", "%%", "**", "++", "~~", ".."].map(|ss| Override(ss.tile()));
let color_animation =
[255, 3, 2, 1, 2, 7, 5, 4].map(|n| Override(NonZeroU8::new(n).unwrap()));
let animation = tile_animation.into_iter().zip(color_animation).collect();
LineClearEffect::Particle(LineClearParticleEffect {
duration_override: Override(Duration::from_millis(500)),
animation,
acceleration: (0.0, 0.0),
momentum_base: (0.0, 40.0),
momentum_rand: (0.0, 40.0),
momentum_xpos: 100.0,
})
}
}