diff --git a/src/exploration.rs b/src/exploration.rs index 14a2bba..662e0d2 100644 --- a/src/exploration.rs +++ b/src/exploration.rs @@ -1,4 +1,4 @@ -use std::error::Error; +use std::{error::Error, hash::Hash, marker::PhantomData}; use bevy::prelude::*; use bevy_input_actionmap::InputMap; @@ -69,83 +69,83 @@ pub struct FocusedExplorationType(pub Option); #[reflect(Component)] pub struct Mappable; -pub const ACTION_EXPLORE_FORWARD: &str = "explore_forward"; -pub const ACTION_EXPLORE_BACKWARD: &str = "explore_backward"; -pub const ACTION_EXPLORE_LEFT: &str = "explore_left"; -pub const ACTION_EXPLORE_RIGHT: &str = "explore_right"; -pub const ACTION_EXPLORE_FOCUS_NEXT: &str = "explore_focus_next"; -pub const ACTION_EXPLORE_FOCUS_PREV: &str = "explore_focus_prev"; -pub const ACTION_EXPLORE_SELECT_NEXT_TYPE: &str = "explore_select_next_type"; -pub const ACTION_EXPLORE_SELECT_PREV_TYPE: &str = "explore_select_prev_type"; -pub const ACTION_NAVIGATE_TO_EXPLORED: &str = "navigate_to"; - -fn exploration_type_change( +fn exploration_type_change( + config: Res>, mut tts: ResMut, - input: Res>, + input: Res>, mut explorers: Query<(&Player, &Viewshed, &mut FocusedExplorationType)>, features: Query<(&Coordinates, &ExplorationType)>, -) -> Result<(), Box> { - let changed = input.just_active(ACTION_EXPLORE_SELECT_NEXT_TYPE) - || input.just_active(ACTION_EXPLORE_SELECT_PREV_TYPE); - if !changed { - return Ok(()); - } - for (_, viewshed, mut focused) in explorers.iter_mut() { - let mut types: Vec = vec![]; - for (coordinates, t) in features.iter() { - let (x, y) = **coordinates; - let x = x as i32; - let y = y as i32; - if viewshed.visible.contains(&(x, y)) { - types.push(*t); - } +) -> Result<(), Box> +where + A: Hash + Eq + Clone + Send + Sync, +{ + if let (Some(select_next_type), Some(select_prev_type)) = ( + config.action_explore_select_next_type.clone(), + config.action_explore_select_prev_type.clone(), + ) { + let changed = input.just_active(select_next_type.clone()) + || input.just_active(select_prev_type.clone()); + if !changed { + return Ok(()); } - types.sort(); - types.dedup(); - if types.is_empty() { - tts.speak("Nothing visible.", true)?; - } else if input.just_active(ACTION_EXPLORE_SELECT_PREV_TYPE) { - if let Some(t) = &focused.0 { - if let Some(i) = types.iter().position(|v| *v == *t) { - if i == 0 { - focused.0 = None; + for (_, viewshed, mut focused) in explorers.iter_mut() { + let mut types: Vec = vec![]; + for (coordinates, t) in features.iter() { + let (x, y) = **coordinates; + let x = x as i32; + let y = y as i32; + if viewshed.visible.contains(&(x, y)) { + types.push(*t); + } + } + types.sort(); + types.dedup(); + if types.is_empty() { + tts.speak("Nothing visible.", true)?; + } else if input.just_active(select_prev_type.clone()) { + if let Some(t) = &focused.0 { + if let Some(i) = types.iter().position(|v| *v == *t) { + if i == 0 { + focused.0 = None; + } else { + let t = &types[i - 1]; + focused.0 = Some(*t); + } } else { - let t = &types[i - 1]; + let t = types.last().unwrap(); focused.0 = Some(*t); } } else { let t = types.last().unwrap(); focused.0 = Some(*t); } - } else { - let t = types.last().unwrap(); - focused.0 = Some(*t); - } - } else if input.just_active(ACTION_EXPLORE_SELECT_NEXT_TYPE) { - if let Some(t) = &focused.0 { - if let Some(i) = types.iter().position(|v| *v == *t) { - if i == types.len() - 1 { - focused.0 = None; + } else if input.just_active(select_next_type.clone()) { + if let Some(t) = &focused.0 { + if let Some(i) = types.iter().position(|v| *v == *t) { + if i == types.len() - 1 { + focused.0 = None; + } else { + let t = &types[i + 1]; + focused.0 = Some(*t); + } } else { - let t = &types[i + 1]; + let t = types.first().unwrap(); focused.0 = Some(*t); } } else { let t = types.first().unwrap(); - focused.0 = Some(*t); + focused.0 = Some(*t) } - } else { - let t = types.first().unwrap(); - focused.0 = Some(*t) } } } Ok(()) } -fn exploration_type_focus( +fn exploration_type_focus( mut commands: Commands, - input: Res>, + config: Res>, + input: Res>, mut tts: ResMut, explorers: Query<( Entity, @@ -155,52 +155,60 @@ fn exploration_type_focus( Option<&Exploring>, )>, features: Query<(&Coordinates, &ExplorationType)>, -) -> Result<(), Box> { - let changed = input.just_active(ACTION_EXPLORE_FOCUS_NEXT) - || input.just_active(ACTION_EXPLORE_FOCUS_PREV); - if !changed { - return Ok(()); - } - for (entity, _, viewshed, focused, exploring) in explorers.iter() { - let mut features = features - .iter() - .filter(|(coordinates, _)| { - let (x, y) = ***coordinates; - let x = x as i32; - let y = y as i32; - viewshed.visible.contains(&(x, y)) - }) - .collect::>(); - features.sort_by(|(c1, _), (c2, _)| c1.partial_cmp(c2).unwrap()); - if let Some(focused) = &focused.0 { - features.retain(|(_, t)| **t == *focused); +) -> Result<(), Box> +where + A: Hash + Eq + Clone + Send + Sync, +{ + if let (Some(explore_focus_next), Some(explore_focus_prev)) = ( + config.action_explore_focus_next.clone(), + config.action_explore_focus_prev.clone(), + ) { + let changed = input.just_active(explore_focus_next.clone()) + || input.just_active(explore_focus_prev.clone()); + if !changed { + return Ok(()); } - if features.is_empty() { - tts.speak("Nothing visible.", true)?; - } else { - let mut target: Option<&(&Coordinates, &ExplorationType)> = None; - if input.just_active(ACTION_EXPLORE_FOCUS_NEXT) { - if let Some(exploring) = exploring { - target = features.iter().find(|(c, _)| ***c > **exploring); - if target.is_none() { - target = features.first(); - } - } else { - target = features.first(); - } - } else if input.just_active(ACTION_EXPLORE_FOCUS_PREV) { - if let Some(exploring) = exploring { - features.reverse(); - target = features.iter().find(|(c, _)| ***c < **exploring); - if target.is_none() { - target = features.first(); - } - } else { - target = features.last(); - } + for (entity, _, viewshed, focused, exploring) in explorers.iter() { + let mut features = features + .iter() + .filter(|(coordinates, _)| { + let (x, y) = ***coordinates; + let x = x as i32; + let y = y as i32; + viewshed.visible.contains(&(x, y)) + }) + .collect::>(); + features.sort_by(|(c1, _), (c2, _)| c1.partial_cmp(c2).unwrap()); + if let Some(focused) = &focused.0 { + features.retain(|(_, t)| **t == *focused); } - if let Some((coordinates, _)) = target { - commands.entity(entity).insert(Exploring(***coordinates)); + if features.is_empty() { + tts.speak("Nothing visible.", true)?; + } else { + let mut target: Option<&(&Coordinates, &ExplorationType)> = None; + if input.just_active(explore_focus_next.clone()) { + if let Some(exploring) = exploring { + target = features.iter().find(|(c, _)| ***c > **exploring); + if target.is_none() { + target = features.first(); + } + } else { + target = features.first(); + } + } else if input.just_active(explore_focus_prev.clone()) { + if let Some(exploring) = exploring { + features.reverse(); + target = features.iter().find(|(c, _)| ***c < **exploring); + if target.is_none() { + target = features.first(); + } + } else { + target = features.last(); + } + } + if let Some((coordinates, _)) = target { + commands.entity(entity).insert(Exploring(***coordinates)); + } } } } @@ -234,58 +242,78 @@ fn exploration_type_changed_announcement( Ok(()) } -fn exploration_focus( +fn exploration_focus( mut commands: Commands, - input: Res>, + config: Res>, + input: Res>, map: Query<&Map>, explorers: Query<(Entity, &Player, &Coordinates, Option<&Exploring>)>, -) { - for map in map.iter() { - for (entity, _, coordinates, exploring) in explorers.iter() { - let coordinates = **coordinates; - let coordinates = (coordinates.0.floor(), coordinates.1.floor()); - let mut exploring = if let Some(exploring) = exploring { - **exploring - } else { - coordinates - }; - let orig = exploring; - if input.just_active(ACTION_EXPLORE_FORWARD) { - exploring.1 += 1.; - } else if input.just_active(ACTION_EXPLORE_BACKWARD) { - exploring.1 -= 1.; - } else if input.just_active(ACTION_EXPLORE_LEFT) { - exploring.0 -= 1.; - } else if input.just_active(ACTION_EXPLORE_RIGHT) { - exploring.0 += 1.; - } - if orig != exploring - && exploring.0 >= 0. - && exploring.0 < map.width() as f32 - && exploring.1 >= 0. - && exploring.1 < map.height() as f32 - { - commands.entity(entity).insert(Exploring(exploring)); +) where + A: Hash + Eq + Clone + Send + Sync, +{ + if let ( + Some(explore_forward), + Some(explore_backward), + Some(explore_left), + Some(explore_right), + ) = ( + config.action_explore_forward.clone(), + config.action_explore_backward.clone(), + config.action_explore_left.clone(), + config.action_explore_right.clone(), + ) { + for map in map.iter() { + for (entity, _, coordinates, exploring) in explorers.iter() { + let coordinates = **coordinates; + let coordinates = (coordinates.0.floor(), coordinates.1.floor()); + let mut exploring = if let Some(exploring) = exploring { + **exploring + } else { + coordinates + }; + let orig = exploring; + if input.just_active(explore_forward.clone()) { + exploring.1 += 1.; + } else if input.just_active(explore_backward.clone()) { + exploring.1 -= 1.; + } else if input.just_active(explore_left.clone()) { + exploring.0 -= 1.; + } else if input.just_active(explore_right.clone()) { + exploring.0 += 1.; + } + if orig != exploring + && exploring.0 >= 0. + && exploring.0 < map.width() as f32 + && exploring.1 >= 0. + && exploring.1 < map.height() as f32 + { + commands.entity(entity).insert(Exploring(exploring)); + } } } } } -fn navigate_to_explored( +fn navigate_to_explored( mut commands: Commands, - input: Res>, + config: Res>, + input: Res>, map: Query<(&Map, &RevealedTiles)>, explorers: Query<(Entity, &Exploring)>, -) { - for (entity, exploring) in explorers.iter() { - for (map, revealed_tiles) in map.iter() { - let point = **exploring; - let idx = point.to_index(map.width()); - let known = revealed_tiles[idx]; - if input.just_active(ACTION_NAVIGATE_TO_EXPLORED) && known { - commands - .entity(entity) - .insert(Destination((point.x_i32(), point.y_i32()))); +) where + A: Hash + Eq + Clone + Send + Sync, +{ + if let Some(navigate_to_explored) = config.action_navigate_to_explored.clone() { + for (entity, exploring) in explorers.iter() { + for (map, revealed_tiles) in map.iter() { + let point = **exploring; + let idx = point.to_index(map.width()); + let known = revealed_tiles[idx]; + if input.just_active(navigate_to_explored.clone()) && known { + commands + .entity(entity) + .insert(Destination((point.x_i32(), point.y_i32()))); + } } } } @@ -351,25 +379,67 @@ fn exploration_changed_announcement( Ok(()) } -pub struct ExplorationPlugin; +#[derive(Clone, Debug)] +pub struct ExplorationConfig { + pub action_explore_forward: Option, + pub action_explore_backward: Option, + pub action_explore_left: Option, + pub action_explore_right: Option, + pub action_explore_focus_next: Option, + pub action_explore_focus_prev: Option, + pub action_explore_select_next_type: Option, + pub action_explore_select_prev_type: Option, + pub action_navigate_to_explored: Option, +} -impl Plugin for ExplorationPlugin { +impl Default for ExplorationConfig { + fn default() -> Self { + Self { + action_explore_forward: None, + action_explore_backward: None, + action_explore_left: None, + action_explore_right: None, + action_explore_focus_next: None, + action_explore_focus_prev: None, + action_explore_select_next_type: None, + action_explore_select_prev_type: None, + action_navigate_to_explored: None, + } + } +} + +pub struct ExplorationPlugin<'a, A>(PhantomData<&'a A>); + +impl<'a, A> Default for ExplorationPlugin<'a, A> { + fn default() -> Self { + Self(PhantomData) + } +} + +impl<'a, A> Plugin for ExplorationPlugin<'a, A> +where + A: Hash + Eq + Clone + Send + Sync, + 'a: 'static, +{ fn build(&self, app: &mut AppBuilder) { + if !app.world().contains_resource::>() { + app.insert_resource(ExplorationConfig::::default()); + } app.register_type::() .register_type::() .register_type::() - .add_system(exploration_focus.system()) + .add_system(exploration_focus::.system()) .add_system( - exploration_type_focus + exploration_type_focus:: .system() .chain(error_handler.system()), ) .add_system( - exploration_type_change + exploration_type_change:: .system() .chain(error_handler.system()), ) - .add_system(navigate_to_explored.system()) + .add_system(navigate_to_explored::.system()) .add_system_to_stage( CoreStage::PostUpdate, exploration_type_changed_announcement