diff --git a/src/game/hand.rs b/src/game/hand.rs index fd5a97b..f17b6ba 100644 --- a/src/game/hand.rs +++ b/src/game/hand.rs @@ -1,16 +1,13 @@ -use bevy::prelude::*; +use bevy::{ecs::relationship::RelationshipSourceCollection, prelude::*}; use crate::{ - game::{GameState, player::Player, wall::Wall}, - tile::Tile, + game::{player::Player /* wall::WallTiles */}, + tiles::Tile, }; #[derive(Component)] pub struct Hand; -#[derive(Component)] -pub struct DrawnTile(pub Entity); - // #[derive(Component, Default)] // enum SortHand { // #[default] @@ -21,7 +18,7 @@ pub struct DrawnTile(pub Entity); pub(crate) fn sort_hands( tiles: Populated<&Tile>, - hands: Populated<&mut Children, (Changed, Without)>, + mut hands: Populated<&mut Children, (Changed, Without)>, ) -> Result { for mut hand in hands { hand.sort_unstable_by_key(|e| tiles.get(*e).unwrap().suit); @@ -29,38 +26,3 @@ pub(crate) fn sort_hands( } Ok(()) } - -pub(crate) fn shuffle_deal( - mut commands: Commands, - tiles: Populated>, - players: Populated>, - wall_ent: Single>, - mut next_gamestate: ResMut>, -) -> Result { - use rand::seq::SliceRandom; - - let mut rng = rand::rng(); - let mut walltiles: Vec<_> = tiles.iter().collect(); - walltiles.shuffle(&mut rng); - - // commands.get_entity(*wall_ent)?.replace_children(&walltiles); - - for player_ent in players { - let handtiles = walltiles.split_off(walltiles.len() - 13); - // commands.get_entity(*wall_ent)?.remove_children(&handtiles); - - let hand_ent = commands.spawn(Hand).add_children(&handtiles).id(); - debug!("hand_ent: {hand_ent:?}"); - - commands - .get_entity(player_ent)? - .replace_children(&[hand_ent]); - - debug!("dealt to player_ent {player_ent:?}"); - } - - commands.get_entity(*wall_ent)?.replace_children(&walltiles); - - next_gamestate.set(GameState::Play); - Ok(()) -} diff --git a/src/game/mod.rs b/src/game/mod.rs index c296e21..8d41908 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -3,11 +3,10 @@ use bevy::prelude::*; use crate::{ game::{ hand::Hand, - player::MainPlayer, - round::{CurrentPlayer, TurnState, Wind}, + player::{MainPlayer, Player}, wall::Wall, }, - tile::{self}, + tiles::{self, *}, }; pub mod hand; @@ -30,32 +29,57 @@ impl Plugin for Riichi { app // start stopper .init_state::() - .add_sub_state::() .init_resource::() .init_resource::() - .add_systems(Startup, tile::init_tiles) + .add_systems(Startup, tiles::init_tiles) .add_systems(OnEnter(GameState::Setup), setup) - .add_systems(OnEnter(GameState::Deal), hand::shuffle_deal) + .add_systems(OnEnter(GameState::Deal), shuffle_deal) .add_systems(Update, hand::sort_hands.run_if(in_state(GameState::Play))) - // .add_systems(Update, turn_manager.run_if(in_state(GameState::Play))) - .add_systems(OnEnter(TurnState::Tsumo), round::tsumo) // semicolon stopper ; } } -// struct TurnEvent { -// pub next: Option, -// pub prev: Option, -// } +fn shuffle_deal( + mut commands: Commands, + tiles: Populated>, + players: Populated>, + wall_ent: Single>, + mut next_gamestate: ResMut>, +) -> Result { + use rand::seq::SliceRandom; -// fn turn_manager() {} + let mut rng = rand::rng(); + let mut walltiles: Vec<_> = tiles.iter().collect(); + walltiles.shuffle(&mut rng); + + // commands.get_entity(*wall_ent)?.replace_children(&walltiles); + + for player_ent in players { + let handtiles = walltiles.split_off(walltiles.len() - 13); + // commands.get_entity(*wall_ent)?.remove_children(&handtiles); + + let hand_ent = commands.spawn(Hand).add_children(&handtiles).id(); + debug!("hand_ent: {hand_ent:?}"); + + commands + .get_entity(player_ent)? + .replace_children(&[hand_ent]); + + debug!("dealt to player_ent {player_ent:?}"); + } + + commands.get_entity(*wall_ent)?.replace_children(&walltiles); + + next_gamestate.set(GameState::Play); + Ok(()) +} pub(crate) fn setup( mut commands: Commands, matchsettings: Res, // mut compass: ResMut - // tiles: Query>, + tiles: Query>, mut next_gamestate: ResMut>, ) { for i in 1..=matchsettings.player_count { @@ -64,16 +88,10 @@ pub(crate) fn setup( }; let points = player::Points(matchsettings.starting_points); - let bundle = ( - player, - points, - Hand, - Wind::from_repr((i - 1) as usize).unwrap(), - ); + let bundle = (player, points, Hand); if i == 1 { - let player = commands.spawn((bundle, MainPlayer)).id(); - commands.insert_resource(CurrentPlayer(player)); + commands.spawn((bundle, MainPlayer)); } else { commands.spawn(bundle); } diff --git a/src/game/player.rs b/src/game/player.rs index d241ba6..c7c3e6c 100644 --- a/src/game/player.rs +++ b/src/game/player.rs @@ -10,9 +10,3 @@ pub struct Points(pub isize); #[derive(Component)] pub struct MainPlayer; - -#[derive(Component)] -pub struct Dealer; - -#[derive(Component)] -pub struct Tsumo(pub Entity); diff --git a/src/game/round.rs b/src/game/round.rs index 9cf95df..fa4873b 100644 --- a/src/game/round.rs +++ b/src/game/round.rs @@ -1,10 +1,6 @@ use bevy::prelude::*; -use strum::{EnumCount, FromRepr}; -use crate::{ - EnumNextCycle, - game::{GameState, hand::DrawnTile, wall::Wall}, -}; +use crate::tiles::*; #[derive(Component)] pub(crate) struct Dice(u8, u8); @@ -44,66 +40,3 @@ impl Default for MatchSettings { } } } - -#[derive(Component, Clone, Copy, FromRepr, EnumCount)] -pub enum Wind { - Ton, - Nan, - Shaa, - Pei, -} - -impl EnumNextCycle for Wind { - fn next(&self) -> Self { - if (*self as usize + 1) >= Self::COUNT { - Self::from_repr(0).unwrap() - } else { - Self::from_repr(*self as usize + 1).unwrap() - } - } -} - -#[derive(Resource)] -pub(crate) struct CurrentPlayer(pub Entity); - -#[derive(SubStates, Default, Clone, Copy, PartialEq, Eq, Hash, Debug, FromRepr, EnumCount)] -#[source(GameState = GameState::Play)] -pub(crate) enum TurnState { - #[default] - Tsumo, - Menzen, - RiichiKan, - Discard, - RonChiiPonKan, - End, -} - -impl EnumNextCycle for TurnState { - fn next(&self) -> Self { - if (*self as usize + 1) >= Self::COUNT { - Self::from_repr(0).unwrap() - } else { - Self::from_repr(*self as usize + 1).unwrap() - } - } -} - -pub(crate) fn tsumo( - mut commands: Commands, - curr_player: Res, - // players: Populated>, - wall_ent: Single>, - walltiles: Single<&Children, With>, - curr_turnstate: Res>, - mut next_turnstate: ResMut>, -) { - trace!("tsumo for: {:?}", curr_player.0); - - let drawn = walltiles.last().unwrap(); - commands.entity(*wall_ent).remove_child(*drawn); - commands.entity(curr_player.0).insert(DrawnTile(*drawn)); - - debug!("drew: {:?}", drawn); - - next_turnstate.set(curr_turnstate.next()); -} diff --git a/src/game/wall.rs b/src/game/wall.rs index e382cf6..4463c26 100644 --- a/src/game/wall.rs +++ b/src/game/wall.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; +use rand::seq::SliceRandom; + +use crate::tiles::Tile; #[derive(Component)] pub struct Wall; - -#[derive(Component)] -pub struct Dead; diff --git a/src/lib.rs b/src/lib.rs index 480c8a5..45412c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,5 @@ -pub mod game; -pub mod tile; -pub mod yakus; +#![allow(unused)] -trait EnumNextCycle { - fn next(&self) -> Self; -} +pub mod game; +pub mod tiles; +pub mod yakus; diff --git a/src/main.rs b/src/main.rs index aa4e2ee..1a8dd9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use bevy::{log::LogPlugin, prelude::*}; use clap::{Parser, Subcommand}; use tracing::Level; diff --git a/src/tile.rs b/src/tiles.rs similarity index 91% rename from src/tile.rs rename to src/tiles.rs index 89fe820..40879fe 100644 --- a/src/tile.rs +++ b/src/tiles.rs @@ -1,12 +1,12 @@ use bevy::{ecs::entity::MapEntities, prelude::*}; use strum::FromRepr; -#[derive(Component, Debug, Clone, Copy)] +#[derive(Component, Debug)] pub struct Tile { pub suit: Suit, } -#[derive(/* MapEntities, */ Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] +#[derive(MapEntities, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] pub enum Suit { Man(Rank), Pin(Rank), diff --git a/src/tui/console.rs b/src/tui/console.rs index 7cd2171..efdcd7a 100644 --- a/src/tui/console.rs +++ b/src/tui/console.rs @@ -1,13 +1,12 @@ use bevy::prelude::*; -use ratatui::widgets::{Block, Clear}; +use bevy_ratatui::RatatuiContext; +use ratatui::widgets::Block; use tui_logger::TuiLoggerWidget; -use crate::tui::render::WidgetStack; - #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)] pub(crate) enum ConsoleState { - #[default] Closed, + #[default] Open, } @@ -22,13 +21,11 @@ impl std::ops::Not for ConsoleState { } } -pub(crate) fn draw_console(mut widgets: ResMut) { - widgets.0.push(Box::new(|frame| { +pub(crate) fn draw_console(mut tui_ctx: ResMut) -> Result { + tui_ctx.draw(|frame| { let block = Block::bordered().title("console"); - frame.render_widget(Clear, frame.area()); - frame.render_widget( - TuiLoggerWidget::default().block(block), - frame.area(), /* .inner(Margin { horizontal: 8, vertical: 8 }) */ - ); - })); + frame.render_widget(TuiLoggerWidget::default().block(block), frame.area()); + })?; + + Ok(()) } diff --git a/src/tui/input/keyboard.rs b/src/tui/input.rs similarity index 71% rename from src/tui/input/keyboard.rs rename to src/tui/input.rs index 6e70e66..44947c3 100644 --- a/src/tui/input/keyboard.rs +++ b/src/tui/input.rs @@ -1,37 +1,33 @@ use bevy::prelude::*; -use bevy_ratatui::crossterm::event::KeyCode; -use bevy_ratatui::event::KeyMessage; +use bevy_ratatui::event::{KeyMessage, MouseMessage}; use jong::game::GameState; -use crate::tui::{TuiState, ZenState, console::ConsoleState}; - -// TODO change this to handle console open request, esc for menu, etc, then -// route other messages to other systems +use crate::tui::{TuiState, console::ConsoleState}; #[allow(clippy::too_many_arguments)] -pub(crate) fn input_system( - mut messages: MessageReader, +pub(crate) fn kb_input_system( + mut kb_messages: MessageReader, curr_tuistate: Res>, curr_consolestate: Res>, curr_gamestate: Res>, - curr_zenstate: Option>>, mut next_tuistate: ResMut>, mut next_consolestate: ResMut>, mut next_gamestate: ResMut>, - mut next_zenstate: ResMut>, mut exit: MessageWriter, ) { + use bevy_ratatui::crossterm::event::KeyCode; + let (ts, cs, gs) = ( curr_tuistate.get(), curr_consolestate.get(), curr_gamestate.get(), ); - for message in messages.read() { + for message in kb_messages.read() { if let KeyCode::Char('`') = message.code { next_consolestate.set(!*curr_consolestate.get()); continue; @@ -60,14 +56,6 @@ pub(crate) fn input_system( next_tuistate.set(TuiState::InGame); next_gamestate.set(GameState::Setup); } - KeyCode::Char('z') => { - if let Some(ref curr_zenstate) = curr_zenstate { - match curr_zenstate.get() { - ZenState::Menu => next_zenstate.set(ZenState::Zen), - ZenState::Zen => next_zenstate.set(ZenState::Menu), - } - } - } KeyCode::Char('q') => { exit.write_default(); } diff --git a/src/tui/input/mod.rs b/src/tui/input/mod.rs deleted file mode 100644 index d7eb1ae..0000000 --- a/src/tui/input/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub(crate) mod keyboard; -pub(crate) mod mouse; diff --git a/src/tui/input/mouse.rs b/src/tui/input/mouse.rs deleted file mode 100644 index acc9fa0..0000000 --- a/src/tui/input/mouse.rs +++ /dev/null @@ -1,65 +0,0 @@ -use bevy::prelude::*; -use bevy_ratatui::{RatatuiContext, event::MouseMessage}; -use ratatui::layout::Position; - -use crate::tui::render::Hovered; - -#[derive(Component)] -pub(crate) struct PickRegion { - pub(crate) area: ratatui::prelude::Rect, -} - -// enum PickEvent { -// Click { col: u16, row: u16 }, -// Hover { col: u16, row: u16 }, -// } - -pub(crate) fn input_system( - mut commands: Commands, - mut messages: MessageReader, - _context: Res, - entities: Query<(Entity, &PickRegion)>, - hovered: Query<(Entity, &PickRegion), With>, -) -> Result { - for message in messages.read() { - let event = message.0; - // let term_size = context.size().unwrap(); - let position = Position::new(event.column, event.row); - match event.kind { - ratatui::crossterm::event::MouseEventKind::Down(mouse_button) => match mouse_button { - ratatui::crossterm::event::MouseButton::Left => { - for (_entity, _region) in &entities {} - } - // ratatui::crossterm::event::MouseButton::Right => todo!(), - // ratatui::crossterm::event::MouseButton::Middle => todo!(), - _ => {} - }, - // ratatui::crossterm::event::MouseEventKind::Up(mouse_button) => todo!(), - // ratatui::crossterm::event::MouseEventKind::Drag(mouse_button) => todo!(), - ratatui::crossterm::event::MouseEventKind::Moved => { - for (entity, region) in &hovered { - if !region.area.contains(position) { - commands.get_entity(entity)?.remove::(); - } - } - for (entity, region) in &entities { - // debug!( - // "{:?}, {position:?}", - // region.area.positions().collect::>() - // ); - if region.area.contains(position) { - commands.get_entity(entity)?.insert(Hovered); - // trace!("{entity:?} hovered!") - } - } - } - // ratatui::crossterm::event::MouseEventKind::ScrollDown => todo!(), - // ratatui::crossterm::event::MouseEventKind::ScrollUp => todo!(), - // ratatui::crossterm::event::MouseEventKind::ScrollLeft => todo!(), - // ratatui::crossterm::event::MouseEventKind::ScrollRight => todo!(), - _ => {} - } - } - - Ok(()) -} diff --git a/src/tui/menu.rs b/src/tui/menu.rs new file mode 100644 index 0000000..104e193 --- /dev/null +++ b/src/tui/menu.rs @@ -0,0 +1,24 @@ +use bevy::prelude::*; +use bevy_ratatui::RatatuiContext; +use bevy_ratatui::event::KeyMessage; +use ratatui::crossterm::event::KeyCode; +use ratatui::layout::Constraint; +use ratatui::layout::Layout; + +use jong::game::GameState; + +use crate::tui::TuiState; + +const MAINMENU_OPTIONS: [&str; 2] = ["(p)lay", "(q)uit"]; + +pub(crate) fn draw_mainmenu(mut tui_ctx: ResMut) { + let options = MAINMENU_OPTIONS; + let layout = Layout::vertical(vec![Constraint::Min(1); options.len()]); + + tui_ctx.draw(|frame| { + let areas = layout.split(frame.area()); + for (opt, area) in options.into_iter().zip(areas.iter()) { + frame.render_widget(opt, *area) + } + }); +} diff --git a/src/tui/mod.rs b/src/tui/mod.rs index 1b3a25f..f96a68a 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -2,14 +2,15 @@ use std::time::Duration; use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; use bevy_ratatui::RatatuiPlugins; +use ratatui::{text::ToSpan, widgets::Paragraph}; use jong::game::GameState; - -use crate::tui::render::{WidgetStack, menu::Splash}; // use jong::game::wall::InWall; +use crate::tui::{console::ConsoleState, menu::draw_mainmenu, render::ingame::draw_ingame}; mod console; +mod menu; mod render; mod input; @@ -28,20 +29,12 @@ impl ComputedStates for InGame { fn compute(sources: Self::SourceStates) -> Option { match sources { + TuiState::MainMenu => None, TuiState::InGame => Some(Self), - _ => None, } } } -#[derive(SubStates, Default, Clone, Copy, PartialEq, Eq, Hash, Debug,)] -#[source(TuiState = TuiState::MainMenu)] -pub(crate) enum ZenState { - #[default] - Menu, - Zen, -} - #[derive(Default)] pub struct RiichiTui; impl Plugin for RiichiTui { @@ -59,33 +52,22 @@ impl Plugin for RiichiTui { )) .add_plugins(StatesPlugin) + // console + .init_state::() + .add_systems(Update, console::draw_console.after_ignore_deferred(draw_mainmenu).after_ignore_deferred(draw_ingame).run_if(in_state(console::ConsoleState::Open))) + // general setup .init_state::() .add_computed_state::() - .init_resource::() - .add_sub_state::() - .init_resource::() - .init_state::() - .add_systems(PostUpdate, console::draw_console.run_if(in_state(console::ConsoleState::Open))) - - // input - .add_systems(PreUpdate, input::keyboard::input_system) - .add_systems(PreUpdate, input::mouse::input_system) + .add_systems(Update, input::kb_input_system) // main menu - .add_systems(PostStartup, render::menu::init_splash) - .insert_resource(Time::::from_seconds(1.0)) - .add_systems(FixedUpdate, render::menu::render_splash.run_if(in_state(TuiState::MainMenu))) - .add_systems(Update, render::menu::draw_splash.run_if(in_state(TuiState::MainMenu))) - .add_systems(Update, render::menu::draw_mainmenu.after(render::menu::draw_splash).run_if(in_state(TuiState::MainMenu).and(in_state(ZenState::Menu)))) + .add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) // gaming .init_resource::() - .add_systems(Update, render::hand::render_hands.run_if(in_state(InGame).and(in_state(GameState::Play)))) .add_systems(Update, render::ingame::draw_ingame.run_if(in_state(InGame))) - - // render - .add_systems(Last, render::draw_system.run_if(not(in_state(InGame)))) + .add_systems(Update, render::hand::render_hand.run_if(in_state(InGame).and(in_state(GameState::Play)))) // semicolon stopper ; diff --git a/src/tui/render/hand.rs b/src/tui/render/hand.rs index 944aa56..a1b5ebc 100644 --- a/src/tui/render/hand.rs +++ b/src/tui/render/hand.rs @@ -1,22 +1,21 @@ use bevy::{platform::collections::HashMap, prelude::*}; +use ratatui::widgets::Paragraph; use jong::{ game::{hand::Hand, player::Player}, - tile::Tile, + tiles::Tile, }; -use crate::tui::render::tile::{self, RenderedTile}; +use crate::tui::render::tiles; #[derive(Resource, Default)] -pub(crate) struct RenderedHand(pub(crate) HashMap>); +pub(crate) struct RenderedHand(pub(crate) HashMap>>); -#[allow(clippy::type_complexity)] -pub(crate) fn render_hands( - mut commands: Commands, - mut rendered_hand: ResMut, +pub(crate) fn render_hand( tiles: Populated<&Tile>, player_hands: Populated<(Entity, &Children), (With, Changed)>, hands: Populated<&Children, (Changed, Without)>, + mut target: ResMut, ) -> Result { let mut rendered = HashMap::new(); @@ -25,21 +24,12 @@ pub(crate) fn render_hands( let tiles = hands .get(hand)? .iter() - .map(|it| { - tiles - .get(it) - // .inspect(|t| debug!("{t:?}")) - .map(tile::draw_tile) - .map(|p| commands.spawn(RenderedTile(p)).id()) - // .inspect(|e| debug!("{e:?}")) - .unwrap() - }) + .map(|it| tiles.get(it).map(tiles::draw_tile).unwrap()) .collect(); rendered.insert(player_ent, tiles); } - rendered_hand.0 = rendered; + target.0 = rendered; - trace!("render_hands"); Ok(()) } diff --git a/src/tui/render/ingame.rs b/src/tui/render/ingame.rs index bb74910..e573cb9 100644 --- a/src/tui/render/ingame.rs +++ b/src/tui/render/ingame.rs @@ -1,25 +1,13 @@ use bevy::prelude::*; use bevy_ratatui::RatatuiContext; -use jong::game::hand::DrawnTile; use jong::game::player::{MainPlayer, Player}; -use jong::tile::Tile; -use ratatui::widgets::{Block, Borders}; -use crate::tui::render::tile::draw_tile; -use crate::tui::{ - input::mouse::PickRegion, - render::{Hovered, hand, tile::RenderedTile}, -}; +use crate::tui::render::hand; pub(crate) fn draw_ingame( - mut commands: Commands, - mut tui_ctx: ResMut, - tiles: Query<&Tile>, - hovered_entity: Query>, - main_player: Single, With)>, - rendered_tiles: Populated<&RenderedTile>, rendered_hand: Res, - drawn_tile: Option>>, + main_player: Single, With)>, + mut tui_ctx: ResMut, ) -> Result { use ratatui::layout::Flex; use ratatui::prelude::*; @@ -27,107 +15,14 @@ pub(crate) fn draw_ingame( tui_ctx.draw(|frame| { // debug!("{}", frame.area()); - let term_area = frame.area(); - - // TODO this is gross - let constraints = [Constraint::Fill(3), Constraint::Fill(18)]; - let horizontal_slicer_right = Layout::horizontal(constraints); - let vertical_slicer_bottom = Layout::vertical(constraints); - let horizontal_slicer_left = Layout::horizontal(constraints.iter().rev()); - let vertical_slicer_top = Layout::vertical(constraints.iter().rev()); - let [left_hand, this_hand] = horizontal_slicer_right.areas::<2>(term_area); - let [_, left_hand] = vertical_slicer_bottom.areas::<2>(left_hand); - let [_, mut this_hand] = vertical_slicer_top.areas::<2>(this_hand); - let [cross_hand, right_hand] = horizontal_slicer_left.areas::<2>(term_area); - let [right_hand, _] = vertical_slicer_top.areas::<2>(right_hand); - let [cross_hand, _] = vertical_slicer_bottom.areas::<2>(cross_hand); - - let margin = Margin::new( - (left_hand.width + right_hand.width) / 2, - (cross_hand.height + this_hand.height) / 2, - ); - let pond_area = term_area.inner(margin); - let all_pond = Layout::horizontal([Constraint::Fill(1); 3]); - let cross_pond = - Layout::vertical([Constraint::Fill(1), Constraint::Max(1), Constraint::Fill(1)]); - let [mut left_pond, center, mut right_pond] = all_pond.areas::<3>(pond_area); - let [cross_pond, _compass, this_pond] = cross_pond.areas::<3>(center); - // let shift = left_pond.height - cross_pond.height; - left_pond.height = cross_pond.height; - left_pond.y += cross_pond.height / 2; - right_pond.height = cross_pond.height; - right_pond.y += cross_pond.height / 2; - - let debug_block = Block::new().borders(Borders::ALL); - frame.render_widget(debug_block.clone(), this_hand); - frame.render_widget(debug_block.clone(), left_hand); - frame.render_widget(debug_block.clone(), cross_hand); - frame.render_widget(debug_block.clone(), right_hand); - frame.render_widget(debug_block.clone(), this_pond); - frame.render_widget(debug_block.clone(), left_pond); - frame.render_widget(debug_block.clone(), cross_pond); - frame.render_widget(debug_block.clone(), right_pond); - - // TODO attempt to merge blocks on smol term? + let layout = Layout::horizontal(vec![Constraint::Max(5); 13]).flex(Flex::Start); + let mut area = frame.area(); + area.height = 4; + let areas = layout.areas::<13>(area); + // if let Some(hand) = rendered_hand.0.get(&*main_player) { if let Some(hand) = rendered_hand.0.get(&*main_player) { - let hand_area_layout = Layout::horizontal([ - Constraint::Max(hand.len() as u16 * 5), - Constraint::Max(if drawn_tile.is_some() { 7 } else { 0 }), - Constraint::Fill(1), - ]) - .flex(Flex::SpaceBetween); - let this_clamped = this_hand.height.abs_diff(5); - if let Some(_val) = this_hand.height.checked_sub(this_clamped) { - this_hand.height = 4 - } else { - // FIXME show error - panic!("terminal too small!"); - } - this_hand.y += this_clamped + 1; - let [this_hand, mut this_drawn, _this_meld] = hand_area_layout.areas::<3>(this_hand); - - // this_hand - let mut constraints = vec![Constraint::Max(5); hand.len()]; - constraints.push(Constraint::Fill(1)); - let layout = Layout::horizontal(constraints).flex(Flex::Start); - let hand_areas = layout.split(this_hand); - for (tile, mut tile_area) in hand.iter().zip(hand_areas.iter().cloned()) { - // tile_area.height = 4; - let mut widget = rendered_tiles.get(*tile).unwrap().0.clone(); - if hovered_entity.contains(*tile) { - widget = widget.add_modifier(Modifier::BOLD); - if let Some(val) = tile_area.y.checked_sub(1) { - tile_area.y = val - } else { - // FIXME show error - panic!("terminal too small!"); - } - } - commands - .entity(*tile) - .insert(PickRegion { area: tile_area }); - frame.render_widget(widget, tile_area); - } - - // this_drawn - if let Some(tile) = drawn_tile { - // this_drawn.height = 4; - this_drawn.width = 5; - this_drawn.x += 2; - let mut widget = draw_tile(tiles.get(tile.0).unwrap()); - if hovered_entity.contains(tile.0) { - widget = widget.add_modifier(Modifier::BOLD); - if let Some(val) = this_drawn.y.checked_sub(1) { - this_drawn.y = val - } else { - // FIXME show error - panic!("terminal too small!"); - } - } - commands - .entity(tile.0) - .insert(PickRegion { area: this_drawn }); - frame.render_widget(widget, this_drawn); + for (tile, area) in hand.iter().zip(areas.iter()) { + frame.render_widget(tile, *area); } } })?; diff --git a/src/tui/render/menu.rs b/src/tui/render/menu.rs deleted file mode 100644 index 2e58526..0000000 --- a/src/tui/render/menu.rs +++ /dev/null @@ -1,96 +0,0 @@ -use bevy::prelude::*; -use bevy_ratatui::RatatuiContext; -use rand::rng; -use rand::seq::SliceRandom; -use ratatui::layout::Constraint; -use ratatui::layout::Flex; -use ratatui::layout::Layout; -use ratatui::layout::Margin; -use ratatui::widgets::Paragraph; -use ratatui::widgets::{Block, Clear}; - -use jong::tile::Tile; - -use crate::tui::render::WidgetStack; -use crate::tui::render::tile; - -const MAINMENU_OPTIONS: [&str; 2] = [ - " ██╗██████╗ ██╗ ██╗ █████╗ ██╗ ██╗██╗ -██╔╝██╔══██╗╚██╗██║ ██╔══██╗╚██╗ ██╔╝██║ -██║ ██████╔╝ ██║██║ ███████║ ╚████╔╝ ██║ -██║ ██╔═══╝ ██║██║ ██╔══██║ ╚██╔╝ ╚═╝ -╚██╗██║ ██╔╝███████╗██║ ██║ ██║ ██╗ - ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ -", - " ██╗ ██████╗ ██╗ ██╗ ██╗██╗████████╗ ██╗ -██╔╝██╔═══██╗╚██╗██║ ██║██║╚══██╔══╝██╗██╔╝ -██║ ██║ ██║ ██║██║ ██║██║ ██║ ╚═╝██║ -██║ ██║▄▄ ██║ ██║██║ ██║██║ ██║ ██╗██║ -╚██╗╚██████╔╝██╔╝╚██████╔╝██║ ██║ ╚═╝╚██╗ - ╚═╝ ╚══▀▀═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ -", -]; - -pub(crate) fn draw_mainmenu(mut widgets: ResMut) { - let options = MAINMENU_OPTIONS; - let layout = - Layout::vertical(vec![Constraint::Fill(1); options.len()]).flex(Flex::SpaceBetween); - let block = Block::bordered(); - - widgets.0.push(Box::new(move |frame| { - let area = frame - .area() - .centered(Constraint::Max(55), Constraint::Max(19)); - frame.render_widget(Clear, area); - frame.render_widget(block, area); - let areas = layout.split(area.centered(Constraint::Max(45), Constraint::Max(14))); - for (opt, area) in options.into_iter().zip(areas.iter()) { - let para = Paragraph::new(opt); - frame.render_widget(para, *area) - } - })); -} - -#[derive(Resource, Default)] -pub(crate) struct Splash(pub Vec>); - -pub(crate) fn init_splash(mut commands: Commands, tiles: Populated<&Tile>) { - let tiles: Vec<_> = tiles - .iter() - .copied() - .map(|tile| tile::draw_tile(&tile)) - .collect(); - - commands.insert_resource(Splash(tiles)); - trace!("init_splash") -} - -pub(crate) fn render_splash(mut splash: ResMut) { - let mut rng = rng(); - splash.0.shuffle(&mut rng); -} - -pub(crate) fn draw_splash(mut widgets: ResMut, splash: Res) { - let tiles: Vec<_> = splash.0.clone(); - widgets.0.push(Box::new(move |frame| { - let area = frame.area().outer(Margin { - horizontal: 1, - vertical: 1, - }); - let layout = Layout::horizontal(vec![Constraint::Length(5); (area.width / 5) as usize]); - let areas = layout.split(area); - let mut tile_chunks = tiles.chunks(areas.len()).cycle(); - for area in areas.iter() { - let layout = Layout::vertical(vec![Constraint::Length(4); (area.height / 4) as usize]); - let areas = layout.split(*area); - // let tiles: Vec<_> = tile_it - // .by_ref() - // .take((area.height / 4 + 1) as usize) - // .map(|t| tile::draw_tile(&t)) - // .collect(); - for (tile, area) in tile_chunks.next().unwrap().iter().zip(areas.iter()) { - frame.render_widget(tile, *area); - } - } - })); -} diff --git a/src/tui/render/mod.rs b/src/tui/render/mod.rs index c206fea..fc6612a 100644 --- a/src/tui/render/mod.rs +++ b/src/tui/render/mod.rs @@ -1,26 +1,3 @@ -use bevy::prelude::*; -use bevy_ratatui::RatatuiContext; -use ratatui::Frame; - pub(crate) mod hand; pub(crate) mod ingame; -pub(crate) mod menu; -pub(crate) mod tile; - -#[derive(Resource, Default)] -pub(crate) struct WidgetStack(pub(crate) Vec>); - -#[derive(Component)] -pub(crate) struct Hovered; - -pub(crate) fn draw_system( - mut tui_ctx: ResMut, - mut widgetstack: ResMut, -) -> Result { - tui_ctx.draw(|frame| { - for widget in widgetstack.0.drain(..) { - widget(frame) - } - })?; - Ok(()) -} +mod tiles; diff --git a/src/tui/render/tile.rs b/src/tui/render/tile.rs deleted file mode 100644 index 95bf282..0000000 --- a/src/tui/render/tile.rs +++ /dev/null @@ -1,34 +0,0 @@ -use bevy::prelude::*; -use ratatui::widgets::Paragraph; - -use jong::tile::Tile; - -#[derive(Component)] -pub(crate) struct RenderedTile(pub(crate) Paragraph<'static>); - -pub(crate) fn draw_tile(tile: &Tile) -> Paragraph<'static> { - - - let block = ratatui::widgets::Block::bordered(); - - Paragraph::new(match &tile.suit { - jong::tile::Suit::Pin(rank) => format!("{}\np", rank.0), - jong::tile::Suit::Sou(rank) => format!("{}\ns", rank.0), - jong::tile::Suit::Man(rank) => format!("{}\nm", rank.0), - jong::tile::Suit::Wind(wind) => (match wind { - jong::tile::Wind::Ton => "e\nw", - jong::tile::Wind::Nan => "s\nw", - jong::tile::Wind::Shaa => "w\nw", - jong::tile::Wind::Pei => "n\nw", - }) - .into(), - jong::tile::Suit::Dragon(dragon) => (match dragon { - jong::tile::Dragon::Haku => "w\nd", - jong::tile::Dragon::Hatsu => "g\nd", - jong::tile::Dragon::Chun => "r\nd", - }) - .into(), - }) - .block(block) - .centered() -} diff --git a/src/tui/render/tiles.rs b/src/tui/render/tiles.rs new file mode 100644 index 0000000..620a2d1 --- /dev/null +++ b/src/tui/render/tiles.rs @@ -0,0 +1,30 @@ +use ratatui::widgets::Paragraph; + +use jong::tiles::Tile; + +pub(crate) fn draw_tile(tile: &Tile) -> Paragraph<'static> { + use ratatui::prelude::*; + + let block = ratatui::widgets::Block::bordered(); + + Paragraph::new(match &tile.suit { + jong::tiles::Suit::Pin(rank) => format!("{}\np", rank.0), + jong::tiles::Suit::Sou(rank) => format!("{}\ns", rank.0), + jong::tiles::Suit::Man(rank) => format!("{}\nm", rank.0), + jong::tiles::Suit::Wind(wind) => (match wind { + jong::tiles::Wind::Ton => "e\nw", + jong::tiles::Wind::Nan => "s\nw", + jong::tiles::Wind::Shaa => "w\nw", + jong::tiles::Wind::Pei => "n\nw", + }) + .into(), + jong::tiles::Suit::Dragon(dragon) => (match dragon { + jong::tiles::Dragon::Haku => "w\nd", + jong::tiles::Dragon::Hatsu => "g\nd", + jong::tiles::Dragon::Chun => "r\nd", + }) + .into(), + }) + .block(block) + .centered() +}