diff --git a/src/entities/tasks/executor.rs b/src/entities/tasks/executor.rs index b10da3d..725d65c 100644 --- a/src/entities/tasks/executor.rs +++ b/src/entities/tasks/executor.rs @@ -146,11 +146,24 @@ pub fn task_executor_system( continue; } if ambulatory.target.is_none() { - // Find the actual walkable surface above the floor at the trunk's XY. - // Scan for a floor tile, then return the z of the tile above it + 1.0 - // (same pattern as spawn_log_cargo's find_surface_at). use crate::constants::ITILE_SIZE; - let target_z = (-3i32..=4i32) + + // The trunk tile itself is impassable (can_stand_in=false). + // Path to the nearest standable tile adjacent to the trunk instead. + // Check 8 surrounding XY positions at the trunk's ground z. + let offsets = [ + (-1, 0), + (1, 0), + (0, -1), + (0, 1), + (-1, -1), + (-1, 1), + (1, -1), + (1, 1), + ]; + + // First find the ground z at the trunk XY (for z reference) + let ground_z = (-3i32..=4i32) .find_map(|z| { let floor_pos = IVec3::new(trunk_pos.x, trunk_pos.y, z * ITILE_SIZE); @@ -161,19 +174,47 @@ pub fn task_executor_system( floor_pos.z + ITILE_SIZE, ); if tilemap_mut.is_standable(above) { - return Some(above.z as f32 + 1.0); + return Some(above.z); } } None }) - .unwrap_or(trunk_pos.z as f32 + 1.0); + .unwrap_or(trunk_pos.z); - ambulatory.target = Some(Vec3::new( - trunk_pos.x as f32, - trunk_pos.y as f32, - target_z, - )); - ambulatory.current_path = None; + // Find nearest standable neighbour to path toward + let approach_target = offsets.iter().find_map(|(dx, dy)| { + let candidate = IVec3::new( + trunk_pos.x + dx * ITILE_SIZE, + trunk_pos.y + dy * ITILE_SIZE, + ground_z, + ); + if tilemap_mut.is_standable(candidate) { + Some(Vec3::new( + candidate.x as f32, + candidate.y as f32, + candidate.z as f32 + 1.0, + )) + } else { + None + } + }); + + match approach_target { + Some(target) => { + ambulatory.target = Some(target); + ambulatory.current_path = None; + } + None => { + // No adjacent standable tile — tree may be surrounded + failed_writer.write(TaskFailed { + entity, + task: current_task.clone(), + reason: "no adjacent standable tile to approach tree", + }); + *state = TaskState::Failed; + continue; + } + } } let dx = transform.translation.x - trunk_pos.x as f32; let dy = transform.translation.y - trunk_pos.y as f32;