#ifdef _MSC_VER #include #endif #include "upkeep.h" #include #include #include #include #include #include #include #include #include #include #include #include "alchemy.h" #include "economy.h" #include "monsters.h" #include "donations.h" #include int lifestyle(const unit * u) { int need; plane *pl; if (is_monsters(u->faction)) return 0; need = maintenance_cost(u); pl = rplane(u->region); if (pl && fval(pl, PFL_NOFEED)) return 0; return need; } static void help_feed(unit * donor, unit * u, int *need_p) { int need = *need_p; int give = get_money(donor) - lifestyle(donor); if (give > need) give = need; if (give > 0) { change_money(donor, -give); change_money(u, give); need -= give; add_donation(donor->faction, u->faction, give, donor->region); } *need_p = need; } static const char *hunger_damage(const race *rc) { const char * damage = rc_hungerdamage(rc); if (!damage) { damage = config_get("hunger.damage"); } if (!damage) { damage = "1d12+12"; } return damage; } static bool hunger(int number, unit * u) { region *r = u->region; int dead = 0, hpsub = 0; int hp = u->hp / u->number; const char *damage = 0; damage = hunger_damage(u_race(u)); while (number--) { int dam = dice_rand(damage); if (dam >= hp) { ++dead; } else { hpsub += dam; } } if (dead) { /* Gestorbene aus der Einheit nehmen, * Sie bekommen keine Beerdingung. */ ADDMSG(&u->faction->msgs, msg_message("starvation", "unit region dead live", u, r, dead, u->number - dead)); scale_number(u, u->number - dead); deathcounts(r, dead); } if (hpsub > 0) { /* Jetzt die Schaeden der nicht gestorbenen abziehen. */ u->hp -= hpsub; /* Meldung nur, wenn noch keine fuer Tote generiert. */ if (dead == 0) { /* Durch unzureichende Ernaehrung wird %s geschwaecht */ ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r)); } } return (dead || hpsub); } void get_food(region * r) { plane *pl = rplane(r); unit *u; int peasantfood = rpeasants(r) * 10; static const race *rc_demon, *rc_insect; static int rc_cache, config_cache; static int food_rules; static bool insect_hunger; static bool demon_hunger; bool is_cold; if (rc_changed(&rc_cache)) { rc_demon = get_race(RC_DAEMON); rc_insect = get_race(RC_INSECT); } if (config_changed(&config_cache)) { food_rules = config_get_int("rules.food.flags", 0); insect_hunger = config_get_int("hunger.insect.cold", 1) != 0; demon_hunger = config_get_int("hunger.demon.peasant_tolerance", 0) == 0; } if (food_rules & FOOD_IS_FREE) { return; } is_cold = insect_hunger && r_insectstalled(r); /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber * wird zunaechst so auf die Einheiten aufgeteilt, dass idealerweise * jede Einheit genug Silber fuer ihren Unterhalt hat. */ for (u = r->units; u; u = u->next) { int need = lifestyle(u); /* Erstmal zuruecksetzen */ freset(u, UFL_HUNGER); if (u->ship && (u->ship->flags & SF_FISHING)) { unit *v; int c = 2; for (v = u; c > 0 && v; v = v->next) { if (v->ship == u->ship) { int get = 0; if (v->number <= c) { get = lifestyle(v); } else { get = lifestyle(v) * c / v->number; } if (get) { change_money(v, get); } } c -= v->number; } u->ship->flags -= SF_FISHING; } if (food_rules & FOOD_FROM_PEASANTS) { struct faction *owner = region_get_owner(r); /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ if (owner != NULL && alliedfaction(owner, u->faction, HELP_MONEY)) { int rm = rmoney(r); int use = (rm < need) ? rm : need; rsetmoney(r, rm - use); need -= use; } } need -= get_money(u); if (need > 0) { unit *v; for (v = r->units; need && v; v = v->next) { if (v->faction == u->faction) { int give = get_money(v) - lifestyle(v); if (give > need) give = need; if (give > 0) { change_money(v, -give); change_money(u, give); need -= give; } } } } } /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird * entsprechend verteilt. */ for (u = r->units; u; u = u->next) { int need; faction *f = u->faction; assert(u->hp > 0); need = lifestyle(u) - get_money(u); if (need > 0) { unit *v; if (food_rules & FOOD_FROM_OWNER) { /* the owner of the region is the first faction to help out when you're hungry */ faction *owner = region_get_owner(r); if (owner && owner != u->faction) { for (v = r->units; v; v = v->next) { if (v->faction == owner && alliedunit(v, f, HELP_MONEY)) { help_feed(v, u, &need); break; } } } } for (v = r->units; need && v; v = v->next) { if (v->faction != f && alliedunit(v, f, HELP_MONEY)) { help_feed(v, u, &need); } } /* Die Einheit hat nicht genug Geld zusammengekratzt und * nimmt Schaden: */ if (need > 0) { int lspp = lifestyle(u) / u->number; if (lspp > 0) { int number = (need + lspp - 1) / lspp; if (hunger(number, u)) fset(u, UFL_HUNGER); } } } } /* 3. bestimmen, wie viele Bauern gefressen werden. * bei fehlenden Bauern den Daemon hungern lassen */ for (u = r->units; u; u = u->next) { const race * rc = u_race(u); if (rc == rc_demon) { int hungry = u->number; /* use peasantblood before eating the peasants themselves */ const struct item_type *it_blood = it_find("peasantblood"); if (it_blood) { /* always start with the unit itself, then the first known unit that may have some blood */ unit *donor = u; while (donor != NULL && hungry > 0) { int blut = get_effect(donor, it_blood); if (hungry < blut) blut = hungry; if (blut > 0) { change_effect(donor, it_blood, -blut); hungry -= blut; } if (donor == u) donor = r->units; while (donor != NULL) { if (u_race(donor) == rc_demon && donor != u) { if (get_effect(donor, it_blood)) { /* if he's in our faction, drain him: */ if (donor->faction == u->faction) break; } } donor = donor->next; } } } /* remaining demons feed on peasants */ if (pl == NULL || !fval(pl, PFL_NOFEED)) { if (peasantfood >= hungry) { peasantfood -= hungry; hungry = 0; } else { hungry -= peasantfood; peasantfood = 0; } if (hungry > 0) { if (demon_hunger) { /* demons who don't feed are hungry */ if (hunger(hungry, u)) fset(u, UFL_HUNGER); } else { /* no damage, but set the hungry-flag */ fset(u, UFL_HUNGER); } } } } else if (is_cold && rc == rc_insect) { /* insects in glaciers get hunger damage */ if (hunger(u->number, u)) { fset(u, UFL_HUNGER); } } } rsetpeasants(r, peasantfood / 10); /* 3. Von den Ueberlebenden das Geld abziehen: */ for (u = r->units; u; u = u->next) { int m = get_money(u); int need = lifestyle(u); if (need > m) need = m; change_money(u, -need); } }