use bevy::prelude::*; use strum::{EnumCount, FromRepr}; use crate::{ EnumNextCycle, game::{ GameMessage, GameState, hand::{Discarded, Drawn, Hand}, player::{CurrentPlayer, Player}, wall::Wall, }, }; // #[derive(Resource)] // pub struct CurrentPlayer(pub Entity); #[derive(Resource)] pub(crate) struct MatchSettings { pub(crate) starting_points: isize, pub(crate) player_count: u8, } #[derive(Component)] pub(crate) struct Dice(u8, u8); #[derive(Resource)] pub(crate) struct Compass { pub(crate) prevalent_wind: Wind, pub(crate) round: u8, pub(crate) dealer_wind: Wind, pub(crate) riichi: usize, pub(crate) honba: usize, } #[derive(Component, Clone, Copy, FromRepr, EnumCount, PartialEq)] pub enum Wind { Ton, Nan, Shaa, Pei, } pub enum WindRelation { Shimocha, Toimen, Kamicha, } #[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 Default for MatchSettings { fn default() -> Self { Self { starting_points: 25000, player_count: 4, } } } impl Default for Compass { fn default() -> Self { Self { prevalent_wind: Wind::Ton, round: 1, dealer_wind: Wind::Ton, riichi: 0, honba: 0, } } } 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() } } } impl Wind { pub fn relate(&self, other: &Self) -> WindRelation { if self.next() == *other { WindRelation::Shimocha } else if other.next() == *self { WindRelation::Kamicha } else { WindRelation::Toimen } } } 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, curr_player: Single>, wall: Single>, walltiles: Single<&Children, With>, curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { let drawn = walltiles.last().unwrap(); commands.entity(*wall).remove_child(*drawn); let drawn = commands.entity(*drawn).insert(Drawn).id(); commands.entity(*curr_player).add_child(drawn); debug!("tsumo for: {:?}, tile: {:?}", *curr_player, drawn); next_turnstate.set(curr_turnstate.next()); } pub(crate) fn menzen( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { trace!("menzen check"); next_turnstate.set(curr_turnstate.next()); } pub(crate) fn riichi_kan( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { trace!("riichi_kan"); next_turnstate.set(curr_turnstate.next()); } #[allow(clippy::too_many_arguments, irrefutable_let_patterns)] pub(crate) fn discard( mut commands: Commands, mut reader: MessageReader, curr_player: Single>, players: Query<&Children, With>, mut hands: Query<(&Children, Entity), (With, Without)>, drawn: Single>, curr_turnstate: Res>, mut next_turnstate: ResMut>, ) -> Result { // trace!("discard"); let curr_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 { if *discarded == *drawn { } else if curr_hand.0.contains(discarded) { commands .entity(curr_hand.1) .remove_child(*discarded) .add_child(*drawn); } else { panic!("current hand nor drawn tile contains discarded tile") } commands .entity(*discarded) .remove::() .insert(Discarded); done = true; break; } } if done { next_turnstate.set(curr_turnstate.next()); } Ok(()) } pub(crate) fn ron_chi_pon_kan( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { next_turnstate.set(curr_turnstate.next()); } pub(crate) fn end( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { next_turnstate.set(curr_turnstate.next()); }