|  |  | @ -8,10 +8,7 @@ use bevy::{ | 
			
		
	
		
		
			
				
					
					|  |  |  | /// TODO: Custom Asset: SpriteSheetAtlas Mapper
 |  |  |  | /// TODO: Custom Asset: SpriteSheetAtlas Mapper
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// TODO: Handle Cursor!
 |  |  |  | /// TODO: Handle Cursor!
 | 
			
		
	
		
		
			
				
					
					|  |  |  | ///
 |  |  |  | ///
 | 
			
		
	
		
		
			
				
					
					|  |  |  | use crate::{ |  |  |  | use crate::{game::*, prelude::*}; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     game::{ActiveTile, Board, BoardIndex, Piece, Side, Tile}, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     prelude::*, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | }; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | const SCALE: f32 = 4.0; |  |  |  | const SCALE: f32 = 4.0; | 
			
		
	
		
		
			
				
					
					|  |  |  | const TILE_SIZE: f32 = 16.0; |  |  |  | const TILE_SIZE: f32 = 16.0; | 
			
		
	
	
		
		
			
				
					|  |  | @ -26,25 +23,19 @@ impl Plugin for Display2dPlugin { | 
			
		
	
		
		
			
				
					
					|  |  |  |             .add_systems( |  |  |  |             .add_systems( | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Update, |  |  |  |                 Update, | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ( |  |  |  |                 ( | 
			
		
	
		
		
			
				
					
					|  |  |  |                     active_tile.run_if(in_state(GameState::Display2d)), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     menu::exit_to_menu.run_if(in_state(GameState::Display2d)), |  |  |  |                     menu::exit_to_menu.run_if(in_state(GameState::Display2d)), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     select_piece.run_if(in_state(GameState::Display2d)), |  |  |  |                     select_2d.run_if(on_event::<MouseButtonInput>()), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                     move_piece |  |  |  |                     move_piece | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(in_state(GameState::Display2d)) |  |  |  |                         .run_if(in_state(GameState::Display2d)) | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(any_with_component::<game::Selected>()), |  |  |  |                         .run_if(any_with_component::<game::Selected>()), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     place_piece |  |  |  |                     place_piece | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(in_state(GameState::Display2d)) |  |  |  |                         .run_if(in_state(GameState::Display2d)) | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(any_with_component::<game::Selected>()), |  |  |  |                         .run_if(any_with_component::<game::Selected>()), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     cancel_place |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(in_state(GameState::Display2d)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(on_event::<MouseButtonInput>()), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     snap_back_cancel |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(in_state(GameState::Display2d)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(any_component_removed::<game::Selected>()), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     update_background.run_if(on_event::<WindowResized>()), |  |  |  |                     update_background.run_if(on_event::<WindowResized>()), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     set_transform |  |  |  |                     set_2d_transform | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .after(game::update_board::<Display2d>) |  |  |  |                         .run_if(any_component_changed::<BoardIndex>) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                         .run_if(any_component_changed::<BoardIndex>), |  |  |  |                         .before(game::update_board::<Display2d>) | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .after(game::manage_piece), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     set_piece_sprite.run_if(any_component_changed::<Side>), |  |  |  |                     set_piece_sprite.run_if(any_component_changed::<Side>), | 
			
		
	
		
		
			
				
					
					|  |  |  |                     set_tile_sprite.run_if(any_component_added::<game::Tile>), |  |  |  |                     set_tile_sprite.run_if(any_component_added::<game::Tile>), | 
			
		
	
		
		
			
				
					
					|  |  |  |                 ), |  |  |  |                 ), | 
			
		
	
	
		
		
			
				
					|  |  | @ -232,91 +223,99 @@ fn set_tile_sprite( | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// Sets a piece location given it's board index
 |  |  |  | /// Sets a piece location given it's board index
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn set_transform( |  |  |  | fn set_2d_transform( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     mut events: Query< |  |  |  |     mut events: Query< | 
			
		
	
		
		
			
				
					
					|  |  |  |         (&mut Transform, &BoardIndex), |  |  |  |         (Entity, &mut Transform, &BoardIndex), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         ( |  |  |  |         ( | 
			
		
	
		
		
			
				
					
					|  |  |  |             With<Display2d>, |  |  |  |             With<Display2d>, | 
			
		
	
		
		
			
				
					
					|  |  |  |             Or<(Changed<BoardIndex>, Added<BoardIndex>)>, |  |  |  |             Or<(Changed<BoardIndex>, Added<BoardIndex>)>, | 
			
		
	
		
		
			
				
					
					|  |  |  |         ), |  |  |  |         ), | 
			
		
	
		
		
			
				
					
					|  |  |  |     >, |  |  |  |     >, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     pieces: Query<Entity, (With<game::Piece>, With<Display2d>)>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     events.iter_mut().for_each(|(mut t, i)| { |  |  |  |     events.iter_mut().for_each(|(e, mut t, i)| { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         let x = SCALE * 16.0 * ((i.x as f32) - 3.5); |  |  |  |         let x = SCALE * 16.0 * ((i.x as f32) - 3.5); | 
			
		
	
		
		
			
				
					
					|  |  |  |         let y = SCALE * 16.0 * ((i.y as f32) - 1.5); |  |  |  |         let y = SCALE * 16.0 * ((i.y as f32) - 1.5); | 
			
		
	
		
		
			
				
					
					|  |  |  |         *t = Transform::from_scale(Vec3::splat(SCALE)).with_translation(Vec3::new(x, y, 0.0)); |  |  |  |         let z = if pieces.contains(e) { 1.0 } else { 0.0 }; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         *t = Transform::from_scale(Vec3::splat(SCALE)).with_translation(Vec3::new(x, y, z)); | 
			
		
	
		
		
			
				
					
					|  |  |  |         debug!("setting position of {:?} to {:?}", i, t); |  |  |  |         debug!("setting position of {:?} to {:?}", i, t); | 
			
		
	
		
		
			
				
					
					|  |  |  |     }); |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn active_tile( |  |  |  | fn select_2d( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     mut events: EventReader<CursorMoved>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     sprite_q: Query<( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         &TextureAtlasSprite, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         &Handle<TextureAtlas>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         &GlobalTransform, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         &BoardIndex, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     )>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     camera_q: Query<(&Camera, &GlobalTransform), With<Display2d>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     atlases: Res<Assets<TextureAtlas>>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut active: ResMut<ActiveTile>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     events.iter().for_each(|CursorMoved { position, .. }| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if let Some(position) = camera_q |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .iter() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             .find_map(|(camera, transform)| camera.viewport_to_world_2d(transform, *position)) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             let idx = sprite_q.iter().find_map( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 |(TextureAtlasSprite { index, anchor, .. }, handle, transform, board_index)| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     // Implementation credit goes to the sprite bevy_mod_picking backend
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     // TODO: Upstream changes
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     let pos = transform.translation(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     let size = { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         let sprite_size = atlases |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             .get(handle) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             .map(|atlas| atlas.textures.get(*index).expect("Get this rect texture")) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             .expect("get this rect") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                             .size(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         let (transform_scale, _, _) = transform.to_scale_rotation_translation(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                         sprite_size * transform_scale.truncate() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     }; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     let center = pos.truncate() - (anchor.as_vec() * size); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     let rect = Rect::from_center_half_size(center, size / 2.0); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     rect.contains(position).then_some(board_index) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             ); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             if active.idx != idx.cloned() { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 active.idx = idx.cloned(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | fn select_piece( |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     mut events: EventReader<MouseButtonInput>, |  |  |  |     mut events: EventReader<MouseButtonInput>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     pieces: Query<(Entity, &BoardIndex), (With<game::Piece>, With<Display2d>)>, |  |  |  |     sprite_q: Query< | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     active: Res<ActiveTile>, |  |  |  |         ( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     mut commands: Commands, |  |  |  |             Entity, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             &TextureAtlasSprite, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             &Handle<TextureAtlas>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             &GlobalTransform, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             &BoardIndex, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         (Without<game::Selected>, With<Display2d>), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     >, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     cameras: Query<(&Camera, &GlobalTransform), With<Display2d>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     atlases: Res<Assets<TextureAtlas>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     windows: Query<&Window, With<PrimaryWindow>>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut writer: EventWriter<game::GameEvent>, |  |  |  |     mut writer: EventWriter<game::GameEvent>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     events |  |  |  |     events | 
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .filter_map(|MouseButtonInput { button, state, .. }| { |  |  |  |         .filter(|ev| ev.state == ButtonState::Pressed) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             active.idx.as_ref().and_then(|index| { |  |  |  |         .for_each(|_| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 pieces.iter().find_map(|(entity, board_idx)| { |  |  |  |             windows | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     (board_idx == index).then_some((entity, button, state)) |  |  |  |                 .iter() | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 .filter_map(|window| window.cursor_position()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 .find_map(|position| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     cameras | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .filter_map(|(camera, gt)| camera.viewport_to_world_2d(gt, position)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         .find_map(|pos| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             // TODO: Sort by Z-Index
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                             sprite_q | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .filter_map( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     |( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         entity, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         TextureAtlasSprite { index, anchor, .. }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         handle, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         transform, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         board_index, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     )| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         // Implementation credit goes to the sprite bevy_mod_picking backend
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         // TODO: Upstream changes (related to sprite atlas correct behavior)
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         let p = transform.translation(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         let size = { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             let sprite_size = atlases | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 .get(handle) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 .map(|atlas| { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                     atlas | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                         .textures | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                         .get(*index) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                         .expect("Get this rect texture") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 }) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 .expect("get this rect") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 .size(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             let (transform_scale, _, _) = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                                 transform.to_scale_rotation_translation(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                             sprite_size * transform_scale.truncate() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         let center = p.truncate() - (anchor.as_vec() * size); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         let rect = Rect::from_center_half_size(center, size / 2.0); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                         rect.contains(pos).then_some((entity, board_index, p.z)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                     }, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                                 .max_by_key(|(_, _, z)| z.round() as usize) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }) |  |  |  |                 }) | 
			
		
	
		
		
			
				
					
					|  |  |  |             }) |  |  |  |                 .iter() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |                 .for_each(|(e, &ref i, _)| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .filter_map(|(entity, button, state)| { |  |  |  |                     info!("Select piece in 2d {:?} {:?}", e, i); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             ((*button, *state) == (MouseButton::Left, ButtonState::Pressed)).then_some(entity) |  |  |  |                     writer.send(game::GameEvent::Select(*e, i.clone())); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |                 }); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         .for_each(|entity| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             commands.entity(entity).insert(game::Selected); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             writer.send(game::GameEvent::SelectPiece); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         }); |  |  |  |         }); | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -339,86 +338,48 @@ fn move_piece( | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | ///
 |  |  |  | ///
 | 
			
		
	
		
		
			
				
					
					|  |  |  | /// TODO: Only place piece if spot is valid move for the selected entity
 |  |  |  | /// 2D Placement Logic
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | ///
 |  |  |  | ///
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fn place_piece( |  |  |  | fn place_piece( | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut events: EventReader<MouseButtonInput>, |  |  |  |     mut events: EventReader<MouseButtonInput>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     current: Query< |  |  |  |     active_piece: Query< | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         (Entity, &BoardIndex), |  |  |  |         (Entity, &BoardIndex), | 
			
		
	
		
		
			
				
					
					|  |  |  |         (With<game::Selected>, With<game::Piece>, With<Display2d>), |  |  |  |         (With<game::Piece>, With<game::Selected>, With<Display2d>), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     >, |  |  |  |     >, | 
			
		
	
		
		
			
				
					
					|  |  |  |     pieces: Query<&BoardIndex, (Without<game::Selected>, With<game::Piece>, With<Display2d>)>, |  |  |  |     active_tile: Query<&BoardIndex, (With<game::Tile>, With<game::Selected>, With<Display2d>)>, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     active: Res<ActiveTile>, |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     mut board: ResMut<Board>, |  |  |  |     mut board: ResMut<Board>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut game_events: EventWriter<game::GameEvent>, |  |  |  |     mut game_events: EventWriter<game::GameEvent>, | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut move_events: EventWriter<game::Move>, |  |  |  |     mut move_events: EventWriter<game::Move>, | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  | ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     events |  |  |  |     events | 
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |         .iter() | 
			
		
	
		
		
			
				
					
					|  |  |  |         .filter_map(|MouseButtonInput { button, state, .. }| { |  |  |  |         .filter_map(|event| match event { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             if (*button, *state) == (MouseButton::Left, ButtonState::Pressed) { |  |  |  |             MouseButtonInput { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 active.idx.as_ref() |  |  |  |                 button: MouseButton::Left, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } else { |  |  |  |                 state: ButtonState::Pressed, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 None |  |  |  |                 .. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } => active_tile.get_single().ok(), | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             _ => None, | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .filter_map(|idx| { |  |  |  |         .filter_map(|to| { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             if !current.is_empty() { |  |  |  |             active_piece | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 (!pieces.iter().any(|board_index| board_index == idx)).then_some(( |  |  |  |                 .get_single() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     current.single().0, |  |  |  |                 .map(|(entity, from)| (entity, from, to)) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     current.single().1, |  |  |  |                 .ok() | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     idx, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 )) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 None |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |         }) | 
			
		
	
		
		
			
				
					
					|  |  |  |         .for_each(|(entity, from, to)| match board.move_piece(from, to) { |  |  |  |         .for_each(|(entity, from, to)| match board.move_piece(from, to) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             Ok(moves) => { |  |  |  |             Ok(moves) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 commands.entity(entity).remove::<game::Selected>(); |  |  |  |                 info!("Moving piece {:?} {:?} -> {:?}", entity, from, to); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 moves.iter().for_each(|m| { |  |  |  |                 moves.iter().for_each(|m| { | 
			
		
	
		
		
			
				
					
					|  |  |  |                     move_events.send(m.clone()); |  |  |  |                     move_events.send(m.clone()); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 }); |  |  |  |                 }); | 
			
		
	
		
		
			
				
					
					|  |  |  |                 game_events.send(game::GameEvent::PlacePiece); |  |  |  |                 game_events.send(game::GameEvent::Place(entity, to.clone())); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Err(game::GameError::NullMove) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 warn!("Null move!"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 game_events.send(game::GameEvent::Place(entity, from.clone())) | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |             Err(game::GameError::NullMove) => game_events.send(game::GameEvent::PlacePiece), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Err(game::GameError::InvalidMove) => warn!("Invalid move!"), |  |  |  |             Err(game::GameError::InvalidMove) => warn!("Invalid move!"), | 
			
		
	
		
		
			
				
					
					|  |  |  |             Err(game::GameError::InvalidIndex) => warn!("Invalid index!"), |  |  |  |             Err(game::GameError::InvalidIndex) => warn!("Invalid index!"), | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |         }) | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | fn cancel_place( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut events: EventReader<MouseButtonInput>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     current: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display2d>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut commands: Commands, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut writer: EventWriter<game::GameEvent>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     events |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .iter() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .filter(|MouseButtonInput { button, state, .. }| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             (*button, *state) == (MouseButton::Right, ButtonState::Pressed) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         .for_each(|_| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             if let Ok(entity) = current.get_single() { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 commands.entity(entity).remove::<game::Selected>(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 writer.send(game::GameEvent::PlacePiece); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | fn snap_back_cancel( |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut events: RemovedComponents<game::Selected>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     query: Query<&game::BoardIndex, (With<game::Piece>, With<Display2d>)>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     mut move_events: EventWriter<game::Move>, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | ) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     events.iter().for_each(|entity| { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if let Ok(idx) = query.get(entity) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             move_events.send(game::Move { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 epoch: 0, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 from: idx.clone(), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 to: Some(idx.clone()), |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             }); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     }) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
	
		
		
			
				
					|  |  | 
 |