/*
* This file is part of sdbclient
* Copyright (C) 2022 Jonni Liljamo <jonni@liljamo.com>
*
* Licensed under GPL-3.0-only.
* See LICENSE for licensing information.
*/
use bevy::{app::AppExit, prelude::*};
use crate::cfg::CfgUser;
use crate::{despawn_screen, GameState};
mod mainmenuscreen;
use mainmenuscreen::*;
mod settingsmenuscreen;
use settingsmenuscreen::*;
mod settingsdisplayscreen;
use settingsdisplayscreen::*;
mod settingsaudioscreen;
use settingsaudioscreen::*;
mod settingsmiscscreen;
use settingsmiscscreen::*;
mod accountscreenloggedout;
use accountscreenloggedout::*;
mod accountscreenloggedin;
use accountscreenloggedin::*;
use super::config::{SaveEvent, SaveEventValue};
mod accountlogin;
mod accountregister;
pub struct MenuPlugin;
impl Plugin for MenuPlugin {
fn build(&self, app: &mut App) {
app.
// Start with no menu. The menu is loaded when the GameState::MainMenu is entered.
add_state(MenuState::None)
.add_system_set(SystemSet::on_enter(GameState::MainMenu).with_system(menu_setup))
// Systems for main menu screen
.add_system_set(SystemSet::on_enter(MenuState::Main).with_system(main_menu_setup))
.add_system_set(SystemSet::on_exit(MenuState::Main).with_system(despawn_screen::<OnMainMenuScreen>))
// Systems for settings menu screen
.add_system_set(SystemSet::on_enter(MenuState::Settings).with_system(settings_menu_setup))
.add_system_set(SystemSet::on_exit(MenuState::Settings).with_system(despawn_screen::<OnSettingsMenuScreen>))
// Systems for settings display screen
.add_system_set(SystemSet::on_enter(MenuState::SettingsDisplay).with_system(settings_display_setup))
.add_system_set(SystemSet::on_exit(MenuState::SettingsDisplay).with_system(despawn_screen::<OnSettingsDisplayScreen>))
// Systems for settings audio screen
.add_system_set(SystemSet::on_enter(MenuState::SettingsAudio).with_system(settings_audio_setup))
.add_system_set(SystemSet::on_exit(MenuState::SettingsAudio).with_system(despawn_screen::<OnSettingsAudioScreen>))
// Systems for settings misc screen
.add_system_set(SystemSet::on_enter(MenuState::SettingsMisc).with_system(settings_misc_setup))
.add_system_set(SystemSet::on_exit(MenuState::SettingsMisc).with_system(despawn_screen::<OnSettingsMiscScreen>))
// Systems for account loggedout screen
.add_system_set(SystemSet::on_enter(MenuState::AccountLoggedOut).with_system(account_loggedout_setup))
.add_system_set(SystemSet::on_exit(MenuState::AccountLoggedOut).with_system(despawn_screen::<OnAccountLoggedOutScreen>))
// Systems for account loggedin screen
.add_system_set(SystemSet::on_enter(MenuState::AccountLoggedIn).with_system(account_loggedin_setup))
.add_system_set(SystemSet::on_exit(MenuState::AccountLoggedIn).with_system(despawn_screen::<OnAccountLoggedInScreen>))
// Common systems
.add_system_set(SystemSet::on_update(GameState::MainMenu).with_system(menu_action).with_system(button_system));
app.add_plugin(accountregister::AccountRegisterPlugin)
.add_plugin(accountlogin::AccountLoginPlugin);
}
}
/// Menu State
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub enum MenuState {
None,
Main,
Settings,
SettingsDisplay,
SettingsAudio,
SettingsMisc,
AccountLoggedIn,
AccountLoggedOut,
AccountLogin,
AccountRegister,
}
/// Tag component for tagging entities on account screen
#[derive(Component)]
struct OnAccountScreen;
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 HOVERED_PRESSED_BUTTON: Color = Color::rgb(0.25, 0.65, 0.25);
const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.75, 0.35);
/// Tag component for tagging currently selected settings tab
#[derive(Component)]
struct SelectedSettingsTab;
/// All button actions
#[derive(Component)]
enum MenuButtonAction {
Play,
Settings,
SettingsDisplay,
SettingsAudio,
SettingsMisc,
Account,
AccountLogin,
AccountRegister,
AccountLogout,
BackToMainMenu,
BackToSettings,
Exit,
}
fn menu_action(
interaction_query: Query<
(&Interaction, &MenuButtonAction),
(Changed<Interaction>, With<Button>),
>,
mut app_exit_events: EventWriter<AppExit>,
mut menu_state: ResMut<State<MenuState>>,
mut register_state: ResMut<State<accountregister::RegisterState>>,
mut login_state: ResMut<State<accountlogin::LoginState>>,
mut cfg_user: ResMut<CfgUser>,
mut save_event_writer: EventWriter<SaveEvent>,
//mut game_state: ResMut<State<GameState>>,
) {
for (interaction, menu_button_action) in &interaction_query {
if *interaction == Interaction::Clicked {
match menu_button_action {
MenuButtonAction::Exit => app_exit_events.send(AppExit),
MenuButtonAction::Play => warn!("todo"),
MenuButtonAction::Settings => menu_state.set(MenuState::Settings).unwrap(),
MenuButtonAction::SettingsDisplay => {
menu_state.set(MenuState::SettingsDisplay).unwrap()
}
MenuButtonAction::SettingsAudio => {
menu_state.set(MenuState::SettingsAudio).unwrap()
}
MenuButtonAction::SettingsMisc => menu_state.set(MenuState::SettingsMisc).unwrap(),
MenuButtonAction::Account => {
if cfg_user.logged_in {
menu_state.set(MenuState::AccountLoggedIn).unwrap()
} else {
menu_state.set(MenuState::AccountLoggedOut).unwrap()
}
}
MenuButtonAction::AccountLogin => {
menu_state.set(MenuState::AccountLogin).unwrap();
login_state.set(accountlogin::LoginState::Input).unwrap();
}
MenuButtonAction::AccountRegister => {
menu_state.set(MenuState::AccountRegister).unwrap();
register_state
.set(accountregister::RegisterState::Input)
.unwrap();
}
MenuButtonAction::AccountLogout => {
// Reset CfgUser to default.
*cfg_user = CfgUser::default();
save_event_writer.send(SaveEvent {
value: SaveEventValue::User(cfg_user.clone()),
});
menu_state.set(MenuState::AccountLoggedOut).unwrap()
}
MenuButtonAction::BackToSettings => menu_state.set(MenuState::Settings).unwrap(),
MenuButtonAction::BackToMainMenu => menu_state.set(MenuState::Main).unwrap(),
}
}
}
}
/// System for handling button hovering
fn button_system(
mut interaction_query: Query<
(
&Interaction,
&mut BackgroundColor,
Option<&SelectedSettingsTab>,
),
(Changed<Interaction>, With<Button>),
>,
) {
for (interaction, mut color, selected) in &mut interaction_query {
*color = match (*interaction, selected) {
(Interaction::Clicked, _) | (Interaction::None, Some(_)) => PRESSED_BUTTON.into(),
(Interaction::Hovered, Some(_)) => HOVERED_PRESSED_BUTTON.into(),
(Interaction::Hovered, None) => HOVERED_BUTTON.into(),
(Interaction::None, None) => NORMAL_BUTTON.into(),
}
}
}
fn menu_setup(mut menu_state: ResMut<State<MenuState>>) {
let _ = menu_state.set(MenuState::Main);
}