]> git.pond.sub.org Git - empserver/blob - src/lib/update/mobility.c
(do_mob_land): Use excess mobility to fortify. Note that units
[empserver] / src / lib / update / mobility.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  *  mobility.c: Add mobility to each of the items which accumulate mobility.
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986
32  *     Steve McClure, 1998-1999
33  */
34
35 #include "misc.h"
36 #include "var.h"
37 #include "sect.h"
38 #include "ship.h"
39 #include "land.h"
40 #include "plane.h"
41 #include "nat.h"
42 #include "file.h"
43 #include "optlist.h"
44 #include "mission.h"
45 #include "update.h"
46 #include "gen.h"
47 #include "subs.h"
48 #include "optlist.h"
49
50 extern int timestamp_fixing;
51 extern int update_pending;
52 int do_upd_checking = 0;
53
54 static void do_mob_land(register struct lndstr *, register int);
55 static void do_mob_plane(register struct plnstr *, register int);
56 static void do_mob_sect(register struct sctstr *sp, register int etus);
57 static void do_mob_ship(register struct shpstr *, register int);
58
59 int
60 increase_mob(time_t * counter, float mult)
61 {
62     time_t secs;
63     time_t now;
64     time_t left;
65     extern long s_p_etu;
66     extern int updating_mob;
67     int newetus;
68     float newmob;
69     int inewmob;
70
71     time(&now);
72
73     secs = now - *counter;
74     if (secs < 1 || secs < s_p_etu)
75         return 0;
76     newetus = (int)(secs / s_p_etu);
77     if (newetus < 1)
78         return 0;
79     left = (secs % s_p_etu);
80     do {
81         newmob = (float)(newetus * mult);
82         inewmob = (int)(newetus * mult);
83         if (newmob == inewmob || newetus > 7)
84             break;
85         newetus--;
86         left += s_p_etu;
87     } while (newetus > 0);
88     if (newetus <= 0)
89         return 0;
90
91     time(counter);
92     *counter = *counter - left;
93
94     if (updating_mob)
95         return (newetus);
96     return 0;
97 }
98
99 void
100 update_timestamps(time_t lastsavedtime)
101 {
102     struct shpstr *shipp;
103     struct sctstr *sectp;
104     struct lndstr *landp;
105     struct plnstr *planep;
106     int n;
107     time_t now;
108     time_t delta;
109
110     timestamp_fixing = 1;
111     time(&now);
112     delta = now - lastsavedtime;
113     for (n = 0; (shipp = getshipp(n)); n++)
114         shipp->shp_access += delta;
115     for (n = 0; (sectp = getsectid(n)); n++)
116         sectp->sct_access += delta;
117     for (n = 0; (landp = getlandp(n)); n++)
118         landp->lnd_access += delta;
119     for (n = 0; (planep = getplanep(n)); n++)
120         planep->pln_access += delta;
121     timestamp_fixing = 0;
122 }
123
124 void
125 update_all_mob(void)
126 {
127     struct shpstr *shipp;
128     struct sctstr *sectp;
129     struct lndstr *landp;
130     struct plnstr *planep;
131     int n;
132
133     n = 0;
134     while (1) {
135         do_upd_checking = 1;
136         shipp = getshipp(n);
137         sectp = getsectid(n);
138         landp = getlandp(n);
139         planep = getplanep(n);
140         do_upd_checking = 0;
141         if (shipp)
142             shp_do_upd_mob(shipp);
143         if (sectp)
144             sct_do_upd_mob(sectp);
145         if (landp)
146             lnd_do_upd_mob(landp);
147         if (planep)
148             pln_do_upd_mob(planep);
149         if (!shipp && !sectp && !landp && !planep)
150             break;
151         n++;
152     }
153     do_upd_checking = 0;
154 }
155
156 void
157 sct_do_upd_mob(register struct sctstr *sp)
158 {
159     extern float sect_mob_scale;
160     int etus;
161
162     if (do_upd_checking || timestamp_fixing || update_pending)
163         return;
164     if (sp->sct_own == 0)
165         return;
166     if (sp->sct_type == SCT_SANCT)
167         return;
168     if ((etus = increase_mob(&sp->sct_access, sect_mob_scale)) == 0)
169         return;
170     do_upd_checking = 1;
171     do_mob_sect(sp, etus);
172 /*    putsect(sp);*/
173     do_upd_checking = 0;
174 }
175
176 void
177 shp_do_upd_mob(register struct shpstr *sp)
178 {
179     extern float ship_mob_scale;
180     int etus;
181
182     if (do_upd_checking || timestamp_fixing || update_pending)
183         return;
184     if (sp->shp_own == 0)
185         return;
186     if ((etus = increase_mob(&sp->shp_access, ship_mob_scale)) == 0)
187         return;
188     do_upd_checking = 1;
189     do_mob_ship(sp, etus);
190     do_upd_checking = 0;
191 }
192
193 void
194 lnd_do_upd_mob(register struct lndstr *lp)
195 {
196     extern float land_mob_scale;
197     int etus;
198
199     if (do_upd_checking || timestamp_fixing || update_pending)
200         return;
201     if (lp->lnd_own == 0)
202         return;
203     if ((etus = increase_mob(&lp->lnd_access, land_mob_scale)) == 0)
204         return;
205
206     do_upd_checking = 1;
207     do_mob_land(lp, etus);
208     do_upd_checking = 0;
209 }
210
211 void
212 pln_do_upd_mob(register struct plnstr *pp)
213 {
214     extern float plane_mob_scale;
215     int etus;
216
217     if (do_upd_checking || timestamp_fixing || update_pending)
218         return;
219     if (pp->pln_own == 0)
220         return;
221     if ((etus = increase_mob(&pp->pln_access, plane_mob_scale)) == 0)
222         return;
223
224     do_upd_checking = 1;
225     do_mob_plane(pp, etus);
226     do_upd_checking = 0;
227 }
228
229 void
230 mob_sect(register int etus)
231 {
232     register struct sctstr *sp;
233     register int n;
234     time_t now;
235
236     time(&now);
237     for (n = 0; NULL != (sp = getsectid(n)); n++) {
238         sp->sct_timestamp = now;
239         if (opt_MOB_ACCESS)
240             sct_do_upd_mob(sp);
241         else
242             do_mob_sect(sp, etus);
243     }
244 }
245
246 static void
247 do_mob_sect(register struct sctstr *sp, register int etus)
248 {
249     extern float sect_mob_scale;
250     extern int sect_mob_max;
251     register int value;
252
253     if (sp->sct_own == 0)
254         return;
255     if (sp->sct_type == SCT_SANCT)
256         return;
257     /* Do we have to even bother? */
258     if (sp->sct_mobil >= sect_mob_max) {
259         /* No, so set just in case and then return */
260         sp->sct_mobil = sect_mob_max;
261         return;
262     }
263     value = sp->sct_mobil + ((float)etus * sect_mob_scale);
264     if (value > sect_mob_max)
265         value = sect_mob_max;
266     sp->sct_mobil = value;
267 }
268
269 void
270 mob_ship(register int etus)
271 {
272     register struct shpstr *sp;
273     register int n;
274     time_t now;
275
276     time(&now);
277     for (n = 0; NULL != (sp = getshipp(n)); n++) {
278         sp->shp_timestamp = now;
279         if (opt_MOB_ACCESS)
280             shp_do_upd_mob(sp);
281         else
282             do_mob_ship(sp, etus);
283     }
284 }
285
286 static void
287 do_mob_ship(register struct shpstr *sp, register int etus)
288 {
289     extern int ship_mob_max;
290     extern float ship_mob_scale;
291     int newfuel = 0;
292     register int value;
293     int can_add, have_fuel_for, total_add;
294     double d;
295     extern int fuel_mult;
296
297     if (sp->shp_own == 0)
298         return;
299
300     /* Do we even have to bother updating this mobility? */
301     if (sp->shp_mobil >= ship_mob_max) {
302         /* No, so don't.  Just set it to max (just in case) and
303            return. */
304         sp->shp_mobil = ship_mob_max;
305         return;
306     }
307
308     if (opt_FUEL == 0) {        /* only a bit to do ... */
309         value = sp->shp_mobil + ((float)etus * ship_mob_scale);
310         if (value > ship_mob_max)
311             value = ship_mob_max;
312         sp->shp_mobil = value;
313         return;                 /* so we ship the FUEL stuff */
314     }
315
316     /* opt_FUEL in force */
317     if (mchr[(int)sp->shp_type].m_fuelu == 0) {
318         value = sp->shp_mobil + ((float)etus * ship_mob_scale);
319         if (value > ship_mob_max)
320             value = ship_mob_max;
321         sp->shp_mobil = (s_char)value;
322     } else {
323         can_add = ship_mob_max - sp->shp_mobil;
324         if (can_add > ((float)etus * ship_mob_scale))
325             can_add = ((float)etus * ship_mob_scale);
326         have_fuel_for = ldround((((double)sp->shp_fuel /
327                                   (double)mchr[(int)sp->shp_type].
328                                   m_fuelu) * (double)fuel_mult), 1);
329
330         if (can_add > have_fuel_for) {
331             int need;
332             need = can_add - have_fuel_for;
333             d = (double)need;
334             d *= (double)mchr[(int)sp->shp_type].m_fuelu;
335             d /= (double)fuel_mult;
336             d /= 5.0;
337             if ((d - (int)d) > 0.0)
338                 d++;
339             need = (int)d;
340             newfuel = supply_commod(sp->shp_own, sp->shp_x,
341                                     sp->shp_y, I_PETROL, need);
342             sp->shp_fuel += (u_char)(newfuel * 5);
343         }
344
345         have_fuel_for = ldround((((double)sp->shp_fuel /
346                                   (double)mchr[(int)sp->shp_type].
347                                   m_fuelu) * (double)fuel_mult), 1);
348
349         if (can_add > have_fuel_for) {
350             int need;
351             need = can_add - have_fuel_for;
352             d = (double)need;
353             d *= (double)mchr[(int)sp->shp_type].m_fuelu;
354             d /= (double)fuel_mult;
355             d /= 50.0;
356             if ((d - (int)d) > 0.0)
357                 d++;
358             need = (int)d;
359             newfuel = supply_commod(sp->shp_own, sp->shp_x,
360                                     sp->shp_y, I_OIL, need);
361             sp->shp_fuel += (u_char)(newfuel * 50);
362         }
363
364         have_fuel_for = ldround((((double)sp->shp_fuel /
365                                   (double)mchr[(int)sp->shp_type].
366                                   m_fuelu) * (double)fuel_mult), 1);
367
368         if (can_add > have_fuel_for)
369             total_add = have_fuel_for;
370         else
371             total_add = can_add;
372         d = (double)total_add;
373         d *= (double)mchr[(int)sp->shp_type].m_fuelu;
374         d /= (double)fuel_mult;
375         sp->shp_fuel -= (u_char)ldround(d, 1);
376         sp->shp_fuel = (u_char)min(sp->shp_fuel,
377                                    mchr[(int)sp->shp_type].m_fuelc);
378         sp->shp_mobil += (s_char)total_add;
379     }
380 }
381
382 void
383 mob_land(register int etus)
384 {
385     register struct lndstr *lp;
386     register int n;
387     time_t now;
388
389     time(&now);
390     for (n = 0; NULL != (lp = getlandp(n)); n++) {
391         lp->lnd_timestamp = now;
392         if (opt_MOB_ACCESS)
393             lnd_do_upd_mob(lp);
394         else
395             do_mob_land(lp, etus);
396     }
397 }
398
399 static void
400 do_mob_land(register struct lndstr *lp, register int etus)
401 {
402     extern int land_mob_max;
403     extern float land_mob_scale;
404     int newfuel = 0;
405     register int value;
406     int can_add, have_fuel_for, total_add;
407     double d;
408     extern int fuel_mult;
409
410     if (lp->lnd_own == 0)
411         return;
412
413     if (lp->lnd_mobil >= land_mob_max) {
414         lp->lnd_mobil = land_mob_max;
415         if (lp->lnd_harden >= land_mob_max) {
416             lp->lnd_harden = land_mob_max;
417             return;
418         }
419     }
420
421     /*
422      * Give damaged units a break. When at low
423      * efficiency, units can go to -100 mob when
424      * marching 1 step, making them slower than
425      * normal mil. This helps take the curse off.
426      * If MOB_ACCESS is on, we don't do this, as it would
427      * be too much of an advantage.  So, we just add double
428      * the small amount of mob if we are < 0 instead.
429      */
430
431     if (!opt_MOB_ACCESS) {
432         if (lp->lnd_mobil < 0)
433             lp->lnd_mobil /= 2;
434     }
435
436     if (opt_FUEL == 0) {        /* just some bits and pieces */
437         if (opt_MOB_ACCESS) {
438             if (lp->lnd_mobil < 0)
439                 value =
440                     lp->lnd_mobil + (2 * ((float)etus * land_mob_scale));
441             else
442                 value = lp->lnd_mobil + ((float)etus * land_mob_scale);
443         } else {
444             value = lp->lnd_mobil + ((float)etus * land_mob_scale);
445         }
446         if (value > land_mob_max) {
447             lnd_fortify(lp, value - land_mob_max);
448             value = land_mob_max;
449         }
450         lp->lnd_mobil = value;
451
452         return;                 /* Done! */
453     }
454
455     /* opt_FUEL in force ... */
456     if (lp->lnd_fuelu == 0) {
457         if (opt_MOB_ACCESS) {
458             if (lp->lnd_mobil < 0)
459                 value =
460                     lp->lnd_mobil + (2 * ((float)etus * land_mob_scale));
461             else
462                 value = lp->lnd_mobil + ((float)etus * land_mob_scale);
463         } else {
464             value = lp->lnd_mobil + ((float)etus * land_mob_scale);
465         }
466         if (value > land_mob_max) {
467             lnd_fortify(lp, value - land_mob_max);
468             value = land_mob_max;
469         }
470         lp->lnd_mobil = value;
471
472     } else {
473
474         can_add = land_mob_max - lp->lnd_mobil;
475
476         if (can_add > ((float)etus * land_mob_scale))
477             can_add = ((float)etus * land_mob_scale);
478
479         have_fuel_for = (lp->lnd_fuel / lp->lnd_fuelu) * fuel_mult;
480
481         if (can_add > have_fuel_for) {
482             int need;
483             need = can_add - have_fuel_for;
484             d = (double)need;
485             d *= (double)lp->lnd_fuelu;
486             d /= (double)fuel_mult;
487             d /= 5.0;
488             if ((d - (int)d) > 0.0)
489                 d++;
490             need = (int)d;
491             newfuel = supply_commod(lp->lnd_own, lp->lnd_x,
492                                     lp->lnd_y, I_PETROL, need);
493             lp->lnd_fuel += (u_char)(newfuel * 5);
494         }
495
496         have_fuel_for = (lp->lnd_fuel / lp->lnd_fuelu) * fuel_mult;
497
498         if (can_add > have_fuel_for) {
499             int need;
500             need = can_add - have_fuel_for;
501             d = (double)need;
502             d *= (double)lp->lnd_fuelu;
503             d /= (double)fuel_mult;
504             d /= 50.0;
505             if ((d - (int)d) > 0.0)
506                 d++;
507             need = (int)d;
508             newfuel = supply_commod(lp->lnd_own, lp->lnd_x,
509                                     lp->lnd_y, I_OIL, need);
510             lp->lnd_fuel += (u_char)(newfuel * 50);
511         }
512
513         have_fuel_for = (lp->lnd_fuel / lp->lnd_fuelu) * fuel_mult;
514
515         if (can_add > have_fuel_for) {
516             total_add = have_fuel_for;
517         } else
518             total_add = can_add;
519         d = (double)total_add;
520         d *= (double)lp->lnd_fuelu;
521         d /= (double)fuel_mult;
522         lp->lnd_fuel -= (u_char)ldround(d, 1);
523         lp->lnd_fuel = (u_char)min(lp->lnd_fuel, lp->lnd_fuelc);
524         if (total_add + lp->lnd_mobil > land_mob_max) {
525             total_add = land_mob_max - lp->lnd_mobil;
526         }
527         /* no automatic fortification here, as it would cost fuel */
528
529         if (opt_MOB_ACCESS) {
530             if (lp->lnd_mobil < 0)
531                 lp->lnd_mobil += (s_char)total_add;
532         }
533         lp->lnd_mobil += (s_char)total_add;
534     }
535 }
536
537 void
538 mob_plane(register int etus)
539 {
540     register struct plnstr *pp;
541     register int n;
542     time_t now;
543
544     time(&now);
545     for (n = 0; NULL != (pp = getplanep(n)); n++) {
546         pp->pln_timestamp = now;
547         if (opt_MOB_ACCESS)
548             pln_do_upd_mob(pp);
549         else
550             do_mob_plane(pp, etus);
551     }
552 }
553
554 static void
555 do_mob_plane(register struct plnstr *pp, register int etus)
556 {
557     extern int plane_mob_max;
558     extern float plane_mob_scale;
559     register int value;
560
561     if (pp->pln_own == 0)
562         return;
563     if (pp->pln_mobil >= plane_mob_max) {
564         pp->pln_mobil = plane_mob_max;
565         return;
566     }
567
568     value = pp->pln_mobil + ((float)etus * plane_mob_scale);
569     if (value > plane_mob_max)
570         value = plane_mob_max;
571     pp->pln_mobil = value;
572 }