@@ 29,7 29,8 @@ impl Plugin for GamePlugin {
.add_plugin(card::CardPlugin)
.add_plugin(supply::SupplyPlugin)
.add_plugin(hand::HandPlugin)
- .add_system(game_setup.in_schedule(OnEnter(AppState::InGame)));
+ .add_system(game_setup.in_schedule(OnEnter(AppState::InGame)))
+ .add_system(handle_refresh_game_event.run_if(on_event::<RefreshGameEvent>()));
}
}
@@ 66,3 67,17 @@ fn game_setup(
.spawn(Collider::cuboid(20., 0.5, 20.))
.insert(TransformBundle::from(Transform::from_xyz(0., -0.5, 0.)));
}
+
+pub struct RefreshGameEvent;
+
+fn handle_refresh_game_event(
+ mut details_ev_w: EventWriter<GameDetailsCallEvent>,
+ mut game_data: ResMut<GameData>,
+) {
+ game_data.game = None;
+ game_data.game_status = None;
+
+ details_ev_w.send(GameDetailsCallEvent {
+ game_id: game_data.game.as_ref().unwrap().id.clone(),
+ });
+}
@@ 12,17 12,20 @@ use bevy_egui::{egui, EguiContexts};
use crate::{
api::game::{Action, Command, Game},
game_status::{Card, PlayerState},
- plugins::{GameActionCreateCallEvent, GameDetailsCallEvent},
+ plugins::GameActionCreateCallEvent,
AppState, Global, seed_gen,
};
use super::{supply::SpawnSupplyPilesEvent, GameData};
+mod state_button;
+
pub struct GameUIPlugin;
impl Plugin for GameUIPlugin {
fn build(&self, app: &mut App) {
- app.add_system(dev_details_ui.run_if(in_state(AppState::InGame)))
+ app.add_plugin(state_button::StateButtonPlugin)
+ .add_system(dev_details_ui.run_if(in_state(AppState::InGame)))
.add_system(setup_details.in_schedule(OnEnter(AppState::InGame)))
.add_systems(
(
@@ 358,7 361,6 @@ pub fn dev_details_ui(
mut contexts: EguiContexts,
global: Res<Global>,
game_data: Res<GameData>,
- mut details_ev_w: EventWriter<GameDetailsCallEvent>,
mut create_action_ev_w: EventWriter<GameActionCreateCallEvent>,
mut ssp_ev_w: EventWriter<SpawnSupplyPilesEvent>,
) {
@@ 377,12 379,6 @@ pub fn dev_details_ui(
return;
};
- if ui.button("Refresh").clicked() {
- details_ev_w.send(GameDetailsCallEvent {
- game_id: game_data.game.as_ref().unwrap().id.clone(),
- });
- }
-
if status.actions.is_empty() && game.host_id == global.user.as_ref().unwrap().id {
if ui.button("Init Game").clicked() {
// NOTE/FIXME: hardcoded game init
@@ 0,0 1,159 @@
+/*
+ * This file is part of laurelin_client
+ * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * Licensed under GPL-3.0-only.
+ * See LICENSE for licensing information.
+ */
+
+use bevy::prelude::*;
+
+use crate::{AppState, plugins::{GameData, GameActionCreateCallEvent}, Global, game_status::PlayerState, api::game::{Action, Command}, seed_gen};
+
+pub struct StateButtonPlugin;
+
+impl Plugin for StateButtonPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_system(setup_state_button.in_schedule(OnEnter(AppState::InGame)))
+ .add_system(update_state_button);
+ }
+}
+
+const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15);
+const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25);
+const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.75, 0.35);
+
+#[derive(Component)]
+struct StateButton;
+
+#[derive(Component)]
+struct StateButtonText;
+
+fn setup_state_button(
+ mut commands: Commands,
+ asset_server: Res<AssetServer>,
+) {
+ commands.spawn((
+ NodeBundle {
+ style: Style {
+ position_type: PositionType::Absolute,
+ position: UiRect {
+ bottom: Val::Px(20.),
+ right: Val::Px(20.),
+ ..Default::default()
+ },
+ ..Default::default()
+ },
+ ..Default::default()
+ },
+ ))
+ .with_children(|parent| {
+ parent
+ .spawn((ButtonBundle {
+ style: Style {
+ size: Size::new(Val::Px(150.), Val::Px(65.)),
+ // center child text
+ justify_content: JustifyContent::Center,
+ align_items: AlignItems::Center,
+ ..Default::default()
+ },
+ background_color: NORMAL_BUTTON.into(),
+ ..Default::default()
+ }, StateButton
+ ))
+ .with_children(|parent| {
+ parent.spawn((
+ TextBundle::from_section(
+ "Pass",
+ TextStyle {
+ font: asset_server.load("fonts/FiraMono-Bold.ttf"),
+ font_size: 40.,
+ color: Color::WHITE,
+ },
+ ),
+ StateButtonText,
+ ));
+ });
+
+ });
+}
+
+fn update_state_button(
+ mut interaction_query: Query<
+ (&Interaction, &mut BackgroundColor, &mut Visibility, &Children),
+ (Changed<Interaction>, With<StateButton>)
+ >,
+ mut text_query: Query<&mut Text>,
+ game_data: Res<GameData>,
+ global: Res<Global>,
+ mut gac_ev_w: EventWriter<GameActionCreateCallEvent>,
+) {
+ for (interaction, mut color, mut visibility, children) in &mut interaction_query {
+ let Some(game) = &game_data.game else {
+ return;
+ };
+ let Some(status) = &game_data.game_status else {
+ return;
+ };
+ let Some(user) = &global.user else {
+ return;
+ };
+ let player = status.players.get(&user.id).unwrap();
+
+ let mut text = text_query.get_mut(children[0]).unwrap();
+
+ match player.state {
+ PlayerState::Idle => {
+ *visibility = Visibility::Hidden;
+ return;
+ }
+ PlayerState::PlayPhase => {
+ text.sections[0].value = "Skip Play".to_string();
+ }
+ PlayerState::BuyPhase => {
+ text.sections[0].value = "End Turn".to_string();
+ }
+ }
+ *visibility = Visibility::Inherited;
+
+ match interaction {
+ Interaction::Clicked => {
+ *color = PRESSED_BUTTON.into();
+
+ match player.state {
+ PlayerState::PlayPhase => {
+ gac_ev_w.send(GameActionCreateCallEvent {
+ action: Action::new(
+ &game.id,
+ &user.id,
+ &user.id,
+ &Command::ChangePlayerState {
+ state: PlayerState::BuyPhase,
+ },
+ seed_gen!(),
+ ),
+ });
+ }
+ PlayerState::BuyPhase => {
+ gac_ev_w.send(GameActionCreateCallEvent {
+ action: Action::new(
+ &game.id,
+ &user.id,
+ &user.id,
+ &Command::EndTurn { },
+ seed_gen!(),
+ ),
+ });
+ }
+ _ => {}
+ }
+ }
+ Interaction::Hovered => {
+ *color = HOVERED_BUTTON.into();
+ }
+ Interaction::None => {
+ *color = NORMAL_BUTTON.into();
+ }
+ }
+ }
+}