production: 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 <math.h>
38 #include "commands.h"
39 #include "item.h"
40 #include "optlist.h"
41 #include "product.h"
42 #include "update.h"
43
44 static void prprod(struct sctstr *, double, double, char,
45                    double, double, double, char[], int[], int[], int);
46
47 int
48 count_pop(int n)
49 {
50     int i;
51     int pop = 0;
52     struct sctstr *sp;
53
54     for (i = 0; NULL != (sp = getsectid(i)); i++) {
55         if (sp->sct_own != n)
56             continue;
57         if (sp->sct_oldown != n)
58             continue;
59         pop += sp->sct_item[I_CIVIL];
60     }
61     return pop;
62 }
63
64 int
65 prod(void)
66 {
67     struct natstr *natp;
68     struct sctstr sect, scratch_sect;
69     struct nstr_sect nstr;
70     struct pchrstr *pp;
71     double p_e;
72     double prodeff;
73     int totpop;
74     double cost;
75     int i;
76     int nsect;
77     double real, maxr;
78     double take, mtake;
79     i_type it;
80     unsigned char *resource;
81     char cmnem[MAXPRCON];
82     int cuse[MAXPRCON], cmax[MAXPRCON];
83     char mnem;
84
85     if (!snxtsct(&nstr, player->argp[1]))
86         return RET_SYN;
87     player->simulation = 1;
88     prdate();
89     nsect = 0;
90     while (nxtsct(&nstr, &sect)) {
91         if (!player->owner)
92             continue;
93         if (sect.sct_off)
94             continue;
95
96         natp = getnatp(sect.sct_own);
97         do_feed(&sect, natp, etu_per_update, 1);
98         buildeff(&sect);
99         if (sect.sct_effic < 60)
100             continue;
101
102         if (sect.sct_type == SCT_ENLIST) {
103             int maxmil;
104             int enlisted;
105
106             if (sect.sct_own != sect.sct_oldown)
107                 continue;
108             enlisted = 0;
109             maxmil = sect.sct_item[I_CIVIL] / 2 - sect.sct_item[I_MILIT];
110             if (maxmil > 0) {
111                 enlisted = (etu_per_update
112                             * (10 + sect.sct_item[I_MILIT])
113                             * 0.05);
114                 if (enlisted > maxmil)
115                     enlisted = maxmil;
116             }
117             if (enlisted < 0)
118                 enlisted = 0;
119             prprod(&sect, sect.sct_effic / 100.0, 1.0,
120                    ichr[I_MILIT].i_mnem, enlisted, maxmil, enlisted * 3,
121                    "c\0\0", &enlisted, &enlisted, nsect++);
122             continue;
123         }
124
125         if (dchr[sect.sct_type].d_prd < 0)
126             continue;
127         pp = &pchr[dchr[sect.sct_type].d_prd];
128         if (pp->p_nrndx)
129             resource = (unsigned char *)&sect + pp->p_nrndx;
130         else
131             resource = NULL;
132
133         /* sector p.e. */
134         p_e = sect.sct_effic / 100.0;
135         if (resource)
136             p_e *= *resource / 100.0;
137
138         prodeff = prod_eff(sect.sct_type, natp->nat_level[pp->p_nlndx]);
139
140         scratch_sect = sect;
141         real = prod_output(&scratch_sect, prodeff);
142
143         scratch_sect = sect;
144         for (i = 0; i < MAXPRCON; ++i)
145             scratch_sect.sct_item[pp->p_ctype[i]] = ITEM_MAX;
146         scratch_sect.sct_item[pp->p_type] = 0;
147         maxr = prod_output(&scratch_sect, prodeff);
148
149         if (prodeff != 0) {
150             take = real / prodeff;
151             mtake = maxr / prodeff;
152         } else
153             mtake = take = 0.0;
154
155         cost = take * pp->p_cost;
156         if (opt_TECH_POP) {
157             if (pp->p_level == NAT_TLEV) {
158                 totpop = count_pop(sect.sct_own);
159                 if (totpop > 50000)
160                     cost *= totpop / 50000.0;
161             }
162         }
163
164         for (i = 0; i < MAXPRCON; ++i) {
165             cmnem[i] = cuse[i] = cmax[i] = 0;
166             if (!pp->p_camt[i])
167                 continue;
168             it = pp->p_ctype[i];
169             if (CANT_HAPPEN(it <= I_NONE || I_MAX < it))
170                 continue;
171             cmnem[i] = ichr[it].i_mnem;
172             cuse[i] = (int)ceil(take * pp->p_camt[i]);
173             cmax[i] = (int)ceil(mtake * pp->p_camt[i]);
174         }
175
176         if (pp->p_type != I_NONE)
177             mnem = ichr[pp->p_type].i_mnem;
178         else if (pp->p_level == NAT_TLEV || pp->p_level == NAT_RLEV)
179             mnem = '.';
180         else
181             mnem = 0;
182         prprod(&sect, p_e, prodeff, mnem, real, maxr, cost,
183                cmnem, cuse, cmax, nsect++);
184     }
185     player->simulation = 0;
186     if (nsect == 0) {
187         if (player->argp[1])
188             pr("%s: No sector(s)\n", player->argp[1]);
189         else
190             pr("%s: No sector(s)\n", "");
191         return RET_FAIL;
192     } else
193         pr("%d sector%s\n", nsect, splur(nsect));
194     return RET_OK;
195 }
196
197 static void
198 prprod(struct sctstr *sp, double p_e, double prodeff,
199        char mnem, double make, double max, double cost,
200        char cmnem[], int cuse[], int cmax[], int nsect)
201 {
202     int i;
203
204     if (nsect == 0) {
205         pr("PRODUCTION SIMULATION\n");
206         pr("   sect  des eff avail  make p.e. cost   use1 use2 use3  max1 max2 max3   max\n");
207     }
208
209     prxy("%4d,%-4d", sp->sct_x, sp->sct_y);
210     pr(" %c %3.0f%% %5d",
211        dchr[sp->sct_type].d_mnem, p_e * 100.0, sp->sct_avail);
212     if (mnem == '.')
213         pr(" %5.2f", make);
214     else
215         pr(" %4.0f%c", make, mnem ? mnem : ' ');
216     pr(" %.2f $%-5.0f", prodeff, cost);
217     for (i = 0; i < 3; i++) {
218         if (i < MAXPRCON && cmnem[i])
219             pr("%4d%c", cuse[i], cmnem[i]);
220         else
221             pr("     ");
222     }
223     pr(" ");
224     for (i = 0; i < 3; i++) {
225         if (i < MAXPRCON && cmnem[i])
226             pr("%4d%c", cmax[i], cmnem[i]);
227         else
228             pr("     ");
229     }
230     if (mnem == '.')
231         pr(" %5.2f\n", max);
232     else
233         pr(" %5.0f\n", max);
234 }