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