diff --git a/src/game.rs b/src/game.rs index 09b4e82..adeb5fd 100644 --- a/src/game.rs +++ b/src/game.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use crate::{ game::{ - hand::Hand, + hand::{Hand, Pond}, player::{CurrentPlayer, MainPlayer}, round::{TurnState, Wind}, wall::Wall, @@ -27,6 +27,17 @@ pub enum GameState { #[derive(Message)] pub enum GameMessage { Discarded(Entity), + CallPending, + Called { player: Entity, calltype: Entity }, +} + +impl GameMessage { + pub(crate) fn is_called(&self) -> bool { + match self { + GameMessage::Called { .. } => true, + _ => false, + } + } } pub struct Riichi; @@ -47,9 +58,9 @@ impl Plugin for Riichi { .add_systems(OnEnter(TurnState::Menzen), round::menzen) .add_systems(Update, round::riichi_kan.run_if(in_state(TurnState::RiichiKan))) .add_systems(Update, round::discard.run_if(in_state(TurnState::Discard))) - .add_systems(Update, round::ron_chi_pon_kan.run_if(in_state(TurnState::RonChiiPonKan))) + .add_systems(OnEnter(TurnState::RonChiiPonKan), round::notify_callable) + .add_systems(Update, round::ron_chi_pon_kan.run_if(in_state(TurnState::RonChiiPonKan)).after(round::notify_callable)) .add_systems(OnEnter(TurnState::End), round::end) - // .add_systems(Update, systems) // semicolon stopper ; } @@ -72,6 +83,7 @@ pub(crate) fn setup( player, points, Hand, + Pond, Wind::from_repr((i - 1) as usize).unwrap(), ); diff --git a/src/game/hand.rs b/src/game/hand.rs index 1ccef15..9717d79 100644 --- a/src/game/hand.rs +++ b/src/game/hand.rs @@ -10,6 +10,9 @@ use crate::{ #[derive(Component)] pub struct Hand; +#[derive(Component)] +pub struct Pond; + #[derive(Component)] pub struct Drawn; @@ -25,8 +28,8 @@ pub struct Discarded; // } pub(crate) fn sort_hands( - tiles: Populated<&Tile>, - hands: Populated<&mut Children, (Changed, Without)>, + tiles: Query<&Tile>, + hands: Query<&mut Children, (Changed, With, Without)>, ) -> Result { for mut hand in hands { hand.sort_unstable_by_key(|e| tiles.get(*e).unwrap().suit); diff --git a/src/game/round.rs b/src/game/round.rs index b33bb53..4e35bb4 100644 --- a/src/game/round.rs +++ b/src/game/round.rs @@ -1,11 +1,13 @@ -use bevy::prelude::*; +use std::rc::Weak; + +use bevy::{platform::collections::HashMap, prelude::*}; use strum::{EnumCount, FromRepr}; use crate::{ EnumNextCycle, game::{ GameMessage, GameState, - hand::{Discarded, Drawn, Hand}, + hand::{Discarded, Drawn, Hand, Pond}, player::{CurrentPlayer, Player}, wall::Wall, }, @@ -58,6 +60,15 @@ pub(crate) enum TurnState { End, } +#[derive(Component, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum CallType { + Skip, + Ron, + Chii, + Pon, + Kan, +} + impl Default for MatchSettings { fn default() -> Self { Self { @@ -162,24 +173,23 @@ pub(crate) fn discard( mut next_turnstate: ResMut>, ) -> Result { // trace!("discard"); - let curr_hand = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?; + let (handtiles, hand) = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?; let mut done = false; while let Some(message) = reader.read().next() { if let GameMessage::Discarded(discarded) = message { + debug!("discarded: {discarded:?}"); if *discarded == *drawn { - } else if curr_hand.0.contains(discarded) { + } else if handtiles.contains(discarded) { commands - .entity(curr_hand.1) + .entity(hand) .remove_child(*discarded) .add_child(*drawn); } else { panic!("current hand nor drawn tile contains discarded tile") } - commands - .entity(*discarded) - .remove::() - .insert(Discarded); + commands.entity(*drawn).remove::(); + commands.entity(*discarded).insert(Discarded); done = true; break; @@ -192,10 +202,45 @@ pub(crate) fn discard( Ok(()) } +#[derive(Resource)] +pub struct PendingCalls { + eligible: Vec, + calls: HashMap, +} + +pub(crate) fn notify_callable() {} + pub(crate) fn ron_chi_pon_kan( + mut commands: Commands, + mut reader: MessageReader, + + discarded: Single>, + mut ponds: Query<(&Children, Entity), (With, Without)>, + calls: Query<&CallType>, + curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { + // check if can call? + // message players? + // collect then prioritize + + // let mut received = vec![]; + let mut received: Vec<_> = reader + .read() + .filter_map(|m| { + if let GameMessage::Called { player, calltype } = m + && let Ok(calltype) = calls.get(*calltype) + { + Some((calltype, player)) + } else { + None + } + }) + .collect(); + received.sort_unstable_by_key(|(c, t)| c); + // received.sort_unstable_by_key(|m| m.); + next_turnstate.set(curr_turnstate.next()); } diff --git a/src/tui.rs b/src/tui.rs index 1244401..f166fb2 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -1,13 +1,12 @@ use std::time::Duration; -use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin, time::TimePlugin}; +use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; use bevy_ratatui::RatatuiPlugins; use jong::game::{ GameMessage, GameState, hand::{Drawn, Hand}, player::{CurrentPlayer, Player}, }; -use tracing::instrument; use tui_logger::TuiWidgetState; use crate::tui::{input::ConfirmSelect, states::ConsoleWidget}; diff --git a/src/tui/render.rs b/src/tui/render.rs index 5c63bba..ae6aae5 100644 --- a/src/tui/render.rs +++ b/src/tui/render.rs @@ -94,6 +94,7 @@ pub(crate) fn render( Ok(()) } +#[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn render_hands( mut commands: Commands, mut tui: ResMut, @@ -102,18 +103,21 @@ pub(crate) fn render_hands( layouts: Res, tiles: Query<&Tile>, - main_player: Single<(&Player, &Wind), With>, + main_player: Single<(&Player, Entity, &Wind), With>, curr_player: Single>, - players: Query<(&Player, &Children)>, + players: Query<(&Player, Entity, &Children)>, hands: Query<(&Children, Entity), (With, Without)>, - drawn_tile: Option>>, + drawn_tile: Single>, ) -> Result { let mut frame = tui.get_frame(); debug_blocks(*layouts, &mut frame); for (hand, hand_ent) in hands { // debug!("{hand:?}"); - let (player, _) = players.iter().find(|(_, c)| c.contains(&hand_ent)).unwrap(); + let (player, player_ent, _) = players + .iter() + .find(|(_, e, c)| c.contains(&hand_ent)) + .unwrap(); let hand: Vec<_> = hand .iter() .map(|entity| -> Result<_> { @@ -128,7 +132,8 @@ pub(crate) fn render_hands( if player == main_player.0 { // split main box into thirds let mut this_hand = layouts.this_hand; - let this_drawer = drawn_tile.as_ref().is_some_and(|dt| dt.0 == player); + // let this_drawer = drawn_tile..is_some_and(|dt| dt.0 == player); + let this_drawer = player_ent == *curr_player; let tile_drawn = if this_drawer { 7 } else { 0 }; let hand_draw_meld = Layout::horizontal([ Constraint::Max(hand.len() as u16 * 5), @@ -170,23 +175,23 @@ pub(crate) fn render_hands( // tsumo tile if this_drawer { - let (_, entity) = **drawn_tile.as_ref().unwrap(); + // trace!("this_drawer"); let mut area = drawn_area.resize(Size { width: 5, height: 4, }); area = area.offset(Offset { x: 2, y: 0 }); - let hovered = hovered.contains(entity); - let widget = render_tile(tiles.get(entity)?, hovered); + let hovered = hovered.contains(*drawn_tile); + let widget = render_tile(tiles.get(*drawn_tile)?, hovered); if hovered { area = area.offset(Offset { x: 0, y: -1 }); let mut hitbox = area.as_size(); hitbox.height += 1; - commands.entity(entity).insert(PickRegion { + commands.entity(*drawn_tile).insert(PickRegion { area: area.resize(hitbox), }); } else { - commands.entity(entity).insert(PickRegion { area }); + commands.entity(*drawn_tile).insert(PickRegion { area }); } frame.render_widget(widget, area); }