]> git.pond.sub.org Git - empserver/blob - src/lib/commands/prod.c
(prod, prprod): Fix to show the designation that actually produces,
[empserver] / src / lib / commands / prod.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 files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  prod.c: Calculate production levels
29  * 
30  *  Known contributors to this file:
31  *     David Muir Sharnoff, 1987
32  *     Steve McClure, 1997-2000
33  *     Markus Armbruster, 2004-2006
34  */
35
36 #include <config.h>
37
38 #include "misc.h"
39 #include "player.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 "optlist.h"
48 #include "commands.h"
49
50 static void prprod(coord, coord, int, double, double, int, char,
51                    double, double, double, char[], int[], int[], int);
52
53 int
54 count_pop(int n)
55 {
56     int i;
57     int pop = 0;
58     struct sctstr *sp;
59
60     for (i = 0; NULL != (sp = getsectid(i)); i++) {
61         if (sp->sct_own != n)
62             continue;
63         if (sp->sct_oldown != n)
64             continue;
65         pop += sp->sct_item[I_CIVIL];
66     }
67     return pop;
68 }
69
70 int
71 prod(void)
72 {
73     struct natstr *natp;
74     struct sctstr sect;
75     struct nstr_sect nstr;
76     struct pchrstr *pp;
77     double p_e;
78     double maxr;                /* floating version of max */
79     double prodeff;
80     double real;                /* floating pt version of act */
81     int work;
82     int totpop;
83     int act;                    /* actual production */
84     double cost;
85     int i;
86     int max;                    /* production w/infinite materials */
87     int nsect;
88     double take;
89     double mtake;
90     int there;
91     int unit_work;              /* sum of component amounts */
92     int used;                   /* production w/infinite workforce */
93     i_type it;
94     i_type vtype;
95     unsigned char *resource;
96     char cmnem[MAXPRCON];
97     int cuse[MAXPRCON], cmax[MAXPRCON];
98     int lcms, hcms;
99     int civs;
100     int uws;
101     int bwork;
102     int twork;
103     int type;
104     int eff;
105     int maxpop;
106     int otype;
107     char mnem;
108
109     if (!snxtsct(&nstr, player->argp[1]))
110         return RET_SYN;
111     player->simulation = 1;
112     prdate();
113     nsect = 0;
114     while (nxtsct(&nstr, &sect)) {
115         if (!player->owner)
116             continue;
117
118         civs = (1.0 + obrate * etu_per_update) * sect.sct_item[I_CIVIL];
119         uws = (1.0 + uwbrate * etu_per_update) * sect.sct_item[I_UW];
120         natp = getnatp(sect.sct_own);
121         maxpop = max_pop(natp->nat_level[NAT_RLEV], &sect);
122
123         work = new_work(&sect,
124                         total_work(sect.sct_work, etu_per_update,
125                                    civs, sect.sct_item[I_MILIT], uws,
126                                    maxpop));
127         bwork = work / 2;
128
129         if (sect.sct_off)
130             continue;
131         type = sect.sct_type;
132         eff = sect.sct_effic;
133         if (sect.sct_newtype != type) {
134             twork = (eff + 3) / 4;
135             if (twork > bwork) {
136                 twork = bwork;
137             }
138             bwork -= twork;
139             eff -= twork * 4;
140             otype = type;
141             if (eff <= 0) {
142                 type = sect.sct_newtype;
143                 eff = 0;
144             }
145             if (!eff && IS_BIG_CITY(otype) && !IS_BIG_CITY(type)) {
146                 natp = getnatp(sect.sct_own);
147                 maxpop = max_population(natp->nat_level[NAT_RLEV],
148                                         type, eff);
149                 work = new_work(&sect,
150                                 total_work(sect.sct_work, etu_per_update,
151                                            civs, sect.sct_item[I_MILIT],
152                                            uws, maxpop));
153                 bwork = MIN(work / 2, bwork);
154             }
155             twork = 100 - eff;
156             if (twork > bwork) {
157                 twork = bwork;
158             }
159             if (dchr[type].d_lcms > 0) {
160                 lcms = sect.sct_item[I_LCM];
161                 lcms /= dchr[type].d_lcms;
162                 if (twork > lcms)
163                     twork = lcms;
164             }
165             if (dchr[type].d_hcms > 0) {
166                 hcms = sect.sct_item[I_HCM];
167                 hcms /= dchr[type].d_hcms;
168                 if (twork > hcms)
169                     twork = hcms;
170             }
171             bwork -= twork;
172             eff += twork;
173         } else if (eff < 100) {
174             twork = 100 - eff;
175             if (twork > bwork) {
176                 twork = bwork;
177             }
178             bwork -= twork;
179             eff += twork;
180         }
181         work = (work + 1) / 2 + bwork;
182         if (eff < 60)
183             continue;
184
185         p_e = eff / 100.0;
186         if (p_e > 1.0)
187             p_e = 1.0;
188
189         if (type == SCT_ENLIST) {
190             int maxmil;
191             int enlisted;
192
193             if (sect.sct_own != sect.sct_oldown)
194                 continue;
195             civs = (1.0 + obrate * etu_per_update) * sect.sct_item[I_CIVIL];
196             natp = getnatp(sect.sct_own);
197             maxpop = max_pop(natp->nat_level[NAT_RLEV], &sect);
198             civs = MIN(civs, maxpop);
199             enlisted = 0;
200             maxmil = (civs / 2) - sect.sct_item[I_MILIT];
201             if (maxmil > 0) {
202                 enlisted = (etu_per_update
203                             * (10 + sect.sct_item[I_MILIT])
204                             * 0.05);
205                 if (enlisted > maxmil)
206                     enlisted = maxmil;
207             }
208             if (enlisted < 0)
209                 enlisted = 0;
210             prprod(sect.sct_x, sect.sct_y, type, p_e, 1.0, work,
211                    ichr[I_MILIT].i_mnem, enlisted, maxmil, enlisted * 3,
212                    "c\0\0", &enlisted, &enlisted, nsect++);
213             continue;
214         }
215
216         if (dchr[type].d_prd < 0)
217             continue;
218         unit_work = 0;
219         pp = &pchr[dchr[type].d_prd];
220         vtype = pp->p_type;
221         natp = getnatp(sect.sct_own);
222         /*
223          * sect p_e  (inc improvements)
224          */
225         if (pp->p_nrndx != 0) {
226             unit_work++;
227             resource = (unsigned char *)&sect + pp->p_nrndx;
228             p_e = (*resource * p_e) / 100.0;
229         }
230         /*
231          * production effic.
232          */
233         prodeff = prod_eff(type, natp->nat_level[pp->p_nlndx]);
234         /*
235          * raw material limit
236          */
237         used = 9999;
238         for (i = 0; i < MAXPRCON; ++i) {
239             it = pp->p_ctype[i];
240             if (!pp->p_camt[i])
241                 continue;
242             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
243                 continue;
244             used = MIN(used, sect.sct_item[it] / pp->p_camt[i]);
245             unit_work += pp->p_camt[i];
246         }
247         if (unit_work == 0)
248             unit_work = 1;
249         /*
250          * is production limited by resources or
251          * workforce?
252          */
253         max = (int)(work * p_e / (double)unit_work + 0.5);
254         if (pp->p_nrdep != 0 && vtype != I_NONE) {
255             if (*resource * 100 < pp->p_nrdep * max)
256                 max = *resource * 100 / pp->p_nrdep;
257         }
258         act = MIN(used, max);
259
260         real = MIN(999.0, (double)act * prodeff);
261         maxr = MIN(999.0, (double)max * prodeff);
262
263         if (vtype != I_NONE) {
264             if (real < 0.0)
265                 real = 0.0;
266             /* production backlog? */
267             there = MIN(ITEM_MAX, sect.sct_item[vtype]);
268             real = MIN(real, ITEM_MAX - there);
269         }
270
271         if (prodeff != 0) {
272             take = real / prodeff;
273             mtake = maxr / prodeff;
274         } else
275             mtake = take = 0.0;
276
277         cost = take * pp->p_cost;
278         if (opt_TECH_POP) {
279             if (pp->p_level == NAT_TLEV) {
280                 totpop = count_pop(sect.sct_own);
281                 if (totpop > 50000)
282                     cost *= totpop / 50000.0;
283             }
284         }
285
286         for (i = 0; i < MAXPRCON; ++i) {
287             cmnem[i] = cuse[i] = cmax[i] = 0;
288             if (!pp->p_camt[i])
289                 continue;
290             it = pp->p_ctype[i];
291             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
292                 continue;
293             cmnem[i] = ichr[it].i_mnem;
294             cuse[i] = (int)(take * pp->p_camt[i] + 0.5);
295             cmax[i] = (int)(mtake * pp->p_camt[i] + 0.5);
296         }
297
298         if (pp->p_type != I_NONE)
299             mnem = ichr[vtype].i_mnem;
300         else if (pp->p_level == NAT_TLEV || pp->p_level == NAT_RLEV)
301             mnem = '.';
302         else
303             mnem = 0;
304         prprod(sect.sct_x, sect.sct_y, type, p_e, prodeff, work,
305                mnem, real, maxr, cost,
306                cmnem, cuse, cmax, nsect++);
307     }
308     player->simulation = 0;
309     if (nsect == 0) {
310         if (player->argp[1])
311             pr("%s: No sector(s)\n", player->argp[1]);
312         else
313             pr("%s: No sector(s)\n", "");
314         return RET_FAIL;
315     } else
316         pr("%d sector%s\n", nsect, splur(nsect));
317     return RET_OK;
318 }
319
320 static void
321 prprod(coord x, coord y, int type, double p_e, double prodeff, int work,
322        char mnem, double make, double max, double cost,
323        char cmnem[], int cuse[], int cmax[], int nsect)
324 {
325     int i;
326
327     if (nsect == 0) {
328         pr("PRODUCTION SIMULATION\n");
329         pr("   sect  des eff avail  make p.e. cost   use1 use2 use3  max1 max2 max3   max\n");
330     }
331
332     prxy("%4d,%-4d", x, y, player->cnum);
333     pr(" %c %3.0f%% %5d", dchr[type].d_mnem, p_e * 100.0, work);
334     if (mnem == '.')
335         pr(" %5.2f", make);
336     else
337         pr(" %4.0f%c", make, mnem ? mnem : ' ');
338     pr(" %.2f $%-5.0f", prodeff, cost);
339     for (i = 0; i < 3; i++) {
340         if (i < MAXPRCON && cmnem[i])
341             pr("%4d%c", cuse[i], cmnem[i]);
342         else
343             pr("     ");
344     }
345     pr(" ");
346     for (i = 0; i < 3; i++) {
347         if (i < MAXPRCON && cmnem[i])
348             pr("%4d%c", cmax[i], cmnem[i]);
349         else
350             pr("     ");
351     }
352     if (mnem == '.')
353         pr(" %5.2f\n", max);
354     else
355         pr(" %5.0f\n", max);
356 }