use std::collections::VecDeque;
use crossterm::{
cursor::{self, MoveToNextLine},
style::{self, Print},
terminal, QueueableCommand,
};
use falling_tetromino_engine::{InGameTime, Notification, State};
use super::*;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, Default)]
pub struct PrototypeRenderer {
notification_feed_buffer: VecDeque<(Notification, InGameTime)>,
}
impl Renderer for PrototypeRenderer {
fn update_feed(
&mut self,
feed: impl IntoIterator<Item = (Notification, InGameTime)>,
_settings: &Settings,
) {
for x in feed {
self.notification_feed_buffer.push_front(x);
}
}
fn reset_veffects_state(&mut self) {
self.notification_feed_buffer.clear();
}
fn reset_viewport_state_with_offset_and_area(
&mut self,
_offsets: (u16, u16),
_dimensions: (u16, u16),
) {
}
fn render<T>(
&mut self,
term: &mut T,
game: &Game,
_meta_data: &GameMetaData,
_settings: &Settings,
_temp_data: &TemporaryAppData,
_keybinds_legend: &KeybindsLegend,
_replay_extra: Option<(InGameTime, f64)>,
) -> io::Result<()>
where
T: Write,
{
let State {
time: game_time,
board,
..
} = game.state();
let mut board = *board;
if let Some(piece) = game.phase().piece() {
for ((x, y), tile_id) in piece.tiles() {
board[y as usize][x as usize] = Some(tile_id);
}
}
term.queue(cursor::MoveTo(0, 0))?
.queue(terminal::Clear(terminal::ClearType::FromCursorDown))?;
term.queue(Print(" +--------------------+"))?
.queue(MoveToNextLine(1))?;
for (idx, line) in board.iter().take(20).enumerate().rev() {
let txt_line = format!(
"{idx:02} |{}|",
line.iter()
.map(|cell| {
cell.map_or(" .", |tile| match tile.get() {
1 => "OO",
2 => "II",
3 => "SS",
4 => "ZZ",
5 => "TT",
6 => "LL",
7 => "JJ",
253 => "WW",
254 => "WW",
255 => "WW",
t => unimplemented!("formatting unknown tile id {t}"),
})
})
.collect::<Vec<_>>()
.join("")
);
term.queue(Print(txt_line))?.queue(MoveToNextLine(1))?;
}
term.queue(Print(" +--------------------+"))?
.queue(MoveToNextLine(1))?;
term.queue(style::Print(format!(" {:?}", game_time)))?
.queue(MoveToNextLine(1))?;
let mut feed_evt_msgs = Vec::new();
for (notif, _) in self.notification_feed_buffer.iter() {
feed_evt_msgs.push(match notif {
Notification::Accolade {
point_bonus,
tetromino,
is_spin,
lineclears,
is_perfect,
combo,
} => {
let mut msg = Vec::new();
msg.push(format!("+{point_bonus}"));
if *is_perfect {
msg.push("Perfect".to_owned());
}
if *is_spin {
msg.push(format!("{tetromino:?}-Spin"));
}
let clear_action = match lineclears {
1 => "Single",
2 => "Double",
3 => "Triple",
4 => "Quadruple",
5 => "Quintuple",
6 => "Sextuple",
7 => "Septuple",
8 => "Octuple",
9 => "Nonuple",
10 => "Decuple",
11 => "Undecuple",
12 => "Duodecuple",
13 => "Tredecuple",
14 => "Quattuordecuple",
15 => "Quindecuple",
16 => "Sexdecuple",
17 => "Septendecuple",
18 => "Octodecuple",
19 => "Novemdecuple",
20 => "Vigintuple",
_ => "Absurduple",
}
.to_string();
msg.push(clear_action);
if *combo > 1 {
msg.push(format!("#{combo}."));
}
msg.join(" ")
}
feedback => format!("{feedback:?}"),
});
}
for str in feed_evt_msgs.iter().take(16) {
term.queue(Print(str))?.queue(MoveToNextLine(1))?;
}
term.flush()?;
Ok(())
}
}