]> git.pond.sub.org Git - empserver/blob - src/lib/update/sect.c
Import of Empire 4.2.12
[empserver] / src / lib / update / sect.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  sect.c: Do production for sectors
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1996
33  */
34
35 #include <math.h>
36 #include "misc.h"
37 #include "var.h"
38 #include "sect.h"
39 #include "nat.h"
40 #include "item.h"
41 #include "news.h"
42 #include "file.h"
43 #include "xy.h"
44 #include "path.h"
45 #include "product.h"
46 #include "distribute.h"
47 #include "optlist.h"
48 #include "budg.h"
49 #include "player.h"
50 #include "land.h"
51 #include "ship.h"
52 #include "update.h"
53 #include "subs.h"
54 #include "common.h"
55 #include "lost.h"
56 #include "gen.h"
57
58 extern  float levels[MAXNOC][4];
59
60 int
61 dodeliver(struct sctstr *sp, int *vec)
62 {
63         register int i;
64         int     del[I_MAX+1];
65         int     thresh;
66         int     dir;
67         int     plague;
68         int     n;
69         int     changed;
70
71         if (sp->sct_mobil <= 0)
72                 return 0;
73         if (getvec(VT_DEL, del, (s_char *)sp, EF_SECTOR) <= 0)
74                 return 0;
75         changed = 0;
76         plague = getvar(V_PSTAGE, (s_char *)sp, EF_SECTOR);
77         for (i=1; i<=I_MAX; i++) {
78                 if (del[i] == 0)
79                         continue;
80                 thresh = del[i] & ~0x7;
81                 dir = del[i] & 0x7;
82                 n = deliver(sp, &ichr[i], dir, thresh, vec[i], plague);
83                 if (n > 0)  {
84                         vec[i] -= n;
85                         changed++;
86                         if (sp->sct_mobil <= 0)
87                                 break;
88                 }
89         }
90         return changed;
91 }
92
93 /*
94  * Increase sector efficiency if old type == new type.
95  * decrease sector efficiency if old type != new type.
96  * Return amount of work used.
97  */
98 int
99 upd_buildeff(struct natstr *np, register struct sctstr *sp, int *workp, int *vec, int etu, int *desig, int sctwork, int *cost)
100 {
101         register int work_cost = 0;
102         int     buildeff_work = (int)(*workp / 2);
103         int     n, hcms, lcms, neweff;
104         u_char  old_type = *desig;
105
106         *cost = 0;
107         neweff = sp->sct_effic;
108
109         if (*desig != sp->sct_newtype) {
110                 /*
111                  * Tear down existing sector.
112                  * Easier to destroy than to build.
113                  */
114                 work_cost = (sp->sct_effic + 3) / 4;
115                 if (work_cost > buildeff_work)
116                         work_cost = buildeff_work;
117                 buildeff_work -= work_cost;
118                 n = sp->sct_effic - work_cost * 4;
119                 if (n <= 0) {
120                         n = 0;
121                         *desig = sp->sct_newtype;
122                 }
123                 neweff = n;
124                 *cost += work_cost;
125                 if (opt_BIG_CITY) {
126                     if (!n && dchr[old_type].d_pkg == UPKG &&
127                         dchr[*desig].d_pkg != UPKG) {
128                         int maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
129                         if (vec[I_CIVIL] > maxpop)
130                             vec[I_CIVIL] = maxpop;
131                         if (vec[I_UW] > maxpop)
132                             vec[I_UW] = maxpop;
133                         *workp = (vec[I_CIVIL] * sctwork) / 100.0
134                             +(vec[I_MILIT] * 2 / 5.0) + vec[I_UW];
135                         *workp = roundavg((etu * (*workp)) / 100.0);
136                         
137                         buildeff_work = min((int)(*workp / 2), buildeff_work);
138                     }
139                 }
140         }
141         if (np->nat_priorities[*desig]) {
142                 if (*desig == sp->sct_newtype) {
143                         work_cost = 100 - neweff;
144                         if (work_cost > buildeff_work)
145                                 work_cost = buildeff_work;
146                         
147                         if (dchr[*desig].d_lcms>0){
148                                 lcms = vec[I_LCM];
149                                 lcms /= dchr[*desig].d_lcms;
150                                 if (work_cost > lcms)
151                                         work_cost = lcms;
152                         }
153                         if (dchr[*desig].d_hcms>0){
154                                 hcms = vec[I_HCM];
155                                 hcms /= dchr[*desig].d_hcms;
156                                 if (work_cost > hcms)
157                                         work_cost = hcms;
158                         }
159
160                         neweff += work_cost;
161                         *cost += work_cost*dchr[*desig].d_build;
162                         buildeff_work -= work_cost;
163                         
164                         if ((dchr[*desig].d_lcms>0) || 
165                             (dchr[*desig].d_hcms>0)){
166                                 vec[I_LCM] -= work_cost *
167                                               dchr[*desig].d_lcms;
168                                 vec[I_HCM] -= work_cost *
169                                               dchr[*desig].d_hcms;
170                         }
171                 }
172         }
173         *workp = *workp/2 + buildeff_work;
174
175         return neweff;
176 }
177
178 /*
179  * enlistment sectors are special; they require military
180  * to convert civ into mil in large numbers.
181  * Conversion will happen much more slowly without
182  * some mil initially.
183  */
184 int
185 enlist(register int *vec, int etu, int *cost)
186 {
187         int     maxmil;
188         int     enlisted;
189
190         /* Need to check treaties here */
191         enlisted = 0;
192         maxmil = (vec[I_CIVIL] / 2) - vec[I_MILIT];
193         if (maxmil > 0) {
194                 enlisted = (etu * (10 + vec[I_MILIT]) * 0.05);
195                 if (enlisted > maxmil)
196                         enlisted = maxmil;
197                 vec[I_CIVIL] -= enlisted;
198                 vec[I_MILIT] += enlisted;
199         }
200         *cost = enlisted * 3;
201         return enlisted;
202 }
203
204 /* Fallout is calculated here. */
205
206 extern int melt_item_denom[];
207
208 void
209 meltitems(int etus, int fallout, int own, int *vec, int type, int x, int y, int uid)
210 {
211   int n;
212   int melt;
213
214   for (n = 1; n <= I_MAX; n++) {
215     melt = roundavg(vec[n] * etus * (long)fallout /
216                     (1000.0 * melt_item_denom[n]));
217     if (melt > 5 && own) {
218       if (type == EF_SECTOR)
219         wu(0, own, "Lost %d %s to radiation in %s.\n",
220            (melt < vec[n] ? melt : vec[n]), ichr[n].i_name,
221            xyas(x, y, own));
222       else if (type == EF_LAND)
223         wu(0, own, "Unit #%d lost %d %s to radiation in %s.\n",
224            uid, (melt < vec[n] ? melt : vec[n]), ichr[n].i_name,
225            xyas(x, y, own));
226       else if (type == EF_SHIP)
227         wu(0, own, "Ship #%d lost %d %s to radiation in %s.\n",
228            uid, (melt < vec[n] ? melt : vec[n]), ichr[n].i_name,
229            xyas(x, y, own));
230     }
231     if (melt < vec[n])
232       vec[n] -= melt;
233     else
234       vec[n] = 0;
235   }
236 }
237
238 /*
239  * do_fallout - calculate fallout for sectors.
240  *
241  * This is etu based.  But, do limit HUGE kill offs in large ETU
242  * games, the melting etus rate is limited to 24 etus.
243  */
244
245 void
246 do_fallout(register struct sctstr *sp, register int etus)
247 {
248   int   vec[I_MAX+1];
249   int   cvec[I_MAX+1];
250   int   tvec[I_MAX+1];
251   struct shpstr *spp;
252   struct lndstr *lp;
253   int   i;
254
255   getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
256   getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
257 /* This check shouldn't be needed, but just in case. :) */
258   if (!cvec[C_FALLOUT] || !sp->sct_updated)
259     return;
260   if (etus > 24)
261     etus = 24;
262 #if 0
263   wu(0,0,"Running fallout in %d,%d\n", sp->sct_x, sp->sct_y);
264 #endif
265   meltitems(etus, cvec[C_FALLOUT], sp->sct_own, vec, EF_SECTOR,
266             sp->sct_x, sp->sct_y, 0);
267   putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
268   for (i = 0; NULL != (lp = getlandp(i)); i++) {
269     if (!lp->lnd_own)
270       continue;
271     if (lp->lnd_x != sp->sct_x || lp->lnd_y != sp->sct_y)
272       continue;
273     getvec(VT_ITEM, tvec, (s_char *)lp, EF_LAND);
274     meltitems(etus, cvec[C_FALLOUT], lp->lnd_own, tvec, EF_LAND,
275               lp->lnd_x, lp->lnd_y, lp->lnd_uid);
276     putvec(VT_ITEM, tvec, (s_char *)lp, EF_LAND);
277   }
278   for (i = 0; NULL != (spp = getshipp(i)); i++) {
279     if (!spp->shp_own)
280       continue;
281     if (spp->shp_x != sp->sct_x || spp->shp_y != sp->sct_y)
282       continue;
283     if (mchr[(int)spp->shp_type].m_flags & M_SUB)
284       continue;
285     getvec(VT_ITEM, tvec, (s_char *)spp, EF_SHIP);
286     meltitems(etus, cvec[C_FALLOUT], spp->shp_own, tvec, EF_SHIP,
287               spp->shp_x, spp->shp_y, spp->shp_uid);
288     putvec(VT_ITEM, tvec, (s_char *)spp, EF_SHIP);
289   }
290 #ifdef  GODZILLA
291   if ((cvec[C_FALLOUT] > 20) && chance(100))
292         do_godzilla(sp);
293 #endif  /* GODZILLA */
294 }
295
296 void
297 spread_fallout(struct sctstr *sp, int etus)
298 {
299   extern double fallout_spread;
300   struct sctstr *ap;
301   int tvec[I_MAX+1];
302   int cvec[I_MAX+1];
303   int n;
304   register int  inc;
305
306   if (etus > 24)
307     etus = 24;
308   getvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
309   for (n = DIR_FIRST; n <= DIR_LAST; n++) {
310     ap = getsectp(sp->sct_x+diroff[n][0], sp->sct_y+diroff[n][1]);
311     getvec(VT_COND, tvec, (char *)ap, EF_SECTOR);
312     if (ap->sct_type == SCT_SANCT)
313         continue;
314     inc = roundavg(etus * fallout_spread * (cvec[C_FALLOUT])) - 1;
315 #if 0
316     if (cvec[C_FALLOUT]) {
317       wu(0,0,"Fallout from sector %d,%d to %d,%d is %d=%d*%e*%d\n",
318          sp->sct_x,sp->sct_y,sp->sct_x+diroff[n][0],
319          sp->sct_y+diroff[n][1], inc, etus,
320          fallout_spread, cvec[C_FALLOUT]);
321     }
322 #endif
323     if (inc < 0)
324       inc = 0;
325     tvec[C_FALLOUT] += inc;
326     putvec(VT_COND, tvec, (char *)ap, EF_SECTOR);
327   }
328 }
329
330 void
331 decay_fallout(struct sctstr *sp, int etus)
332 {
333   extern double decay_per_etu;
334   extern double fallout_spread;
335   int cvec[I_MAX+1];
336   int decay;
337
338   if (etus > 24)
339     etus = 24;
340   getvec(VT_COND, cvec, (char *)sp, EF_SECTOR);
341   decay = roundavg(((decay_per_etu + 6.0) * fallout_spread) *
342                    (double)etus * (double)cvec[C_FALLOUT]);
343
344 #if 0
345   if (decay || cvec[C_FALLOUT])
346     wu(0,0,"Fallout decay in %d,%d is %d from %d\n", sp->sct_x, sp->sct_y, decay, cvec[C_FALLOUT]);
347 #endif
348
349   cvec[C_FALLOUT] = (decay < cvec[C_FALLOUT]) ? (cvec[C_FALLOUT] - decay) : 0;
350   if (cvec[C_FALLOUT] < 0)
351     cvec[C_FALLOUT] = 0;
352   putvec(VT_COND, cvec, (s_char *)sp, EF_SECTOR);
353 }
354
355 #define SHOULD_PRODUCE(sp,t)    (((sp->sct_type == t) || (t == -1)) ? 1 : 0)
356
357 /*
358  * Produce only a set sector type for a specific nation
359  * (or all, if sector_type == -1)
360  *
361  */
362 void
363 produce_sect(int natnum, int etu, int *bp, long int (*p_sect)[2], int sector_type)
364 {
365         register struct sctstr *sp;
366         register struct natstr *np;
367         int     vec[I_MAX+1];
368         int     work, cost, ecost, pcost, sctwork;
369         int     n, desig, maxpop, neweff, amount;
370
371         for (n=0; NULL != (sp = getsectid(n)); n++) {
372                 if (sp->sct_type == SCT_WATER)
373                         continue;
374                 if (sp->sct_own != natnum)
375                         continue;
376                 if (sp->sct_updated != 0)
377                         continue;
378                 if (!SHOULD_PRODUCE(sp,sector_type))
379                         continue;
380
381                 if ((sp->sct_type == SCT_CAPIT) && (sp->sct_effic > 60)) {
382                         p_sect[SCT_CAPIT][0]++;
383                         p_sect[SCT_CAPIT][1] += etu;
384                 }
385
386                 if (getvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR) <= 0)
387                         continue;
388                 /* If everybody is dead, the sector reverts to unowned. 
389                 * This is also checked at the end of the production in
390                 * they all starved or were plagued off.
391                 */
392                 if (vec[I_CIVIL] == 0 && vec[I_MILIT] == 0 &&
393                         !has_units(sp->sct_x,sp->sct_y,sp->sct_own,0)) {
394                         makelost(EF_SECTOR, sp->sct_own, 0, sp->sct_x, sp->sct_y);
395                         sp->sct_own = 0;
396                         sp->sct_oldown = 0;
397                         continue;
398                 }
399
400                 sp->sct_updated = 1;
401                 work = 0;
402
403                 np = getnatp(natnum);
404
405                 /* do_feed trys to supply.  So, we need to enable cacheing
406                    here */
407                 bp_enable_cachepath();
408
409                 sctwork = do_feed(sp, np, vec, &work, bp, etu);
410
411                 bp_disable_cachepath();
412                 bp_clear_cachepath();
413
414                 if (sp->sct_off || np->nat_money < 0) {
415                   if (!player->simulation) {
416                     putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
417                     sp->sct_off = 0;
418                   }
419                   continue;
420                 }
421                 if ((np->nat_priorities[sp->sct_type] == 0) &&
422                     (sp->sct_type == sp->sct_newtype) &&
423                     ((pchr[dchr[sp->sct_type].d_prd].p_cost != 0) ||
424                      (sp->sct_type == SCT_ENLIST))){
425                     if (!player->simulation) {
426                         putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
427                         logerror("Skipping %s production for country %s\n",
428                                  dchr[sp->sct_type].d_name,np->nat_cnam);
429                     }
430                     continue;
431                 }
432
433                 neweff = sp->sct_effic;
434                 amount = 0;
435                 pcost = cost = ecost = 0;
436
437                 desig = sp->sct_type;
438
439                 if ((sp->sct_effic < 100 || sp->sct_type != sp->sct_newtype) &&
440                         np->nat_money > 0) {
441                         neweff = upd_buildeff(np, sp, &work, vec, etu, &desig, sctwork, &cost);
442                         pt_bg_nmbr(bp, sp, I_LCM, vec[I_LCM]);
443                         pt_bg_nmbr(bp, sp, I_HCM, vec[I_HCM]);
444                         p_sect[SCT_EFFIC][0]++;
445                         p_sect[SCT_EFFIC][1] += cost;
446                         if (!player->simulation) {
447                           np->nat_money -= cost;
448                           /* No longer tear down infrastructure
449                           if (sp->sct_type != desig) {
450                             sp->sct_road = 0;
451                             sp->sct_defense = 0;
452                           } else if (neweff < sp->sct_effic) {
453                             sp->sct_road -= (sp->sct_road * (sp->sct_effic - neweff) / 100.0);
454                             sp->sct_defense -= (sp->sct_defense * (sp->sct_effic - neweff) / 100.0);
455                             if (sp->sct_road < 0)
456                               sp->sct_road = 0;
457                             if (sp->sct_defense < 0)
458                               sp->sct_defense = 0;
459                           }
460                           */
461                           sp->sct_type = desig;
462                           sp->sct_effic = neweff;
463                           if (!opt_DEFENSE_INFRA)
464                             sp->sct_defense = sp->sct_effic;
465                         }
466                 }
467
468                 if ((np->nat_priorities[desig] == 0) &&
469                     ((pchr[dchr[desig].d_prd].p_cost != 0) ||
470                      (desig == SCT_ENLIST))) {
471                     if (!player->simulation) {
472                         putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
473                         logerror("Skipping %s production for country %s\n",
474                                  dchr[sp->sct_type].d_name,np->nat_cnam);
475                     }
476                     continue;
477                 }
478
479                 if (desig == SCT_ENLIST && neweff >= 60 &&
480                         sp->sct_own == sp->sct_oldown) {
481                         p_sect[desig][0] += enlist(vec, etu, &ecost);
482                         p_sect[desig][1] += ecost;
483                         if (!player->simulation)
484                           np->nat_money -= ecost;
485                       }
486
487                 /*
488                 * now do the production (if sector effic >= 60%)
489                 */
490
491                 if (neweff >= 60) {
492                     if (np->nat_money > 0 && dchr[desig].d_prd)
493                         work -= produce(np, sp, vec, work, sctwork, desig, neweff, &pcost, &amount);
494                 }
495
496                 pt_bg_nmbr(bp, sp, I_MAX+1, work);
497                 p_sect[desig][0] += amount;
498                 p_sect[desig][1] += pcost;
499                 if (!player->simulation) {
500                   maxpop = max_pop(np->nat_level[NAT_RLEV], sp);
501                   if (vec[I_CIVIL] > maxpop)
502                     vec[I_CIVIL] = maxpop;
503                   if (vec[I_UW] > maxpop)
504                     vec[I_UW] = maxpop;
505                   putvec(VT_ITEM, vec, (s_char *)sp, EF_SECTOR);
506                   sp->sct_avail = work;
507                   np->nat_money -= pcost;
508                 }
509         }
510 }