]> git.pond.sub.org Git - empserver/blob - src/lib/commands/prod.c
commands: Rename the command functions
[empserver] / src / lib / commands / prod.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire 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 3 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, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  prod.c: Calculate production levels
28  *
29  *  Known contributors to this file:
30  *     David Muir Sharnoff, 1987
31  *     Steve McClure, 1997-2000
32  *     Markus Armbruster, 2004-2016
33  */
34
35 #include <config.h>
36
37 #include <math.h>
38 #include "commands.h"
39 #include "item.h"
40 #include "land.h"
41 #include "optlist.h"
42 #include "product.h"
43 #include "ship.h"
44 #include "update.h"
45
46 static void prprod(struct sctstr *, double, double, char,
47                    double, double, double, char[], int[], int[], int);
48
49 static int
50 count_pop(void)
51 {
52     /* FIXME don't duplicate the update's workings, use its code */
53     int i;
54     int pop = 0;
55     struct sctstr *sectp;
56     struct shpstr *sp;
57     struct lndstr *lp;
58
59     for (i = 0; (sectp = getsectid(i)); i++) {
60         if (sectp->sct_own == player->cnum) {
61             if (sectp->sct_own == sectp->sct_oldown)
62                 pop += sectp->sct_item[I_CIVIL];
63         }
64     }
65
66     for (i = 0; (sp = getshipp(i)); i++) {
67         if (sp->shp_own == player->cnum)
68             pop += sp->shp_item[I_CIVIL];
69     }
70
71     for (i = 0; (lp = getlandp(i)); i++) {
72         if (lp->lnd_own == player->cnum)
73             pop += lp->lnd_item[I_CIVIL];
74     }
75
76     return pop;
77 }
78
79 int
80 c_production(void)
81 {
82     struct natstr *natp;
83     struct sctstr sect, scratch_sect;
84     struct nstr_sect nstr;
85     struct pchrstr *pp;
86     double p_e;
87     double prodeff;
88     int totpop = -1;
89     double cost;
90     int i;
91     int nsect;
92     double real, maxr;
93     double take, mtake;
94     i_type it;
95     unsigned char *resource;
96     char cmnem[MAXPRCON];
97     int cuse[MAXPRCON], cmax[MAXPRCON];
98     char mnem;
99
100     if (!snxtsct(&nstr, player->argp[1]))
101         return RET_SYN;
102     player->simulation = 1;
103     prdate();
104     nsect = 0;
105     while (nxtsct(&nstr, &sect)) {
106         if (!player->owner)
107             continue;
108         if (sect.sct_off)
109             continue;
110
111         natp = getnatp(sect.sct_own);
112         do_feed(&sect, natp, etu_per_update, 1);
113         buildeff(&sect);
114         if (sect.sct_effic < 60)
115             continue;
116
117         if (sect.sct_type == SCT_ENLIST) {
118             int maxmil;
119             int enlisted;
120
121             if (sect.sct_own != sect.sct_oldown)
122                 continue;
123             enlisted = 0;
124             maxmil = sect.sct_item[I_CIVIL] / 2 - sect.sct_item[I_MILIT];
125             if (maxmil > 0) {
126                 enlisted = (etu_per_update
127                             * (10 + sect.sct_item[I_MILIT])
128                             * 0.05);
129                 if (enlisted > maxmil)
130                     enlisted = maxmil;
131             }
132             if (enlisted < 0)
133                 enlisted = 0;
134             prprod(&sect, sect.sct_effic / 100.0, 1.0,
135                    ichr[I_MILIT].i_mnem, enlisted, maxmil, enlisted * 3,
136                    "c\0\0", &enlisted, &enlisted, nsect++);
137             continue;
138         }
139
140         if (dchr[sect.sct_type].d_prd < 0)
141             continue;
142         pp = &pchr[dchr[sect.sct_type].d_prd];
143         if (pp->p_nrndx)
144             resource = (unsigned char *)&sect + pp->p_nrndx;
145         else
146             resource = NULL;
147
148         /* sector p.e. */
149         p_e = sect.sct_effic / 100.0;
150         if (resource)
151             p_e *= *resource / 100.0;
152
153         prodeff = prod_eff(sect.sct_type, natp->nat_level[pp->p_nlndx]);
154
155         scratch_sect = sect;
156         real = prod_output(&scratch_sect, prodeff);
157
158         scratch_sect = sect;
159         for (i = 0; i < MAXPRCON; ++i)
160             scratch_sect.sct_item[pp->p_ctype[i]] = ITEM_MAX;
161         scratch_sect.sct_item[pp->p_type] = 0;
162         maxr = prod_output(&scratch_sect, prodeff);
163
164         if (prodeff != 0) {
165             take = real / prodeff;
166             mtake = maxr / prodeff;
167         } else
168             mtake = take = 0.0;
169
170         cost = take * pp->p_cost;
171         if (opt_TECH_POP) {
172             if (pp->p_level == NAT_TLEV) {
173                 if (totpop < 0)
174                     totpop = count_pop();
175                 if (totpop > 50000)
176                     cost *= totpop / 50000.0;
177             }
178         }
179
180         for (i = 0; i < MAXPRCON; ++i) {
181             cmnem[i] = cuse[i] = cmax[i] = 0;
182             if (!pp->p_camt[i])
183                 continue;
184             it = pp->p_ctype[i];
185             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
186                 continue;
187             cmnem[i] = ichr[it].i_mnem;
188             cuse[i] = (int)ceil(take * pp->p_camt[i]);
189             cmax[i] = (int)ceil(mtake * pp->p_camt[i]);
190         }
191
192         if (pp->p_type != I_NONE)
193             mnem = ichr[pp->p_type].i_mnem;
194         else if (pp->p_level == NAT_TLEV || pp->p_level == NAT_RLEV)
195             mnem = '.';
196         else
197             mnem = 0;
198         prprod(&sect, p_e, prodeff, mnem, real, maxr, cost,
199                cmnem, cuse, cmax, nsect++);
200     }
201     player->simulation = 0;
202     if (nsect == 0) {
203         if (player->argp[1])
204             pr("%s: No sector(s)\n", player->argp[1]);
205         else
206             pr("%s: No sector(s)\n", "");
207         return RET_FAIL;
208     } else
209         pr("%d sector%s\n", nsect, splur(nsect));
210     return RET_OK;
211 }
212
213 static void
214 prprod(struct sctstr *sp, double p_e, double prodeff,
215        char mnem, double make, double max, double cost,
216        char cmnem[], int cuse[], int cmax[], int nsect)
217 {
218     int i;
219
220     if (nsect == 0) {
221         pr("PRODUCTION SIMULATION\n");
222         pr("   sect  des eff avail  make p.e. cost   use1 use2 use3  max1 max2 max3   max\n");
223     }
224
225     prxy("%4d,%-4d", sp->sct_x, sp->sct_y);
226     pr(" %c %3.0f%% %5d",
227        dchr[sp->sct_type].d_mnem, p_e * 100.0, sp->sct_avail);
228     if (mnem == '.')
229         pr(" %5.2f", make);
230     else
231         pr(" %4.0f%c", make, mnem ? mnem : ' ');
232     pr(" %.2f $%-5.0f", prodeff, cost);
233     for (i = 0; i < 3; i++) {
234         if (i < MAXPRCON && cmnem[i])
235             pr("%4d%c", cuse[i], cmnem[i]);
236         else
237             pr("     ");
238     }
239     pr(" ");
240     for (i = 0; i < 3; i++) {
241         if (i < MAXPRCON && cmnem[i])
242             pr("%4d%c", cmax[i], cmnem[i]);
243         else
244             pr("     ");
245     }
246     if (mnem == '.')
247         pr(" %5.2f\n", max);
248     else
249         pr(" %5.0f\n", max);
250 }