]> git.pond.sub.org Git - empserver/blob - src/lib/commands/prod.c
neweff production: Consider insufficient food
[empserver] / src / lib / commands / prod.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2016, 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 "commands.h"
38 #include "item.h"
39 #include "optlist.h"
40 #include "product.h"
41
42 static void prprod(coord, coord, int, double, double, int, char,
43                    double, double, double, char[], int[], int[], int);
44
45 int
46 count_pop(int n)
47 {
48     int i;
49     int pop = 0;
50     struct sctstr *sp;
51
52     for (i = 0; NULL != (sp = getsectid(i)); i++) {
53         if (sp->sct_own != n)
54             continue;
55         if (sp->sct_oldown != n)
56             continue;
57         pop += sp->sct_item[I_CIVIL];
58     }
59     return pop;
60 }
61
62 int
63 prod(void)
64 {
65     struct natstr *natp;
66     struct sctstr sect;
67     struct nstr_sect nstr;
68     struct pchrstr *pp;
69     double p_e;
70     double maxr;                /* floating version of max */
71     double prodeff;
72     double real;                /* floating pt version of act */
73     int work;
74     int totpop;
75     int material_consume;       /* actual production */
76     double cost;
77     int i;
78     int max_consume;            /* production w/infinite materials */
79     int nsect;
80     double take;
81     double mtake;
82     int there;
83     int unit_work;              /* sum of component amounts */
84     int mat_limit, res_limit;
85     double worker_limit;
86     i_type it;
87     i_type vtype;
88     unsigned char *resource;
89     char cmnem[MAXPRCON];
90     int cuse[MAXPRCON], cmax[MAXPRCON];
91     int lcms, hcms;
92     int bwork;
93     int twork;
94     int type;
95     int eff;
96     char mnem;
97
98     if (!snxtsct(&nstr, player->argp[1]))
99         return RET_SYN;
100     player->simulation = 1;
101     prdate();
102     nsect = 0;
103     while (nxtsct(&nstr, &sect)) {
104         if (!player->owner)
105             continue;
106         if (sect.sct_off)
107             continue;
108
109         natp = getnatp(sect.sct_own);
110         work = do_feed(&sect, natp, etu_per_update, 1);
111         bwork = work / 2;
112
113         type = sect.sct_type;
114         eff = sect.sct_effic;
115         if (sect.sct_newtype != type) {
116             twork = (eff + 3) / 4;
117             if (twork > bwork) {
118                 twork = bwork;
119             }
120             bwork -= twork;
121             eff -= twork * 4;
122             if (eff <= 0) {
123                 type = sect.sct_newtype;
124                 eff = 0;
125             }
126             twork = 100 - eff;
127             if (twork > bwork) {
128                 twork = bwork;
129             }
130             if (dchr[type].d_lcms > 0) {
131                 lcms = sect.sct_item[I_LCM];
132                 lcms /= dchr[type].d_lcms;
133                 if (twork > lcms)
134                     twork = lcms;
135             }
136             if (dchr[type].d_hcms > 0) {
137                 hcms = sect.sct_item[I_HCM];
138                 hcms /= dchr[type].d_hcms;
139                 if (twork > hcms)
140                     twork = hcms;
141             }
142             bwork -= twork;
143             eff += twork;
144         } else if (eff < 100) {
145             twork = 100 - eff;
146             if (twork > bwork) {
147                 twork = bwork;
148             }
149             bwork -= twork;
150             eff += twork;
151         }
152         work = (work + 1) / 2 + bwork;
153         if (eff < 60)
154             continue;
155
156         if (type == SCT_ENLIST) {
157             int maxmil;
158             int enlisted;
159
160             if (sect.sct_own != sect.sct_oldown)
161                 continue;
162             enlisted = 0;
163             maxmil = sect.sct_item[I_CIVIL] / 2 - sect.sct_item[I_MILIT];
164             if (maxmil > 0) {
165                 enlisted = (etu_per_update
166                             * (10 + sect.sct_item[I_MILIT])
167                             * 0.05);
168                 if (enlisted > maxmil)
169                     enlisted = maxmil;
170             }
171             if (enlisted < 0)
172                 enlisted = 0;
173             prprod(sect.sct_x, sect.sct_y, type, eff / 100.0, 1.0, work,
174                    ichr[I_MILIT].i_mnem, enlisted, maxmil, enlisted * 3,
175                    "c\0\0", &enlisted, &enlisted, nsect++);
176             continue;
177         }
178
179         if (dchr[type].d_prd < 0)
180             continue;
181         pp = &pchr[dchr[type].d_prd];
182         vtype = pp->p_type;
183         if (pp->p_nrndx)
184             resource = (unsigned char *)&sect + pp->p_nrndx;
185         else
186             resource = NULL;
187
188         mat_limit = prod_materials_cost(pp, sect.sct_item, &unit_work);
189
190         /* sector p.e. */
191         p_e = eff / 100.0;
192         if (resource) {
193             unit_work++;
194             p_e *= *resource / 100.0;
195         }
196         if (unit_work == 0)
197             unit_work = 1;
198
199         worker_limit = work * p_e / (double)unit_work;
200         res_limit = prod_resource_limit(pp, resource);
201
202         max_consume = res_limit;
203         if (max_consume > worker_limit)
204             max_consume = (int)worker_limit;
205         material_consume = MIN(max_consume, mat_limit);
206
207         prodeff = prod_eff(type, natp->nat_level[pp->p_nlndx]);
208         real = (double)material_consume * prodeff;
209         maxr = (double)max_consume * prodeff;
210
211         if (vtype != I_NONE) {
212             real = MIN(999.0, real);
213             maxr = MIN(999.0, maxr);
214             if (real < 0.0)
215                 real = 0.0;
216             /* production backlog? */
217             there = MIN(ITEM_MAX, sect.sct_item[vtype]);
218             real = MIN(real, ITEM_MAX - there);
219         }
220
221         if (prodeff != 0) {
222             take = real / prodeff;
223             mtake = maxr / prodeff;
224         } else
225             mtake = take = 0.0;
226
227         cost = take * pp->p_cost;
228         if (opt_TECH_POP) {
229             if (pp->p_level == NAT_TLEV) {
230                 totpop = count_pop(sect.sct_own);
231                 if (totpop > 50000)
232                     cost *= totpop / 50000.0;
233             }
234         }
235
236         for (i = 0; i < MAXPRCON; ++i) {
237             cmnem[i] = cuse[i] = cmax[i] = 0;
238             if (!pp->p_camt[i])
239                 continue;
240             it = pp->p_ctype[i];
241             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
242                 continue;
243             cmnem[i] = ichr[it].i_mnem;
244             cuse[i] = (int)(take * pp->p_camt[i] + 0.5);
245             cmax[i] = (int)(mtake * pp->p_camt[i] + 0.5);
246         }
247
248         if (pp->p_type != I_NONE)
249             mnem = ichr[vtype].i_mnem;
250         else if (pp->p_level == NAT_TLEV || pp->p_level == NAT_RLEV)
251             mnem = '.';
252         else
253             mnem = 0;
254         prprod(sect.sct_x, sect.sct_y, type, p_e, prodeff, work,
255                mnem, real, maxr, cost,
256                cmnem, cuse, cmax, nsect++);
257     }
258     player->simulation = 0;
259     if (nsect == 0) {
260         if (player->argp[1])
261             pr("%s: No sector(s)\n", player->argp[1]);
262         else
263             pr("%s: No sector(s)\n", "");
264         return RET_FAIL;
265     } else
266         pr("%d sector%s\n", nsect, splur(nsect));
267     return RET_OK;
268 }
269
270 static void
271 prprod(coord x, coord y, int type, double p_e, double prodeff, int work,
272        char mnem, double make, double max, double cost,
273        char cmnem[], int cuse[], int cmax[], int nsect)
274 {
275     int i;
276
277     if (nsect == 0) {
278         pr("PRODUCTION SIMULATION\n");
279         pr("   sect  des eff avail  make p.e. cost   use1 use2 use3  max1 max2 max3   max\n");
280     }
281
282     prxy("%4d,%-4d", x, y);
283     pr(" %c %3.0f%% %5d", dchr[type].d_mnem, p_e * 100.0, work);
284     if (mnem == '.')
285         pr(" %5.2f", make);
286     else
287         pr(" %4.0f%c", make, mnem ? mnem : ' ');
288     pr(" %.2f $%-5.0f", prodeff, cost);
289     for (i = 0; i < 3; i++) {
290         if (i < MAXPRCON && cmnem[i])
291             pr("%4d%c", cuse[i], cmnem[i]);
292         else
293             pr("     ");
294     }
295     pr(" ");
296     for (i = 0; i < 3; i++) {
297         if (i < MAXPRCON && cmnem[i])
298             pr("%4d%c", cmax[i], cmnem[i]);
299         else
300             pr("     ");
301     }
302     if (mnem == '.')
303         pr(" %5.2f\n", max);
304     else
305         pr(" %5.0f\n", max);
306 }