/*
* 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::{
api::game::{Action, Command},
game_status::PlayerState,
plugins::{GameActionCreateCallEvent, GameData},
seed_gen, AppState, Global,
};
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)
.add_system(interact_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 button_query: Query<(&mut Visibility, &Children), With<StateButton>>,
mut text_query: Query<&mut Text>,
game_data: Res<GameData>,
global: Res<Global>,
) {
for (mut visibility, children) in &mut button_query {
// NOTE: horrible clones because of borrow funnies
let Some(status) = game_data.clone().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;
}
}
fn interact_state_button(
mut interaction_query: Query<
(&Interaction, &mut BackgroundColor),
(Changed<Interaction>, With<StateButton>),
>,
mut game_data: ResMut<GameData>,
global: Res<Global>,
mut gac_ev_w: EventWriter<GameActionCreateCallEvent>,
) {
for (interaction, mut color) in &mut interaction_query {
// NOTE: horrible clones because of borrow funnies
let Some(game) = game_data.clone().game else {
return;
};
let Some(status) = game_data.clone().game_status else {
return;
};
let Some(user) = &global.user else {
return;
};
let player = status.players.get(&user.id).unwrap();
if game_data.locked {
// input locked rn, so don't show any signs of interactivity
return;
}
match interaction {
Interaction::Clicked => {
*color = PRESSED_BUTTON.into();
game_data.locked = true;
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 => {
let next_turn_n: usize = if (player.turn_n + 1) > (status.players.len() - 1)
{
0
} else {
player.turn_n + 1
};
let next_player = status
.players
.iter()
.find(|np| np.1.turn_n == next_turn_n)
.unwrap();
gac_ev_w.send(GameActionCreateCallEvent {
action: Action::new(
&game.id,
&user.id,
next_player.0,
&Command::EndTurn {},
seed_gen!(),
),
});
}
_ => {}
}
}
Interaction::Hovered => {
*color = HOVERED_BUTTON.into();
}
Interaction::None => {
*color = NORMAL_BUTTON.into();
}
}
}
}