]> git.pond.sub.org Git - empserver/blob - src/lib/common/bestpath.c
Cleanup #includes of (mostly a long time) unused header files.
[empserver] / src / lib / common / bestpath.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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  *  bestpath.c: Find the best path between sectors
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 1998-2000
32  */
33
34 /* 
35  * IMPORTANT: These routines are very selectively used in the server.
36  *
37  * "bestpath" is now obsolete (and removed)
38  * "bestownedpath" is only used to determine paths for ships and planes.
39  * 
40  * Callers should not be calling these directly anymore. They should use
41  * the "BestShipPath", "BestAirPath", "BestLandPath" and "BestDistPath"
42  * functions.  Note that those last two use the A* algorithms to find
43  * information.
44  */
45
46 #include "misc.h"
47 #include "xy.h"
48 #include "sect.h"
49 #include "file.h"
50 #include "nat.h"
51 #include "common.h"
52 #include "optlist.h"
53
54 static int owned_and_navigable(s_char *, int, int, s_char *, int);
55
56 #define MAXROUTE        100     /* return '?' if path longer than this */
57 #define valid(x,y)      (((x^y)&1)==0)
58
59 /* ________________________________________________________________
60 **
61 **  bestpath(x1,y1,x2,y2,(s_char *)terrain);
62 **
63 **  Calculate routing string to get from sector [x1,y1] to sector [x2,y2]
64 **  via a specified type of terrain.
65 **
66 **  Specify:
67 **
68 **      x1,y1        starting coordinates
69 **
70 **      x2,y2        destination coordinates
71 **
72 **      terrain      ptr to string showing the types of sectors that
73 **                   we're allowed to pass through:
74 **
75 **                   A null string enables routing through any kind of
76 **                   sector (useful for airplanes).
77 **
78 **                   A string that begins with an 'R' ensures that
79 **                   the source and destination sectors also match
80 **                   the specified type of terrain.
81 **
82 **                   A string that begins with a '~' (after the 'R',
83 **                   if necessary) specifies that we can pass through
84 **                   any kind of sector EXCEPT those in the remainder
85 **                   of the string.
86 **
87 **                   Examples:
88 **
89 **                      "R~.^"  all sectors along route must be
90 **                              non-ocean, non-mountain
91 **
92 **                      "+"     all sectors between start and end
93 **                              must be highway
94 **
95 **                      "h. "   all sectors along route must be
96 **                              harbor, water, or unmapped
97 **
98 **  'bestpath' returns a pointer to a route string containing either:
99 **
100 **     yugjbn - string of normal routing characters if route possible
101 **     ?      - if route is longer than MAXROUTE characters
102 **     \0     - (null string) if no route possible
103 **     h      - if start and end points are the same sector
104 ** ________________________________________________________________
105 */
106
107 s_char *dirchar = "juygbn";
108 int dx[6] = { 2, 1, -1, -2, -1, 1 };
109 int dy[6] = { 0, -1, -1, 0, 1, 1 };
110
111 /*
112  * Ok, note that here we malloc some buffers.  BUT, we never
113  * free them.  Why, you may ask?  Because we want to allocate
114  * them based on world size which is now (or soon to be) dynamic,
115  * but we don't want to allocate each and every time, since that
116  * would be slow.  And, since world size only changes at init
117  * time, we can do this safely.
118  * We also share these buffers between "bestpath" and "bestownedpath"
119  * since you can never be in both functions at the same time.  If that
120  * did happen, we'd already be so broken that it won't matter.
121  */
122 static unsigned int *mapbuf = (unsigned int *)0;
123 static unsigned int **mapindex = (unsigned int **)0;
124
125 s_char *
126 bestownedpath(s_char *bpath,
127               s_char *bigmap,
128               int x, int y, int ex, int ey, s_char *terrain, int own)
129 {
130     int i, j, tx, ty, markedsectors, restr2;
131     int minx, maxx, miny, maxy, scanx, scany;
132     unsigned int routelen;
133
134     if (!mapbuf)
135         mapbuf = (unsigned int *)malloc((WORLD_X * WORLD_Y) *
136                                         sizeof(unsigned int));
137     if (!mapbuf)
138         return ((s_char *)0);
139     if (!mapindex) {
140         mapindex =
141             (unsigned int **)malloc(WORLD_X * sizeof(unsigned int *));
142         if (mapindex) {
143             /* Setup the map pointers */
144             for (i = 0; i < WORLD_X; i++)
145                 mapindex[i] = &mapbuf[WORLD_Y * i];
146         }
147     }
148     if (!mapindex)
149         return ((s_char *)0);
150
151     bpath[0] = 0;
152     if (0 != (restr2 = (*terrain == 'R')))
153         terrain++;
154
155     x = XNORM(x);
156     y = YNORM(y);
157     ex = XNORM(ex);
158     ey = YNORM(ey);
159
160     if (x == ex && y == ey) {
161         bpath[0] = 'h';
162         bpath[1] = 0;
163         return ((s_char *)bpath);
164     }
165
166     if (!valid(x, y) || !valid(ex, ey))
167         return ((s_char *)0);
168
169     if (restr2 && (!owned_and_navigable(bigmap, x, y, terrain, own) ||
170                    !owned_and_navigable(bigmap, x, y, terrain, own)))
171         return ((s_char *)0);
172
173     for (i = 0; i < WORLD_X; i++)
174         for (j = 0; j < WORLD_Y; j++)
175             mapindex[i][j] = 0xFFFF;    /* clear the workspace  */
176
177     routelen = 0;               /* path length is now 0 */
178     mapindex[x][y] = 0;         /* mark starting spot   */
179     markedsectors = 1;          /* source sector marked */
180     minx = x - 2;               /* set X scan bounds    */
181     maxx = x + 2;
182     miny = y - 1;               /* set Y scan bounds    */
183     maxy = y + 1;
184
185     do {
186         if (++routelen == MAXROUTE) {
187             bpath[0] = '?';
188             bpath[1] = 0;
189             return ((s_char *)bpath);
190         }
191         markedsectors = 0;
192         for (scanx = minx; scanx <= maxx; scanx++) {
193             x = XNORM(scanx);
194             for (scany = miny; scany <= maxy; scany++) {
195                 y = YNORM(scany);
196                 if (valid(x, y)) {
197                     if ((((mapindex[x][y]) & 0x1FFF) == (routelen - 1))) {
198                         for (i = 0; i < 6; i++) {
199                             tx = x + dx[i];
200                             ty = y + dy[i];
201                             tx = XNORM(tx);
202                             ty = YNORM(ty);
203                             if (mapindex[tx][ty] == 0xFFFF) {
204                                 if (owned_and_navigable(bigmap, tx, ty,
205                                                         terrain, own)
206                                     || (tx == ex && ty == ey && !restr2)) {
207                                     mapindex[tx][ty] =
208                                         ((i + 1) << 13) + routelen;
209                                     markedsectors++;
210                                 }
211                             }
212                             if (tx == ex && ty == ey) {
213                                 bpath[routelen] = 0;
214                                 while (routelen--) {
215                                     i = ((mapindex[tx][ty]) >> 13) - 1;
216                                     bpath[routelen] = dirchar[i];
217                                     tx = tx - dx[i];
218                                     ty = ty - dy[i];
219                                     tx = XNORM(tx);
220                                     ty = YNORM(ty);
221                                 }
222                                 return ((s_char *)bpath);
223                             }
224                         }
225                     }
226                 }
227             }
228         }
229         miny--;
230         maxy++;
231         minx -= 2;
232         maxx += 2;
233     } while (markedsectors);
234
235     bpath[0] = 0;
236     return ((s_char *)0);       /* no route possible    */
237 }
238
239 /* return TRUE if sector is passable */
240 static int
241 owned_and_navigable(s_char *map, int x, int y, s_char *terrain, int own)
242 {
243     s_char c;
244     s_char *t;
245     s_char mapspot;             /* What this spot on the bmap is */
246     int negate;
247     struct sctstr *sect;
248     int rel;
249
250     /* No terrain to check?  Everything is navigable! (this
251        probably means we are flying) */
252     if (!(*terrain))
253         return (1);
254
255     /* Are we checking this map? */
256     if (map) {
257         /* Do we know what this sector is?  If not, we assume it's ok,
258            since otherwise we'll never venture anywhere */
259         mapspot = map[sctoff(x, y)];
260         if (mapspot == ' ' || mapspot == 0)
261             return (1);
262
263         /* Now, is it marked with a 'x' or 'X'? If so, avoid it! */
264         if (mapspot == 'x' || mapspot == 'X')
265             return (0);
266     } else {
267         /* We don't know what it is since we have no map, so return ok! */
268         return (1);
269     }
270
271     /* Now, check this bmap entry to see if it is one of the
272        terrain types. */
273     t = terrain;
274     if (*t == '~') {
275         negate = 1;
276         t++;
277     } else
278         negate = 0;
279
280     while (*t) {
281         if (*t == mapspot)
282             break;
283         t++;
284     }
285     if (negate && *t) {
286         /* We found it, so we say it's bad since we are negating */
287         return (0);
288     } else if (!negate && !*t) {
289         /* We didn't find it, so we say it's bad since we aren't negating */
290         return (0);
291     }
292
293     /* According to our bmap, this sector is ok so far. */
294
295     /* Ok, we made it this far.  Now get the sector */
296     sect = getsectp(x, y);
297     c = dchr[sect->sct_type].d_mnem;
298     /* Ok, now, check the owner if needed */
299     if (own >= 0) {
300         if (sect->sct_own != own) {
301             rel = getrel(getnatp(sect->sct_own), own);
302             /* We can't sail through deity sectors, but we can sail
303                through any ocean */
304             if (rel < FRIENDLY && sect->sct_type != SCT_WATER)
305                 return (0);
306         }
307     }
308     /* Ok, now, check these two sector types */
309     /* check for bad harbors. */
310     if (c == 'h' && sect->sct_effic < 2)
311         return (0);
312     /* check for bad bridges  */
313     if (c == '=' && sect->sct_effic < 60)
314         return (0);
315     /* Woo-hoo, it's ok! */
316     return (1);
317 }