1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2021, 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  *  mobility.c: Add mobility to each of the items which accumulate mobility.
28  *
29  *  Known contributors to this file:
30  *     Dave Pare, 1986
31  *     Steve McClure, 1998-1999
32  *     Markus Armbruster, 2004-2016
33  */
34 
35 #include <config.h>
36 
37 #include "game.h"
38 #include "land.h"
39 #include "optlist.h"
40 #include "plane.h"
41 #include "sect.h"
42 #include "ship.h"
43 #include "update.h"
44 
45 /* Increase mobility of everything for @etus ETUs, update timestamps */
46 void
mob_inc_all(int etus)47 mob_inc_all(int etus)
48 {
49     struct sctstr *sectp;
50     struct shpstr *sp;
51     struct plnstr *pp;
52     struct lndstr *lp;
53     int i;
54     time_t now;
55 
56     time(&now);
57 
58     for (i = 0; (sectp = getsectid(i)); i++) {
59 	sectp->sct_timestamp = now;
60 	if (!opt_MOB_ACCESS)
61 	    mob_inc_sect(sectp, etus);
62     }
63 
64     for (i = 0; (sp = getshipp(i)); i++) {
65 	sp->shp_timestamp = now;
66 	if (!opt_MOB_ACCESS)
67 	    mob_inc_ship(sp, etus);
68     }
69 
70     for (i = 0; (pp = getplanep(i)); i++) {
71 	pp->pln_timestamp = now;
72 	if (!opt_MOB_ACCESS)
73 	    mob_inc_plane(pp, etus);
74     }
75 
76     for (i = 0; (lp = getlandp(i)); i++) {
77 	lp->lnd_timestamp = now;
78 	if (!opt_MOB_ACCESS)
79 	    mob_inc_land(lp, etus);
80     }
81 }
82 
83 /* Increase @sp's mobility for @etus ETUs */
84 void
mob_inc_sect(struct sctstr * sp,int etus)85 mob_inc_sect(struct sctstr *sp, int etus)
86 {
87     int value;
88 
89     if (CANT_HAPPEN(etus < 0))
90 	etus = 0;
91 
92     if (sp->sct_own == 0)
93 	return;
94     if (sp->sct_type == SCT_WATER || sp->sct_type == SCT_SANCT)
95 	return;
96 
97     value = sp->sct_mobil + ((float)etus * sect_mob_scale);
98     if (value > sect_mob_max)
99 	value = sect_mob_max;
100     sp->sct_mobil = value;
101 }
102 
103 /* Increase @sp's mobility for @etus ETUs */
104 void
mob_inc_ship(struct shpstr * sp,int etus)105 mob_inc_ship(struct shpstr *sp, int etus)
106 {
107     int value;
108 
109     if (CANT_HAPPEN(etus < 0))
110 	etus = 0;
111 
112     if (sp->shp_own == 0)
113 	return;
114 
115     value = sp->shp_mobil + (float)etus * ship_mob_scale;
116     if (value > ship_mob_max)
117 	value = ship_mob_max;
118     sp->shp_mobil = (signed char)value;
119 }
120 
121 /* Increase @lp's mobility for @etus ETUs */
122 void
mob_inc_land(struct lndstr * lp,int etus)123 mob_inc_land(struct lndstr *lp, int etus)
124 {
125     int value;
126 
127     if (CANT_HAPPEN(etus < 0))
128 	etus = 0;
129 
130     if (lp->lnd_own == 0)
131 	return;
132 
133     value = lp->lnd_mobil + ((float)etus * land_mob_scale);
134     if (value > land_mob_max) {
135 	if (lp->lnd_harden < land_mob_max && !opt_MOB_ACCESS) {
136 	    /*
137 	     * Automatic fortification on excess mobility.
138 	     * Disabled for MOB_ACCESS, because it leads to
139 	     * excessively deep recursion and thus miserable
140 	     * performance as the number of land units grows.
141 	     *
142 	     * Provide mobility to be used in lnd_fortify()
143 	     * without overflowing lnd_mobil.
144 	     */
145 	    lp->lnd_mobil = land_mob_max;
146 	    lnd_fortify(lp, value - land_mob_max);
147 	}
148 	value = land_mob_max;
149     }
150     lp->lnd_mobil = value;
151 }
152 
153 /* Increase @pp's mobility for @etus ETUs */
154 void
mob_inc_plane(struct plnstr * pp,int etus)155 mob_inc_plane(struct plnstr *pp, int etus)
156 {
157     int value;
158 
159     if (CANT_HAPPEN(etus < 0))
160 	etus = 0;
161 
162     if (pp->pln_own == 0)
163 	return;
164 
165     value = pp->pln_mobil + ((float)etus * plane_mob_scale);
166     if (value > plane_mob_max)
167 	value = plane_mob_max;
168     pp->pln_mobil = value;
169 }
170 
171 /*
172  * Credit the turn's remaining MOB_ACCESS mobility.
173  * Exactly as if everything was accessed right now.
174  */
175 void
mob_access_all(void)176 mob_access_all(void)
177 {
178     struct sctstr *sectp;
179     struct shpstr *sp;
180     struct plnstr *pp;
181     struct lndstr *lp;
182     int i;
183 
184     if (CANT_HAPPEN(!opt_MOB_ACCESS))
185 	return;
186 
187     for (i = 0; (sectp = getsectid(i)); i++)
188 	mob_inc_sect(sectp, game_reset_tick(&sectp->sct_access));
189 
190     for (i = 0; (sp = getshipp(i)); i++)
191 	mob_inc_ship(sp, game_reset_tick(&sp->shp_access));
192 
193     for (i = 0; (pp = getplanep(i)); i++)
194 	mob_inc_plane(pp, game_reset_tick(&pp->pln_access));
195 
196     for (i = 0; (lp = getlandp(i)); i++)
197 	mob_inc_land(lp, game_reset_tick(&lp->lnd_access));
198 }
199