diff --git a/include/prototypes.h b/include/prototypes.h index b8edba98..44a3671e 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -730,10 +730,11 @@ extern void finish_sects(int); extern int new_work(struct sctstr *, int); extern int do_feed(struct sctstr *, struct natstr *, short *, int *, int *, int); -extern int feed_people(short *, int, int *); +extern int feed_people(short *, int); +extern double food_needed(short *, int); +extern int famine_victims(short *, int); /* land.c */ extern int prod_land(int, int, int *, int); -extern int feed_land(struct lndstr *, int, int *, int); /* main.c */ /* in server.h */ /* material.c */ @@ -796,7 +797,6 @@ extern void produce_sect(int natnum, int etu, int *bp, long (*p_sect)[2], int sector_type); /* ship.c */ extern int prod_ship(int, int, int *, int); -extern int feed_ship(struct shpstr *, int, int *, int); /* * src/server diff --git a/src/lib/commands/strv.c b/src/lib/commands/strv.c index 75e6bff4..7d877048 100644 --- a/src/lib/commands/strv.c +++ b/src/lib/commands/strv.c @@ -33,6 +33,7 @@ #include +#include #include "misc.h" #include "player.h" #include "xy.h" @@ -94,13 +95,20 @@ starve(void) return RET_OK; } +static void +starv_people(short *vec, int victims) +{ + pr(" will starve %d people. %.0f more food needed\n", victims, + ceil(food_needed(vec, etu_per_update) - vec[I_FOOD])); +} + static void starv_sects(char *range) { struct nstr_sect nstr; struct sctstr sect; int nsect = 0; - int s, needed; + int s; if (!snxtsct(&nstr, range)) return; @@ -110,10 +118,9 @@ starv_sects(char *range) if (sect.sct_type == SCT_SANCT) continue; -/* This next 2 lines were added to overcompensate for the needy */ - if (sect.sct_item[I_FOOD]) - sect.sct_item[I_FOOD]--; - s = feed_people(sect.sct_item, etu_per_update, &needed); + if (sect.sct_item[I_FOOD] == 0) + sect.sct_item[I_FOOD] = 1; /* see growfood() */ + s = famine_victims(sect.sct_item, etu_per_update); if (s == 0) continue; @@ -129,7 +136,7 @@ starv_sects(char *range) else pr(" "); pr("%4d%%", sect.sct_effic); - pr(" will starve %d people. %d more food needed\n", s, needed); + starv_people(sect.sct_item, s); } if (nsect == 0) { if (player->argp[1]) @@ -160,7 +167,7 @@ starv_ships(char *range) struct nstr_item ni; struct shpstr ship; int nship = 0; - int s, needed; + int s; if (!snxtitem(&ni, EF_SHIP, range)) return; @@ -169,7 +176,7 @@ starv_ships(char *range) if (!player->owner || !ship.shp_own) continue; - s = feed_ship(&ship, etu_per_update, &needed, 0); + s = famine_victims(ship.shp_item, etu_per_update); if (s == 0) continue; if (nship++ == 0) @@ -178,7 +185,7 @@ starv_ships(char *range) pr("%3d ", ship.shp_own); pr("%5d ", ship.shp_uid); pr("%-16.16s ", mchr[(int)ship.shp_type].m_name); - pr(" will starve %d people. %d more food needed\n", s, needed); + starv_people(ship.shp_item, s); } if (nship == 0) { if (range) @@ -217,7 +224,7 @@ starv_units(char *range) if (!player->owner || !land.lnd_own) continue; - s = feed_land(&land, etu_per_update, &needed, 0); + s = famine_victims(land.lnd_item, etu_per_update); if (s == 0) continue; if (nunit++ == 0) @@ -226,7 +233,7 @@ starv_units(char *range) pr("%3d ", land.lnd_own); pr("%5d ", land.lnd_uid); pr("%-16.16s ", lchr[(int)land.lnd_type].l_name); - pr(" will starve %d mil. %d more food needed\n", s, needed); + starv_people(land.lnd_item, s); } if (nunit == 0) { if (range) diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 6d417f36..b770ee2d 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -33,6 +33,7 @@ #include +#include #include "misc.h" #include "nat.h" #include "ship.h" @@ -202,11 +203,9 @@ s_commod(int own, int x, int y, i_type type, int total_wanted, continue; if (!BestLandPath(buf, &dest, §, &move_cost, MOB_ROAD)) continue; - if (!opt_NOFOOD && type == I_FOOD) { - minimum = 2 + ((etu_per_update * eatrate) - * (sect.sct_item[I_CIVIL] + sect.sct_item[I_MILIT] - + sect.sct_item[I_UW])); - } + if (!opt_NOFOOD && type == I_FOOD) + minimum = 1 + (int)ceil(food_needed(sect.sct_item, + etu_per_update)); if (sect.sct_item[type] <= minimum) { /* Don't bother... */ continue; @@ -278,9 +277,8 @@ s_commod(int own, int x, int y, i_type type, int total_wanted, if (!BestLandPath(buf, &dest, §, &move_cost, MOB_ROAD)) continue; if (!opt_NOFOOD && type == I_FOOD) - minimum = 2 + ((etu_per_update * eatrate) - * (ship.shp_item[I_CIVIL] + ship.shp_item[I_MILIT] - + ship.shp_item[I_UW])); + minimum = 1 + (int)ceil(food_needed(ship.shp_item, + etu_per_update)); if (ship.shp_item[type] <= minimum) { /* Don't bother... */ continue; @@ -438,7 +436,7 @@ get_minimum(struct lndstr *lp, i_type type) case I_FOOD: if (opt_NOFOOD) return 0; /* no food reqd, get out */ - want = (double)etu_per_update * eatrate * lp->lnd_item[I_MILIT] + 1; + want = (int)ceil(food_needed(lp->lnd_item, etu_per_update)); break; case I_SHELL: want = lp->lnd_ammo; diff --git a/src/lib/update/human.c b/src/lib/update/human.c index 0efa96f5..ea1a42d2 100644 --- a/src/lib/update/human.c +++ b/src/lib/update/human.c @@ -34,6 +34,7 @@ #include +#include #include "misc.h" #include "sect.h" #include "nat.h" @@ -48,23 +49,20 @@ #include "gen.h" #include "subs.h" -static int grow_people(struct sctstr *, int, - struct natstr *, int *, int, +static int growfood(struct sctstr *, short *, int, int); +static int starve_some(short *, i_type, int); +static void trunc_people(struct sctstr *, struct natstr *, short *); +static int grow_people(struct sctstr *, int, struct natstr *, int *, int, short *); static int babies(int, int, double, int, int); -static int growfood(struct sctstr *, short *, int, int); -static void trunc_people(struct sctstr *, struct natstr *, - short *); /* * feed the individual sector - * */ int do_feed(struct sctstr *sp, struct natstr *np, short *vec, int *workp, int *bp, int etu) { - int people; int work_avail; int starved, sctwork; int needed; @@ -79,35 +77,26 @@ do_feed(struct sctstr *sp, struct natstr *np, short *vec, vec[I_CIVIL], vec[I_MILIT], vec[I_UW], maxpop)); - people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]; if (sp->sct_type != SCT_SANCT) { if (opt_NOFOOD == 0) { - if (vec[I_FOOD] < 1 + etu * people * eatrate) { + needed = (int)ceil(food_needed(vec, etu)); + if (vec[I_FOOD] < needed) { /* need to grow "emergency rations" */ - work_avail -= (2 * - growfood(sp, vec, (int)(work_avail / 2), - etu)); + work_avail -= 2 * growfood(sp, vec, work_avail / 2, etu); /* It's twice as hard to grow those than norm */ pt_bg_nmbr(bp, sp, I_MAX + 1, work_avail); if (!player->simulation) sp->sct_avail = work_avail; } - if ((vec[I_FOOD] < 1 + etu * people * eatrate) && - (sp->sct_own == sp->sct_oldown)) { - + if (vec[I_FOOD] < needed && sp->sct_own == sp->sct_oldown) { /* steal food from warehouses, headquarters, supply ships in port, or supply units */ - int needed; - - needed = ldround(1.0 + etu * people * eatrate, 1); - - /* Now, find some food */ vec[I_FOOD] = supply_commod(sp->sct_own, sp->sct_x, sp->sct_y, I_FOOD, needed); } } - starved = feed_people(vec, etu, &needed); + starved = feed_people(vec, etu); if (starved > 0) { if (!player->simulation) { /* don't report POGO starvation */ @@ -179,58 +168,61 @@ growfood(struct sctstr *sp, short *vec, int work, int etu) * returns the number who starved, if any. */ int -feed_people(short *vec, int etu, int *needed) +feed_people(short *vec, int etu) { - double food_eaten; - int ifood_eaten; - int can_eat; - int total_people; - int to_starve; - int starved; + int to_starve, starved; if (opt_NOFOOD) return 0; - total_people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]; - food_eaten = etu * eatrate * total_people; - ifood_eaten = (int)food_eaten; - if (food_eaten - ifood_eaten > 0) - ifood_eaten++; - if (ifood_eaten <= 1) - return 0; - starved = 0; - *needed = 0; - if (ifood_eaten > vec[I_FOOD]) { - *needed = ifood_eaten - vec[I_FOOD]; - can_eat = vec[I_FOOD] / (etu * eatrate); - /* only want to starve off at most 1/2 the populace. */ - if (can_eat < total_people / 2) - can_eat = total_people / 2; - - to_starve = total_people - can_eat; - while (to_starve && vec[I_UW]) { - to_starve--; - starved++; - vec[I_UW]--; - } - while (to_starve && vec[I_CIVIL]) { - to_starve--; - starved++; - vec[I_CIVIL]--; - } - while (to_starve && vec[I_MILIT]) { - to_starve--; - starved++; - vec[I_MILIT]--; - } - + to_starve = famine_victims(vec, etu); + starved = starve_some(vec, I_UW, to_starve); + starved += starve_some(vec, I_CIVIL, to_starve - starved); + starved += starve_some(vec, I_MILIT, to_starve - starved); + vec[I_FOOD] -= roundavg(food_needed(vec, etu)); + if (vec[I_FOOD] < 0) vec[I_FOOD] = 0; - } else { - vec[I_FOOD] -= roundavg(food_eaten); - } return starved; } +/* + * Return food eaten by people in VEC[] in ETU ETUs. + */ +double +food_needed(short *vec, int etu) +{ + int people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]; + double need = etu * eatrate * people; + return need; +} + +/* + * Return number of famine victims in VEC[] for ETU ETUs. + */ +int +famine_victims(short *vec, int etu) +{ + double can_eat = vec[I_FOOD] / (etu * eatrate); + int people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]; + if (people < can_eat) + return 0; + if (can_eat < people / 2) + return people / 2; + return (int)(people - can_eat); +} + +/* + * Starve up to NUM people of VEC[WHOM]. + * Return the number of actually starved. + */ +static int +starve_some(short *vec, i_type whom, int num) +{ + int retval = MIN(num, vec[whom]); + vec[whom] -= retval; + return retval; +} + /* * Truncate any extra people that may be around */ diff --git a/src/lib/update/land.c b/src/lib/update/land.c index 3defbdb4..5a6a22e9 100644 --- a/src/lib/update/land.c +++ b/src/lib/update/land.c @@ -35,6 +35,7 @@ #include +#include #include "misc.h" #include "plague.h" #include "sect.h" @@ -57,6 +58,7 @@ int mil_dbl_pay; static void landrepair(struct lndstr *, struct natstr *, int *, int); static void upd_land(struct lndstr *, int, struct natstr *, int *, int); +static int feed_land(struct lndstr *, int); int prod_land(int etus, int natnum, int *bp, int build) @@ -120,7 +122,6 @@ upd_land(struct lndstr *lp, int etus, int n; int min = morale_base - (int)np->nat_level[NAT_HLEV]; int mult; - int needed; int cost; int eff; @@ -160,7 +161,7 @@ upd_land(struct lndstr *lp, int etus, if (!player->simulation) { /* feed */ - if ((n = feed_land(lp, etus, &needed, 1)) > 0) { + if ((n = feed_land(lp, etus)) > 0) { wu(0, lp->lnd_own, "%d starved in %s%s\n", n, prland(lp), (lp->lnd_effic < LAND_MINEFF ? ", killing it" : "")); @@ -337,62 +338,20 @@ landrepair(struct lndstr *land, struct natstr *np, int *bp, int etus) /* * returns the number who starved, if any. */ -int -feed_land(struct lndstr *lp, int etus, int *needed, int doit) +static int +feed_land(struct lndstr *lp, int etus) { - double food_eaten, ship_eaten; - int ifood_eaten; - double people_left; - int need; - int total_people; - int starved; + int needed, give, take; struct shpstr *sp; if (opt_NOFOOD) - return 0; /* no food no work to be done */ + return 0; - total_people = lp->lnd_item[I_MILIT]; - food_eaten = etus * eatrate * total_people; - ifood_eaten = (int)food_eaten; - if (food_eaten - ifood_eaten > 0) - ifood_eaten++; - starved = 0; - *needed = 0; + needed = (int)ceil(food_needed(lp->lnd_item, etus)); - if (doit) + /* scrounge */ + if (needed > lp->lnd_item[I_FOOD]) resupply_commod(lp, I_FOOD); - /* - * If we're on a ship, and we don't have enough food, - * get some food off the carrying ship. (Don't starve - * the ship, tho... - */ -/* doit - Only try to take food off the ship during the update */ - if (ifood_eaten > lp->lnd_item[I_FOOD] && lp->lnd_ship >= 0 && doit) { - need = ifood_eaten - lp->lnd_item[I_FOOD]; - sp = getshipp(lp->lnd_ship); - ship_eaten = etus * eatrate * (sp->shp_item[I_CIVIL] - + sp->shp_item[I_MILIT] - + sp->shp_item[I_UW]); - if (sp->shp_item[I_FOOD] - need > ship_eaten) { - lp->lnd_item[I_FOOD] += need; - sp->shp_item[I_FOOD] -= need; - } else if (sp->shp_item[I_FOOD] - ship_eaten > 0) { - lp->lnd_item[I_FOOD] += sp->shp_item[I_FOOD] - ship_eaten; - sp->shp_item[I_FOOD] -= sp->shp_item[I_FOOD] - ship_eaten; - } - } - if (ifood_eaten > lp->lnd_item[I_FOOD]) { - *needed = ifood_eaten - lp->lnd_item[I_FOOD]; - people_left = (lp->lnd_item[I_FOOD] + 0.01) / (food_eaten + 0.01); - /* only want to starve off at most 1/2 the populace. */ - if (people_left < 0.5) - people_left = 0.5; - starved = total_people * (1 - people_left); - lp->lnd_item[I_MILIT] -= starved; - lp->lnd_item[I_FOOD] = 0; - } else { - lp->lnd_item[I_FOOD] -= (int)food_eaten; - } - return starved; + return feed_people(lp->lnd_item, etus); } diff --git a/src/lib/update/ship.c b/src/lib/update/ship.c index 51c8ffa1..f7d2b37e 100644 --- a/src/lib/update/ship.c +++ b/src/lib/update/ship.c @@ -35,6 +35,7 @@ #include +#include #include "misc.h" #include "plague.h" #include "sect.h" @@ -57,6 +58,7 @@ static void shiprepair(struct shpstr *, struct natstr *, int *, int); static void upd_ship(struct shpstr *, int, struct natstr *, int *, int); +static int feed_ship(struct shpstr *, int); int prod_ship(int etus, int natnum, int *bp, int build) @@ -128,7 +130,6 @@ upd_ship(struct shpstr *sp, int etus, int dep; int n; int mult; - int needed; int cost; int eff; @@ -202,7 +203,7 @@ upd_ship(struct shpstr *sp, int etus, * prod_eff(product, sp->shp_tech)); } /* feed */ - if ((n = feed_ship(sp, etus, &needed, 1)) > 0) { + if ((n = feed_ship(sp, etus)) > 0) { wu(0, sp->shp_own, "%d starved on %s\n", n, prship(sp)); if (n > 10) nreport(sp->shp_own, N_DIE_FAMINE, 0, 1); @@ -396,79 +397,38 @@ shiprepair(struct shpstr *ship, struct natstr *np, int *bp, int etus) /* * returns the number who starved, if any. */ -int -feed_ship(struct shpstr *sp, int etus, int *needed, int doit) +static int +feed_ship(struct shpstr *sp, int etus) { - double food_eaten, land_eaten; - int ifood_eaten; - int can_eat, need; - int total_people; - int to_starve; - int starved; + int needed, take; + double give; struct nstr_item ni; struct lndstr *lp; if (opt_NOFOOD) - return 0; /* no food no work to do */ + return 0; - total_people - = sp->shp_item[I_CIVIL] + sp->shp_item[I_MILIT] + sp->shp_item[I_UW]; - food_eaten = etus * eatrate * total_people; - ifood_eaten = (int)food_eaten; - if (food_eaten - ifood_eaten > 0) - ifood_eaten++; - starved = 0; - *needed = 0; - if (!player->simulation && ifood_eaten > sp->shp_item[I_FOOD]) - sp->shp_item[I_FOOD] - += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y, - I_FOOD, ifood_eaten - sp->shp_item[I_FOOD]); + needed = (int)ceil(food_needed(sp->shp_item, etus)); -/* doit - only steal food from land units during the update */ - if (ifood_eaten > sp->shp_item[I_FOOD] && sp->shp_nland > 0 && doit) { + /* scrounge */ + if (needed > sp->shp_item[I_FOOD]) + sp->shp_item[I_FOOD] += supply_commod(sp->shp_own, + sp->shp_x, sp->shp_y, I_FOOD, + needed - sp->shp_item[I_FOOD]); + if (needed > sp->shp_item[I_FOOD]) { + /* take from embarked land units, but don't starve them */ snxtitem_all(&ni, EF_LAND); - while ((lp = nxtitemp(&ni)) && ifood_eaten > sp->shp_item[I_FOOD]) { + while ((lp = nxtitemp(&ni)) && needed > sp->shp_item[I_FOOD]) { if (lp->lnd_ship != sp->shp_uid) continue; - need = ifood_eaten - sp->shp_item[I_FOOD]; - land_eaten = etus * eatrate * lp->lnd_item[I_MILIT]; - if (lp->lnd_item[I_FOOD] - need > land_eaten) { - sp->shp_item[I_FOOD] += need; - lp->lnd_item[I_FOOD] -= need; - } else if (lp->lnd_item[I_FOOD] - land_eaten > 0) { - sp->shp_item[I_FOOD] += lp->lnd_item[I_FOOD] - land_eaten; - lp->lnd_item[I_FOOD] -= lp->lnd_item[I_FOOD] - land_eaten; - } + give = lp->lnd_item[I_FOOD] - food_needed(lp->lnd_item, etus); + if (give < 1.0) + continue; + take = MIN((int)give, needed - sp->shp_item[I_FOOD]); + sp->shp_item[I_FOOD] += take; + lp->lnd_item[I_FOOD] -= take; } } - if (ifood_eaten > sp->shp_item[I_FOOD]) { - *needed = ifood_eaten - sp->shp_item[I_FOOD]; - can_eat = sp->shp_item[I_FOOD] / (etus * eatrate); - /* only want to starve off at most 1/2 the populace. */ - if (can_eat < total_people / 2) - can_eat = total_people / 2; - - to_starve = total_people - can_eat; - while (to_starve && sp->shp_item[I_UW]) { - to_starve--; - starved++; - sp->shp_item[I_UW]--; - } - while (to_starve && sp->shp_item[I_CIVIL]) { - to_starve--; - starved++; - sp->shp_item[I_CIVIL]--; - } - while (to_starve && sp->shp_item[I_MILIT]) { - to_starve--; - starved++; - sp->shp_item[I_MILIT]--; - } - - sp->shp_item[I_FOOD] = 0; - } else { - sp->shp_item[I_FOOD] -= (int)food_eaten; - } - return starved; + return feed_people(sp->shp_item, etus); }