Files
pomomon-garden/src/features/phase/mod.rs

268 lines
8.4 KiB
Rust

use crate::features::savegame::messages::SavegameDumpMessage;
use crate::prelude::*;
use components::{SessionTracker, TimerSettings};
use messages::*;
pub mod components;
pub mod messages;
pub mod utils;
pub struct PhasePlugin;
impl Plugin for PhasePlugin {
fn build(&self, app: &mut App) {
app.init_resource::<TimerSettings>();
app.init_resource::<SessionTracker>();
app.insert_resource(CurrentPhase(Phase::Focus {
duration: 25.0 * 60.0,
}));
app.add_message::<PhaseTimerFinishedMessage>();
app.add_message::<PhaseMinutePassedMessage>();
app.add_systems(OnEnter(AppState::GameScreen), load_rules);
app.add_systems(
Update,
(
tick_timer,
handle_pause,
handle_continue,
grant_focus_rewards,
)
.run_if(in_state(AppState::GameScreen)),
);
#[cfg(debug_assertions)]
app.add_systems(Update, debug_short_phase_duration);
}
}
#[cfg(debug_assertions)]
fn debug_short_phase_duration(
mut phase_res: ResMut<CurrentPhase>,
keys: Res<ButtonInput<KeyCode>>,
) {
if keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight])
&& keys.just_pressed(KeyCode::Enter)
{
let phase = &mut phase_res.0;
match phase {
Phase::Focus { duration } | Phase::Break { duration } => {
*duration = 3.0;
println!("Debug: Phase duration set to 3 seconds!");
}
_ => {}
}
}
}
fn load_rules(mut phase_res: ResMut<CurrentPhase>, settings: Res<TimerSettings>) {
let phase = &mut phase_res.0;
let new_phase = match phase {
Phase::Focus { .. } => Some(Phase::Focus {
duration: settings.focus_duration as f32,
}),
Phase::Break { .. } => Some(Phase::Break { duration: 0.0 }),
_ => None,
};
if let Some(p) = new_phase {
*phase = p;
}
}
fn tick_timer(
time: Res<Time>,
mut phase_res: ResMut<CurrentPhase>,
mut finish_writer: MessageWriter<PhaseTimerFinishedMessage>,
mut minute_writer: MessageWriter<PhaseMinutePassedMessage>,
mut savegame_messages: MessageWriter<SavegameDumpMessage>,
) {
let delta = time.delta_secs();
let phase = &mut phase_res.0;
match phase {
Phase::Focus { duration } | Phase::Break { duration } => {
let old_minutes = (*duration / 60.0).floor() as i32;
*duration -= delta;
let new_minutes = (*duration / 60.0).floor() as i32;
if new_minutes < old_minutes {
minute_writer.write(PhaseMinutePassedMessage);
}
if *duration <= 0.0 {
finish_writer.write(PhaseTimerFinishedMessage {
phase: phase.clone(),
});
let completed = phase.clone();
*phase = Phase::Finished {
completed_phase: Box::new(completed),
};
println!("phase ended");
savegame_messages.write(SavegameDumpMessage);
}
}
_ => {}
}
}
fn grant_focus_rewards(
mut messages: MessageReader<PhaseMinutePassedMessage>,
phase_res: Res<CurrentPhase>,
config: Res<GameConfig>,
mut inventory: ResMut<Inventory>,
mut commands: Commands,
mut items_query: Query<&mut ItemStack>,
mut session_tracker: ResMut<SessionTracker>,
game_config: Res<GameConfig>,
mut notifications: ResMut<Notifications>,
) {
for _ in messages.read() {
if let Phase::Focus { .. } = &phase_res.0 {
println!(
"A minute of focus has been completed. Granting {} berries as a reward.",
config.berries_per_focus_minute
);
inventory.update_item_stack(
&mut commands,
&mut items_query,
ItemType::Berry,
config.berries_per_focus_minute as i32,
);
session_tracker.total_berries_earned += config.berries_per_focus_minute;
let berries_name = match config.berries_per_focus_minute {
1 => ItemType::Berry.singular(&game_config),
_ => ItemType::Berry.plural(&game_config),
};
notifications.info(
Some("Fokus Belohnung"),
format!(
"Du hast {} {} als Belohnung für das Abschließen einer Minute der Fokus-Phase erhalten!",
config.berries_per_focus_minute, berries_name
),
);
}
}
}
fn handle_pause(
mut messages: MessageReader<PhaseTimerPauseMessage>,
mut phase_res: ResMut<CurrentPhase>,
) {
for _ in messages.read() {
let phase = &mut phase_res.0;
match phase {
Phase::Focus { .. } | Phase::Break { .. } => {
let current_state = phase.clone();
*phase = Phase::Paused {
previous_phase: Box::new(current_state),
};
println!("Phase paused");
}
Phase::Paused { previous_phase } => {
*phase = *previous_phase.clone();
println!("Phase resumed");
}
_ => {}
}
}
}
pub fn next_phase(
current_phase: &mut CurrentPhase,
session_tracker: &mut SessionTracker,
settings: &TimerSettings,
) {
if let Phase::Finished { completed_phase } = &current_phase.0 {
match **completed_phase {
Phase::Focus { .. } => {
session_tracker.completed_focus_phases += 1;
let is_long_break = session_tracker.completed_focus_phases > 0
&& session_tracker.completed_focus_phases % settings.long_break_interval == 0;
if is_long_break {
current_phase.0 = Phase::Break {
duration: settings.long_break_duration as f32,
};
} else {
current_phase.0 = Phase::Break {
duration: settings.short_break_duration as f32,
};
}
}
Phase::Break { .. } => {
current_phase.0 = Phase::Focus {
duration: settings.focus_duration as f32,
};
}
_ => {}
}
}
}
pub fn handle_continue(
mut messages: MessageReader<NextPhaseMessage>,
mut phase_res: ResMut<CurrentPhase>,
mut session_tracker: ResMut<SessionTracker>,
settings: Res<TimerSettings>,
mut tile_query: Query<&mut TileState>,
game_config: Res<GameConfig>,
) {
for _ in messages.read() {
let entering_break = if let Phase::Finished { completed_phase } = &phase_res.0 {
matches!(**completed_phase, Phase::Focus { .. })
} else {
false
};
next_phase(&mut phase_res, &mut session_tracker, &settings);
if entering_break {
println!("Growing crops and resetting watered state.");
for mut state in tile_query.iter_mut() {
if let TileState::Occupied {
seed,
watered,
growth_stage,
withered,
dry_counter,
} = &*state
{
let mut new_stage = *growth_stage;
let mut new_withered = *withered;
let mut new_dry_counter = *dry_counter;
if *watered {
new_dry_counter = 0;
if let Some(config) = seed.get_seed_config(&game_config) {
if new_stage < config.growth_stages && !new_withered {
new_stage += 1;
}
}
} else {
new_dry_counter += 1;
if new_dry_counter >= 2 {
new_withered = true;
}
}
*state = TileState::Occupied {
seed: seed.clone(),
watered: false,
growth_stage: new_stage,
withered: new_withered,
dry_counter: new_dry_counter,
};
}
}
}
}
}