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