This commit is contained in:
2026-03-22 15:23:44 +00:00
parent 3b9b2d9c88
commit c46e23af06
4 changed files with 31 additions and 10 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ pub fn spawn_log_cargo(
); );
// Find nearest free tile from biased position // Find nearest free tile from biased position
let drop_pos = tilemap.find_nearest_free_cargo_tile(biased_pos, 4)?; let drop_pos = tilemap.find_nearest_free_cargo_tile(biased_pos, 4, &[])?;
// TODO: OuchEvent — if a living entity occupies drop_pos, they take impact damage. // TODO: OuchEvent — if a living entity occupies drop_pos, they take impact damage.
// Check tilemap occupancy here when the combat/injury system exists. // Check tilemap occupancy here when the combat/injury system exists.
+12 -4
View File
@@ -283,13 +283,21 @@ pub fn demo_system(
let idle_dorfs: SmallVec<[Entity; 8]> = let idle_dorfs: SmallVec<[Entity; 8]> =
idle_dorfs.into_iter().map(|(e, _)| e).collect(); idle_dorfs.into_iter().map(|(e, _)| e).collect();
// Track destinations reserved this tick to avoid assigning the same tile
// to multiple dorfs before any have physically dropped their cargo.
let mut reserved: SmallVec<[IVec3; 8]> = SmallVec::new();
for dorf_entity in idle_dorfs { for dorf_entity in idle_dorfs {
// Compute haul destination fresh for each assignment // Compute haul destination fresh for each assignment,
// as logs accumulate near origin, each new assignment correctly // excluding tiles already reserved this tick.
// finds the next free tile.
let dest = tilemap let dest = tilemap
.find_nearest_free_cargo_tile(IVec3::ZERO, HAUL_DEST_SEARCH_RADIUS) .find_nearest_free_cargo_tile(
IVec3::ZERO,
HAUL_DEST_SEARCH_RADIUS,
&reserved,
)
.unwrap_or(IVec3::ZERO); .unwrap_or(IVec3::ZERO);
reserved.push(dest);
let Some((log_entity, log_pos)) = unassigned.pop_front() else { let Some((log_entity, log_pos)) = unassigned.pop_front() else {
break; break;
+2 -2
View File
@@ -276,7 +276,7 @@ pub fn task_executor_system(
if chosen_drop.is_none() { if chosen_drop.is_none() {
*chosen_drop = Some( *chosen_drop = Some(
tilemap_mut tilemap_mut
.find_nearest_free_cargo_tile(*dest, 8) .find_nearest_free_cargo_tile(*dest, 8, &[])
.unwrap_or(*dest), .unwrap_or(*dest),
); );
} }
@@ -331,7 +331,7 @@ pub fn task_executor_system(
if chosen_drop.is_none() { if chosen_drop.is_none() {
*chosen_drop = Some( *chosen_drop = Some(
tilemap_mut tilemap_mut
.find_nearest_free_cargo_tile(*pos, 8) .find_nearest_free_cargo_tile(*pos, 8, &[])
.unwrap_or(*pos), .unwrap_or(*pos),
); );
} }
+16 -3
View File
@@ -467,8 +467,18 @@ impl TileMap {
/// Uses a spiral outward search — O(radius²) worst case but returns immediately /// Uses a spiral outward search — O(radius²) worst case but returns immediately
/// on first free tile found. Searches only at origin.z (same z-level). /// on first free tile found. Searches only at origin.z (same z-level).
/// Returns None if no free tile found within radius. /// Returns None if no free tile found within radius.
pub fn find_nearest_free_cargo_tile(&self, origin: IVec3, max_radius: i32) -> Option<IVec3> { /// Excludes any tiles in `exclude` from consideration — useful when
if !self.cargo_tiles.contains_key(&origin) && self.is_standable(origin) { /// reserving multiple destinations in the same tick.
pub fn find_nearest_free_cargo_tile(
&self,
origin: IVec3,
max_radius: i32,
exclude: &[IVec3],
) -> Option<IVec3> {
if !self.cargo_tiles.contains_key(&origin)
&& !exclude.contains(&origin)
&& self.is_standable(origin)
{
return Some(origin); return Some(origin);
} }
@@ -483,7 +493,10 @@ impl TileMap {
origin.y + dy * ITILE_SIZE, origin.y + dy * ITILE_SIZE,
origin.z, origin.z,
); );
if !self.cargo_tiles.contains_key(&candidate) && self.is_standable(candidate) { if !self.cargo_tiles.contains_key(&candidate)
&& !exclude.contains(&candidate)
&& self.is_standable(candidate)
{
return Some(candidate); return Some(candidate);
} }
} }