]> git.pond.sub.org Git - empserver/blob - src/lib/subs/supply.c
Declare all configuration variables in optlist.h. Include that
[empserver] / src / lib / subs / supply.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  *  supply.c: Supply subroutines
29  * 
30  *  Known contributors to this file:
31  *  
32  */
33
34 #include "misc.h"
35 #include "nat.h"
36 #include "var.h"
37 #include "retreat.h"
38 #include "ship.h"
39 #include "land.h"
40 #include "sect.h"
41 #include "news.h"
42 #include "xy.h"
43 #include "nsc.h"
44 #include "path.h"
45 #include "deity.h"
46 #include "item.h"
47 #include "file.h"
48 #include "options.h"
49 #include "optlist.h"
50 #include "player.h"
51 #include "prototypes.h"
52
53 static int get_minimum(struct lndstr *, int);
54 static s_char *itemname(int);
55 static int s_commod(int, int, int, int, int, int);
56
57 /*
58  * We want to get enough guns to be maxed out, enough shells to
59  *      fire once, one update's worth of food, enough fuel for
60  *      one update.
61  *
62  * Firts, try to forage in the sector
63  * Second look for a warehouse or headquarters to leech
64  * Third, look for a ship we own in a harbor
65  * Fourth, look for supplies in a supply unit we own
66  *              (one good reason to do this last is that the supply
67  *               unit will then call resupply, taking more time)
68  *
69  * May want to put code to resupply with SAMs here, later --ts
70  *
71  */
72
73 void
74 resupply_all(struct lndstr *lp)
75 {
76     if (!opt_NOFOOD)
77         resupply_commod(lp, I_FOOD);
78     resupply_commod(lp, I_SHELL);
79     if (opt_FUEL)
80         resupply_commod(lp, I_PETROL);
81 }
82
83 /*
84  * If the unit has less than it's minimum level of a
85  * certain commodity, fill it, to the best of our abilities.
86  */
87
88 void
89 resupply_commod(struct lndstr *lp, int type)
90 {
91     int vec[I_MAX + 1];
92     int svec[I_MAX + 1];
93     int amt;
94     struct lchrstr *lcp;
95     struct shpstr ship;
96
97     lcp = &lchr[(int)lp->lnd_type];
98
99     getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
100     /* Ok, do we now have enough? */
101     if (vec[type] < get_minimum(lp, type)) {
102         vec[type] += supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y, type,
103                                    get_minimum(lp, type) - vec[type]);
104         putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
105     }
106     /* Now, check again to see if we have enough. */
107     if (vec[type] < get_minimum(lp, type)) {
108         /* Nope.  How much do we need? */
109         amt = (get_minimum(lp, type) - vec[type]);
110         /* Are we on a ship?  if so, try to get it from the ship first. */
111         if (lp->lnd_ship >= 0) {
112             getship(lp->lnd_ship, &ship);
113             getvec(VT_ITEM, svec, (s_char *)&ship, EF_SHIP);
114             /* Now, determine how much we can get */
115             amt = (amt < svec[type]) ? amt : svec[type];
116             /* Now, add and subtract */
117             vec[type] += amt;
118             svec[type] -= amt;
119             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
120             putvec(VT_ITEM, svec, (s_char *)&ship, EF_SHIP);
121             putship(lp->lnd_ship, &ship);
122         }
123     }
124
125     if (opt_FUEL && type == I_PETROL) {
126         int fuel_needed = (lp->lnd_fuelu * (((float)etu_per_update
127                                              * land_mob_scale)) / 10.0);
128
129         while ((lp->lnd_fuel < fuel_needed) && vec[I_PETROL]) {
130             lp->lnd_fuel += 10;
131             if (lp->lnd_fuel > lp->lnd_fuelc)
132                 lp->lnd_fuel = lp->lnd_fuelc;
133             vec[I_PETROL]--;
134             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
135         }
136     }
137 }
138
139 /*
140  * Actually get the commod
141  */
142 int
143 supply_commod(int own, int x, int y, int type, int total_wanted)
144 {
145     if (total_wanted < 0)
146         return 0;
147     return s_commod(own, x, y, type, total_wanted, !player->simulation);
148 }
149
150 /*
151  * Just return the number you COULD get, without doing it
152  */
153 int
154 try_supply_commod(int own, int x, int y, int type, int total_wanted)
155 {
156     if (total_wanted < 0)
157         return 0;
158
159     return s_commod(own, x, y, type, total_wanted, 0);
160 }
161
162 /* Get supplies of a certain type */
163 static int
164 s_commod(int own, int x, int y, int type, int total_wanted,
165          int actually_doit)
166 {
167     int wanted = total_wanted;
168     int gotten = 0, lookrange;
169     struct sctstr sect, dest;
170     int vec[I_MAX + 1];
171     struct nstr_sect ns;
172     struct nstr_item ni;
173     struct lchrstr *lcp;
174     struct shpstr ship;
175     struct lndstr land;
176     /* leave at least 1 military in sectors/ships */
177     int minimum = (type == I_MILIT ? 1 : 0);
178     int can_move;
179     double move_cost, weight, mobcost;
180     int packing;
181     struct dchrstr *dp;
182     struct ichrstr *ip;
183     s_char buf[1024];
184
185     /* try to get it from sector we're in */
186     getsect(x, y, &dest);
187     getsect(x, y, &sect);
188     if (sect.sct_own == own) {
189         getvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
190         if ((vec[type] - minimum) >= wanted) {
191             vec[type] -= wanted;
192             if (actually_doit) {
193                 putvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
194                 putsect(&sect);
195             }
196             return total_wanted;
197         } else if ((vec[type] - minimum) > 0) {
198             gotten += (vec[type] - minimum);
199             wanted -= (vec[type] - minimum);
200             vec[type] = minimum;
201             if (actually_doit) {
202                 putvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
203                 putsect(&sect);
204             }
205         }
206     }
207     /* look for a headquarters or warehouse */
208     lookrange = tfact(own, (double)10.0);
209     snxtsct_dist(&ns, x, y, lookrange);
210     while (nxtsct(&ns, &sect) && wanted) {
211         if (sect.sct_own != own)
212             continue;
213         if ((sect.sct_type != SCT_WAREH) &&
214             (sect.sct_type != SCT_HEADQ) && (sect.sct_type != SCT_HARBR))
215             continue;
216         if ((sect.sct_type == SCT_HEADQ) &&
217             (sect.sct_dist_x == sect.sct_x) &&
218             (sect.sct_dist_y == sect.sct_y))
219             continue;
220         if (sect.sct_effic < 60)
221             continue;
222         if (BestLandPath(buf, &dest, &sect, &move_cost, MOB_ROAD) ==
223             (s_char *)0)
224             continue;
225         getvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
226         if (!opt_NOFOOD && type == I_FOOD) {
227             minimum = (((double)etu_per_update * eatrate) *
228                        (double)(vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]))
229                 + 2;
230         }
231         if (vec[type] <= minimum) {
232             /* Don't bother... */
233             continue;
234         }
235         ip = &ichr[type];
236         dp = &dchr[sect.sct_type];
237         packing = ip->i_pkg[dp->d_pkg];
238         if (packing > 1 && sect.sct_effic < 60)
239             packing = 1;
240         weight = ((double)ip->i_lbs / (double)packing);
241         mobcost = move_cost * weight;
242         if (mobcost > 0)
243             can_move = ((double)sect.sct_mobil / mobcost);
244         else
245             can_move = vec[type] - minimum;
246         if (can_move > (vec[type] - minimum))
247             can_move = (vec[type] - minimum);
248
249         if (can_move >= wanted) {
250             int n;
251
252             vec[type] -= wanted;
253
254             /* take off mobility for delivering sect */
255             n = roundavg(total_wanted * weight * move_cost);
256             if (n < 0)
257                 n = 0;
258             if (n > sect.sct_mobil)
259                 n = sect.sct_mobil;
260             sect.sct_mobil -= (u_char)n;
261
262             if (actually_doit) {
263                 putvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
264                 putsect(&sect);
265             }
266
267             return total_wanted;
268         } else if (can_move > 0) {
269             int n;
270             gotten += can_move;
271             wanted -= can_move;
272             vec[type] -= can_move;
273
274             /* take off mobility for delivering sect */
275             n = roundavg(can_move * weight * move_cost);
276             if (n < 0)
277                 n = 0;
278             if (n > sect.sct_mobil)
279                 n = sect.sct_mobil;
280             sect.sct_mobil -= (u_char)n;
281
282             if (actually_doit) {
283                 putvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
284                 putsect(&sect);
285             }
286         }
287     }
288
289     /* look for an owned ship in a harbor */
290     snxtitem_dist(&ni, EF_SHIP, x, y, lookrange);
291
292     while (nxtitem(&ni, (s_char *)&ship) && wanted) {
293         if (ship.shp_own != own)
294             continue;
295
296         if (!(mchr[(int)ship.shp_type].m_flags & M_SUPPLY))
297             continue;
298         getsect(ship.shp_x, ship.shp_y, &sect);
299         if (sect.sct_type != SCT_HARBR)
300             continue;
301         if (sect.sct_effic < 2)
302             continue;
303         if (BestLandPath(buf, &dest, &sect, &move_cost, MOB_ROAD) ==
304             (s_char *)0)
305             continue;
306         getvec(VT_ITEM, vec, (s_char *)&ship, EF_SHIP);
307         if (!opt_NOFOOD && type == I_FOOD)
308             minimum = (((double)etu_per_update * eatrate) *
309                        (double)(vec[I_CIVIL] + vec[I_MILIT] + vec[I_UW]))
310                 + 2;
311         if (vec[type] <= minimum) {
312             /* Don't bother... */
313             continue;
314         }
315         ip = &ichr[type];
316         dp = &dchr[sect.sct_type];
317         packing = ip->i_pkg[dp->d_pkg];
318         if (packing > 1 && sect.sct_effic < 60)
319             packing = 1;
320         weight = ((double)ip->i_lbs / (double)packing);
321         mobcost = move_cost * weight;
322         if (mobcost > 0)
323             can_move = ((double)sect.sct_mobil / mobcost);
324         else
325             can_move = vec[type] - minimum;
326         if (can_move > (vec[type] - minimum))
327             can_move = (vec[type] - minimum);
328         if (can_move >= wanted) {
329             int n;
330             vec[type] -= wanted;
331
332             n = roundavg(wanted * weight * move_cost);
333             if (n < 0)
334                 n = 0;
335             if (n > sect.sct_mobil)
336                 n = sect.sct_mobil;
337             sect.sct_mobil -= (u_char)n;
338             if (actually_doit) {
339                 putvec(VT_ITEM, vec, (s_char *)&ship, EF_SHIP);
340                 putship(ship.shp_uid, &ship);
341                 putsect(&sect);
342             }
343             return total_wanted;
344         } else if (can_move > 0) {
345             int n;
346             gotten += can_move;
347             wanted -= can_move;
348             vec[type] -= can_move;
349
350             n = roundavg(can_move * weight * move_cost);
351             if (n < 0)
352                 n = 0;
353             if (n > sect.sct_mobil)
354                 n = sect.sct_mobil;
355             sect.sct_mobil -= (u_char)n;
356
357             if (actually_doit) {
358                 putvec(VT_ITEM, vec, (s_char *)&ship, EF_SHIP);
359                 putship(ship.shp_uid, &ship);
360                 putsect(&sect);
361             }
362         }
363     }
364
365     /* look for an owned supply unit */
366     snxtitem_dist(&ni, EF_LAND, x, y, lookrange);
367
368     while (nxtitem(&ni, (s_char *)&land) && wanted) {
369         int min;
370
371         if (land.lnd_own != own)
372             continue;
373
374         lcp = &lchr[(int)land.lnd_type];
375         if (!(lcp->l_flags & L_SUPPLY))
376             continue;
377
378         getvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
379         if (vec[type] <= get_minimum(&land, type))
380             continue;
381
382         getsect(land.lnd_x, land.lnd_y, &sect);
383         if (BestLandPath(buf, &dest, &sect, &move_cost, MOB_ROAD) ==
384             (s_char *)0)
385             continue;
386
387         if ((land.lnd_ship >= 0) && (sect.sct_type != SCT_HARBR))
388             continue;
389
390         if ((land.lnd_ship >= 0) && (sect.sct_effic < 2))
391             continue;
392
393         if ((vec[type] - wanted) < get_minimum(&land, type)) {
394             int hold;
395             struct lndstr l2;
396
397             l2 = land;
398             hold = vec[type];
399             vec[type] = 0;
400             putvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
401             land.lnd_fuel = 0;
402             putland(land.lnd_uid, &land);
403             hold +=
404                 s_commod(own, land.lnd_x, land.lnd_y, type, wanted,
405                          actually_doit);
406             vec[type] = hold;
407             putvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
408             putland(land.lnd_uid, &land);
409             if (!actually_doit)
410                 putland(l2.lnd_uid, &l2);
411         }
412
413         getvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
414         ip = &ichr[type];
415         weight = ((double)ip->i_lbs);
416         mobcost = move_cost * weight;
417         if (mobcost > 0)
418             can_move = ((double)land.lnd_mobil / mobcost);
419         else
420             can_move = vec[type] - min;
421         min = get_minimum(&land, type);
422         if (can_move > (vec[type] - min))
423             can_move = (vec[type] - min);
424
425         if (can_move >= wanted) {
426             vec[type] -= wanted;
427
428             /* resupply the supply unit */
429             resupply_commod(&land, type);
430
431             land.lnd_mobil -= roundavg(wanted * weight * move_cost);
432
433             if (actually_doit) {
434                 putvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
435                 putland(land.lnd_uid, &land);
436             }
437             return total_wanted;
438         } else if (can_move > 0) {
439             gotten += can_move;
440             wanted -= can_move;
441             vec[type] -= can_move;
442
443             land.lnd_mobil -= roundavg(can_move * weight * move_cost);
444
445             if (actually_doit) {
446                 putvec(VT_ITEM, vec, (s_char *)&land, EF_LAND);
447                 putland(land.lnd_uid, &land);
448             }
449         }
450     }
451
452     /* We've done the best we could */
453     /* return the number gotten */
454     return gotten;
455 }
456
457
458 static s_char *
459 itemname(int type)
460 {
461     register int t;
462     register struct ichrstr *ip;
463
464     t = V_ITEM(type);
465     for (ip = &ichr[1]; ip->i_mnem != 0; ip++) {
466         if (t == ip->i_vtype)
467             return ip->i_name;
468     }
469     return 0;
470 }
471
472 /*
473  * We want to get enough shells to fire once,
474  * one update's worth of food, enough fuel for
475  * one update.
476  */
477
478 static int
479 get_minimum(struct lndstr *lp, int type)
480 {
481     struct lchrstr *lcp;
482     int max, want = 0;
483
484     lcp = &lchr[(int)lp->lnd_type];
485     max = vl_find(V_ITEM(type), lcp->l_vtype, lcp->l_vamt, (int)lcp->l_nv);
486
487     switch (type) {
488     case I_FOOD:
489         if (opt_NOFOOD)
490             return 0;           /* no food reqd, get out */
491         want = (((double)etu_per_update * eatrate) *
492                 (double)total_mil(lp)) + 1;
493         break;
494     case I_SHELL:
495         want = lp->lnd_ammo;
496         break;
497
498         /*
499          * return the amount of pet we'd need to get to 
500          * enough fuel for 1 update
501          *
502          */
503     case I_PETROL:
504         if (opt_FUEL == 0)
505             return 0;
506         want = (lp->lnd_fuelu * (((float)etu_per_update *
507                                   land_mob_scale)) / 10.0);
508         want -= lp->lnd_fuel;
509         if (want > 0) {
510             double d;
511             d = (double)want / 10.0;
512             want = (int)d;
513             if (want == 0)
514                 want++;
515         }
516
517         max = want;
518         break;
519     default:
520         return 0;
521     }
522
523     if (want > max)
524         want = max;
525
526     return want;
527 }
528
529 int
530 has_supply(struct lndstr *lp)
531 {
532     struct lchrstr *lcp;
533     int vec[I_MAX + 1], shells_needed, shells, keepshells;
534     int food, food_needed, keepfood;
535     int fuel_needed, fuel, petrol_needed, petrol, keeppetrol;
536
537     lcp = &lchr[(int)lp->lnd_type];
538     getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
539
540     if (!opt_NOFOOD) {
541         food_needed = get_minimum(lp, I_FOOD);
542         food = keepfood = vec[I_FOOD];
543         if (food < food_needed) {
544             vec[I_FOOD] = 0;
545             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
546             food += try_supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y,
547                                       I_FOOD, (food_needed - food));
548             vec[I_FOOD] = keepfood;
549             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
550         }
551         if (food < food_needed)
552             return 0;
553
554     }
555
556     shells_needed = lp->lnd_ammo;
557     shells = keepshells = vec[I_SHELL];
558     if (shells < shells_needed) {
559         vec[I_SHELL] = 0;
560         putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
561         shells += try_supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y,
562                                     I_SHELL, (shells_needed - shells));
563         vec[I_SHELL] = keepshells;
564         putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
565     }
566
567     if (shells < shells_needed)
568         return 0;
569
570     if (opt_FUEL) {
571         fuel_needed = lp->lnd_fuelu;
572
573         fuel = lp->lnd_fuel;
574
575         petrol = petrol_needed = 0;
576
577         if (fuel < fuel_needed) {
578             petrol_needed =
579                 ldround(((double)(fuel_needed - fuel) / 10.0), 1);
580             petrol = keeppetrol = vec[I_PETROL];
581         }
582
583         if (petrol < petrol_needed) {
584             vec[I_PETROL] = 0;
585             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
586             petrol += try_supply_commod(lp->lnd_own,
587                                         lp->lnd_x, lp->lnd_y,
588                                         I_PETROL,
589                                         (petrol_needed - petrol));
590             vec[I_PETROL] = keeppetrol;
591             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
592             fuel += petrol * 10;
593         }
594
595         if (fuel < fuel_needed)
596             return 0;
597     }
598     /* end opt_FUEL */
599     return 1;
600 }
601
602 int
603 use_supply(struct lndstr *lp)
604 {
605     struct lchrstr *lcp;
606     int vec[I_MAX + 1], shells_needed, shells, food, food_needed;
607     int fuel_needed, fuel, petrol_needed, petrol;
608
609     lcp = &lchr[(int)lp->lnd_type];
610     getvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
611
612     shells_needed = lp->lnd_ammo;
613     shells = vec[I_SHELL];
614     if (shells < shells_needed) {
615         vec[I_SHELL] = 0;
616         putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
617         shells += supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y, I_SHELL,
618                                 (shells_needed - shells));
619         vec[I_SHELL] = shells;
620     }
621
622     vec[I_SHELL] = max(vec[I_SHELL] - shells_needed, 0);
623
624     if (lp->lnd_frg)            /* artillery */
625         goto artillery;
626
627     food_needed = get_minimum(lp, I_FOOD);
628     food = vec[I_SHELL];
629
630     if (food < food_needed) {
631         vec[I_FOOD] = 0;
632         putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
633         food += supply_commod(lp->lnd_own, lp->lnd_x, lp->lnd_y, I_FOOD,
634                               (food_needed - food));
635         vec[I_FOOD] = food;
636     }
637
638     vec[I_FOOD] = max(vec[I_FOOD] - food_needed, 0);
639
640     if (opt_FUEL) {
641         fuel_needed = lp->lnd_fuelu;
642         fuel = lp->lnd_fuel;
643
644         petrol = petrol_needed = 0;
645
646         if (fuel < fuel_needed) {
647             petrol_needed =
648                 ldround(((double)(fuel_needed - fuel) / 10.0), 1);
649             petrol = vec[I_PETROL];
650         }
651
652         if (petrol < petrol_needed) {
653             vec[I_PETROL] = 0;
654             putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
655             petrol += supply_commod(lp->lnd_own,
656                                     lp->lnd_x, lp->lnd_y,
657                                     I_PETROL, (petrol_needed - petrol));
658             vec[I_PETROL] = petrol;
659         }
660
661         if (petrol_needed) {
662             if (petrol >= petrol_needed) {
663                 vec[I_PETROL] = max(vec[I_PETROL] - petrol_needed, 0);
664                 lp->lnd_fuel += petrol_needed * 10;
665             } else {
666                 lp->lnd_fuel += vec[I_PETROL] * 10;
667                 vec[I_PETROL] = 0;
668             }
669         }
670
671         lp->lnd_fuel = max(lp->lnd_fuel - fuel_needed, 0);
672     }
673     /* end opt_FUEL */
674   artillery:
675     putvec(VT_ITEM, vec, (s_char *)lp, EF_LAND);
676     putland(lp->lnd_uid, lp);
677     return 1;
678 }