Reed baskets an now be placed in storage for residents to collect fruits and nuts. Should help offset food costs for upkeep.

This commit is contained in:
Storm Dragon
2026-01-24 23:26:37 -05:00
parent cbacdd7a26
commit 8099e1b9a5
5 changed files with 97 additions and 11 deletions

View File

@@ -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);
}
}
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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");
}

View File

@@ -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();