use std::time::Duration; use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; use bevy_ratatui::RatatuiPlugins; use bevy_ratatui::event::KeyMessage; use ratatui::{text::ToSpan, widgets::Paragraph}; use jong::game::GameState; // use jong::game::wall::InWall; use crate::tui::{console::ConsoleState, menu::draw_mainmenu, render::ingame::draw_ingame}; mod console; mod menu; mod render; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)] pub(crate) enum TuiState { #[default] MainMenu, InGame, } #[derive(Clone, PartialEq, Eq, Hash, Debug)] struct InGame; impl ComputedStates for InGame { type SourceStates = TuiState; fn compute(sources: Self::SourceStates) -> Option { match sources { TuiState::MainMenu => None, TuiState::InGame => Some(Self), } } } #[derive(Default)] pub struct RiichiTui; impl Plugin for RiichiTui { fn build(&self, app: &mut App) { app.add_plugins(( MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32( 1. / 60., ))), RatatuiPlugins { // enable_kitty_protocol: todo!(), enable_mouse_capture: true, enable_input_forwarding: true, ..Default::default() }, )) .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::() .add_systems(Update, input_system) // main menu .add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) // gaming .init_resource::() .add_systems(Update, render::ingame::draw_ingame.run_if(in_state(InGame))) // .add_systems(Update, render::hand::render_changed_hand.run_if(in_state(InGame).and(in_state(GameState::Play)))) // semicolon stopper ; } } #[allow(clippy::too_many_arguments)] pub(crate) fn input_system( mut messages: MessageReader, curr_tuistate: Res>, curr_consolestate: Res>, curr_gamestate: Res>, mut next_tuistate: ResMut>, mut next_consolestate: ResMut>, mut next_gamestate: 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() { if let KeyCode::Char('`') = message.code { next_consolestate.set(!*curr_consolestate.get()); continue } match ts { TuiState::MainMenu => match message.code { KeyCode::Char('p') => { next_tuistate.set(TuiState::InGame); next_gamestate.set(GameState::Setup); } KeyCode::Char('q') => { exit.write_default(); } _ => {} }, TuiState::InGame => match gs { GameState::Setup => match message.code { _ => {} }, GameState::Play => match message.code { KeyCode::Char('q') => { exit.write_default(); } _ => {} }, _ => todo!(), _ => unreachable!("TuiState::InGame but GameState invalid") }, } } }