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