1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct FadePalette {
6 pub bgp: u8,
7 pub obp0: u8,
8 pub obp1: u8,
9}
10
11impl FadePalette {
12 pub const fn new(bgp: u8, obp0: u8, obp1: u8) -> Self {
13 Self { bgp, obp0, obp1 }
14 }
15}
16
17pub const FADE_PAL_1: FadePalette = FadePalette::new(0xFF, 0xFF, 0xFF); pub const FADE_PAL_2: FadePalette = FadePalette::new(0xFE, 0xFE, 0xF8); pub const FADE_PAL_3: FadePalette = FadePalette::new(0xF9, 0xE4, 0xE4); pub const FADE_PAL_4: FadePalette = FadePalette::new(0xE4, 0xD0, 0xE0); pub const FADE_PAL_5: FadePalette = FadePalette::new(0xE4, 0xD0, 0xE0); pub const FADE_PAL_6: FadePalette = FadePalette::new(0x90, 0x80, 0x90); pub const FADE_PAL_7: FadePalette = FadePalette::new(0x40, 0x40, 0x40); pub const FADE_PAL_8: FadePalette = FadePalette::new(0x00, 0x00, 0x00); pub const FADE_PALETTES: [FadePalette; 8] = [
28 FADE_PAL_1, FADE_PAL_2, FADE_PAL_3, FADE_PAL_4, FADE_PAL_5, FADE_PAL_6, FADE_PAL_7, FADE_PAL_8,
29];
30
31pub const FADE_DELAY_FRAMES: u8 = 8;
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum FadeDirection {
35 InFromBlack, OutToBlack, OutToWhite, InFromWhite, }
40
41impl FadeDirection {
42 pub fn palette_indices(&self) -> &'static [usize] {
43 match self {
44 FadeDirection::InFromBlack => &[0, 1, 2, 3],
45 FadeDirection::OutToBlack => &[3, 2, 1, 0],
46 FadeDirection::OutToWhite => &[5, 6, 7],
47 FadeDirection::InFromWhite => &[6, 5, 4],
48 }
49 }
50
51 pub fn step_count(&self) -> usize {
52 self.palette_indices().len()
53 }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum InstantPalette {
58 Normal, WhiteOut, }
61
62impl InstantPalette {
63 pub fn palette(&self) -> FadePalette {
64 match self {
65 InstantPalette::Normal => FadePalette::new(0xE4, 0xD0, 0xE4),
66 InstantPalette::WhiteOut => FadePalette::new(0x00, 0x00, 0x00),
67 }
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub enum FadeState {
73 Idle,
74 Fading { step: usize, delay_remaining: u8 },
75 Done,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum FadeTickResult {
80 Fading(FadePalette),
81 Done(FadePalette),
82 Idle,
83}
84
85#[derive(Debug, Clone)]
86pub struct FadeTransition {
87 direction: Option<FadeDirection>,
88 state: FadeState,
89}
90
91impl FadeTransition {
92 pub fn new() -> Self {
93 Self {
94 direction: None,
95 state: FadeState::Idle,
96 }
97 }
98
99 pub fn start(&mut self, direction: FadeDirection) {
100 self.direction = Some(direction);
101 self.state = FadeState::Fading {
102 step: 0,
103 delay_remaining: FADE_DELAY_FRAMES,
104 };
105 }
106
107 pub fn is_active(&self) -> bool {
108 matches!(self.state, FadeState::Fading { .. })
109 }
110
111 pub fn is_done(&self) -> bool {
112 matches!(self.state, FadeState::Done)
113 }
114
115 pub fn state(&self) -> FadeState {
116 self.state
117 }
118
119 pub fn current_palette(&self) -> Option<FadePalette> {
120 let dir = self.direction.as_ref()?;
121 let indices = dir.palette_indices();
122 match self.state {
123 FadeState::Fading { step, .. } => {
124 if step < indices.len() {
125 Some(FADE_PALETTES[indices[step]])
126 } else {
127 Some(FADE_PALETTES[*indices.last().unwrap()])
128 }
129 }
130 FadeState::Done => Some(FADE_PALETTES[*indices.last().unwrap()]),
131 FadeState::Idle => None,
132 }
133 }
134
135 pub fn tick(&mut self) -> FadeTickResult {
136 let dir = match &self.direction {
137 Some(d) => *d,
138 None => return FadeTickResult::Idle,
139 };
140
141 match self.state {
142 FadeState::Idle => FadeTickResult::Idle,
143 FadeState::Done => {
144 self.state = FadeState::Idle;
145 self.direction = None;
146 FadeTickResult::Idle
147 }
148 FadeState::Fading {
149 step,
150 delay_remaining,
151 } => {
152 let indices = dir.palette_indices();
153 let palette = FADE_PALETTES[indices[step]];
154
155 if delay_remaining > 1 {
156 self.state = FadeState::Fading {
157 step,
158 delay_remaining: delay_remaining - 1,
159 };
160 FadeTickResult::Fading(palette)
161 } else {
162 let next_step = step + 1;
163 if next_step >= indices.len() {
164 self.state = FadeState::Done;
165 FadeTickResult::Done(palette)
166 } else {
167 self.state = FadeState::Fading {
168 step: next_step,
169 delay_remaining: FADE_DELAY_FRAMES,
170 };
171 FadeTickResult::Fading(FADE_PALETTES[indices[next_step]])
172 }
173 }
174 }
175 }
176 }
177
178 pub fn cancel(&mut self) {
179 self.state = FadeState::Idle;
180 self.direction = None;
181 }
182}
183
184impl Default for FadeTransition {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190pub fn load_gb_pal(map_pal_offset: u8) -> FadePalette {
193 let steps_back = (map_pal_offset / 3) as usize;
194 let index = 3usize.saturating_sub(steps_back);
195 FADE_PALETTES[index]
196}
197
198pub fn get_health_bar_color(hp_pixels: u8) -> u8 {
200 if hp_pixels >= 27 {
201 0
202 } else if hp_pixels >= 10 {
203 1
204 } else {
205 2
206 }
207}