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