diff --git a/src/base_system.nvgt b/src/base_system.nvgt index 23ae728..641c55b 100644 --- a/src/base_system.nvgt +++ b/src/base_system.nvgt @@ -1,7 +1,15 @@ // Base automation helpers int get_food_requirement() { if (residents_count <= 0) return 0; - return residents_count; // 1 meat per resident per 8 hours + return residents_count; // 1 food per resident per 8 hours +} + +int get_total_storage_food() { + return get_storage_count(ITEM_MEAT) + get_storage_count(ITEM_SMOKED_FISH) + get_storage_count(ITEM_BASKET_FOOD); +} + +bool has_any_storage_food() { + return get_total_storage_food() > 0; } bool has_any_streams() { @@ -28,18 +36,28 @@ void consume_food_for_residents() { if (needed <= 0) return; int meat_available = get_storage_count(ITEM_MEAT); int smoked_fish_available = get_storage_count(ITEM_SMOKED_FISH); - int total_food = meat_available + smoked_fish_available; + int basket_food_available = get_storage_count(ITEM_BASKET_FOOD); + int total_food = meat_available + smoked_fish_available + basket_food_available; if (total_food >= needed) { + // Priority: meat -> smoked fish -> basket food int from_meat = (meat_available >= needed) ? needed : meat_available; add_storage_count(ITEM_MEAT, -from_meat); int remaining = needed - from_meat; + if (remaining > 0) { - add_storage_count(ITEM_SMOKED_FISH, -remaining); + int from_fish = (smoked_fish_available >= remaining) ? remaining : smoked_fish_available; + add_storage_count(ITEM_SMOKED_FISH, -from_fish); + remaining -= from_fish; + } + + if (remaining > 0) { + add_storage_count(ITEM_BASKET_FOOD, -remaining); } } else { set_storage_count(ITEM_MEAT, 0); set_storage_count(ITEM_SMOKED_FISH, 0); + set_storage_count(ITEM_BASKET_FOOD, 0); if (x <= BASE_END) { notify("No food, residents are hungry."); } @@ -116,8 +134,7 @@ void attempt_resident_fish_smoking() { void keep_base_fires_fed() { if (residents_count <= 0) return; - int total_food = get_storage_count(ITEM_MEAT) + get_storage_count(ITEM_SMOKED_FISH); - if (total_food <= 0) return; + if (!has_any_storage_food()) return; if (get_storage_count(ITEM_STICKS) <= 0 && get_storage_count(ITEM_LOGS) <= 0) return; for (uint i = 0; i < world_fires.length(); i++) { @@ -318,7 +335,7 @@ void attempt_resident_snare_retrieval() { if (residents_count <= 0) return; // Need food in storage (same limitation as other resident tasks) - if (get_storage_count(ITEM_MEAT) <= 0) return; + if (!has_any_storage_food()) return; // Check each snare that has a catch for (int i = int(world_snares.length()) - 1; i >= 0; i--) { @@ -368,7 +385,7 @@ void attempt_resident_butchering() { if (residents_count <= 0) return; // Need food in storage (same limitation as other resident tasks) - if (get_storage_count(ITEM_MEAT) <= 0) return; + if (!has_any_storage_food()) return; // Need game in storage if (get_storage_count(ITEM_SMALL_GAME) <= 0 && get_storage_count(ITEM_BOAR_CARCASSES) <= 0) return; @@ -539,3 +556,63 @@ void attempt_resident_collection() { } } } + +// Resident foraging - produces baskets of fruits and nuts from reed baskets +void attempt_resident_foraging() { + // Only during daytime + if (!is_daytime) return; + + // Need residents + if (residents_count <= 0) return; + + // Need reed baskets in storage + if (get_storage_count(ITEM_REED_BASKETS) <= 0) return; + + // Check if storage has room for basket food + if (get_storage_count(ITEM_BASKET_FOOD) >= BASE_STORAGE_MAX) return; + + // Number of residents who can forage = min(residents, baskets) + int active_foragers = (residents_count < get_storage_count(ITEM_REED_BASKETS)) ? residents_count : get_storage_count(ITEM_REED_BASKETS); + + int baskets_produced = 0; + int baskets_broken = 0; + + for (int i = 0; i < active_foragers; i++) { + // Check for basket breakage during foraging + if (random(1, 100) <= RESIDENT_TOOL_BREAK_CHANCE) { + baskets_broken++; + continue; + } + + // Check if foraging succeeds + if (random(1, 100) > RESIDENT_FORAGING_CHANCE) continue; + + // Check storage capacity + if (get_storage_count(ITEM_BASKET_FOOD) >= BASE_STORAGE_MAX) break; + + // Consume a reed basket and produce a basket of fruits and nuts + add_storage_count(ITEM_REED_BASKETS, -1); + add_storage_count(ITEM_BASKET_FOOD, 1); + baskets_produced++; + } + + // Apply basket breakage (from failed foraging attempts) + if (baskets_broken > 0) { + add_storage_count(ITEM_REED_BASKETS, -baskets_broken); + if (x <= BASE_END) { + string msg = (baskets_broken == 1) + ? "A resident's basket broke while foraging." + : baskets_broken + " baskets broke while foraging."; + speak_with_history(msg, true); + } + } + + // Notify of production + if (baskets_produced > 0 && x <= BASE_END) { + if (baskets_produced == 1) { + speak_with_history("Resident gathered a basket of fruits and nuts.", true); + } else { + speak_with_history("Residents gathered " + baskets_produced + " baskets of fruits and nuts.", true); + } + } +} diff --git a/src/constants.nvgt b/src/constants.nvgt index 1471a55..52ce5a0 100644 --- a/src/constants.nvgt +++ b/src/constants.nvgt @@ -242,6 +242,7 @@ const int FALL_DAMAGE_MAX = 4; // Base Automation const int RESIDENT_SLING_COOLDOWN = 4000; // 4 seconds between shots const int RESIDENT_COLLECTION_CHANCE = 10; // 10% chance per basket per hour +const int RESIDENT_FORAGING_CHANCE = 50; // 50% chance per resident per attempt (twice daily) // Utility functions int abs(int value) { diff --git a/src/item_registry.nvgt b/src/item_registry.nvgt index 3e8617b..4f12664 100644 --- a/src/item_registry.nvgt +++ b/src/item_registry.nvgt @@ -40,7 +40,8 @@ const int ITEM_CANOES = 34; const int ITEM_FISH = 35; const int ITEM_SMOKED_FISH = 36; const int ITEM_HEAL_SCROLL = 37; -const int ITEM_COUNT = 38; // Total number of item types +const int ITEM_BASKET_FOOD = 38; +const int ITEM_COUNT = 39; // Total number of item types // Item definition class class ItemDefinition { @@ -126,6 +127,7 @@ void init_item_registry() { item_registry[ITEM_FISH] = ItemDefinition(ITEM_FISH, "fish", "fish", "Fish", 0.10); item_registry[ITEM_SMOKED_FISH] = ItemDefinition(ITEM_SMOKED_FISH, "smoked fish", "smoked fish", "Smoked Fish", 0.20); item_registry[ITEM_HEAL_SCROLL] = ItemDefinition(ITEM_HEAL_SCROLL, "heal scrolls", "heal scroll", "Heal Scrolls", 0.50); + item_registry[ITEM_BASKET_FOOD] = ItemDefinition(ITEM_BASKET_FOOD, "baskets of fruits and nuts", "basket of fruits and nuts", "Baskets of Fruits and Nuts", 0.15); // Define display order for inventory menus // This controls the order items appear in menus @@ -148,6 +150,7 @@ void init_item_registry() { // Food items ITEM_FISH, ITEM_SMOKED_FISH, + ITEM_BASKET_FOOD, // Misc items ITEM_INCENSE, ITEM_HEAL_SCROLL, diff --git a/src/menus/base_info.nvgt b/src/menus/base_info.nvgt index ddeb0e7..4a99b6f 100644 --- a/src/menus/base_info.nvgt +++ b/src/menus/base_info.nvgt @@ -19,8 +19,9 @@ void run_base_info_menu() { int daily_food = residents_count * 3; // 1 per resident per 8 hours = 3 per day int meat_in_storage = get_storage_count(ITEM_MEAT); int smoked_fish_in_storage = get_storage_count(ITEM_SMOKED_FISH); - int total_food = meat_in_storage + smoked_fish_in_storage; - options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage + " smoked fish. Total " + total_food + ". Daily use " + daily_food); + int basket_food_in_storage = get_storage_count(ITEM_BASKET_FOOD); + int total_food = meat_in_storage + smoked_fish_in_storage + basket_food_in_storage; + options.insert_last("Food in storage " + meat_in_storage + " meat, " + smoked_fish_in_storage + " smoked fish, " + basket_food_in_storage + " baskets of fruits and nuts. Total " + total_food + ". Daily use " + daily_food); } else { options.insert_last("Storage not built"); } diff --git a/src/time_system.nvgt b/src/time_system.nvgt index 5293d23..4c38245 100644 --- a/src/time_system.nvgt +++ b/src/time_system.nvgt @@ -400,7 +400,7 @@ void update_time() { check_ambience_transition(); if (is_daytime && residents_count > 0 && barricade_health < BARRICADE_MAX_HEALTH && current_hour % 4 == 0) { - if (get_storage_count(ITEM_MEAT) > 0) { + if (has_any_storage_food()) { int gained = add_barricade_health(residents_count); if (gained > 0 && x <= BASE_END) { speak_with_history("Residents repaired the barricade. +" + gained + " health.", true); @@ -412,6 +412,10 @@ void update_time() { process_daily_weapon_breakage(); attempt_daily_quest(); attempt_resident_butchering(); + attempt_resident_foraging(); + } + if (current_hour == 12) { + attempt_resident_foraging(); } attempt_daily_invasion(); keep_base_fires_fed();