]> git.pond.sub.org Git - empserver/blob - src/lib/commands/budg.c
Remove a bunch of redundant casts.
[empserver] / src / lib / commands / budg.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2005, 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  *  budg.c: Calculate production levels, prioritize
29  * 
30  *  Known contributors to this file:
31  *     Thomas Ruschak, 1992
32  *     Ville Virrankoski, 1995
33  *     Steve McClure, 1997-2000
34  */
35
36 #include <string.h>
37 #include "misc.h"
38 #include "player.h"
39 #include "xy.h"
40 #include "nsc.h"
41 #include "sect.h"
42 #include "product.h"
43 #include "nat.h"
44 #include "item.h"
45 #include "file.h"
46 #include "ship.h"
47 #include "land.h"
48 #include "plane.h"
49 #include "optlist.h"
50 #include "budg.h"
51 #include "commands.h"
52
53 static void calc_all(long int (*p_sect)[2], int *taxes, int *Ncivs,
54                      int *Nuws, int *bars, int *Nbars, int *mil,
55                      int *ships, int *sbuild, int *nsbuild, int *smaint,
56                      int *units, int *lbuild, int *nlbuild, int *lmaint,
57                      int *planes, int *pbuild, int *npbuild, int *pmaint);
58 static int change_prio(struct natstr *np, char code, char *newval);
59 static char *dotsprintf(char *buf, char *format, int data);
60 static void prexpense(long int cash, int *expensesp, int priority, int amount);
61
62 int
63 budg(void)
64 {
65     int i, res;
66     long p_sect[SCT_MAXDEF+1][2];
67     int taxes, Ncivs, Nuws, bars, Nbars, mil;
68     int ships, sbuild, nsbuild, smaint;
69     int units, lbuild, nlbuild, lmaint;
70     int planes, pbuild, npbuild, pmaint;
71     int n, etu;
72     int income, expenses;
73     struct natstr *np;
74     char buf[1024];
75     char in[80];
76
77     etu = etu_per_update;
78
79     np = getnatp(player->cnum);
80     if (player->argp[1]) {
81         res = change_prio(np, player->argp[1][0], player->argp[2]);
82         if (res != RET_OK) {
83             putnat(np);
84             return res;
85         }
86     }
87
88     player->simulation = 1;
89     calc_all(p_sect,
90              &taxes, &Ncivs, &Nuws, &bars, &Nbars, &mil,
91              &ships, &sbuild, &nsbuild, &smaint,
92              &units, &lbuild, &nlbuild, &lmaint,
93              &planes, &pbuild, &npbuild, &pmaint);
94
95     income = taxes + bars;
96     expenses = 0;
97     pr("Sector Type\t\tAbbr\tProduction\tPriority\t    Cost\n");
98     for (i = 0; i <= SCT_MAXDEF; i++) {
99         if (!p_sect[i][1] && np->nat_priorities[i] == -1)
100             continue;
101         if (!pchr[dchr[i].d_prd].p_cost &&
102             np->nat_priorities[i] == -1 && i != SCT_ENLIST)
103             continue;
104
105         pr("%-17s\t%c\t", dchr[i].d_name, dchr[i].d_mnem);
106         if (i == SCT_ENLIST)
107             pr("%ld mil    \t", p_sect[i][0]);
108         else if (pchr[dchr[i].d_prd].p_cost != 0)
109             pr("%ld %-7s\t", p_sect[i][0], pchr[dchr[i].d_prd].p_sname);
110         else
111             pr("\t\t");
112
113         if (np->nat_priorities[i] != -1)
114             pr("%d", np->nat_priorities[i]);
115         prexpense(np->nat_money + income, &expenses,
116                   np->nat_priorities[i], p_sect[i][1]);
117     }
118
119     if (lbuild) {
120         sprintf(buf, "%d unit%s", nlbuild, splur(nlbuild));
121         pr("Unit building\t\tL\t%-16s", buf);
122         if (np->nat_priorities[PRI_LBUILD] != -1)
123             pr("%d", np->nat_priorities[PRI_LBUILD]);
124         prexpense(np->nat_money + income, &expenses,
125                   np->nat_priorities[PRI_LBUILD], -1 * lbuild);
126     }
127
128     if (lmaint) {
129         sprintf(buf, "%d unit%s", units, splur(units));
130         pr("Unit maintenance\tA\t%-16s", buf);
131         if (np->nat_priorities[PRI_LMAINT] != -1)
132             pr("%d", np->nat_priorities[PRI_LMAINT]);
133         prexpense(np->nat_money + income, &expenses,
134                   np->nat_priorities[PRI_LMAINT], -1 * lmaint);
135     }
136
137     if (sbuild) {
138         sprintf(buf, "%d ship%s", nsbuild, splur(nsbuild));
139         pr("Ship building\t\tS\t%-16s", buf);
140         if (np->nat_priorities[PRI_SBUILD] != -1)
141             pr("%d", np->nat_priorities[PRI_SBUILD]);
142         prexpense(np->nat_money + income, &expenses,
143                   np->nat_priorities[PRI_SBUILD], -1 * sbuild);
144     }
145
146     if (smaint) {
147         sprintf(buf, "%d ship%s", ships, splur(ships));
148         pr("Ship maintenance\tM\t%-16s", buf);
149         if (np->nat_priorities[PRI_SMAINT] != -1)
150             pr("%d", np->nat_priorities[PRI_SMAINT]);
151         prexpense(np->nat_money + income, &expenses,
152                   np->nat_priorities[PRI_SMAINT], -1 * smaint);
153     }
154
155     if (pbuild) {
156         sprintf(buf, "%d plane%s", npbuild, splur(npbuild));
157         pr("Plane building\t\tP\t%-16s", buf);
158         if (np->nat_priorities[PRI_PBUILD] != -1)
159             pr("%d", np->nat_priorities[PRI_PBUILD]);
160         prexpense(np->nat_money + income, &expenses,
161                   np->nat_priorities[PRI_PBUILD], -1 * pbuild);
162     }
163
164     if (pmaint) {
165         sprintf(buf, "%d plane%s", planes, splur(planes));
166         pr("Plane maintenance\tN\t%-16s", buf);
167         if (np->nat_priorities[PRI_PMAINT] != -1)
168             pr("%d", np->nat_priorities[PRI_PMAINT]);
169         prexpense(np->nat_money + income, &expenses,
170                   np->nat_priorities[PRI_PMAINT], -1 * pmaint);
171     }
172     if (p_sect[SCT_EFFIC][1]) {
173         pr("Sector building\t\t\t\t%8ld sct(s)\t\t%8ld\n",
174            p_sect[SCT_EFFIC][0], p_sect[SCT_EFFIC][1]);
175         expenses += p_sect[SCT_EFFIC][1];
176     }
177     if (mil) {
178         n = (mil - np->nat_reserve * money_res * etu) / (etu * money_mil);
179         sprintf(in, "%d mil, %d res", n, (int)np->nat_reserve);
180         pr("Military payroll\t\t%-32s%8d\n", in, -mil);
181         expenses -= mil;
182     }
183     if (p_sect[SCT_CAPIT][0]) {
184         n = p_sect[SCT_CAPIT][0];
185         sprintf(in, "%d %s%s",
186                 n,
187                 opt_BIG_CITY ? "cit" : "capital",
188                 opt_BIG_CITY ? iesplur(n) : splur(n));
189         pr("%s maintenance\t\t%-32s%8ld\n",
190            opt_BIG_CITY ? "City" : "Capital", in, p_sect[SCT_CAPIT][1]);
191         expenses += p_sect[SCT_CAPIT][1];
192     }
193     pr("Total expenses%s\n", dotsprintf(buf, "%58d", expenses));
194     if (taxes) {
195         sprintf(in, "%d civ%s, %d uw%s",
196                 Ncivs, splur(Ncivs), Nuws, splur(Nuws));
197         pr("Income from taxes\t\t%-32s%+8d\n", in, taxes);
198     }
199     if (bars) {
200         sprintf(in, "%d bar%s", Nbars, splur(Nbars));
201         pr("Income from bars\t\t%-32s%+8d\n", in, bars);
202     }
203     pr("Total income%s\n", dotsprintf(buf, "%+60d", income));
204     pr("Balance forward\t\t\t\t\t\t      %10ld\n", np->nat_money);
205     pr("Estimated delta\t\t\t\t\t\t      %+10d\n", income - expenses);
206     pr("Estimated new treasury%s\n",
207        dotsprintf(buf, "%50d", np->nat_money + income - expenses));
208     if (((np->nat_money + income - expenses) < 0) && !player->god) {
209         pr("After processsing sectors, you will be broke!\n");
210         pr("Sectors will not produce, distribute, or deliver!\n\n");
211     }
212
213     player->simulation = 0;
214     return RET_OK;
215 }
216
217 static void
218 calc_all(long p_sect[][2],
219          int *taxes, int *Ncivs, int *Nuws, int *bars, int *Nbars, int *mil,
220          int *ships, int *sbuild, int *nsbuild, int *smaint,
221          int *units, int *lbuild, int *nlbuild, int *lmaint,
222          int *planes, int *pbuild, int *npbuild, int *pmaint)
223 {
224     int y, z;
225     struct natstr *np;
226     int sm = 0, sb = 0, pm = 0, pb = 0, lm = 0, lb = 0;
227     int *bp;
228     long pop = 0;
229     int n, civ_tax, uw_tax, mil_pay;
230     struct sctstr *sp;
231     int etu = etu_per_update;
232     long tmp_money;
233
234     lnd_money[player->cnum] = sea_money[player->cnum] = 0;
235     air_money[player->cnum] = 0;
236     mil_dbl_pay = 0;
237     memset(p_sect, 0, sizeof(**p_sect) * (SCT_MAXDEF+1) * 2);
238     *taxes = *Ncivs = *Nuws = *bars = *Nbars = *mil = 0;
239     *ships = *sbuild = *nsbuild = *smaint = 0;
240     *units = *lbuild = *nlbuild = *lmaint = 0;
241     *planes = *pbuild = *npbuild = *pmaint = 0;
242     
243     np = getnatp(player->cnum);
244     bp = calloc(WORLD_X * WORLD_Y * 8, sizeof(int));
245     for (n = 0; NULL != (sp = getsectid(n)); n++) {
246         fill_update_array(bp, sp);
247         if (sp->sct_own == player->cnum) {
248             sp->sct_updated = 0;
249             tax(sp, np, etu, &pop, &civ_tax, &uw_tax, &mil_pay);
250             *Ncivs += sp->sct_item[I_CIVIL];
251             *Nuws += sp->sct_item[I_UW];
252             *taxes += civ_tax + uw_tax;
253             *mil += mil_pay;
254             if (sp->sct_type == SCT_BANK) {
255                 *bars += bank_income(sp, etu);
256                 *Nbars += sp->sct_item[I_BAR];
257             }
258         }
259     }
260     tpops[player->cnum] = pop;
261     *mil += (int)(np->nat_reserve * money_res * etu);
262
263     *mil += (int)upd_slmilcosts(np->nat_cnum, etu);
264
265     for (y = 1; y <= PRI_MAX; y++) {
266         for (z = 0; z <= PRI_MAX; z++)
267             if (np->nat_priorities[z] == y)
268                 switch (z) {
269                 case PRI_SMAINT:
270                     tmp_money = lnd_money[player->cnum];
271                     *ships = prod_ship(etu, player->cnum, bp, 0);
272                     *smaint = lnd_money[player->cnum] - tmp_money;
273                     sm = 1;
274                     break;
275                 case PRI_SBUILD:
276                     tmp_money = sea_money[player->cnum];
277                     *nsbuild = prod_ship(etu, player->cnum, bp, 1);
278                     *sbuild = sea_money[player->cnum] - tmp_money;
279                     sb = 1;
280                     break;
281                 case PRI_LMAINT:
282                     tmp_money = lnd_money[player->cnum];
283                     *units = prod_land(etu, player->cnum, bp, 0);
284                     *lmaint = lnd_money[player->cnum] - tmp_money;
285                     lm = 1;
286                     break;
287                 case PRI_LBUILD:
288                     tmp_money = lnd_money[player->cnum];
289                     *nlbuild = prod_land(etu, player->cnum, bp, 1);
290                     *lbuild = lnd_money[player->cnum] - tmp_money;
291                     lb = 1;
292                     break;
293                 case PRI_PMAINT:
294                     tmp_money = air_money[player->cnum];
295                     *planes = prod_plane(etu, player->cnum, bp, 0);
296                     *pmaint = air_money[player->cnum] - tmp_money;
297                     pm = 1;
298                     break;
299                 case PRI_PBUILD:
300                     tmp_money = air_money[player->cnum];
301                     *npbuild = prod_plane(etu, player->cnum, bp, 1);
302                     *pbuild = air_money[player->cnum] - tmp_money;
303                     pb = 1;
304                     break;
305                 default:
306                     produce_sect(player->cnum, etu, bp, p_sect, z);
307                     break;
308                 }
309     }
310     /* 0 is maintain, 1 is build */
311     if (!sm) {
312         tmp_money = sea_money[player->cnum];
313         *ships = prod_ship(etu, player->cnum, bp, 0);
314         *smaint = sea_money[player->cnum] - tmp_money;
315     }
316     if (!sb) {
317         tmp_money = sea_money[player->cnum];
318         *nsbuild = prod_ship(etu, player->cnum, bp, 1);
319         *sbuild = sea_money[player->cnum] - tmp_money;
320     }
321     if (!lm) {
322         tmp_money = lnd_money[player->cnum];
323         *units = prod_land(etu, player->cnum, bp, 0);
324         *lmaint = lnd_money[player->cnum] - tmp_money;
325     }
326     if (!lb) {
327         tmp_money = lnd_money[player->cnum];
328         *nlbuild = prod_land(etu, player->cnum, bp, 1);
329         *lbuild = lnd_money[player->cnum] - tmp_money;
330     }
331     if (!pm) {
332         tmp_money = air_money[player->cnum];
333         *planes = prod_plane(etu, player->cnum, bp, 0);
334         *pmaint = air_money[player->cnum] - tmp_money;
335     }
336     if (!pb) {
337         tmp_money = air_money[player->cnum];
338         *npbuild = prod_plane(etu, player->cnum, bp, 1);
339         *pbuild = air_money[player->cnum] - tmp_money;
340     }
341
342     /* produce all sects that haven't produced yet */
343     produce_sect(player->cnum, etu, bp, p_sect, -1);
344
345     lnd_money[player->cnum] = sea_money[player->cnum] = 0;
346     air_money[player->cnum] = 0;
347     free(bp);
348 }
349
350 static int
351 change_prio(struct natstr *np, char code, char *newval)
352 {
353     int idx, i, prio;
354     char *p;
355     char buf[1024];
356
357     switch (code) {
358     case 'P':
359         idx = PRI_PBUILD;
360         break;
361     case 'S':
362         idx = PRI_SBUILD;
363         break;
364     case 'L':
365         idx = PRI_LBUILD;
366         break;
367     case 'A':
368         idx = PRI_LMAINT;
369         break;
370     case 'M':
371         idx = PRI_SMAINT;
372         break;
373     case 'N':
374         idx = PRI_PMAINT;
375         break;
376     case 'C':
377         for (i = 0; i <= PRI_MAX; ++i)
378             np->nat_priorities[i] = -1;
379         return RET_OK;
380     default:
381         idx = sct_typematch(player->argp[1]);
382         if (idx < 0 || idx == SCT_CAPIT)
383             return RET_SYN;
384     }
385
386     if (!(p = getstarg(newval, "Priority? ", buf)))
387         return RET_SYN;
388     if (isdigit(p[0])) {
389         prio = atoi(p);
390         if (prio < 0 || PRI_MAX < prio) {
391             pr("Priorities must be between 0 and %d!\n", PRI_MAX);
392             return RET_FAIL;
393         }
394         for (i = 0; i <= PRI_MAX; i++) {
395             if (i != idx && prio && np->nat_priorities[i] == prio) {
396                 pr("Priorities must be unique!\n");
397                 return RET_FAIL;
398             }
399         }
400     } else if (p[0] == '~')
401         prio = -1;
402     else
403         return RET_SYN;
404
405     np->nat_priorities[idx] = prio;
406
407     return RET_OK;
408 }
409
410
411 static char *
412 dotsprintf(char *buf, char *format, int data)
413 {
414     sprintf(buf, format, data);
415     return memset(buf, '.', strspn(buf, " "));
416 }
417
418 static void
419 prexpense(long int cash, int *expensesp, int priority, int amount)
420 {
421     if (cash > *expensesp) {
422         if (priority) {
423             pr("\t\t%8d\n", amount);
424             *expensesp += amount;
425         } else
426             pr("\t\t(%7d)\n", amount);
427     } else {
428         if (priority) {
429             pr("\t\t[%7d]\n", amount);
430             *expensesp += amount;
431         } else
432             pr("\t\t[(%6d)]\n", amount);
433     }
434 }