diff --git a/src/constants.rs b/src/constants.rs index a31d151..e960a29 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -4,5 +4,11 @@ pub const FLOOR_Y_OFFSET: u8 = 200; pub const MOVEMENT_COOLDOWN: f32 = 1.0; // one second cooldown pub const TITLE: &str = "Maze Ascension: The Labyrinth of Echoes"; -pub const FLOOR_SCORE_MULTIPLIER: f32 = 100.; -pub const TIME_SCORE_MULTIPLIER: f32 = 10.0; +// Base score constants +pub const BASE_FLOOR_SCORE: usize = 1000; +pub const BASE_TIME_SCORE: usize = 100; + +// Floor progression constants +pub const FLOOR_DIFFICULTY_MULTIPLIER: f32 = 1.2; // Higher floors are exponentially harder +pub const MIN_TIME_MULTIPLIER: f32 = 0.1; // Minimum score multiplier for time +pub const TIME_REFERENCE_SECONDS: f32 = 60.0; // Reference time for score calculation diff --git a/src/stats/components.rs b/src/stats/components.rs index 8aad2aa..d714fbd 100644 --- a/src/stats/components.rs +++ b/src/stats/components.rs @@ -4,6 +4,22 @@ use bevy::prelude::*; #[reflect(Component)] pub struct Score(pub usize); -#[derive(Debug, Reflect, Component)] +#[derive(Debug, Clone, Reflect, Component)] #[reflect(Component)] -pub struct StatsText; +pub struct FloorDisplay; + +#[derive(Debug, Clone, Reflect, Component)] +#[reflect(Component)] +pub struct HighestFloorDisplay; + +#[derive(Debug, Clone, Reflect, Component)] +#[reflect(Component)] +pub struct ScoreDisplay; + +#[derive(Debug, Clone, Reflect, Component)] +#[reflect(Component)] +pub struct FloorTimerDisplay; + +#[derive(Debug, Clone, Reflect, Component)] +#[reflect(Component)] +pub struct TotalTimerDisplay; diff --git a/src/stats/stats.rs b/src/stats/container.rs similarity index 100% rename from src/stats/stats.rs rename to src/stats/container.rs diff --git a/src/stats/mod.rs b/src/stats/mod.rs index 76c2c8a..083f6d6 100644 --- a/src/stats/mod.rs +++ b/src/stats/mod.rs @@ -1,17 +1,16 @@ pub mod components; +pub mod container; pub mod resources; -pub mod stats; mod systems; use bevy::{ecs::system::RunSystemOnce, prelude::*}; use components::Score; -use resources::{FloorTimer, GameTimer}; +use resources::{FloorTimer, TotalTimer}; pub(super) fn plugin(app: &mut App) { app.register_type::() - .init_resource::() + .init_resource::() .init_resource::() - .insert_resource(FloorTimer(Timer::from_seconds(0.0, TimerMode::Once))) .add_plugins(systems::plugin); } diff --git a/src/stats/resources.rs b/src/stats/resources.rs index 5c7123f..b4e2be8 100644 --- a/src/stats/resources.rs +++ b/src/stats/resources.rs @@ -1,21 +1,27 @@ +use std::time::Duration; + use bevy::prelude::*; #[derive(Debug, Reflect, Resource, Deref, DerefMut)] #[reflect(Resource)] -pub struct GameTimer(pub Timer); +pub struct TotalTimer(pub Timer); #[derive(Debug, Reflect, Resource, Deref, DerefMut)] #[reflect(Resource)] pub struct FloorTimer(pub Timer); -impl Default for GameTimer { +impl Default for TotalTimer { fn default() -> Self { - Self(Timer::from_seconds(0.0, TimerMode::Once)) + Self(init_timer()) } } impl Default for FloorTimer { fn default() -> Self { - Self(Timer::from_seconds(0.0, TimerMode::Once)) + Self(init_timer()) } } + +fn init_timer() -> Timer { + Timer::new(Duration::MAX, TimerMode::Once) +} diff --git a/src/stats/systems/common.rs b/src/stats/systems/common.rs new file mode 100644 index 0000000..e769e8b --- /dev/null +++ b/src/stats/systems/common.rs @@ -0,0 +1,28 @@ +pub fn format_duration_adaptive(seconds: f32) -> String { + let total_millis = (seconds * 1000.0) as u64; + let millis = total_millis % 1000; + let total_seconds = total_millis / 1000; + let seconds = total_seconds % 60; + let total_minutes = total_seconds / 60; + let minutes = total_minutes % 60; + let total_hours = total_minutes / 60; + let hours = total_hours % 24; + let days = total_hours / 24; + + let mut result = String::new(); + + if days > 0 { + result.push_str(&format!("{}d ", days)); + } + if hours > 0 || days > 0 { + result.push_str(&format!("{:02}:", hours)); + } + if minutes > 0 || hours > 0 || days > 0 { + result.push_str(&format!("{:02}:", minutes)); + } + + // Always show at least seconds and milliseconds + result.push_str(&format!("{:02}.{:03}", seconds, millis)); + + result +} diff --git a/src/stats/systems/floor.rs b/src/stats/systems/floor.rs new file mode 100644 index 0000000..463abef --- /dev/null +++ b/src/stats/systems/floor.rs @@ -0,0 +1,39 @@ +use bevy::prelude::*; + +use crate::{ + floor::{ + components::{CurrentFloor, Floor}, + resources::HighestFloor, + }, + stats::components::{FloorDisplay, HighestFloorDisplay}, +}; + +pub fn update_floor_display( + floor_query: Query<&Floor, With>, + mut text_query: Query<&mut Text, With>, +) { + let Ok(floor) = floor_query.get_single() else { + return; + }; + + let Ok(mut text) = text_query.get_single_mut() else { + return; + }; + + text.0 = format!("Floor: {}", floor.0); +} + +pub fn update_highest_floor_display( + hightes_floor: Res, + mut text_query: Query<&mut Text, With>, +) { + if !hightes_floor.is_changed() { + return; + } + + let Ok(mut text) = text_query.get_single_mut() else { + return; + }; + + text.0 = format!("Highest Floor: {}", hightes_floor.0); +} diff --git a/src/stats/systems/floor_timer.rs b/src/stats/systems/floor_timer.rs new file mode 100644 index 0000000..c5aec96 --- /dev/null +++ b/src/stats/systems/floor_timer.rs @@ -0,0 +1,33 @@ +use bevy::prelude::*; + +use crate::{ + floor::resources::HighestFloor, + stats::{components::FloorTimerDisplay, resources::FloorTimer}, +}; + +use super::common::format_duration_adaptive; + +pub fn update_floor_timer( + mut floor_timer: ResMut, + time: Res