]> git.pond.sub.org Git - empserver/blob - src/lib/common/maps.c
COPYING duplicates information from README. Remove. Move GPL from
[empserver] / src / lib / common / maps.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, 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 files README, COPYING and CREDITS in the root of the source
23  *  tree for related information and legal notices.  It is expected
24  *  that future projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  maps.c: Map routines
29  * 
30  *  Known contributors to this file:
31  *     Ken Stevens, 1995
32  *     Steve McClure, 1998
33  */
34
35 #include <config.h>
36
37 #include "misc.h"
38 #include "player.h"
39 #include "sect.h"
40 #include "xy.h"
41 #include "nsc.h"
42 #include "file.h"
43 #include "nat.h"
44 #include "map.h"
45 #include "ship.h"
46 #include "land.h"
47 #include "plane.h"
48 #include "common.h"
49 #include "gen.h"
50 #include "subs.h"
51 #include "optlist.h"
52
53 static int bmnxtsct(struct nstr_sect *);
54 static s_char map_char(u_char type, natid own, int owner_or_god);
55
56 int
57 draw_map(int bmap, s_char origin, int map_flags, struct nstr_sect *nsp)
58 {
59     struct natstr *np;
60     struct range range;
61     struct nstr_item ni;
62     struct shpstr ship;
63     struct lndstr land;
64     struct plnstr plane;
65     coord x, y;
66     int i;
67     /* Note this is not re-entrant anyway, so we keep the buffers
68        around */
69     static u_char *bitmap = (u_char *)0;
70     static s_char *wmapbuf = (s_char *)0;
71     static s_char **wmap = (s_char **)0;
72
73     if (!wmapbuf)
74         wmapbuf = malloc((WORLD_Y * MAPWIDTH(1)) * sizeof(s_char));
75     if (!wmap) {
76         wmap = malloc(WORLD_Y * sizeof(s_char *));
77         if (wmap && wmapbuf) {
78             for (i = 0; i < WORLD_Y; i++)
79                 wmap[i] = &wmapbuf[MAPWIDTH(1) * i];
80         } else if (wmap) {
81             free(wmap);
82             wmap = (s_char **)0;
83         }
84     }
85     if (!bitmap)
86         bitmap = malloc((WORLD_X * WORLD_Y) / 8);
87     if (!wmapbuf || !wmap || !bitmap) {
88         pr("Memory error, tell the deity.\n");
89         logerror("malloc failed in draw_map\n");
90         return RET_FAIL;
91     }
92
93     if (bmap == 'r') {
94         if (!confirm("Are you sure you want to revert your bmap? "))
95             return RET_OK;
96     }
97     if (!(player->command->c_flags & C_MOD)) {
98         logerror("%s command needs C_MOD flag set",
99                  player->command->c_form);
100         player->command->c_flags |= C_MOD;
101     }
102     np = getnatp(player->cnum);
103     /* zap any conditionals */
104     nsp->ncond = 0;
105     xyrelrange(np, &nsp->range, &range);
106     border(&range, "     ", "");
107     blankfill((s_char *)wmapbuf, &nsp->range, 1);
108     if (bmap) {
109         int c;
110         switch (bmap) {
111         default:
112             CANT_HAPPEN("bad BMAP");
113             bmap = 'b';
114             /* fall through */
115         case 'b':
116             while (bmnxtsct(nsp) && !player->aborted) {
117                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
118                     wmap[nsp->dy][nsp->dx] = c;
119             }
120             break;
121         case 't':
122             while (bmnxtsct(nsp) && !player->aborted) {
123                 if (0 != (c = player->map[sctoff(nsp->x, nsp->y)]))
124                     wmap[nsp->dy][nsp->dx] = c;
125             }
126             break;
127         case 'r':
128             while (bmnxtsct(nsp) && !player->aborted) {
129                 player->bmap[sctoff(nsp->x, nsp->y)] =
130                     player->map[sctoff(nsp->x, nsp->y)];
131                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
132                     wmap[nsp->dy][nsp->dx] = c;
133             }
134             ef_write(EF_BMAP, player->cnum, player->bmap);
135             break;
136         case 'n':
137             {
138                 struct sctstr sect;
139
140                 if (!player->god) {
141                     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
142                     bitinit2(nsp, bitmap, player->cnum);
143                 }
144                 while (nxtsct(nsp, &sect) && !player->aborted) {
145                     if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
146                         continue;
147                     wmap[nsp->dy][nsp->dx]
148                         = map_char(sect.sct_newtype, sect.sct_own,
149                                    player->owner);
150                 }
151                 break;
152             }
153         }
154     } else {
155         struct sctstr sect;
156         s_char mapch;
157         int changed = 0;
158
159         if (!player->god) {
160             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
161             bitinit2(nsp, bitmap, player->cnum);
162         }
163         while (nxtsct(nsp, &sect) && !player->aborted) {
164             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
165                 continue;
166             mapch = map_char(sect.sct_type, sect.sct_own, player->owner);
167             wmap[nsp->dy][nsp->dx] = mapch;
168             changed |= map_set(player->cnum, nsp->x, nsp->y, mapch, 0);
169         }
170         if (changed)
171             writemap(player->cnum);
172     }
173     if (player->aborted)
174         return RET_OK;
175     if (map_flags & MAP_PLANE) {
176         snxtitem_all(&ni, EF_PLANE);
177         while (nxtitem(&ni, &plane)) {
178             if (plane.pln_own == 0)
179                 continue;
180             if (plane.pln_own != player->cnum && !player->god)
181                 continue;
182             if (!xyinrange(plane.pln_x, plane.pln_y, &nsp->range))
183                 continue;
184
185             x = xnorm(plane.pln_x - nsp->range.lx);
186             y = ynorm(plane.pln_y - nsp->range.ly);
187             wmap[y][x] = (*plchr[(int)plane.pln_type].pl_name) & ~0x20;
188         }
189     }
190     if (map_flags & MAP_SHIP) {
191         snxtitem_all(&ni, EF_SHIP);
192         while (nxtitem(&ni, &ship)) {
193             if (ship.shp_own == 0)
194                 continue;
195             if (ship.shp_own != player->cnum && !player->god)
196                 continue;
197             if (!xyinrange(ship.shp_x, ship.shp_y, &nsp->range))
198                 continue;
199
200             x = xnorm(ship.shp_x - nsp->range.lx);
201             y = ynorm(ship.shp_y - nsp->range.ly);
202             wmap[y][x] = (*mchr[(int)ship.shp_type].m_name) & ~0x20;
203         }
204     }
205     if (map_flags & MAP_LAND) {
206         snxtitem_all(&ni, EF_LAND);
207         while (nxtitem(&ni, &land)) {
208             if (land.lnd_own == 0)
209                 continue;
210             if (land.lnd_own != player->cnum && !player->god)
211                 continue;
212             if (!xyinrange(land.lnd_x, land.lnd_y, &nsp->range))
213                 continue;
214
215             x = xnorm(land.lnd_x - nsp->range.lx);
216             y = ynorm(land.lnd_y - nsp->range.ly);
217             wmap[y][x] = (*lchr[(int)land.lnd_type].l_name) & ~0x20;
218         }
219     }
220     if (map_flags & MAP_HIGH) {
221         s_char *ptr;
222         struct sctstr sect;
223
224         snxtsct_rewind(nsp);
225         if (!player->god) {
226             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
227             bitinit2(nsp, bitmap, player->cnum);
228         }
229         while (nxtsct(nsp, &sect) && !player->aborted) {
230             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
231                 continue;
232             ptr = &wmap[nsp->dy][nsp->dx];
233             if (sect.sct_own == player->cnum)
234                  *ptr |= 0x80;
235         }
236     }
237     if (origin)
238         wmap[5][10] = origin & ~0x20;
239     for (y = nsp->range.ly, i = 0; i < nsp->range.height; y++, i++) {
240         int yval;
241
242         yval = yrel(np, y);
243         wmap[i][nsp->range.width] = '\0';
244         pr("%4d %s %-4d\n", yval, wmap[i], yval);
245         if (y >= WORLD_Y)
246             y -= WORLD_Y;
247     }
248     border(&range, "     ", "");
249     return RET_OK;
250 }
251
252 /*
253  * get the next sector in the range
254  */
255 static int
256 bmnxtsct(struct nstr_sect *np)
257 {
258     while (1) {
259         np->dx++;
260         np->x++;
261         if (np->x >= WORLD_X)
262             np->x = 0;
263         if (np->dx >= np->range.width) {
264             np->dx = 0;
265             np->x = np->range.lx;
266             np->dy++;
267             if (np->dy >= np->range.height)
268                 return 0;
269             np->y++;
270             if (np->y >= WORLD_Y)
271                 np->y = 0;
272         }
273         if ((np->y + np->x) & 01)
274             continue;
275         if (np->type == NS_DIST) {
276             np->curdist = mapdist(np->x, np->y, np->cx, np->cy);
277             if (np->curdist > np->dist)
278                 continue;
279         }
280         np->id = sctoff(np->x, np->y);
281         return 1;
282     }
283     /*NOTREACHED*/
284 }
285
286 /*
287  * Return character to use in maps for sector type TYPE owned by OWN.
288  * If OWNER_OR_GOD, the map is for the sector's owner or a deity.
289  */
290 static s_char
291 map_char(u_char type, natid own, int owner_or_god)
292 {
293     if (type > SCT_MAXDEF) {
294         logerror("bad sector type %d\n", type);
295         return '?';
296     }
297     if (owner_or_god
298         || type == SCT_WATER || type == SCT_MOUNT || type == SCT_WASTE
299         || (!own && (type == SCT_RURAL || type == SCT_PLAINS)))
300         return dchr[type].d_mnem;
301     return '?';
302 }
303
304 int
305 unit_map(int unit_type, int i, struct nstr_sect *nsp, s_char *originp)
306 {
307     struct shpstr origs;
308     struct lndstr origl;
309     struct plnstr origp;
310     s_char what[64];
311     struct natstr *np;
312
313     np = getnatp(player->cnum);
314     if (unit_type == EF_LAND) {
315         if (!getland(i, &origl) ||
316             (origl.lnd_own != player->cnum && !player->god) ||
317             (origl.lnd_own == 0))
318             return RET_FAIL;
319         sprintf(what, "%d:%d,%d:%d", xrel(np, origl.lnd_x - 10),
320                 xrel(np, origl.lnd_x + 10),
321                 yrel(np, origl.lnd_y - 5), yrel(np, origl.lnd_y + 5));
322         *originp = *lchr[(int)origl.lnd_type].l_name;
323     } else if (unit_type == EF_PLANE) {
324         if (!getplane(i, &origp) ||
325             (origp.pln_own != player->cnum && !player->god) ||
326             (origp.pln_own == 0))
327             return RET_FAIL;
328         sprintf(what, "%d:%d,%d:%d", xrel(np, origp.pln_x - 10),
329                 xrel(np, origp.pln_x + 10),
330                 yrel(np, origp.pln_y - 5), yrel(np, origp.pln_y + 5));
331         *originp = *plchr[(int)origp.pln_type].pl_name;
332     } else {
333         if (!getship(i, &origs) ||
334             (origs.shp_own != player->cnum && !player->god) ||
335             (origs.shp_own == 0))
336             return RET_FAIL;
337         sprintf(what, "%d:%d,%d:%d", xrel(np, origs.shp_x - 10),
338                 xrel(np, origs.shp_x + 10),
339                 yrel(np, origs.shp_y - 5), yrel(np, origs.shp_y + 5));
340         unit_type = EF_SHIP;
341         *originp = *mchr[(int)origs.shp_type].m_name;
342     }
343     if (!snxtsct(nsp, what))
344         return RET_FAIL;
345     return RET_OK;
346 }
347
348 int
349 bmaps_intersect(natid a, natid b)
350 {
351     s_char *mapa = ef_ptr(EF_MAP, a);
352     s_char *mapb = ef_ptr(EF_MAP, b);
353     int i;
354
355     for (i = 0; i < WORLD_X * WORLD_Y / 2; ++i, ++mapa, ++mapb)
356         if (*mapa && *mapa != ' ' && *mapb && *mapb != ' ')
357             return 1;
358     return 0;
359 }
360
361 /* Note that this requires that the BMAP is mapped into memory */
362
363 int
364 share_bmap(natid from, natid to, struct nstr_sect *ns, s_char des,
365            s_char *from_name)
366 {
367     s_char *from_bmap = ef_ptr(EF_BMAP, from);
368     s_char *to_bmap = ef_ptr(EF_BMAP, to);
369     int n = 0;
370     struct sctstr sect;
371     s_char fromdes;
372     s_char todes;
373     s_char from_des = *from_name;
374
375     if (isalpha(from_des))
376         from_des &= ~0x20;
377
378     while (nxtsct(ns, &sect)) {
379         if (!(fromdes = from_bmap[sctoff(ns->x, ns->y)]))
380             continue;
381         todes = to_bmap[sctoff(ns->x, ns->y)];
382         if (todes &&
383             todes != '?' &&
384             todes != '.' && todes != ' ' && todes != from_des)
385             continue;
386         if (sect.sct_own == from) {
387             if (fromdes != '=' && fromdes != 'h' && fromdes != des)
388                 fromdes = from_des;
389         }
390         if (todes == fromdes)
391             continue;
392         n += map_set(to, ns->x, ns->y, fromdes, 1);
393     }
394
395     if (n)
396         writebmap(to);
397     return n;
398 }