jong/src/tui/mod.rs

129 lines
3.7 KiB
Rust
Raw Normal View History

2026-01-08 20:49:19 -08:00
use std::time::Duration;
2026-01-09 06:54:17 -08:00
use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin};
2026-01-09 23:14:29 -08:00
use bevy_ratatui::RatatuiPlugins;
2026-01-12 21:07:34 -08:00
use bevy_ratatui::event::KeyMessage;
2026-01-09 23:14:29 -08:00
use ratatui::{text::ToSpan, widgets::Paragraph};
2026-01-11 20:10:30 -08:00
use jong::game::GameState;
use jong::game::wall::InWall;
2026-01-12 21:07:34 -08:00
use crate::tui::console::ConsoleState;
2026-01-09 03:34:54 -08:00
mod console;
mod menu;
2026-01-09 23:14:29 -08:00
mod render;
2026-01-08 20:49:19 -08:00
2026-01-11 20:10:30 -08:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)]
2026-01-12 21:07:34 -08:00
pub(crate) enum TuiState {
2026-01-11 20:10:30 -08:00
#[default]
2026-01-11 22:32:30 -08:00
MainMenu,
2026-01-11 20:10:30 -08:00
InGame,
}
2026-01-12 20:56:30 -08:00
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct InGame;
impl ComputedStates for InGame {
type SourceStates = TuiState;
fn compute(sources: Self::SourceStates) -> Option<Self> {
match sources {
TuiState::MainMenu => None,
TuiState::InGame => Some(Self),
}
}
2026-01-11 20:10:30 -08:00
}
2026-01-07 00:51:57 -08:00
2026-01-12 20:56:30 -08:00
#[derive(Default)]
pub struct RiichiTui;
2026-01-08 20:49:19 -08:00
impl Plugin for RiichiTui {
fn build(&self, app: &mut App) {
app.add_plugins((
MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32(
2026-01-09 03:34:54 -08:00
1. / 60.,
2026-01-08 20:49:19 -08:00
))),
RatatuiPlugins {
// enable_kitty_protocol: todo!(),
enable_mouse_capture: true,
2026-01-12 01:54:59 -08:00
enable_input_forwarding: true,
2026-01-08 20:49:19 -08:00
..Default::default()
},
))
2026-01-09 03:34:54 -08:00
.add_plugins(StatesPlugin)
2026-01-12 01:54:59 -08:00
// console
2026-01-09 03:34:54 -08:00
.init_state::<console::ConsoleState>()
.add_systems(Update, console::draw_console.run_if(in_state(console::ConsoleState::Open)))
2026-01-12 01:54:59 -08:00
// general setup
2026-01-09 23:14:29 -08:00
.init_state::<TuiState>()
.add_computed_state::<InGame>()
2026-01-12 21:07:34 -08:00
.add_systems(Update, input_system)
2026-01-12 01:54:59 -08:00
// main menu
2026-01-12 21:07:34 -08:00
.add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu)))
2026-01-12 01:54:59 -08:00
// gaming
2026-01-12 01:54:59 -08:00
.init_resource::<render::hand::RenderedHand>()
2026-01-12 20:56:30 -08:00
.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))))
2026-01-12 01:54:59 -08:00
2026-01-09 03:34:54 -08:00
// semicolon stopper
;
2026-01-08 20:49:19 -08:00
}
}
2026-01-07 00:51:57 -08:00
2026-01-12 21:07:34 -08:00
#[allow(clippy::too_many_arguments)]
pub(crate) fn input_system(
mut messages: MessageReader<KeyMessage>,
curr_tuistate: Res<State<TuiState>>,
curr_consolestate: Res<State<ConsoleState>>,
curr_gamestate: Res<State<GameState>>,
mut next_tuistate: ResMut<NextState<TuiState>>,
mut next_consolestate: ResMut<NextState<ConsoleState>>,
mut next_gamestate: ResMut<NextState<GameState>>,
mut exit: MessageWriter<AppExit>,
) {
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();
}
_ => {}
},
GameState::Score => todo!(),
_ => unreachable!("TuiState::InGame but GameState invalid")
},
}
}
}