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