Prioritise beds and shelter, gather build material from several piles

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

author
Marijn Besseling <njirambem@gmail.com> · 2026-10-24 11:23 UTC
commit
6f6ec2bac339a5da0a8c1d7948bcf654964f4fb9
parent
8a7e338052
tree
browse at this commit

2 files changed +54 -11

src/jobs/mod.rs +40 -11

@@ -650,12 +650,22 @@ impl BuildContext<'_> {
650 650 }
651 651
652 652 fn material_source(&self, from: UVec2, (kind, amount): (ItemKind, u32)) -> Option<UVec2> {
653 + let free = |pos: UVec2| self.reservations.is_free(Target::Pickup(pos));
654 + let available: u32 = self
655 + .items
656 + .iter()
657 + .filter(|(item, pos)| item.kind == kind && free(pos.0))
658 + .map(|(item, _)| item.count)
659 + .sum();
660 + if available < amount {
661 + return None;
662 + }
653 663 nearest_tile(self.map, from, SEARCH_TILES, |p| {
654 - self.reservations.is_free(Target::Pickup(p))
664 + free(p)
655 665 && self
656 666 .items
657 667 .iter()
658 - .any(|(item, pos)| pos.0 == p && item.kind == kind && item.count >= amount)
668 + .any(|(item, pos)| pos.0 == p && item.kind == kind)
659 669 })
660 670 }
661 671
@@ -926,6 +936,8 @@ fn choose_jobs(
926 936 })
927 937 .flatten()
928 938 })
939 + .or_else(|| find_bed_site(&build, colonist_count, tile.0))
940 + .or_else(|| find_blueprint_work(&build, tile.0))
929 941 .or_else(|| find_work(&map, &reservations, tile.0, wanted))
930 942 .or_else(|| {
931 943 wanted(ItemKind::Meat)
@@ -934,8 +946,6 @@ fn choose_jobs(
934 946 })
935 947 .or_else(|| find_sowing(&map, &zones, &reservations, tile.0))
936 948 .or_else(|| find_haul(&map, &zones, &reservations, &snapshot, tile.0))
937 - .or_else(|| find_bed_site(&build, colonist_count, tile.0))
938 - .or_else(|| find_blueprint_work(&build, tile.0))
939 949 };
940 950 if let Some(task) = task {
941 951 if let Task::Work { site, .. } = task
@@ -1276,17 +1286,36 @@ fn run_jobs(
1276 1286 Step::Done
1277 1287 } else if tile.0 != from {
1278 1288 walk_to(&map, tile.0, from, &mut path)
1289 + } else if carrying.0.is_some_and(|load| load.kind != material) {
1290 + Step::Done
1279 1291 } else {
1280 - let load = take_items(&mut commands, &mut items, from, cost)
1281 - .filter(|load| load.kind == material && load.count > 0);
1282 - carrying.0 = load;
1283 - match load {
1284 - Some(load) if load.count >= cost => {
1285 - reservations.release(Target::Pickup(from));
1292 + let have = carrying.0.map_or(0, |load| load.count);
1293 + let taken = take_items(&mut commands, &mut items, from, cost - have)
1294 + .filter(|load| load.kind == material)
1295 + .map_or(0, |load| load.count);
1296 + reservations.release(Target::Pickup(from));
1297 + let total = have + taken;
1298 + carrying.0 = (total > 0).then_some(Item {
1299 + kind: material,
1300 + count: total,
1301 + });
1302 + let next = nearest_tile(&map, tile.0, SEARCH_TILES, |p| {
1303 + reservations.is_free(Target::Pickup(p))
1304 + && items.iter().any(|(_, item, pos)| {
1305 + pos.0 == p && item.kind == material && item.count > 0
1306 + })
1307 + });
1308 + match next {
1309 + _ if total >= cost => {
1286 1310 *pickup = None;
1287 1311 Step::Continue
1288 1312 }
1289 - _ => Step::Done,
1313 + Some(next) => {
1314 + reservations.reserve(Target::Pickup(next), entity);
1315 + *pickup = Some(next);
1316 + Step::Continue
1317 + }
1318 + None => Step::Done,
1290 1319 }
1291 1320 }
1292 1321 } else if !carrying

src/jobs/tests.rs +14 -0

@@ -979,3 +979,17 @@ fn no_cooking_without_demand_for_meals() {
979 979 run_ticks(&mut app, 60 * 10);
980 980 assert_eq!(items_of(&mut app, ItemKind::Meal), 0);
981 981 }
982 +
983 +// Chopping and hauling leave material in many small piles; a builder gathers from several
984 +// piles instead of waiting for one big enough to cover the whole cost.
985 +#[test]
986 +fn builders_gather_material_from_several_piles() {
987 + let mut app = test_app(map_with_trees(&[]));
988 + set_goals(&mut app, &[]);
989 + put_wood(&mut app, UVec2::new(4, 4), 10);
990 + put_wood(&mut app, UVec2::new(15, 4), 10);
991 + spawn_colonist(&mut app, UVec2::new(2, 2));
992 + run_ticks(&mut app, 60 * 30);
993 + assert_eq!(beds(&mut app), 1);
994 + assert_eq!(wood_on_map(&mut app), 20 - StructureKind::Bed.cost().1);
995 +}