]> git.pond.sub.org Git - empserver/blob - src/lib/commands/prod.c
neweff prod work: Use update code instead of duplicating it
[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(struct sctstr *, double, double, 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 totpop;
74     int material_consume;       /* actual production */
75     double cost;
76     int i;
77     int max_consume;            /* production w/infinite materials */
78     int nsect;
79     double take;
80     double mtake;
81     int there;
82     int unit_work;              /* sum of component amounts */
83     int mat_limit, res_limit;
84     double worker_limit;
85     i_type it;
86     i_type vtype;
87     unsigned char *resource;
88     char cmnem[MAXPRCON];
89     int cuse[MAXPRCON], cmax[MAXPRCON];
90     char mnem;
91
92     if (!snxtsct(&nstr, player->argp[1]))
93         return RET_SYN;
94     player->simulation = 1;
95     prdate();
96     nsect = 0;
97     while (nxtsct(&nstr, &sect)) {
98         if (!player->owner)
99             continue;
100         if (sect.sct_off)
101             continue;
102
103         natp = getnatp(sect.sct_own);
104         sect.sct_avail = do_feed(&sect, natp, etu_per_update, 1);
105         buildeff(&sect);
106         if (sect.sct_effic < 60)
107             continue;
108
109         if (sect.sct_type == SCT_ENLIST) {
110             int maxmil;
111             int enlisted;
112
113             if (sect.sct_own != sect.sct_oldown)
114                 continue;
115             enlisted = 0;
116             maxmil = sect.sct_item[I_CIVIL] / 2 - sect.sct_item[I_MILIT];
117             if (maxmil > 0) {
118                 enlisted = (etu_per_update
119                             * (10 + sect.sct_item[I_MILIT])
120                             * 0.05);
121                 if (enlisted > maxmil)
122                     enlisted = maxmil;
123             }
124             if (enlisted < 0)
125                 enlisted = 0;
126             prprod(&sect, sect.sct_effic / 100.0, 1.0,
127                    ichr[I_MILIT].i_mnem, enlisted, maxmil, enlisted * 3,
128                    "c\0\0", &enlisted, &enlisted, nsect++);
129             continue;
130         }
131
132         if (dchr[sect.sct_type].d_prd < 0)
133             continue;
134         pp = &pchr[dchr[sect.sct_type].d_prd];
135         vtype = pp->p_type;
136         if (pp->p_nrndx)
137             resource = (unsigned char *)&sect + pp->p_nrndx;
138         else
139             resource = NULL;
140
141         mat_limit = prod_materials_cost(pp, sect.sct_item, &unit_work);
142
143         /* sector p.e. */
144         p_e = sect.sct_effic / 100.0;
145         if (resource) {
146             unit_work++;
147             p_e *= *resource / 100.0;
148         }
149         if (unit_work == 0)
150             unit_work = 1;
151
152         worker_limit = sect.sct_avail * p_e / (double)unit_work;
153         res_limit = prod_resource_limit(pp, resource);
154
155         max_consume = res_limit;
156         if (max_consume > worker_limit)
157             max_consume = (int)worker_limit;
158         material_consume = MIN(max_consume, mat_limit);
159
160         prodeff = prod_eff(sect.sct_type, natp->nat_level[pp->p_nlndx]);
161         real = (double)material_consume * prodeff;
162         maxr = (double)max_consume * prodeff;
163
164         if (vtype != I_NONE) {
165             real = MIN(999.0, real);
166             maxr = MIN(999.0, maxr);
167             if (real < 0.0)
168                 real = 0.0;
169             /* production backlog? */
170             there = MIN(ITEM_MAX, sect.sct_item[vtype]);
171             real = MIN(real, ITEM_MAX - there);
172         }
173
174         if (prodeff != 0) {
175             take = real / prodeff;
176             mtake = maxr / prodeff;
177         } else
178             mtake = take = 0.0;
179
180         cost = take * pp->p_cost;
181         if (opt_TECH_POP) {
182             if (pp->p_level == NAT_TLEV) {
183                 totpop = count_pop(sect.sct_own);
184                 if (totpop > 50000)
185                     cost *= totpop / 50000.0;
186             }
187         }
188
189         for (i = 0; i < MAXPRCON; ++i) {
190             cmnem[i] = cuse[i] = cmax[i] = 0;
191             if (!pp->p_camt[i])
192                 continue;
193             it = pp->p_ctype[i];
194             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
195                 continue;
196             cmnem[i] = ichr[it].i_mnem;
197             cuse[i] = (int)(take * pp->p_camt[i] + 0.5);
198             cmax[i] = (int)(mtake * pp->p_camt[i] + 0.5);
199         }
200
201         if (pp->p_type != I_NONE)
202             mnem = ichr[vtype].i_mnem;
203         else if (pp->p_level == NAT_TLEV || pp->p_level == NAT_RLEV)
204             mnem = '.';
205         else
206             mnem = 0;
207         prprod(&sect, p_e, prodeff, mnem, real, maxr, cost,
208                cmnem, cuse, cmax, nsect++);
209     }
210     player->simulation = 0;
211     if (nsect == 0) {
212         if (player->argp[1])
213             pr("%s: No sector(s)\n", player->argp[1]);
214         else
215             pr("%s: No sector(s)\n", "");
216         return RET_FAIL;
217     } else
218         pr("%d sector%s\n", nsect, splur(nsect));
219     return RET_OK;
220 }
221
222 static void
223 prprod(struct sctstr *sp, double p_e, double prodeff,
224        char mnem, double make, double max, double cost,
225        char cmnem[], int cuse[], int cmax[], int nsect)
226 {
227     int i;
228
229     if (nsect == 0) {
230         pr("PRODUCTION SIMULATION\n");
231         pr("   sect  des eff avail  make p.e. cost   use1 use2 use3  max1 max2 max3   max\n");
232     }
233
234     prxy("%4d,%-4d", sp->sct_x, sp->sct_y);
235     pr(" %c %3.0f%% %5d",
236        dchr[sp->sct_type].d_mnem, p_e * 100.0, sp->sct_avail);
237     if (mnem == '.')
238         pr(" %5.2f", make);
239     else
240         pr(" %4.0f%c", make, mnem ? mnem : ' ');
241     pr(" %.2f $%-5.0f", prodeff, cost);
242     for (i = 0; i < 3; i++) {
243         if (i < MAXPRCON && cmnem[i])
244             pr("%4d%c", cuse[i], cmnem[i]);
245         else
246             pr("     ");
247     }
248     pr(" ");
249     for (i = 0; i < 3; i++) {
250         if (i < MAXPRCON && cmnem[i])
251             pr("%4d%c", cmax[i], cmnem[i]);
252         else
253             pr("     ");
254     }
255     if (mnem == '.')
256         pr(" %5.2f\n", max);
257     else
258         pr(" %5.0f\n", max);
259 }