use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const WIKI_PAGES: [&str; 3] = [
"Firework Rocket",
"Data component format/fireworks",
"Data component format/equippable",
];
pub const ROCKET_ENTITY: &str = "minecraft:firework_rocket";
pub const ROCKET_ITEM: &str = "minecraft:firework_rocket";
pub const FIREWORKS_COMPONENT: &str = "minecraft:fireworks";
pub const ITEM_FIELD: &str = "FireworksItem";
pub const MIN_FLIGHT: u8 = 1;
pub const MAX_FLIGHT: u8 = 3;
pub const MIN_EXPLOSIONS: usize = 1;
pub const MAX_EXPLOSIONS: usize = 7;
pub const DAMAGE_ONE_STAR_HP: u32 = 7;
pub const DAMAGE_PER_EXTRA_STAR_HP: u32 = 2;
pub const BLAST_RADIUS: i32 = 5;
#[must_use]
pub fn worst_damage_hp() -> u32 {
DAMAGE_ONE_STAR_HP + DAMAGE_PER_EXTRA_STAR_HP * (MAX_EXPLOSIONS as u32 - 1)
}
pub const LIFETIME_STEP_TICKS: u32 = 10;
#[must_use]
pub fn lifetime_ticks(flight: u8) -> u32 {
(u32::from(flight) + 1) * LIFETIME_STEP_TICKS
}
pub const BURST_HEIGHTS: [i32; 3] = [8, 18, 32];
#[must_use]
pub fn burst_height(flight: u8) -> i32 {
let i = flight.clamp(MIN_FLIGHT, MAX_FLIGHT) as usize - 1;
BURST_HEIGHTS[i]
}
#[derive(
Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum FireworkShape {
SmallBall,
LargeBall,
Star,
Creeper,
Burst,
}
impl FireworkShape {
pub const ALL: [FireworkShape; 5] = [
FireworkShape::SmallBall,
FireworkShape::LargeBall,
FireworkShape::Star,
FireworkShape::Creeper,
FireworkShape::Burst,
];
#[must_use]
pub fn token(self) -> &'static str {
match self {
FireworkShape::SmallBall => "small_ball",
FireworkShape::LargeBall => "large_ball",
FireworkShape::Star => "star",
FireworkShape::Creeper => "creeper",
FireworkShape::Burst => "burst",
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct FireworkExplosion {
pub shape: FireworkShape,
#[schemars(length(min = 1), inner(pattern(r"^#[0-9a-fA-F]{6}$")))]
pub colors: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[schemars(inner(pattern(r"^#[0-9a-fA-F]{6}$")))]
pub fade_colors: Vec<String>,
#[serde(default, skip_serializing_if = "is_false")]
pub trail: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub twinkle: bool,
}
fn is_false(b: &bool) -> bool {
!*b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_worst_burst_cannot_kill_an_unhurt_player() {
assert_eq!(worst_damage_hp(), 19);
assert!(worst_damage_hp() < 20);
}
#[test]
fn lifetime_is_the_floor_of_the_games_range() {
assert_eq!(lifetime_ticks(1), 20);
assert_eq!(lifetime_ticks(2), 30);
assert_eq!(lifetime_ticks(3), 40);
}
#[test]
fn a_height_per_crafted_flight() {
assert_eq!(burst_height(1), 8);
assert_eq!(burst_height(2), 18);
assert_eq!(burst_height(3), 32);
}
}