diff --git a/src/features/pom/components.rs b/src/features/pom/components.rs index 7cf4043..089438a 100644 --- a/src/features/pom/components.rs +++ b/src/features/pom/components.rs @@ -36,3 +36,8 @@ impl MovingState { ) } } + +#[derive(Component, Default)] +pub struct InteractionTarget { + pub target: Option<(u32, u32)>, +} diff --git a/src/features/pom/mod.rs b/src/features/pom/mod.rs index ce4a7d5..aaa1e74 100644 --- a/src/features/pom/mod.rs +++ b/src/features/pom/mod.rs @@ -1,7 +1,9 @@ use crate::prelude::*; use components::*; -use messages::InvalidMoveMessage; +use messages::{InteractStartMessage, InvalidMoveMessage}; +use std::collections::VecDeque; use utils::find_path; +use utils::manhattan_distance; pub mod components; pub mod messages; @@ -16,7 +18,14 @@ impl Plugin for PomPlugin { app.add_systems( Update, - (handle_move, move_pom, update_pom).run_if(in_state(AppState::GameScreen)), + ( + handle_move, + handle_interact, + move_pom, + update_pom, + perform_interaction, + ) + .run_if(in_state(AppState::GameScreen)), ); } } @@ -27,6 +36,7 @@ fn setup(mut commands: Commands, asset_server: Res, config: Res, grid: Res, tile_query: Query<&TileState>, - mut pom_query: Query<(&GridPosition, &mut PathQueue)>, + mut pom_query: Query<(&GridPosition, &mut PathQueue, &mut InteractionTarget)>, ) { for message in move_messages.read() { - for (grid_pos, mut path_queue) in pom_query.iter_mut() { + for (grid_pos, mut path_queue, mut interaction_target) in pom_query.iter_mut() { + // Clear any pending interaction when moving manually + interaction_target.target = None; + let grid_start = (grid_pos.x, grid_pos.y); let start = path_queue.steps.front().unwrap_or(&grid_start); let end = (message.x, message.y); @@ -78,6 +91,86 @@ fn handle_move( } } +fn handle_interact( + mut interact_messages: MessageReader, + mut pom_query: Query<(&GridPosition, &mut PathQueue, &mut InteractionTarget)>, + grid: Res, + tile_query: Query<&TileState>, +) { + for message in interact_messages.read() { + for (grid_pos, mut path_queue, mut interaction_target) in pom_query.iter_mut() { + let target_pos = (message.x, message.y); + let current_pos = (grid_pos.x, grid_pos.y); + + // If we are already adjacent to the target, just set the target and clear path + if manhattan_distance(current_pos.0, current_pos.1, target_pos.0, target_pos.1) == 1 { + path_queue.steps.clear(); + interaction_target.target = Some(target_pos); + continue; + } + + // Find a path to an adjacent tile + let neighbors = [ + (target_pos.0 as i32 + 1, target_pos.1 as i32), + (target_pos.0 as i32 - 1, target_pos.1 as i32), + (target_pos.0 as i32, target_pos.1 as i32 + 1), + (target_pos.0 as i32, target_pos.1 as i32 - 1), + ]; + + let mut best_path: Option> = None; + + for (nx, ny) in neighbors { + if nx < 0 || ny < 0 { + continue; + } + let neighbor_pos = (nx as u32, ny as u32); + + if let Some(path) = find_path(current_pos, neighbor_pos, &grid, &tile_query) { + // Pick the shortest path + if best_path.as_ref().map_or(true, |p| path.len() < p.len()) { + best_path = Some(path); + } + } + } + + if let Some(path) = best_path { + path_queue.steps = path; + interaction_target.target = Some(target_pos); + } else { + println!("Cannot reach interaction target at {:?}", target_pos); + // Don't set target if unreachable + interaction_target.target = None; + } + } + } +} + +fn perform_interaction( + mut pom_query: Query<(&GridPosition, &mut InteractionTarget, &PathQueue)>, + // grid: Res, + // mut tile_query: Query<&mut TileState>, +) { + for (pos, mut target_component, path_queue) in pom_query.iter_mut() { + if let Some(target) = target_component.target { + // Wait until movement stops + if !path_queue.steps.is_empty() { + continue; + } + + if manhattan_distance(pos.x, pos.y, target.0, target.1) == 1 { + println!( + "Performing interaction on tile ({}, {})", + target.0, target.1 + ); + + // TODO: Implement interaction logic + } + + target_component.target = None; + } + } +} + fn move_pom( time: Res