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