Merge branch '65-add-code-comments' into 'dev'
Add code documentation See merge request softwaregrundprojekt/2025-2026/einzelprojekt/tutorium-moritz/bernroider-dominik/bernroider-dominik!40
This commit is contained in:
@@ -2,6 +2,7 @@ use crate::prelude::*;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
/// Global configuration loaded from file, containing balancing numbers and paths.
|
||||||
#[derive(Resource, Deserialize, Debug)]
|
#[derive(Resource, Deserialize, Debug)]
|
||||||
pub struct GameConfig {
|
pub struct GameConfig {
|
||||||
pub grid_width: u32,
|
pub grid_width: u32,
|
||||||
@@ -14,6 +15,7 @@ pub struct GameConfig {
|
|||||||
pub berries_per_focus_minute: u32,
|
pub berries_per_focus_minute: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configuration for a specific type of seed.
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct BerrySeedConfig {
|
pub struct BerrySeedConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -61,10 +63,12 @@ impl Default for GameConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GameConfig {
|
impl GameConfig {
|
||||||
|
/// Reads `config.json` from assets.
|
||||||
pub fn read_config() -> Option<Self> {
|
pub fn read_config() -> Option<Self> {
|
||||||
Self::read_from_path(std::path::Path::new("assets/config.json"))
|
Self::read_from_path(std::path::Path::new("assets/config.json"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads configuration from a specific path.
|
||||||
pub fn read_from_path(path: &std::path::Path) -> Option<Self> {
|
pub fn read_from_path(path: &std::path::Path) -> Option<Self> {
|
||||||
let file = File::open(path).ok()?;
|
let file = File::open(path).ok()?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
pub mod states;
|
pub mod states;
|
||||||
|
|
||||||
|
/// Handles core engine setup like camera and initial state.
|
||||||
pub struct CorePlugin;
|
pub struct CorePlugin;
|
||||||
|
|
||||||
impl Plugin for CorePlugin {
|
impl Plugin for CorePlugin {
|
||||||
@@ -11,6 +12,7 @@ impl Plugin for CorePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns the main 2D camera.
|
||||||
fn setup_camera(mut commands: Commands) {
|
fn setup_camera(mut commands: Commands) {
|
||||||
commands.spawn(Camera2d::default());
|
commands.spawn(Camera2d::default());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Global states of the application.
|
||||||
#[derive(States, Clone, PartialEq, Eq, Debug, Hash, Default)]
|
#[derive(States, Clone, PartialEq, Eq, Debug, Hash, Default)]
|
||||||
pub enum AppState {
|
pub enum AppState {
|
||||||
#[default]
|
#[default]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Plugin for the main game screen, managing the game loop and environment.
|
||||||
pub struct GameScreenPlugin;
|
pub struct GameScreenPlugin;
|
||||||
|
|
||||||
impl Plugin for GameScreenPlugin {
|
impl Plugin for GameScreenPlugin {
|
||||||
@@ -9,10 +10,12 @@ impl Plugin for GameScreenPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets up the game screen environment (e.g., background color).
|
||||||
fn setup(mut clear_color: ResMut<ClearColor>) {
|
fn setup(mut clear_color: ResMut<ClearColor>) {
|
||||||
*clear_color = ClearColor(Color::srgb(0.294, 0.412, 0.184));
|
*clear_color = ClearColor(Color::srgb(0.294, 0.412, 0.184));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cleans up resources when exiting the game screen.
|
||||||
fn cleanup(mut clear_color: ResMut<ClearColor>) {
|
fn cleanup(mut clear_color: ResMut<ClearColor>) {
|
||||||
*clear_color = ClearColor(Color::srgb(0.2, 0.2, 0.2));
|
*clear_color = ClearColor(Color::srgb(0.2, 0.2, 0.2));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
use super::errors::GridError;
|
use super::errors::GridError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Component representing a single tile on the grid.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
pub y: u32,
|
pub y: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Visual marker component for the crop on a tile.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct CropVisual;
|
pub struct CropVisual;
|
||||||
|
|
||||||
|
/// Visual marker component for the water on a tile.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct WaterVisual;
|
pub struct WaterVisual;
|
||||||
|
|
||||||
|
/// The logical state of a tile.
|
||||||
#[derive(Component, Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
#[derive(Component, Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum TileState {
|
pub enum TileState {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -38,6 +42,7 @@ impl TileState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resource containing grid dimensions and tile entities.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
@@ -46,6 +51,7 @@ pub struct Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Grid {
|
impl Grid {
|
||||||
|
/// Returns the entity of the tile at the given position.
|
||||||
pub fn get_tile(&self, pos: (u32, u32)) -> Result<Entity, GridError> {
|
pub fn get_tile(&self, pos: (u32, u32)) -> Result<Entity, GridError> {
|
||||||
if pos.0 >= self.width || pos.1 >= self.height {
|
if pos.0 >= self.width || pos.1 >= self.height {
|
||||||
return Err(GridError::OutOfBounds {
|
return Err(GridError::OutOfBounds {
|
||||||
@@ -56,6 +62,7 @@ impl Grid {
|
|||||||
Ok(self.tiles[pos.0 as usize][pos.1 as usize])
|
Ok(self.tiles[pos.0 as usize][pos.1 as usize])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Modifies the state of a tile using a mapping function.
|
||||||
pub fn map_tile_state<F>(
|
pub fn map_tile_state<F>(
|
||||||
&self,
|
&self,
|
||||||
pos: (u32, u32),
|
pos: (u32, u32),
|
||||||
@@ -75,6 +82,7 @@ impl Grid {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Counts the number of tiles that are not unclaimed.
|
||||||
pub fn count_claimed_tiles(&self, tile_query: &Query<&TileState>) -> u32 {
|
pub fn count_claimed_tiles(&self, tile_query: &Query<&TileState>) -> u32 {
|
||||||
self.tiles
|
self.tiles
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
/// The pixel size of a tile (width and height).
|
||||||
pub const TILE_SIZE: f32 = 32.0;
|
pub const TILE_SIZE: f32 = 32.0;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::{error::Error, fmt};
|
use std::{error::Error, fmt};
|
||||||
|
|
||||||
|
/// Errors related to grid operations.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum GridError {
|
pub enum GridError {
|
||||||
OutOfBounds { x: i32, y: i32 },
|
OutOfBounds { x: i32, y: i32 },
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ pub mod consts;
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Manages the game grid, including tiles, visuals, and updates.
|
||||||
pub struct GridPlugin;
|
pub struct GridPlugin;
|
||||||
|
|
||||||
impl Plugin for GridPlugin {
|
impl Plugin for GridPlugin {
|
||||||
@@ -18,6 +19,7 @@ impl Plugin for GridPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes the grid and spawns tile entities.
|
||||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<GameConfig>) {
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<GameConfig>) {
|
||||||
let grid_width = config.grid_width;
|
let grid_width = config.grid_width;
|
||||||
let grid_height = config.grid_height;
|
let grid_height = config.grid_height;
|
||||||
@@ -96,6 +98,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<Gam
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Despawns all grid entities and removes resources.
|
||||||
fn cleanup(mut commands: Commands, tile_query: Query<Entity, With<Tile>>) {
|
fn cleanup(mut commands: Commands, tile_query: Query<Entity, With<Tile>>) {
|
||||||
for tile_entity in tile_query.iter() {
|
for tile_entity in tile_query.iter() {
|
||||||
commands.entity(tile_entity).despawn();
|
commands.entity(tile_entity).despawn();
|
||||||
@@ -103,6 +106,7 @@ fn cleanup(mut commands: Commands, tile_query: Query<Entity, With<Tile>>) {
|
|||||||
commands.remove_resource::<Grid>();
|
commands.remove_resource::<Grid>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates tile visuals based on their state (e.g., crop growth, highlighting).
|
||||||
fn update_tiles(
|
fn update_tiles(
|
||||||
mut query: Query<
|
mut query: Query<
|
||||||
(&TileState, &mut AseSlice, &Children, &Tile),
|
(&TileState, &mut AseSlice, &Children, &Tile),
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
use super::errors::GridError;
|
use super::errors::GridError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Calculates the starting X coordinate for centering the grid.
|
||||||
pub fn grid_start_x(grid_width: u32) -> f32 {
|
pub fn grid_start_x(grid_width: u32) -> f32 {
|
||||||
-(grid_width as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0
|
-(grid_width as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the starting Y coordinate for centering the grid.
|
||||||
pub fn grid_start_y(grid_height: u32) -> f32 {
|
pub fn grid_start_y(grid_height: u32) -> f32 {
|
||||||
-(grid_height as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0
|
-(grid_height as f32 * TILE_SIZE) / 2.0 + TILE_SIZE / 2.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts world coordinates to grid coordinates.
|
||||||
pub fn world_to_grid_coords(
|
pub fn world_to_grid_coords(
|
||||||
world_pos: Vec3,
|
world_pos: Vec3,
|
||||||
grid_width: u32,
|
grid_width: u32,
|
||||||
@@ -30,6 +33,7 @@ pub fn world_to_grid_coords(
|
|||||||
Ok((x as u32, y as u32))
|
Ok((x as u32, y as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts grid coordinates to world coordinates.
|
||||||
pub fn grid_to_world_coords(
|
pub fn grid_to_world_coords(
|
||||||
grid_x: u32,
|
grid_x: u32,
|
||||||
grid_y: u32,
|
grid_y: u32,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{features::phase::components::TimerSettings, prelude::*};
|
use crate::{features::phase::components::TimerSettings, prelude::*};
|
||||||
|
|
||||||
|
/// Markers for root UI nodes.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
Status,
|
Status,
|
||||||
@@ -7,12 +8,14 @@ pub enum RootMarker {
|
|||||||
ShovelOverlay,
|
ShovelOverlay,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Markers for text components in the HUD.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum TextType {
|
pub enum TextType {
|
||||||
Phase,
|
Phase,
|
||||||
Timer,
|
Timer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Markers for buttons in the HUD and settings.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
SettingsOpen,
|
SettingsOpen,
|
||||||
@@ -24,6 +27,7 @@ pub enum ButtonType {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Types of timers available in the game.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TimerType {
|
pub enum TimerType {
|
||||||
Focus,
|
Focus,
|
||||||
@@ -32,6 +36,7 @@ pub enum TimerType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TimerSettings {
|
impl TimerSettings {
|
||||||
|
/// Changes the duration of a specific timer.
|
||||||
pub fn change(&mut self, timer_type: &TimerType, amount: i32) {
|
pub fn change(&mut self, timer_type: &TimerType, amount: i32) {
|
||||||
match timer_type {
|
match timer_type {
|
||||||
TimerType::Focus => {
|
TimerType::Focus => {
|
||||||
@@ -59,6 +64,7 @@ impl TimerSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Input types for adjusting timer settings.
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
pub enum SettingsTimerInput {
|
pub enum SettingsTimerInput {
|
||||||
Minutes(TimerType),
|
Minutes(TimerType),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use ui::*;
|
|||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
|
/// Plugin for the Head-Up Display (HUD) containing status bars and buttons.
|
||||||
pub struct HudPlugin;
|
pub struct HudPlugin;
|
||||||
|
|
||||||
impl Plugin for HudPlugin {
|
impl Plugin for HudPlugin {
|
||||||
@@ -27,6 +28,7 @@ impl Plugin for HudPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes the HUD UI.
|
||||||
fn setup(mut commands: Commands, game_config: Res<GameConfig>, asset_server: Res<AssetServer>) {
|
fn setup(mut commands: Commands, game_config: Res<GameConfig>, asset_server: Res<AssetServer>) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
RootMarker::Status,
|
RootMarker::Status,
|
||||||
@@ -126,6 +128,7 @@ fn setup(mut commands: Commands, game_config: Res<GameConfig>, asset_server: Res
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the status text (phase and timer).
|
||||||
fn update_status(phase_res: Res<CurrentPhase>, mut text_query: Query<(&mut Text, &TextType)>) {
|
fn update_status(phase_res: Res<CurrentPhase>, mut text_query: Query<(&mut Text, &TextType)>) {
|
||||||
if !phase_res.is_changed() {
|
if !phase_res.is_changed() {
|
||||||
return;
|
return;
|
||||||
@@ -140,6 +143,7 @@ fn update_status(phase_res: Res<CurrentPhase>, mut text_query: Query<(&mut Text,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles HUD button interactions.
|
||||||
fn buttons(
|
fn buttons(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||||
@@ -181,12 +185,14 @@ fn buttons(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cleans up HUD resources.
|
||||||
fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
|
fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
|
||||||
for entity in query.iter() {
|
for entity in query.iter() {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the timer settings display in the settings menu.
|
||||||
fn update_timer_settings(
|
fn update_timer_settings(
|
||||||
timer_settings: ResMut<TimerSettings>,
|
timer_settings: ResMut<TimerSettings>,
|
||||||
mut query: Query<(&SettingsTimerInput, &mut Text)>,
|
mut query: Query<(&SettingsTimerInput, &mut Text)>,
|
||||||
@@ -215,6 +221,7 @@ fn update_timer_settings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the visibility of the shovel overlay based on inventory.
|
||||||
fn update_shovel_overlay_visibility(
|
fn update_shovel_overlay_visibility(
|
||||||
inventory: Res<inventory::components::Inventory>,
|
inventory: Res<inventory::components::Inventory>,
|
||||||
item_stacks: Query<&inventory::components::ItemStack>,
|
item_stacks: Query<&inventory::components::ItemStack>,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use super::super::components::*;
|
|||||||
use super::timer_settings::timer_settings;
|
use super::timer_settings::timer_settings;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Spawns the settings popup.
|
||||||
pub fn open_settings(commands: &mut Commands) {
|
pub fn open_settings(commands: &mut Commands) {
|
||||||
spawn_popup(
|
spawn_popup(
|
||||||
commands,
|
commands,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::super::components::*;
|
use super::super::components::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Creates a UI bundle for a specific timer setting.
|
||||||
pub fn timer_settings(timer_type: TimerType) -> impl Bundle {
|
pub fn timer_settings(timer_type: TimerType) -> impl Bundle {
|
||||||
(
|
(
|
||||||
Node {
|
Node {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use bevy::window::PrimaryWindow;
|
|||||||
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Handles user input for the game.
|
||||||
pub struct InputPlugin;
|
pub struct InputPlugin;
|
||||||
|
|
||||||
impl Plugin for InputPlugin {
|
impl Plugin for InputPlugin {
|
||||||
@@ -45,6 +46,7 @@ impl Plugin for InputPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles right-click movement input.
|
||||||
fn move_click(
|
fn move_click(
|
||||||
mut move_messages: MessageWriter<MoveMessage>,
|
mut move_messages: MessageWriter<MoveMessage>,
|
||||||
mouse_btn: Res<ButtonInput<MouseButton>>,
|
mouse_btn: Res<ButtonInput<MouseButton>>,
|
||||||
@@ -75,6 +77,7 @@ fn move_click(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles left-click interactions (tile selection, shovel).
|
||||||
fn interact_click(
|
fn interact_click(
|
||||||
mut tile_click_messages: MessageWriter<TileClickMessage>,
|
mut tile_click_messages: MessageWriter<TileClickMessage>,
|
||||||
mouse_btn: Res<ButtonInput<MouseButton>>,
|
mouse_btn: Res<ButtonInput<MouseButton>>,
|
||||||
@@ -174,6 +177,7 @@ fn interact_click(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Handles debug interactions (shift + left click).
|
||||||
fn debug_click(
|
fn debug_click(
|
||||||
mouse_btn: Res<ButtonInput<MouseButton>>,
|
mouse_btn: Res<ButtonInput<MouseButton>>,
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
@@ -220,6 +224,7 @@ fn debug_click(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pauses/resumes the phase timer on Space press.
|
||||||
fn phase_timer_pause(
|
fn phase_timer_pause(
|
||||||
mut pause_messages: MessageWriter<PhaseTimerPauseMessage>,
|
mut pause_messages: MessageWriter<PhaseTimerPauseMessage>,
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
@@ -229,12 +234,14 @@ fn phase_timer_pause(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Skips to the next phase on Enter press.
|
||||||
fn next_phase(mut messages: MessageWriter<NextPhaseMessage>, keys: Res<ButtonInput<KeyCode>>) {
|
fn next_phase(mut messages: MessageWriter<NextPhaseMessage>, keys: Res<ButtonInput<KeyCode>>) {
|
||||||
if keys.just_pressed(KeyCode::Enter) {
|
if keys.just_pressed(KeyCode::Enter) {
|
||||||
messages.write(NextPhaseMessage);
|
messages.write(NextPhaseMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens the shop on 'P' press.
|
||||||
fn shop_keybind(
|
fn shop_keybind(
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -254,6 +261,7 @@ fn shop_keybind(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes popups on Escape press.
|
||||||
fn popup_keybind(
|
fn popup_keybind(
|
||||||
mut close_popup_messages: MessageWriter<ClosePopupMessage>,
|
mut close_popup_messages: MessageWriter<ClosePopupMessage>,
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bevy::window::PrimaryWindow;
|
use bevy::window::PrimaryWindow;
|
||||||
|
|
||||||
|
/// Converts mouse position to grid coordinates, respecting UI blocks.
|
||||||
pub fn mouse_to_grid(
|
pub fn mouse_to_grid(
|
||||||
window: Single<&Window, With<PrimaryWindow>>,
|
window: Single<&Window, With<PrimaryWindow>>,
|
||||||
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::features::config::components::BerrySeedConfig;
|
use crate::features::config::components::BerrySeedConfig;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Types of items available in the game.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ItemType {
|
pub enum ItemType {
|
||||||
Berry,
|
Berry,
|
||||||
@@ -102,18 +103,21 @@ impl ItemType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A stack of items of a specific type.
|
||||||
#[derive(Component, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Component, Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct ItemStack {
|
pub struct ItemStack {
|
||||||
pub item_type: ItemType,
|
pub item_type: ItemType,
|
||||||
pub amount: u32,
|
pub amount: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resource containing all items owned by the player.
|
||||||
#[derive(Resource, Default, Serialize, Deserialize)]
|
#[derive(Resource, Default, Serialize, Deserialize)]
|
||||||
pub struct Inventory {
|
pub struct Inventory {
|
||||||
pub items: Vec<Entity>,
|
pub items: Vec<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inventory {
|
impl Inventory {
|
||||||
|
/// Checks if the inventory contains a specific item type.
|
||||||
pub fn has_item_type(&self, items_query: &Query<&ItemStack>, item_type: ItemType) -> bool {
|
pub fn has_item_type(&self, items_query: &Query<&ItemStack>, item_type: ItemType) -> bool {
|
||||||
self.items.iter().any(|&entity| {
|
self.items.iter().any(|&entity| {
|
||||||
if let Ok(stack) = items_query.get(entity) {
|
if let Ok(stack) = items_query.get(entity) {
|
||||||
@@ -124,6 +128,7 @@ impl Inventory {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds or removes items from the inventory.
|
||||||
pub fn update_item_stack(
|
pub fn update_item_stack(
|
||||||
&mut self,
|
&mut self,
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
@@ -193,11 +198,13 @@ impl Inventory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Markers for inventory UI root nodes.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
Inventory,
|
Inventory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Markers for inventory-related buttons.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
InventoryOpen,
|
InventoryOpen,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use components::*;
|
|||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
|
/// Plugin for the inventory system, including storage and UI.
|
||||||
pub struct InventoryPlugin;
|
pub struct InventoryPlugin;
|
||||||
|
|
||||||
impl Plugin for InventoryPlugin {
|
impl Plugin for InventoryPlugin {
|
||||||
@@ -18,6 +19,7 @@ impl Plugin for InventoryPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles inventory button interactions.
|
||||||
fn buttons(
|
fn buttons(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||||
@@ -37,6 +39,7 @@ fn buttons(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Debug system to add/remove berries with arrow keys.
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn debug_modify_berries(
|
fn debug_modify_berries(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use super::super::components::RootMarker;
|
|||||||
use crate::prelude::GameConfig;
|
use crate::prelude::GameConfig;
|
||||||
use crate::{features::inventory::ui::list_itemstack, prelude::*};
|
use crate::{features::inventory::ui::list_itemstack, prelude::*};
|
||||||
|
|
||||||
|
/// Spawns the inventory popup.
|
||||||
pub fn open_inventory(
|
pub fn open_inventory(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
items: Query<&ItemStack>,
|
items: Query<&ItemStack>,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Creates a UI bundle for a single item stack in the inventory list.
|
||||||
pub fn list_itemstack(
|
pub fn list_itemstack(
|
||||||
itemstack: &ItemStack,
|
itemstack: &ItemStack,
|
||||||
game_config: &GameConfig,
|
game_config: &GameConfig,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Resource managing active notifications.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct Notifications {
|
pub struct Notifications {
|
||||||
items: Vec<(Notification, NotificationLevel)>,
|
items: Vec<(Notification, NotificationLevel)>,
|
||||||
@@ -44,18 +45,22 @@ impl Notifications {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marker for the UI node containing notifications.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct NotificationContainer;
|
pub struct NotificationContainer;
|
||||||
|
|
||||||
|
/// Component tracking the lifetime of a displayed notification.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct NotificationLifetime(pub Timer);
|
pub struct NotificationLifetime(pub Timer);
|
||||||
|
|
||||||
|
/// Data for a single notification.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Notification {
|
pub struct Notification {
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Severity level of a notification.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum NotificationLevel {
|
pub enum NotificationLevel {
|
||||||
Info,
|
Info,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use components::{NotificationContainer, NotificationLifetime, Notifications};
|
|||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
|
/// Plugin for the notification system.
|
||||||
pub struct NotificationPlugin;
|
pub struct NotificationPlugin;
|
||||||
|
|
||||||
impl Plugin for NotificationPlugin {
|
impl Plugin for NotificationPlugin {
|
||||||
@@ -17,12 +18,12 @@ impl Plugin for NotificationPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns the notification container up
|
/// Spawns the notification container up.
|
||||||
fn setup(mut commands: Commands) {
|
fn setup(mut commands: Commands) {
|
||||||
commands.spawn(notification_container());
|
commands.spawn(notification_container());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns/Despawns UI elements for each item in the `Notifications` Resource
|
/// Spawns/Despawns UI elements for each item in the `Notifications` Resource.
|
||||||
fn handle_notification(
|
fn handle_notification(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut notifications: ResMut<Notifications>,
|
mut notifications: ResMut<Notifications>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::components::*;
|
use super::components::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Creates the notification container UI bundle.
|
||||||
pub fn notification_container() -> impl Bundle {
|
pub fn notification_container() -> impl Bundle {
|
||||||
(
|
(
|
||||||
NotificationContainer,
|
NotificationContainer,
|
||||||
@@ -16,6 +17,7 @@ pub fn notification_container() -> impl Bundle {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns a single notification UI element.
|
||||||
pub fn spawn_notification(
|
pub fn spawn_notification(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
content: Notification,
|
content: Notification,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::utils::format_time;
|
use super::utils::format_time;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Represents the different states of the Pomodoro timer.
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum Phase {
|
pub enum Phase {
|
||||||
Break { duration: f32 },
|
Break { duration: f32 },
|
||||||
@@ -37,9 +38,11 @@ impl Phase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resource holding the current phase state.
|
||||||
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct CurrentPhase(pub Phase);
|
pub struct CurrentPhase(pub Phase);
|
||||||
|
|
||||||
|
/// Configuration for phase durations.
|
||||||
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
#[derive(Resource, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct TimerSettings {
|
pub struct TimerSettings {
|
||||||
pub focus_duration: u32,
|
pub focus_duration: u32,
|
||||||
@@ -59,6 +62,7 @@ impl Default for TimerSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks statistics for the current session.
|
||||||
#[derive(Resource, Debug, Default, Serialize, Deserialize, Clone)]
|
#[derive(Resource, Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct SessionTracker {
|
pub struct SessionTracker {
|
||||||
pub completed_focus_phases: u32,
|
pub completed_focus_phases: u32,
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Message sent when a phase timer reaches zero.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct PhaseTimerFinishedMessage {
|
pub struct PhaseTimerFinishedMessage {
|
||||||
pub phase: Phase,
|
pub phase: Phase,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Message to toggle pause state.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct PhaseTimerPauseMessage;
|
pub struct PhaseTimerPauseMessage;
|
||||||
|
|
||||||
|
/// Message to proceed to the next phase.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct NextPhaseMessage;
|
pub struct NextPhaseMessage;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ pub mod components;
|
|||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Plugin managing the Pomodoro phase timer and state.
|
||||||
pub struct PhasePlugin;
|
pub struct PhasePlugin;
|
||||||
|
|
||||||
impl Plugin for PhasePlugin {
|
impl Plugin for PhasePlugin {
|
||||||
@@ -36,6 +37,7 @@ impl Plugin for PhasePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Debug system to shorten phase duration for testing.
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn debug_short_phase_duration(
|
fn debug_short_phase_duration(
|
||||||
mut phase_res: ResMut<CurrentPhase>,
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
@@ -55,6 +57,7 @@ fn debug_short_phase_duration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the current phase duration from settings.
|
||||||
fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>) {
|
fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>) {
|
||||||
let phase = &mut phase_res.0;
|
let phase = &mut phase_res.0;
|
||||||
|
|
||||||
@@ -71,6 +74,7 @@ fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ticks the phase timer and handles completion.
|
||||||
fn tick_timer(
|
fn tick_timer(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
@@ -107,7 +111,7 @@ fn tick_timer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rewards the player at the end of a focus phase with `berries_per_focus_minute` * `focus_duration`
|
/// Rewards the player at the end of a focus phase with `berries_per_focus_minute` * `focus_duration`.
|
||||||
fn grant_focus_rewards(
|
fn grant_focus_rewards(
|
||||||
mut messages: MessageReader<PhaseTimerFinishedMessage>,
|
mut messages: MessageReader<PhaseTimerFinishedMessage>,
|
||||||
config: Res<GameConfig>,
|
config: Res<GameConfig>,
|
||||||
@@ -147,6 +151,7 @@ fn grant_focus_rewards(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Toggles pause state of the timer.
|
||||||
fn handle_pause(
|
fn handle_pause(
|
||||||
mut messages: MessageReader<PhaseTimerPauseMessage>,
|
mut messages: MessageReader<PhaseTimerPauseMessage>,
|
||||||
mut phase_res: ResMut<CurrentPhase>,
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
@@ -171,6 +176,7 @@ fn handle_pause(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transitions to the next phase based on current state.
|
||||||
pub fn next_phase(
|
pub fn next_phase(
|
||||||
current_phase: &mut CurrentPhase,
|
current_phase: &mut CurrentPhase,
|
||||||
session_tracker: &mut SessionTracker,
|
session_tracker: &mut SessionTracker,
|
||||||
@@ -204,6 +210,7 @@ pub fn next_phase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles transition to the next phase after user confirmation.
|
||||||
pub fn handle_continue(
|
pub fn handle_continue(
|
||||||
mut messages: MessageReader<NextPhaseMessage>,
|
mut messages: MessageReader<NextPhaseMessage>,
|
||||||
mut phase_res: ResMut<CurrentPhase>,
|
mut phase_res: ResMut<CurrentPhase>,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/// Formats seconds into MM:SS or HH:MM:SS string.
|
||||||
pub fn format_time(seconds: f32) -> String {
|
pub fn format_time(seconds: f32) -> String {
|
||||||
let seconds = seconds.max(0.0) as u32;
|
let seconds = seconds.max(0.0) as u32;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{features::phase::components::SessionTracker, prelude::*};
|
use crate::{features::phase::components::SessionTracker, prelude::*};
|
||||||
|
|
||||||
|
/// Actions Pom can perform on tiles.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum InteractionAction {
|
pub enum InteractionAction {
|
||||||
Plant(ItemType),
|
Plant(ItemType),
|
||||||
|
|||||||
@@ -2,20 +2,24 @@ use crate::features::pom::actions::InteractionAction;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
/// Marker component for the main character.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Pom;
|
pub struct Pom;
|
||||||
|
|
||||||
|
/// Current logical position on the grid.
|
||||||
#[derive(Component, Serialize, Deserialize, Clone, Copy, Default)]
|
#[derive(Component, Serialize, Deserialize, Clone, Copy, Default)]
|
||||||
pub struct GridPosition {
|
pub struct GridPosition {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
pub y: u32,
|
pub y: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue of grid positions to visit.
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub struct PathQueue {
|
pub struct PathQueue {
|
||||||
pub steps: VecDeque<(u32, u32)>,
|
pub steps: VecDeque<(u32, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Movement direction state for animation.
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub enum MovingState {
|
pub enum MovingState {
|
||||||
#[default]
|
#[default]
|
||||||
@@ -38,6 +42,7 @@ impl MovingState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Target tile and action for pending interaction.
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub struct InteractionTarget {
|
pub struct InteractionTarget {
|
||||||
pub target: Option<(u32, u32)>,
|
pub target: Option<(u32, u32)>,
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
use crate::features::pom::actions::InteractionAction;
|
use crate::features::pom::actions::InteractionAction;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Request to move Pom to a specific tile.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct MoveMessage {
|
pub struct MoveMessage {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
pub y: u32,
|
pub y: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notification that a move request was invalid.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct InvalidMoveMessage {
|
pub struct InvalidMoveMessage {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request to start an interaction sequence.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct InteractStartMessage {
|
pub struct InteractStartMessage {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
@@ -19,6 +22,7 @@ pub struct InteractStartMessage {
|
|||||||
pub action: InteractionAction,
|
pub action: InteractionAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Notification that a tile was clicked (requesting context menu).
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct TileClickMessage {
|
pub struct TileClickMessage {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub mod messages;
|
|||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Plugin controlling the main character (Pom) behavior.
|
||||||
pub struct PomPlugin;
|
pub struct PomPlugin;
|
||||||
|
|
||||||
impl Plugin for PomPlugin {
|
impl Plugin for PomPlugin {
|
||||||
@@ -34,6 +35,7 @@ impl Plugin for PomPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws the path Pom will follow using gizmos.
|
||||||
fn draw_path(
|
fn draw_path(
|
||||||
mut gizmos: Gizmos,
|
mut gizmos: Gizmos,
|
||||||
query: Query<(&Transform, &PathQueue), With<Pom>>,
|
query: Query<(&Transform, &PathQueue), With<Pom>>,
|
||||||
@@ -65,6 +67,7 @@ fn draw_path(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns the Pom character.
|
||||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<GameConfig>) {
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<GameConfig>) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Pom,
|
Pom,
|
||||||
@@ -87,12 +90,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, config: Res<Gam
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Despawns the Pom character.
|
||||||
fn cleanup(mut commands: Commands, pom_query: Query<Entity, With<Pom>>) {
|
fn cleanup(mut commands: Commands, pom_query: Query<Entity, With<Pom>>) {
|
||||||
for pom_entity in pom_query.iter() {
|
for pom_entity in pom_query.iter() {
|
||||||
commands.entity(pom_entity).despawn();
|
commands.entity(pom_entity).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates path for manual movement requests.
|
||||||
fn handle_move(
|
fn handle_move(
|
||||||
mut move_messages: MessageReader<MoveMessage>,
|
mut move_messages: MessageReader<MoveMessage>,
|
||||||
mut invalid_move_messages: MessageWriter<InvalidMoveMessage>,
|
mut invalid_move_messages: MessageWriter<InvalidMoveMessage>,
|
||||||
@@ -127,6 +132,7 @@ fn handle_move(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates path to interaction target.
|
||||||
fn handle_interact(
|
fn handle_interact(
|
||||||
mut interact_messages: MessageReader<InteractStartMessage>,
|
mut interact_messages: MessageReader<InteractStartMessage>,
|
||||||
mut pom_query: Query<(&GridPosition, &mut PathQueue, &mut InteractionTarget)>,
|
mut pom_query: Query<(&GridPosition, &mut PathQueue, &mut InteractionTarget)>,
|
||||||
@@ -184,6 +190,7 @@ fn handle_interact(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes the pending interaction when target is reached.
|
||||||
pub fn perform_interaction(
|
pub fn perform_interaction(
|
||||||
mut pom_query: Query<(&GridPosition, &mut InteractionTarget, &PathQueue)>,
|
mut pom_query: Query<(&GridPosition, &mut InteractionTarget, &PathQueue)>,
|
||||||
grid: Res<Grid>,
|
grid: Res<Grid>,
|
||||||
@@ -239,6 +246,7 @@ pub fn perform_interaction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Moves the Pom character along the path.
|
||||||
fn move_pom(
|
fn move_pom(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut query: Query<(
|
mut query: Query<(
|
||||||
@@ -288,6 +296,7 @@ fn move_pom(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates Pom animation based on movement state.
|
||||||
fn update_pom(asset_server: Res<AssetServer>, mut query: Query<(&MovingState, &mut AseAnimation)>) {
|
fn update_pom(asset_server: Res<AssetServer>, mut query: Query<(&MovingState, &mut AseAnimation)>) {
|
||||||
for (moving_state, mut animation) in query.iter_mut() {
|
for (moving_state, mut animation) in query.iter_mut() {
|
||||||
match moving_state {
|
match moving_state {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ use crate::features::ui::utils::ui_blocks;
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bevy::window::PrimaryWindow;
|
use bevy::window::PrimaryWindow;
|
||||||
|
|
||||||
|
/// Marker for context menu UI root.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Buttons available in the context menu.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
Interact {
|
Interact {
|
||||||
@@ -19,6 +21,7 @@ pub enum ButtonType {
|
|||||||
Cancel,
|
Cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns the context menu at the clicked tile position.
|
||||||
pub fn open_context_menu(
|
pub fn open_context_menu(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut tile_click_messages: MessageReader<TileClickMessage>,
|
mut tile_click_messages: MessageReader<TileClickMessage>,
|
||||||
@@ -87,6 +90,7 @@ pub fn open_context_menu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes context menu when clicking elsewhere.
|
||||||
pub fn click_outside_context_menu(
|
pub fn click_outside_context_menu(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mouse_btn: Res<ButtonInput<MouseButton>>,
|
mouse_btn: Res<ButtonInput<MouseButton>>,
|
||||||
@@ -107,6 +111,7 @@ pub fn click_outside_context_menu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles context menu button clicks.
|
||||||
pub fn buttons(
|
pub fn buttons(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut button_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
mut button_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||||
@@ -133,6 +138,7 @@ pub fn buttons(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Closes context menu on ClosePopupMessage.
|
||||||
pub fn close_context_menu(
|
pub fn close_context_menu(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut close_popup_reader: MessageReader<ClosePopupMessage>,
|
mut close_popup_reader: MessageReader<ClosePopupMessage>,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
pub mod context_menu;
|
pub mod context_menu;
|
||||||
|
|
||||||
|
/// Plugin for Pom-related UI (context menu).
|
||||||
pub struct PomUiPlugin;
|
pub struct PomUiPlugin;
|
||||||
|
|
||||||
impl Plugin for PomUiPlugin {
|
impl Plugin for PomUiPlugin {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::prelude::*;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
|
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
|
||||||
|
|
||||||
|
/// A star pathfinding node.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
x: u32,
|
x: u32,
|
||||||
@@ -25,11 +26,12 @@ impl PartialOrd for Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates Manhattan distance between two points.
|
||||||
pub fn manhattan_distance(x1: u32, y1: u32, x2: u32, y2: u32) -> u32 {
|
pub fn manhattan_distance(x1: u32, y1: u32, x2: u32, y2: u32) -> u32 {
|
||||||
x1.abs_diff(x2) + y1.abs_diff(y2)
|
x1.abs_diff(x2) + y1.abs_diff(y2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if Pom would be trapped in a small, isolated area if a specific tile is blocked
|
/// Checks if Pom would be trapped in a small, isolated area if a specific tile is blocked.
|
||||||
pub fn is_trapped<F>(
|
pub fn is_trapped<F>(
|
||||||
start: (u32, u32),
|
start: (u32, u32),
|
||||||
blocked_pos: (u32, u32),
|
blocked_pos: (u32, u32),
|
||||||
@@ -98,6 +100,7 @@ where
|
|||||||
visited.len() < min_safe_area
|
visited.len() < min_safe_area
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds a path from start to end using A* algorithm.
|
||||||
pub fn find_path(
|
pub fn find_path(
|
||||||
start: (u32, u32),
|
start: (u32, u32),
|
||||||
end: (u32, u32),
|
end: (u32, u32),
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ use crate::prelude::*;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Resource containing the path to the current save file.
|
||||||
#[derive(Resource, Clone, Debug)]
|
#[derive(Resource, Clone, Debug)]
|
||||||
pub struct SavegamePath(pub PathBuf);
|
pub struct SavegamePath(pub PathBuf);
|
||||||
|
|
||||||
|
/// Metadata about a savegame.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SavegameInfo {
|
pub struct SavegameInfo {
|
||||||
pub path: SavegamePath,
|
pub path: SavegamePath,
|
||||||
@@ -13,11 +15,13 @@ pub struct SavegameInfo {
|
|||||||
pub completed_focus: u32,
|
pub completed_focus: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for partial JSON deserialization.
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PartialSaveData {
|
struct PartialSaveData {
|
||||||
session_tracker: PartialSessionTracker,
|
session_tracker: PartialSessionTracker,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper for partial JSON deserialization of session stats.
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PartialSessionTracker {
|
struct PartialSessionTracker {
|
||||||
completed_focus_phases: u32,
|
completed_focus_phases: u32,
|
||||||
@@ -26,6 +30,7 @@ struct PartialSessionTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SavegamePath {
|
impl SavegamePath {
|
||||||
|
/// Constructs a new path for a specific save index.
|
||||||
pub fn new(index: u32) -> Self {
|
pub fn new(index: u32) -> Self {
|
||||||
let base_path = get_internal_path().unwrap_or_else(|| {
|
let base_path = get_internal_path().unwrap_or_else(|| {
|
||||||
println!(
|
println!(
|
||||||
@@ -41,6 +46,7 @@ impl SavegamePath {
|
|||||||
Self(base_path.join(format!("savegame-{}.json", index)))
|
Self(base_path.join(format!("savegame-{}.json", index)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists all available savegames.
|
||||||
pub fn list() -> Vec<SavegameInfo> {
|
pub fn list() -> Vec<SavegameInfo> {
|
||||||
let mut savegames = Vec::new();
|
let mut savegames = Vec::new();
|
||||||
|
|
||||||
@@ -88,6 +94,7 @@ impl SavegamePath {
|
|||||||
savegames
|
savegames
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a path for a new savegame (incremented index).
|
||||||
pub fn next() -> Self {
|
pub fn next() -> Self {
|
||||||
let savegames = Self::list();
|
let savegames = Self::list();
|
||||||
let next_index = savegames.last().map(|s| s.index + 1).unwrap_or(0);
|
let next_index = savegames.last().map(|s| s.index + 1).unwrap_or(0);
|
||||||
@@ -95,11 +102,13 @@ impl SavegamePath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Markers for savegame UI.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
PopupSavegameLoad,
|
PopupSavegameLoad,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Buttons for savegame management.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
SavegameLoad { savegame_path: SavegamePath },
|
SavegameLoad { savegame_path: SavegamePath },
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Trigger to save the current game.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct SavegameDumpMessage;
|
pub struct SavegameDumpMessage;
|
||||||
|
|
||||||
|
/// Trigger to load a game from disk.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct SavegameLoadMessage;
|
pub struct SavegameLoadMessage;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ pub mod components;
|
|||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
|
/// Plugin dealing with savegame loading and saving.
|
||||||
pub struct SavegamePlugin;
|
pub struct SavegamePlugin;
|
||||||
|
|
||||||
impl Plugin for SavegamePlugin {
|
impl Plugin for SavegamePlugin {
|
||||||
@@ -25,6 +26,7 @@ impl Plugin for SavegamePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The structure of a save file.
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct SaveData {
|
struct SaveData {
|
||||||
grid_width: u32,
|
grid_width: u32,
|
||||||
@@ -37,6 +39,7 @@ struct SaveData {
|
|||||||
inventory: Vec<ItemStack>,
|
inventory: Vec<ItemStack>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes game state and writes it to a file.
|
||||||
fn dump_savegame(
|
fn dump_savegame(
|
||||||
mut messages: MessageReader<SavegameDumpMessage>,
|
mut messages: MessageReader<SavegameDumpMessage>,
|
||||||
save_path: Res<SavegamePath>,
|
save_path: Res<SavegamePath>,
|
||||||
@@ -106,6 +109,7 @@ fn dump_savegame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a save file and restores game state.
|
||||||
fn load_savegame(
|
fn load_savegame(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut messages: MessageReader<SavegameLoadMessage>,
|
mut messages: MessageReader<SavegameLoadMessage>,
|
||||||
@@ -174,7 +178,7 @@ fn load_savegame(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets all components/resources loaded by `load_savegame`
|
/// Resets all components/resources loaded by `load_savegame`.
|
||||||
fn reset_savegame(
|
fn reset_savegame(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
grid: Res<Grid>,
|
grid: Res<Grid>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::super::components::{ButtonType, RootMarker};
|
use super::super::components::{ButtonType, RootMarker};
|
||||||
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
use crate::{features::savegame::messages::SavegameLoadMessage, prelude::*};
|
||||||
|
|
||||||
|
/// Spawns the "Load Game" popup.
|
||||||
pub fn spawn_load_popup(commands: &mut Commands) {
|
pub fn spawn_load_popup(commands: &mut Commands) {
|
||||||
spawn_popup(
|
spawn_popup(
|
||||||
commands,
|
commands,
|
||||||
@@ -88,6 +89,7 @@ pub fn spawn_load_popup(commands: &mut Commands) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles interactions in the load popup.
|
||||||
pub fn load_popup_handler(
|
pub fn load_popup_handler(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Markers for shop UI.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
Shop,
|
Shop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Buttons in the shop.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
ShopOpen,
|
ShopOpen,
|
||||||
ShopBuyItem(ShopOffer),
|
ShopBuyItem(ShopOffer),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An item available for purchase.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ShopOffer {
|
pub struct ShopOffer {
|
||||||
pub item: ItemStack,
|
pub item: ItemStack,
|
||||||
@@ -18,6 +21,7 @@ pub struct ShopOffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ShopOffer {
|
impl ShopOffer {
|
||||||
|
/// Generates a list of all current offers.
|
||||||
pub fn list_all(game_config: &GameConfig, tile_count: u32) -> Vec<ShopOffer> {
|
pub fn list_all(game_config: &GameConfig, tile_count: u32) -> Vec<ShopOffer> {
|
||||||
let mut offers = Vec::new();
|
let mut offers = Vec::new();
|
||||||
|
|
||||||
@@ -50,6 +54,7 @@ impl ShopOffer {
|
|||||||
offers
|
offers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to purchase the offer.
|
||||||
pub fn buy(
|
pub fn buy(
|
||||||
&self,
|
&self,
|
||||||
inventory: &mut Inventory,
|
inventory: &mut Inventory,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use ui::open_shop;
|
|||||||
pub mod components;
|
pub mod components;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|
||||||
|
/// Plugin for the in-game shop.
|
||||||
pub struct ShopPlugin;
|
pub struct ShopPlugin;
|
||||||
|
|
||||||
impl Plugin for ShopPlugin {
|
impl Plugin for ShopPlugin {
|
||||||
@@ -13,6 +14,7 @@ impl Plugin for ShopPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles shop button interactions.
|
||||||
fn buttons(
|
fn buttons(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
mut interaction_query: Query<(&Interaction, &ButtonType), (Changed<Interaction>, With<Button>)>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::super::components::*;
|
use super::super::components::*;
|
||||||
use crate::{features::inventory::ui::item::list_itemstack, prelude::*};
|
use crate::{features::inventory::ui::item::list_itemstack, prelude::*};
|
||||||
|
|
||||||
|
/// Creates the UI bundle for a shop offer.
|
||||||
pub fn shop_offer(
|
pub fn shop_offer(
|
||||||
offer: &ShopOffer,
|
offer: &ShopOffer,
|
||||||
game_config: &GameConfig,
|
game_config: &GameConfig,
|
||||||
@@ -26,6 +27,7 @@ pub fn shop_offer(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates the UI bundle for displaying a price.
|
||||||
pub fn shop_price(
|
pub fn shop_price(
|
||||||
price: u32,
|
price: u32,
|
||||||
asset_server: &Res<AssetServer>,
|
asset_server: &Res<AssetServer>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::super::components::*;
|
use super::super::components::*;
|
||||||
use crate::{features::shop::ui::shop_offer, prelude::*};
|
use crate::{features::shop::ui::shop_offer, prelude::*};
|
||||||
|
|
||||||
|
/// Spawns the shop popup.
|
||||||
pub fn open_shop(
|
pub fn open_shop(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
game_config: &GameConfig,
|
game_config: &GameConfig,
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Markers for main menu UI.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum RootMarker {
|
pub enum RootMarker {
|
||||||
MainMenu,
|
MainMenu,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Buttons in the main menu.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub enum ButtonType {
|
pub enum ButtonType {
|
||||||
LoadGame,
|
LoadGame,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use components::*;
|
|||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
|
|
||||||
|
/// Plugin for the main menu screen.
|
||||||
pub struct StartScreenPlugin;
|
pub struct StartScreenPlugin;
|
||||||
|
|
||||||
impl Plugin for StartScreenPlugin {
|
impl Plugin for StartScreenPlugin {
|
||||||
@@ -14,6 +15,7 @@ impl Plugin for StartScreenPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns the main menu UI.
|
||||||
fn setup(mut commands: Commands) {
|
fn setup(mut commands: Commands) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
RootMarker::MainMenu,
|
RootMarker::MainMenu,
|
||||||
@@ -60,6 +62,7 @@ fn setup(mut commands: Commands) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles main menu button interactions.
|
||||||
fn menu(
|
fn menu(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
@@ -84,6 +87,7 @@ fn menu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cleans up main menu resources.
|
||||||
fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
|
fn cleanup(mut commands: Commands, query: Query<Entity, With<RootMarker>>) {
|
||||||
for entity in query.iter() {
|
for entity in query.iter() {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Event triggering a scroll action on an entity.
|
||||||
#[derive(EntityEvent, Debug)]
|
#[derive(EntityEvent, Debug)]
|
||||||
#[entity_event(propagate, auto_propagate)]
|
#[entity_event(propagate, auto_propagate)]
|
||||||
pub struct Scroll {
|
pub struct Scroll {
|
||||||
@@ -7,6 +8,7 @@ pub struct Scroll {
|
|||||||
pub delta: Vec2,
|
pub delta: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Visual styles for buttons.
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
pub enum ButtonVariant {
|
pub enum ButtonVariant {
|
||||||
Primary,
|
Primary,
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Pixel height of a single scroll line.
|
||||||
pub const LINE_HEIGHT: f32 = 21.0;
|
pub const LINE_HEIGHT: f32 = 21.0;
|
||||||
|
/// Default background color for buttons.
|
||||||
pub const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
|
pub const NORMAL_BUTTON: Color = Color::srgb(0.15, 0.15, 0.15);
|
||||||
|
/// Background color when hovering a button.
|
||||||
pub const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
|
pub const HOVERED_BUTTON: Color = Color::srgb(0.25, 0.25, 0.25);
|
||||||
|
/// Background color when pressing a button.
|
||||||
pub const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
|
pub const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Message to close any open popup.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct ClosePopupMessage;
|
pub struct ClosePopupMessage;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ pub mod messages;
|
|||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
/// Plugin for general UI behavior like scrolling and button states.
|
||||||
pub struct UiPlugin;
|
pub struct UiPlugin;
|
||||||
|
|
||||||
impl Plugin for UiPlugin {
|
impl Plugin for UiPlugin {
|
||||||
@@ -20,6 +21,7 @@ impl Plugin for UiPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads mouse wheel events and triggers scroll actions.
|
||||||
fn scroll_events(
|
fn scroll_events(
|
||||||
mut mouse_wheel_reader: MessageReader<MouseWheel>,
|
mut mouse_wheel_reader: MessageReader<MouseWheel>,
|
||||||
hover_map: Res<HoverMap>,
|
hover_map: Res<HoverMap>,
|
||||||
@@ -45,6 +47,7 @@ fn scroll_events(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates scroll position based on scroll events.
|
||||||
fn on_scroll_handler(
|
fn on_scroll_handler(
|
||||||
mut scroll: On<components::Scroll>,
|
mut scroll: On<components::Scroll>,
|
||||||
mut query: Query<(&mut ScrollPosition, &Node, &ComputedNode)>,
|
mut query: Query<(&mut ScrollPosition, &Node, &ComputedNode)>,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Creates a standard button UI bundle.
|
||||||
pub fn button<C, R>(
|
pub fn button<C, R>(
|
||||||
button_type: impl Component,
|
button_type: impl Component,
|
||||||
variant: ButtonVariant,
|
variant: ButtonVariant,
|
||||||
@@ -24,6 +25,7 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a rounded pill-shaped button UI bundle.
|
||||||
pub fn pill_button<C, R>(
|
pub fn pill_button<C, R>(
|
||||||
button_type: impl Component,
|
button_type: impl Component,
|
||||||
variant: ButtonVariant,
|
variant: ButtonVariant,
|
||||||
@@ -48,6 +50,7 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates button colors based on interaction state.
|
||||||
pub fn update_buttons(
|
pub fn update_buttons(
|
||||||
mut interaction_query: Query<
|
mut interaction_query: Query<
|
||||||
(&Interaction, &ButtonVariant, &mut BackgroundColor),
|
(&Interaction, &ButtonVariant, &mut BackgroundColor),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Trait for easy flexbox layout construction.
|
||||||
pub trait Flexbox {
|
pub trait Flexbox {
|
||||||
fn hstack(spacing: Val) -> Self;
|
fn hstack(spacing: Val) -> Self;
|
||||||
fn vstack(spacing: Val) -> Self;
|
fn vstack(spacing: Val) -> Self;
|
||||||
|
|||||||
@@ -3,12 +3,15 @@ use bevy::ecs::relationship::RelatedSpawnerCommands;
|
|||||||
use super::super::messages::ClosePopupMessage;
|
use super::super::messages::ClosePopupMessage;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Marker for popup root nodes.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct PopupRoot;
|
pub struct PopupRoot;
|
||||||
|
|
||||||
|
/// Marker for the close button in a popup.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct PopupCloseButton;
|
pub struct PopupCloseButton;
|
||||||
|
|
||||||
|
/// Spawns a generic popup window.
|
||||||
pub fn spawn_popup(
|
pub fn spawn_popup(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
root: impl Component,
|
root: impl Component,
|
||||||
@@ -68,6 +71,7 @@ pub fn spawn_popup(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns a context menu at a specific position.
|
||||||
pub fn spawn_context_menu(
|
pub fn spawn_context_menu(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
root: impl Component,
|
root: impl Component,
|
||||||
@@ -93,6 +97,7 @@ pub fn spawn_context_menu(
|
|||||||
.with_children(child);
|
.with_children(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles closing popups via message or close button.
|
||||||
pub fn handle_popup_close(
|
pub fn handle_popup_close(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
root_query: Query<Entity, With<PopupRoot>>,
|
root_query: Query<Entity, With<PopupRoot>>,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub use crate::prelude::*;
|
pub use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Creates a basic text bundle.
|
||||||
pub fn text(content: impl Into<String>, size: f32, color: Color) -> (Text, TextFont, TextColor) {
|
pub fn text(content: impl Into<String>, size: f32, color: Color) -> (Text, TextFont, TextColor) {
|
||||||
(
|
(
|
||||||
Text::new(content),
|
Text::new(content),
|
||||||
@@ -8,6 +9,7 @@ pub fn text(content: impl Into<String>, size: f32, color: Color) -> (Text, TextF
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a text bundle with an additional component attached.
|
||||||
pub fn text_with_component(
|
pub fn text_with_component(
|
||||||
component: impl Component,
|
component: impl Component,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bevy::window::PrimaryWindow;
|
use bevy::window::PrimaryWindow;
|
||||||
|
|
||||||
|
/// Checks if the cursor is hovering over any UI element.
|
||||||
pub fn ui_blocks(
|
pub fn ui_blocks(
|
||||||
window: Single<&Window, With<PrimaryWindow>>,
|
window: Single<&Window, With<PrimaryWindow>>,
|
||||||
cursor_pos: Vec2,
|
cursor_pos: Vec2,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
/// Defines the bounds of the grid for the server.
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub struct MaxFieldSize {
|
pub struct MaxFieldSize {
|
||||||
#[serde(rename = "minX")]
|
#[serde(rename = "minX")]
|
||||||
@@ -12,12 +13,14 @@ pub struct MaxFieldSize {
|
|||||||
pub max_y: u32,
|
pub max_y: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Coordinates for a wonder event target.
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub x: u32,
|
pub x: u32,
|
||||||
pub y: u32,
|
pub y: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// WebSocket messages exchanged with the wonder event server.
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||||
#[serde(tag = "messageType")]
|
#[serde(tag = "messageType")]
|
||||||
pub enum WonderEventMessage {
|
pub enum WonderEventMessage {
|
||||||
|
|||||||
@@ -9,20 +9,25 @@ use url::Url;
|
|||||||
|
|
||||||
pub mod components;
|
pub mod components;
|
||||||
|
|
||||||
|
/// Plugin managing random wonder events via WebSocket.
|
||||||
pub struct WonderEventPlugin;
|
pub struct WonderEventPlugin;
|
||||||
|
|
||||||
|
/// Message to initiate a wonder event request.
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct RequestWonderEvent {
|
pub struct RequestWonderEvent {
|
||||||
pub url_str: String,
|
pub url_str: String,
|
||||||
pub max_field_size: MaxFieldSize,
|
pub max_field_size: MaxFieldSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resource holding the channel sender for wonder events.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct WonderEventSender(pub Sender<WonderEventMessage>);
|
pub struct WonderEventSender(pub Sender<WonderEventMessage>);
|
||||||
|
|
||||||
|
/// Resource holding the channel receiver for wonder events.
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct WonderEventReceiver(pub Mutex<Receiver<WonderEventMessage>>);
|
pub struct WonderEventReceiver(pub Mutex<Receiver<WonderEventMessage>>);
|
||||||
|
|
||||||
|
/// Component for animated floating text effects.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct FloatingText {
|
struct FloatingText {
|
||||||
timer: Timer,
|
timer: Timer,
|
||||||
@@ -49,11 +54,13 @@ impl Plugin for WonderEventPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tracks if an event has already triggered this phase.
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
struct WonderEventState {
|
struct WonderEventState {
|
||||||
triggered_for_current_phase: bool,
|
triggered_for_current_phase: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the focus phase is halfway through to trigger an event.
|
||||||
fn check_halfway_focus(
|
fn check_halfway_focus(
|
||||||
mut state: ResMut<WonderEventState>,
|
mut state: ResMut<WonderEventState>,
|
||||||
phase_res: Res<CurrentPhase>,
|
phase_res: Res<CurrentPhase>,
|
||||||
@@ -95,6 +102,7 @@ fn check_halfway_focus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns a thread to request a wonder event from the server.
|
||||||
fn handle_wonder_event_trigger(
|
fn handle_wonder_event_trigger(
|
||||||
mut events: MessageReader<RequestWonderEvent>,
|
mut events: MessageReader<RequestWonderEvent>,
|
||||||
sender: Res<WonderEventSender>,
|
sender: Res<WonderEventSender>,
|
||||||
@@ -159,6 +167,7 @@ fn handle_wonder_event_trigger(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Processes responses from the wonder event server.
|
||||||
fn handle_wonder_event_response(
|
fn handle_wonder_event_response(
|
||||||
receiver: Res<WonderEventReceiver>,
|
receiver: Res<WonderEventReceiver>,
|
||||||
grid: Res<Grid>,
|
grid: Res<Grid>,
|
||||||
@@ -241,6 +250,7 @@ fn handle_wonder_event_response(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates floating text positions and lifetimes.
|
||||||
fn animate_floating_text(
|
fn animate_floating_text(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Returns the platform-specific data directory for the application.
|
||||||
pub fn get_internal_path() -> Option<PathBuf> {
|
pub fn get_internal_path() -> Option<PathBuf> {
|
||||||
let project_dirs = ProjectDirs::from("de", "demenik", "pomomon-garden");
|
let project_dirs = ProjectDirs::from("de", "demenik", "pomomon-garden");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user