use crate::bms::prelude::SwBgaEvent;
use crate::bms::prelude::{Argb, BgaLayer, Key, NoteKind, PlayerSide};
use crate::chart::process::{BmpId, ChartEventId, WavId};
use gametime::TimeSpan;
use strict_num_extended::FinF64;
use strict_num_extended::NonNegativeF64;
use strict_num_extended::PositiveF64;
use crate::chart::MAX_NON_NEGATIVE_F64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct YCoordinate(pub NonNegativeF64);
impl YCoordinate {
#[must_use]
pub const fn new(value: NonNegativeF64) -> Self {
Self(value)
}
#[must_use]
pub const fn value(&self) -> &NonNegativeF64 {
&self.0
}
#[must_use]
pub const fn as_f64(&self) -> f64 {
self.0.as_f64()
}
pub const ZERO: Self = Self(NonNegativeF64::ZERO);
pub const ONE: Self = Self(NonNegativeF64::ONE);
}
impl From<NonNegativeF64> for YCoordinate {
fn from(value: NonNegativeF64) -> Self {
Self(value)
}
}
impl From<YCoordinate> for NonNegativeF64 {
fn from(value: YCoordinate) -> Self {
value.0
}
}
impl AsRef<NonNegativeF64> for YCoordinate {
fn as_ref(&self) -> &NonNegativeF64 {
&self.0
}
}
impl std::ops::Add for YCoordinate {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.add(rhs.0).unwrap_or(MAX_NON_NEGATIVE_F64))
}
}
impl std::ops::Add<NonNegativeF64> for YCoordinate {
type Output = Self;
fn add(self, rhs: NonNegativeF64) -> Self::Output {
Self(self.0.add(rhs).unwrap_or(MAX_NON_NEGATIVE_F64))
}
}
impl std::ops::Sub for YCoordinate {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(NonNegativeF64::new(self.0.as_f64() - rhs.0.as_f64()).unwrap_or(NonNegativeF64::ZERO))
}
}
impl std::ops::Sub<NonNegativeF64> for YCoordinate {
type Output = Self;
fn sub(self, rhs: NonNegativeF64) -> Self::Output {
Self(NonNegativeF64::new(self.0.as_f64() - rhs.as_f64()).unwrap_or(NonNegativeF64::ZERO))
}
}
impl std::ops::Mul<FinF64> for YCoordinate {
type Output = Self;
fn mul(self, rhs: FinF64) -> Self::Output {
Self(NonNegativeF64::new(self.0.as_f64() * rhs.as_f64()).unwrap_or(self.0))
}
}
impl std::ops::Div<FinF64> for YCoordinate {
type Output = Self;
fn div(self, rhs: FinF64) -> Self::Output {
Self(NonNegativeF64::new(self.0.as_f64() / rhs.as_f64()).unwrap_or(self.0))
}
}
#[derive(Debug, Clone)]
pub enum ChartEvent {
Note {
side: PlayerSide,
key: Key,
kind: NoteKind,
wav_id: Option<WavId>,
length: Option<NonNegativeF64>,
continue_play: Option<TimeSpan>,
},
Bgm {
wav_id: Option<WavId>,
},
BpmChange {
bpm: PositiveF64,
},
ScrollChange {
factor: FinF64,
},
SpeedChange {
factor: PositiveF64,
},
Stop {
duration: NonNegativeF64,
},
BgaChange {
layer: BgaLayer,
bmp_id: Option<BmpId>,
},
BgaOpacityChange {
layer: BgaLayer,
opacity: u8,
},
BgaArgbChange {
layer: BgaLayer,
argb: Argb,
},
BgmVolumeChange {
volume: u8,
},
KeyVolumeChange {
volume: u8,
},
TextDisplay {
text: String,
},
JudgeLevelChange {
level: crate::bms::command::JudgeLevel,
},
VideoSeek {
seek_time: f64,
},
BgaKeybound {
event: SwBgaEvent,
},
OptionChange {
option: String,
},
BarLine,
}
#[derive(Debug, Clone)]
pub struct PlayheadEvent {
pub id: ChartEventId,
pub position: YCoordinate,
pub event: ChartEvent,
pub activate_time: TimeSpan,
}
impl PlayheadEvent {
#[must_use]
pub const fn new(
id: ChartEventId,
position: YCoordinate,
event: ChartEvent,
activate_time: TimeSpan,
) -> Self {
Self {
id,
position,
event,
activate_time,
}
}
#[must_use]
pub const fn id(&self) -> ChartEventId {
self.id
}
#[must_use]
pub const fn position(&self) -> &YCoordinate {
&self.position
}
#[must_use]
pub const fn event(&self) -> &ChartEvent {
&self.event
}
#[must_use]
pub const fn activate_time(&self) -> &TimeSpan {
&self.activate_time
}
}
impl PartialEq for PlayheadEvent {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for PlayheadEvent {}
impl std::hash::Hash for PlayheadEvent {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
#[derive(Debug, Clone)]
pub enum FlowEvent {
Bpm(PositiveF64),
Speed(PositiveF64),
Scroll(FinF64),
}