Count only stock within the colony's reach
- author
- Marijn Besseling <njirambem@gmail.com> · 2026-10-24 21:34 UTC
- commit
- 588a85c4565cbcae8d657e76a27f7180e916d90f
- parent
- f85e87cb45
- tree
- browse at this commit
5 files changed +64 -8
| src/economy.rs | +5 -0 | |
| src/jobs/mod.rs | +7 -2 | |
| src/jobs/tests.rs | +34 -0 | |
| src/population.rs | +10 -3 | |
| src/selection.rs | +8 -3 |
src/economy.rs +5 -0
| @@ -17,6 +17,7 @@ impl Plugin for EconomyPlugin { | ||
| 17 | 17 | } |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | +pub const COLONY_RADIUS: i32 = 60; | |
| 20 | 21 | const HOURS_OF_MEMORY: f32 = 24.0; |
| 21 | 22 | const MAX_GOAL: f32 = 300.0; |
| 22 | 23 | |
| @@ -177,6 +178,10 @@ impl ColonyGoals { | ||
| 177 | 178 | } |
| 178 | 179 | } |
| 179 | 180 | |
| 181 | +pub fn in_colony(home: UVec2, tile: UVec2) -> bool { | |
| 182 | + (tile.as_ivec2() - home.as_ivec2()).abs().max_element() <= COLONY_RADIUS | |
| 183 | +} | |
| 184 | + | |
| 180 | 185 | pub fn planned_needs(blueprints: &Blueprints) -> HashMap<Stock, u32> { |
| 181 | 186 | let mut needs = HashMap::new(); |
| 182 | 187 | for kind in blueprints.0.values() { |
src/jobs/mod.rs +7 -2
| @@ -10,7 +10,7 @@ use crate::{ | ||
| 10 | 10 | animals::{Animal, AnimalKind}, |
| 11 | 11 | building::{Blueprints, BuildKind}, |
| 12 | 12 | colonist::{Colonist, Path, repath}, |
| 13 | - economy::ColonyGoals, | |
| 13 | + economy::{ColonyGoals, in_colony}, | |
| 14 | 14 | food::{EAT_TICKS, Hunger, STARVING, find_food, portion, wants_food}, |
| 15 | 15 | items::{ |
| 16 | 16 | CARRY_CAPACITY, Carrying, Item, ItemAssets, ItemKind, ItemQuery, drop_items, room_for, |
| @@ -807,10 +807,15 @@ fn choose_jobs( | ||
| 807 | 807 | .collect(); |
| 808 | 808 | let dark = dark_soon(*tick); |
| 809 | 809 | let carried: Vec<Item> = colonists.iter().filter_map(|c| c.5.0).collect(); |
| 810 | + let home = zones.home(map.size / 2); | |
| 810 | 811 | let stocks: HashMap<ItemKind, u32> = ItemKind::ALL |
| 811 | 812 | .iter() |
| 812 | 813 | .map(|&kind| { |
| 813 | - let all = items.iter().map(|(_, item, _)| item).chain(carried.iter()); | |
| 814 | + let all = items | |
| 815 | + .iter() | |
| 816 | + .filter(|(_, _, pos)| in_colony(home, pos.0)) | |
| 817 | + .map(|(_, item, _)| item) | |
| 818 | + .chain(carried.iter()); | |
| 814 | 819 | (kind, stock(all, kind)) |
| 815 | 820 | }) |
| 816 | 821 | .collect(); |
src/jobs/tests.rs +34 -0
| @@ -4,6 +4,7 @@ use super::*; | ||
| 4 | 4 | use crate::{ |
| 5 | 5 | animals::{Animal, AnimalKind}, |
| 6 | 6 | colonist::follow_path, |
| 7 | + economy::COLONY_RADIUS, | |
| 7 | 8 | food::Hunger, |
| 8 | 9 | items::STACK_LIMIT, |
| 9 | 10 | sim::{SimPos, sim_pos}, |
| @@ -939,6 +940,39 @@ fn ripe_crops_are_harvested_into_vegetables_and_resown() { | ||
| 939 | 940 | assert!(map.growth(farm[0].as_ivec2()) < 0.1); |
| 940 | 941 | } |
| 941 | 942 | |
| 943 | +// Food the colony cannot reach must not count towards its stock: a stray stack far from home | |
| 944 | +// once satisfied the raw food target, so nobody harvested ripe crops while everyone starved. | |
| 945 | +#[test] | |
| 946 | +fn stock_out_of_the_colonys_reach_does_not_stop_harvesting() { | |
| 947 | + let farm = UVec2::new(8, 8); | |
| 948 | + let mut map = WorldMap::filled(UVec2::splat(150), Terrain::Grass); | |
| 949 | + map.set(farm, Terrain::Soil); | |
| 950 | + map.set_plant(farm, Some(Plant::Crop)); | |
| 951 | + map.set_growth(farm, 1.0); | |
| 952 | + let mut app = test_app(map.clone()); | |
| 953 | + set_goals(&mut app, &[(ItemKind::Vegetables, 10)]); | |
| 954 | + put_beds(&mut app, 1); | |
| 955 | + let mut zones = app.world_mut().resource_mut::<Zones>(); | |
| 956 | + zones.add_farm_tiles(&map, [farm]); | |
| 957 | + zones.add_tiles(&map, [UVec2::new(4, 4)]); | |
| 958 | + let far = UVec2::new(4, 4) + UVec2::splat(COLONY_RADIUS as u32 + 1); | |
| 959 | + put_items(&mut app, far, ItemKind::Meat, 20); | |
| 960 | + spawn_colonist(&mut app, UVec2::new(2, 2)); | |
| 961 | + run_ticks(&mut app, 60 * 15); | |
| 962 | + assert!(items_of(&mut app, ItemKind::Vegetables) > 0); | |
| 963 | +} | |
| 964 | + | |
| 965 | +#[test] | |
| 966 | +fn colonist_searches_cover_the_colony_radius() { | |
| 967 | + let map = WorldMap::filled(UVec2::splat(200), Terrain::Grass); | |
| 968 | + let home = UVec2::splat(100); | |
| 969 | + let corner = home + UVec2::splat(COLONY_RADIUS as u32); | |
| 970 | + assert_eq!( | |
| 971 | + nearest_tile(&map, home, SEARCH_TILES, |p| p == corner), | |
| 972 | + Some(corner) | |
| 973 | + ); | |
| 974 | +} | |
| 975 | + | |
| 942 | 976 | #[test] |
| 943 | 977 | fn colonists_cook_raw_food_into_meals_at_a_campfire() { |
| 944 | 978 | let mut app = test_app(map_with_trees(&[])); |
src/population.rs +10 -3
| @@ -4,6 +4,7 @@ use bevy::prelude::*; | ||
| 4 | 4 | |
| 5 | 5 | use crate::{ |
| 6 | 6 | colonist::{Colonist, ColonistAssets, NAMES, spawn_colonist}, |
| 7 | + economy::in_colony, | |
| 7 | 8 | food::Hunger, |
| 8 | 9 | items::{Carrying, Item, ItemAssets, ItemQuery, drop_items}, |
| 9 | 10 | jobs::{CurrentJob, Job, Reservations, Task}, |
| @@ -123,7 +124,7 @@ fn arrivals( | ||
| 123 | 124 | mut materials: ResMut<Assets<ColorMaterial>>, |
| 124 | 125 | mut rng: ResMut<SimRng>, |
| 125 | 126 | mut log: ResMut<ColonyLog>, |
| 126 | - items: Query<&Item>, | |
| 127 | + items: Query<(&Item, &TilePos)>, | |
| 127 | 128 | structures: Query<&Structure>, |
| 128 | 129 | colonists: Query<&Colonist>, |
| 129 | 130 | ) { |
| @@ -135,12 +136,18 @@ fn arrivals( | ||
| 135 | 136 | .iter() |
| 136 | 137 | .filter(|s| s.kind == StructureKind::Bed) |
| 137 | 138 | .count(); |
| 138 | - let wood = items | |
| 139 | + let home = zones.home(map.size / 2); | |
| 140 | + let stored: Vec<&Item> = items | |
| 141 | + .iter() | |
| 142 | + .filter(|(_, pos)| in_colony(home, pos.0)) | |
| 143 | + .map(|(item, _)| item) | |
| 144 | + .collect(); | |
| 145 | + let wood = stored | |
| 139 | 146 | .iter() |
| 140 | 147 | .filter(|i| i.kind == crate::items::ItemKind::Wood) |
| 141 | 148 | .map(|i| i.count) |
| 142 | 149 | .sum(); |
| 143 | - let food = food_in_store(items.iter()); | |
| 150 | + let food = food_in_store(stored.iter().copied()); | |
| 144 | 151 | let lucky = rng.range_f32(0.0..1.0) < ARRIVAL_CHANCE; |
| 145 | 152 | if !lucky || !prosperous(count, food, beds.saturating_sub(count), wood) { |
| 146 | 153 | return; |
src/selection.rs +8 -3
| @@ -6,7 +6,7 @@ use crate::{ | ||
| 6 | 6 | building::Blueprints, |
| 7 | 7 | camera::CameraController, |
| 8 | 8 | colonist::{Colonist, Path}, |
| 9 | - economy::{ColonyGoals, Stock}, | |
| 9 | + economy::{ColonyGoals, Stock, in_colony}, | |
| 10 | 10 | food::Hunger, |
| 11 | 11 | items::{Carrying, Item, stock}, |
| 12 | 12 | jobs::{COOK_WORK, CurrentJob, EXPAND_WORK, Job, Order, Task, WorkKind}, |
| @@ -289,8 +289,9 @@ fn update_tile_info( | ||
| 289 | 289 | format_clock(*tick), |
| 290 | 290 | time_of_day(hour_of_day(*tick)) |
| 291 | 291 | ); |
| 292 | - let speed = describe_speed(*speed, time.is_paused()); | |
| 292 | + let speed = describe_speed(*speed, time.is_paused(), time.relative_speed()); | |
| 293 | 293 | let carried: Vec<Item> = colonists.iter().filter_map(|c| c.4.0).collect(); |
| 294 | + let home = zones.home(map.size / 2); | |
| 294 | 295 | let stock_line = |food: bool| { |
| 295 | 296 | Stock::ALL |
| 296 | 297 | .iter() |
| @@ -300,7 +301,11 @@ fn update_tile_info( | ||
| 300 | 301 | .members() |
| 301 | 302 | .map(|kind| { |
| 302 | 303 | stock( |
| 303 | - items.iter().map(|(item, _)| item).chain(carried.iter()), | |
| 304 | + items | |
| 305 | + .iter() | |
| 306 | + .filter(|(_, pos)| in_colony(home, pos.0)) | |
| 307 | + .map(|(item, _)| item) | |
| 308 | + .chain(carried.iter()), | |
| 304 | 309 | kind, |
| 305 | 310 | ) |
| 306 | 311 | }) |