feat: Implement shovel interaction and tile highlighting (#15)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::prelude::*;
|
||||
use components::{CropVisual, WaterVisual};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub mod components;
|
||||
pub mod consts;
|
||||
@@ -88,7 +89,10 @@ fn cleanup(mut commands: Commands, tile_query: Query<Entity, With<Tile>>) {
|
||||
}
|
||||
|
||||
fn update_tiles(
|
||||
mut query: Query<(&TileState, &mut AseSlice, &Children), (With<Tile>, Without<CropVisual>)>,
|
||||
mut query: Query<
|
||||
(&TileState, &mut AseSlice, &Children, &Tile),
|
||||
(With<Tile>, Without<CropVisual>),
|
||||
>,
|
||||
mut crop_query: Query<
|
||||
(&mut Visibility, &mut Transform, &mut AseSlice),
|
||||
(With<CropVisual>, Without<WaterVisual>, Without<Tile>),
|
||||
@@ -99,8 +103,27 @@ fn update_tiles(
|
||||
>,
|
||||
asset_server: Res<AssetServer>,
|
||||
game_config: Res<GameConfig>,
|
||||
inventory: Res<Inventory>,
|
||||
item_stacks: Query<&ItemStack>,
|
||||
grid: Res<Grid>,
|
||||
mut sprite_query: Query<&mut Sprite, With<Tile>>,
|
||||
) {
|
||||
for (state, mut slice, children) in &mut query {
|
||||
let has_shovel = inventory.has_item_type(&item_stacks, ItemType::Shovel);
|
||||
|
||||
let owned_tiles: HashSet<(u32, u32)> = query
|
||||
.iter()
|
||||
.filter_map(|(state, _, _, tile)| {
|
||||
if !matches!(state, TileState::Unclaimed) {
|
||||
Some((tile.x, tile.y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (state, mut slice, children, tile) in &mut query {
|
||||
let entity = grid.get_tile((tile.x, tile.y)).unwrap(); // Get entity for sprite query
|
||||
|
||||
slice.name = match state {
|
||||
TileState::Unclaimed => "Unclaimed",
|
||||
TileState::Empty => "Empty",
|
||||
@@ -133,6 +156,34 @@ fn update_tiles(
|
||||
_ => Vec3::ONE,
|
||||
};
|
||||
|
||||
let mut is_highlighted = false;
|
||||
if has_shovel && matches!(state, TileState::Unclaimed) {
|
||||
// Check if not on edge
|
||||
if tile.x > 0 && tile.x < grid.width - 1 && tile.y > 0 && tile.y < grid.height - 1 {
|
||||
// Check neighbors
|
||||
let neighbors = [
|
||||
(tile.x + 1, tile.y),
|
||||
(tile.x.saturating_sub(1), tile.y),
|
||||
(tile.x, tile.y + 1),
|
||||
(tile.x, tile.y.saturating_sub(1)),
|
||||
];
|
||||
for n in neighbors.iter() {
|
||||
if owned_tiles.contains(n) {
|
||||
is_highlighted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(mut sprite) = sprite_query.get_mut(entity) {
|
||||
if is_highlighted {
|
||||
sprite.color = Color::srgb(0.3, 1.0, 0.3); // Green tint
|
||||
} else {
|
||||
sprite.color = Color::WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
for child in children.iter() {
|
||||
if let Ok((mut visibility, mut transform, mut sprite)) = crop_query.get_mut(child) {
|
||||
*visibility = match state {
|
||||
|
||||
@@ -53,7 +53,13 @@ fn move_click(
|
||||
config: Res<GameConfig>,
|
||||
phase: Res<CurrentPhase>,
|
||||
ui_query: Query<(&ComputedNode, &GlobalTransform), With<Node>>,
|
||||
inventory: Res<Inventory>,
|
||||
item_stacks: Query<&ItemStack>,
|
||||
) {
|
||||
if inventory.has_item_type(&item_stacks, ItemType::Shovel) {
|
||||
return; // Block movement if player has a shovel
|
||||
}
|
||||
|
||||
match phase.0 {
|
||||
Phase::Focus { .. } => return,
|
||||
_ => {}
|
||||
@@ -78,12 +84,25 @@ fn interact_click(
|
||||
config: Res<GameConfig>,
|
||||
phase: Res<CurrentPhase>,
|
||||
ui_query: Query<(&ComputedNode, &GlobalTransform), With<Node>>,
|
||||
mut commands: Commands,
|
||||
mut inventory: ResMut<Inventory>,
|
||||
mut item_stacks: Query<&mut ItemStack>,
|
||||
grid: Res<Grid>,
|
||||
mut tile_states: Query<&mut TileState>,
|
||||
) {
|
||||
match phase.0 {
|
||||
Phase::Focus { .. } => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let has_shovel = inventory.items.iter().any(|&entity| {
|
||||
if let Ok(stack) = item_stacks.get(entity) {
|
||||
stack.item_type == ItemType::Shovel
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if mouse_btn.just_pressed(MouseButton::Left) {
|
||||
if keys.pressed(KeyCode::ShiftLeft) || keys.pressed(KeyCode::ShiftRight) {
|
||||
return;
|
||||
@@ -92,10 +111,69 @@ fn interact_click(
|
||||
return;
|
||||
};
|
||||
|
||||
tile_click_messages.write(TileClickMessage { x, y });
|
||||
if has_shovel {
|
||||
// Shovel interaction logic
|
||||
let tile_entity = match grid.get_tile((x, y)) {
|
||||
Ok(entity) => entity,
|
||||
Err(_) => return, // Clicked outside grid
|
||||
};
|
||||
|
||||
// Before getting mutable tile_state, check neighbors with immutable borrow
|
||||
let mut has_claimed_neighbor = false;
|
||||
// Check if not on edge first for early exit to avoid checking neighbors outside grid.
|
||||
if x == 0 || x == grid.width - 1 || y == 0 || y == grid.height - 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let neighbors = [
|
||||
(x + 1, y),
|
||||
(x.saturating_sub(1), y),
|
||||
(x, y + 1),
|
||||
(x, y.saturating_sub(1)),
|
||||
];
|
||||
|
||||
for (nx, ny) in neighbors.iter() {
|
||||
// Ensure neighbor coordinates are within grid boundaries before attempting to get tile
|
||||
if *nx < grid.width && *ny < grid.height {
|
||||
if let Ok(neighbor_entity) = grid.get_tile((*nx, *ny)) {
|
||||
if let Ok(neighbor_state) = tile_states.get(neighbor_entity) {
|
||||
if !matches!(*neighbor_state, TileState::Unclaimed) {
|
||||
has_claimed_neighbor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !has_claimed_neighbor {
|
||||
return; // No claimed neighbor, cannot unlock
|
||||
}
|
||||
|
||||
// Now get mutable tile_state, after all immutable neighbor checks are done
|
||||
let mut tile_state = match tile_states.get_mut(tile_entity) {
|
||||
Ok(state) => state,
|
||||
Err(_) => return, // Should not happen
|
||||
};
|
||||
|
||||
// Check if unclaimed AFTER determining neighbor status
|
||||
if !matches!(*tile_state, TileState::Unclaimed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if has_claimed_neighbor {
|
||||
// This check is redundant due to early return above, but kept for clarity
|
||||
// Unlock tile
|
||||
*tile_state = TileState::Empty;
|
||||
inventory.update_item_stack(&mut commands, &mut item_stacks, ItemType::Shovel, -1);
|
||||
}
|
||||
return; // Consume click event, prevent normal tile_click_messages
|
||||
} else {
|
||||
// Normal interaction
|
||||
tile_click_messages.write(TileClickMessage { x, y });
|
||||
}
|
||||
}
|
||||
}
|
||||
fn debug_click(
|
||||
mouse_btn: Res<ButtonInput<MouseButton>>,
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
|
||||
Reference in New Issue
Block a user