use bevy::prelude::*; use strum::{EnumCount, FromRepr}; use crate::{ EnumNextCycle, game::{ GameMessage, GameState, hand::{DrawnTile, Hand}, player::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, } #[derive(EntityEvent)] pub struct Discard(pub Entity); 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, // players: Populated>, wall_ent: Single>, walltiles: Single<&Children, With>, curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { debug!("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()); } pub(crate) fn menzen( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { next_turnstate.set(curr_turnstate.next()); } pub(crate) fn riichi_kan( curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { next_turnstate.set(curr_turnstate.next()); } pub(crate) fn discard( mut reader: MessageReader, currplayer: Res, drawntile: Single>, player_hands: Populated<(&Player, &Children), With>, hands: Populated<&Children, (With, Without)>, curr_turnstate: Res>, mut next_turnstate: ResMut>, ) { let curr = currplayer.0; let hand_ent = player_hands.get(curr).unwrap().1.iter().next().unwrap(); let hand = hands.get(hand_ent).unwrap(); while let Some(message) = reader.read().next() { if let GameMessage::Discarded(entity) = message { if *entity == *drawntile { } else if hand.contains(entity) { } else { panic!("discarded illegal player tile?") } break; } } }