]> git.pond.sub.org Git - empserver/blob - src/lib/update/human.c
Indented with src/scripts/indent-emp.
[empserver] / src / lib / update / human.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  human.c: Food related functions
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1996
33  */
34
35 #include <math.h>
36 #include "misc.h"
37 #include "var.h"
38 #include "sect.h"
39 #include "nat.h"
40 #include "item.h"
41 #include "news.h"
42 #include "file.h"
43 #include "xy.h"
44 #include "optlist.h"
45 #include "budg.h"
46 #include "player.h"
47 #include "update.h"
48 #include "common.h"
49 #include "gen.h"
50 #include "subs.h"
51
52 /*
53  * feed the individual sector
54  *
55  */
56 int
57 do_feed(register struct sctstr *sp, register struct natstr *np, int *vec,
58         int *workp, int *bp, int etu)
59 {
60     extern double eatrate;
61     int people;
62     int work_avail;
63     int starved, sctwork;
64     int needed, dummy;
65     int civvies, uws;
66     int mil;
67     int maxpop;
68
69     /* grow people & stuff */
70     sctwork = sp->sct_work;
71
72     maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
73     civvies = (vec[I_CIVIL] > maxpop) ? maxpop : vec[I_CIVIL];
74     uws = (vec[I_UW] > maxpop) ? maxpop : vec[I_UW];
75     mil = (vec[I_MILIT] > maxpop) ? maxpop : vec[I_MILIT];
76     work_avail = total_work(sctwork, etu, civvies, mil, uws);
77
78     people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
79     if (sp->sct_type != SCT_SANCT) {
80         if (opt_NOFOOD == 0) {
81             if (vec[I_FOOD] < 1 + etu * people * eatrate) {
82                 /* need to grow "emergency rations" */
83                 work_avail -= (2 *
84                                growfood(sp, vec, (int)(work_avail / 2),
85                                         etu));
86                 /* It's twice as hard to grow those than norm */
87                 pt_bg_nmbr(bp, sp, I_MAX + 1, work_avail);
88                 if (!player->simulation)
89                     sp->sct_avail = work_avail;
90             }
91             if ((vec[I_FOOD] < 1 + etu * people * eatrate) &&
92                 (sp->sct_own == sp->sct_oldown)) {
93
94                 /* steal food from warehouses, headquarters,
95                    supply ships in port, or supply units */
96                 int needed;
97
98                 needed = ldround((double)(1 + etu * people * eatrate), 1);
99
100                 /* Now, find some food */
101                 vec[I_FOOD] = supply_commod(sp->sct_own, sp->sct_x,
102                                             sp->sct_y, I_FOOD, needed);
103
104             }
105         }
106         starved = feed_people(vec, etu, &needed);
107         if ((starved > 0 && sp->sct_own) && (!player->simulation)) {
108             /* don't report POGO starvation */
109             wu(0, sp->sct_own, "%d starved in %s.\n", starved,
110                xyas(sp->sct_x, sp->sct_y, sp->sct_own));
111             if (starved > 25)
112                 nreport(sp->sct_own, N_DIE_FAMINE, 0, 1);
113         }
114         if (starved > 0) {
115             if (!player->simulation)
116                 starvation(sp);
117             sctwork = 0;
118         } else {
119             if (sp->sct_work < 100)
120                 sctwork = sp->sct_work + 8 + (random() % 15);
121             if (sctwork > 100)
122                 sctwork = 100;
123             if (!player->simulation)
124                 sp->sct_work = sctwork;
125             dummy = grow_people(sp, etu, np, &work_avail, sctwork, vec);
126         }
127     } else
128         sctwork = sp->sct_work = 100;
129     /* Here is where we truncate extra people, always */
130     trunc_people(sp, np, vec);
131
132     pt_bg_nmbr(bp, sp, I_CIVIL, vec[I_CIVIL]);
133     pt_bg_nmbr(bp, sp, I_UW, vec[I_UW]);
134     pt_bg_nmbr(bp, sp, I_MILIT, vec[I_MILIT]);
135     *workp = work_avail;
136     return sctwork;
137 }
138
139 int
140 growfood(struct sctstr *sp, register int *vec, int work, int etu)
141 {
142     extern double fgrate;
143     extern double fcrate;
144     double food_fertil;
145     double food_workers;
146     double food;
147     int work_used;
148
149     /* I'm being very nice and commenting out this so players
150      * won't whine about starvation
151      if (sp->sct_fertil == 0 || work == 0)
152      return 0;
153      */
154     food_workers = work * fcrate;
155     food_fertil = etu * sp->sct_fertil * fgrate;
156     food = food_fertil;
157     if (food > food_workers)
158         food = food_workers;
159     /*
160      * be nice; grow minimum one food unit.
161      * This makes life simpler for the player.
162      */
163     vec[I_FOOD] += (int)food;
164     if (vec[I_FOOD] == 0)
165         vec[I_FOOD] = 1;
166     if (vec[I_FOOD] > 9999)
167         vec[I_FOOD] = 9999;
168     work_used = (int)food / fcrate;
169     return work_used;
170 }
171
172 /*
173  * returns the number who starved, if any.
174  */
175 int
176 feed_people(register int *vec, int etu, int *needed)
177 {
178     extern double eatrate;
179     double food_eaten;
180     double people_left;
181     int can_eat;
182     int total_people;
183     int to_starve;
184     int starved;
185
186     if (opt_NOFOOD)
187         return 0;
188     food_eaten = (double)(((double)etu * (double)eatrate) *
189                           (double)(vec[I_CIVIL] + vec[I_MILIT] +
190                                    vec[I_UW]));
191     if (food_eaten <= 1)
192         return 0;
193     starved = 0;
194     *needed = 0;
195     if (food_eaten > vec[I_FOOD]) {
196         *needed = food_eaten - vec[I_FOOD];
197         if ((double)(*needed) < (double)(food_eaten - (double)vec[I_FOOD]))
198             (*needed)++;
199         if (opt_NEW_STARVE) {
200             can_eat = (vec[I_FOOD] / (etu * eatrate));
201             total_people = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
202
203             /* only want to starve off at most 1/2 the populace. */
204             if (can_eat < (total_people / 2))
205                 can_eat = total_people / 2;
206
207             to_starve = total_people - can_eat;
208             while (to_starve && vec[I_UW]) {
209                 to_starve--;
210                 starved++;
211                 vec[I_UW]--;
212             }
213             while (to_starve && vec[I_CIVIL]) {
214                 to_starve--;
215                 starved++;
216                 vec[I_CIVIL]--;
217             }
218             while (to_starve && vec[I_MILIT]) {
219                 to_starve--;
220                 starved++;
221                 vec[I_MILIT]--;
222             }
223
224             vec[I_FOOD] = 0;
225         } else {                /* ! opt_NEW_STARVE */
226
227             people_left = (vec[I_FOOD] + 0.01) / (food_eaten + 0.01);
228             starved = vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
229             /* only want to starve off at most 1/2 the populace. */
230             if (people_left < 0.5)
231                 people_left = 0.5;
232             vec[I_CIVIL] = (int)(vec[I_CIVIL] * people_left);
233             vec[I_MILIT] = (int)(vec[I_MILIT] * people_left);
234             vec[I_UW] = (int)(vec[I_UW] * people_left);
235             starved -= vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW];
236             vec[I_FOOD] = 0;
237         }                       /* end opt_NEW_STARVE */
238     } else {
239         vec[I_FOOD] -= roundavg(food_eaten);
240     }
241     return starved;
242 }
243
244 /*
245  * Truncate any extra people that may be around
246  */
247 void
248 trunc_people(struct sctstr *sp, register struct natstr *np,
249              register int *vec)
250 {
251     int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
252
253     if (vec[I_CIVIL] > maxpop)
254         vec[I_CIVIL] = maxpop;
255     if (vec[I_UW] > maxpop)
256         vec[I_UW] = maxpop;
257 }
258
259 /*
260  * Grow babies, and add to populace.
261  * XXX Might think about dropping in a birth
262  * rate limitation on countries with high tech
263  * production?  Maybe with just high education?
264  */
265 int
266 grow_people(struct sctstr *sp, register int etu,
267             register struct natstr *np, int *workp, int sctwork,
268             register int *vec)
269 {
270     extern double obrate;
271     extern double uwbrate;
272     extern double babyeat;
273     int newciv;
274     int newuw;
275     int new_birth;
276     int new_food;
277     int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
278
279     newciv = 0;
280     newuw = 0;
281     if (vec[I_CIVIL] < maxpop) {
282         new_birth = (int)roundavg(obrate * (double)(etu * vec[I_CIVIL]));
283         if (opt_NOFOOD)
284             new_food = (int)(0.5 + maxpop / (2.0 * babyeat));
285         else                    /* we are using food */
286             new_food = (int)(0.5 + vec[I_FOOD] / (2.0 * babyeat));
287
288         newciv = new_birth;
289         if (newciv > new_food)
290             newciv = new_food;
291         /* Now, check max pops */
292         if ((vec[I_CIVIL] + newciv) > maxpop)
293             newciv = maxpop - vec[I_CIVIL];
294         vec[I_CIVIL] += newciv;
295     }
296     if (vec[I_UW] < maxpop) {
297         /*
298          * now grow uw's
299          */
300         new_birth = (int)roundavg(uwbrate * (double)(etu * vec[I_UW]));
301         if (opt_NOFOOD)
302             new_food = (int)(0.5 + maxpop / (2.0 * babyeat));
303         else                    /* food is important */
304             new_food = (int)(0.5 + vec[I_FOOD] / (2.0 * babyeat));
305
306         newuw = new_birth;
307         if (newuw > new_food)
308             newuw = new_food;
309         /* Now, check max pops */
310         if ((vec[I_UW] + newuw) > maxpop)
311             newuw = maxpop - vec[I_UW];
312         vec[I_UW] += newuw;
313     }
314     /*
315      * subtract the baby eat food (if we are using FOOD) and return
316      * # of births.
317      */
318     if (opt_NOFOOD == 0 && (newciv || newuw))
319         vec[I_FOOD] -= roundavg((newciv + newuw) * babyeat);
320     *workp += total_work(sctwork, etu, newciv, 0, newuw);
321     return newciv + newuw;
322 }
323
324 /*
325  * percentage of people who starved
326  */
327 void
328 starvation(struct sctstr *sp)
329 {
330     sp->sct_work = 0;
331     sp->sct_loyal += (random() % 8) + 2;
332 }