]> git.pond.sub.org Git - empserver/blob - src/lib/common/maps.c
(map, unit_map, draw_map, player_coms[]):
[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 char map_char(unsigned char type, natid own, int owner_or_god);
55
56 int
57 draw_map(int bmap, 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     struct nukstr nuke;
66     coord x, y;
67     int i;
68     /* Note this is not re-entrant anyway, so we keep the buffers
69        around */
70     static unsigned char *bitmap = NULL;
71     static char *wmapbuf = NULL;
72     static char **wmap = NULL;
73
74     if (!wmapbuf)
75         wmapbuf = malloc(WORLD_Y * MAPWIDTH(1));
76     if (!wmap) {
77         wmap = malloc(WORLD_Y * sizeof(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(wmap);
83             wmap = NULL;
84         }
85     }
86     if (!bitmap)
87         bitmap = 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 == 'r') {
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(player->cnum);
104     /* zap any conditionals */
105     nsp->ncond = 0;
106     xyrelrange(np, &nsp->range, &range);
107     border(&range, "     ", "");
108     blankfill(wmapbuf, &nsp->range, 1);
109     if (bmap) {
110         int c;
111         switch (bmap) {
112         default:
113             CANT_REACH();
114             bmap = 'b';
115             /* fall through */
116         case 'b':
117             while (bmnxtsct(nsp) && !player->aborted) {
118                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
119                     wmap[nsp->dy][nsp->dx] = c;
120             }
121             break;
122         case 't':
123             while (bmnxtsct(nsp) && !player->aborted) {
124                 if (0 != (c = player->map[sctoff(nsp->x, nsp->y)]))
125                     wmap[nsp->dy][nsp->dx] = c;
126             }
127             break;
128         case 'r':
129             while (bmnxtsct(nsp) && !player->aborted) {
130                 player->bmap[sctoff(nsp->x, nsp->y)] =
131                     player->map[sctoff(nsp->x, nsp->y)];
132                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
133                     wmap[nsp->dy][nsp->dx] = c;
134             }
135             ef_write(EF_BMAP, player->cnum, player->bmap);
136             break;
137         case 'n':
138             {
139                 struct sctstr sect;
140
141                 if (!player->god) {
142                     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
143                     bitinit2(nsp, bitmap, player->cnum);
144                 }
145                 while (nxtsct(nsp, &sect) && !player->aborted) {
146                     if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
147                         continue;
148                     wmap[nsp->dy][nsp->dx]
149                         = map_char(sect.sct_newtype, sect.sct_own,
150                                    player->owner);
151                 }
152                 break;
153             }
154         }
155     } else {
156         struct sctstr sect;
157         char mapch;
158         int changed = 0;
159
160         if (!player->god) {
161             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
162             bitinit2(nsp, bitmap, player->cnum);
163         }
164         while (nxtsct(nsp, &sect) && !player->aborted) {
165             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
166                 continue;
167             mapch = map_char(sect.sct_type, sect.sct_own, player->owner);
168             wmap[nsp->dy][nsp->dx] = mapch;
169             changed |= map_set(player->cnum, nsp->x, nsp->y, mapch, 0);
170         }
171         if (changed)
172             writemap(player->cnum);
173     }
174     if (player->aborted)
175         return RET_OK;
176     if (map_flags & MAP_PLANE) {
177         snxtitem_all(&ni, EF_PLANE);
178         while (nxtitem(&ni, &plane)) {
179             if (plane.pln_own == 0)
180                 continue;
181             if (plane.pln_own != player->cnum && !player->god)
182                 continue;
183             if (!xyinrange(plane.pln_x, plane.pln_y, &nsp->range))
184                 continue;
185
186             x = xnorm(plane.pln_x - nsp->range.lx);
187             y = ynorm(plane.pln_y - nsp->range.ly);
188             wmap[y][x] = (*plchr[(int)plane.pln_type].pl_name) & ~0x20;
189         }
190     }
191     if (map_flags & MAP_SHIP) {
192         snxtitem_all(&ni, EF_SHIP);
193         while (nxtitem(&ni, &ship)) {
194             if (ship.shp_own == 0)
195                 continue;
196             if (ship.shp_own != player->cnum && !player->god)
197                 continue;
198             if (!xyinrange(ship.shp_x, ship.shp_y, &nsp->range))
199                 continue;
200
201             x = xnorm(ship.shp_x - nsp->range.lx);
202             y = ynorm(ship.shp_y - nsp->range.ly);
203             wmap[y][x] = (*mchr[(int)ship.shp_type].m_name) & ~0x20;
204         }
205     }
206     if (map_flags & MAP_LAND) {
207         snxtitem_all(&ni, EF_LAND);
208         while (nxtitem(&ni, &land)) {
209             if (land.lnd_own == 0)
210                 continue;
211             if (land.lnd_own != player->cnum && !player->god)
212                 continue;
213             if (!xyinrange(land.lnd_x, land.lnd_y, &nsp->range))
214                 continue;
215
216             x = xnorm(land.lnd_x - nsp->range.lx);
217             y = ynorm(land.lnd_y - nsp->range.ly);
218             wmap[y][x] = (*lchr[(int)land.lnd_type].l_name) & ~0x20;
219         }
220     }
221     if (map_flags & MAP_NUKE) {
222         snxtitem_all(&ni, EF_NUKE);
223         while (nxtitem(&ni, &nuke)) {
224             if (nuke.nuk_own == 0)
225                 continue;
226             if (nuke.nuk_own != player->cnum && !player->god)
227                 continue;
228             if (!xyinrange(nuke.nuk_x, nuke.nuk_y, &nsp->range))
229                 continue;
230
231             x = xnorm(nuke.nuk_x - nsp->range.lx);
232             y = ynorm(nuke.nuk_y - nsp->range.ly);
233             wmap[y][x] = 'N';
234         }
235     }
236     if (map_flags & MAP_HIGH) {
237         char *ptr;
238         struct sctstr sect;
239
240         snxtsct_rewind(nsp);
241         if (!player->god) {
242             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
243             bitinit2(nsp, bitmap, player->cnum);
244         }
245         while (nxtsct(nsp, &sect) && !player->aborted) {
246             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
247                 continue;
248             ptr = &wmap[nsp->dy][nsp->dx];
249             if (sect.sct_own == player->cnum)
250                  *ptr |= 0x80;
251         }
252     }
253     if (origin)
254         wmap[5][10] = origin & ~0x20;
255     for (y = nsp->range.ly, i = 0; i < nsp->range.height; y++, i++) {
256         int yval;
257
258         yval = yrel(np, y);
259         wmap[i][nsp->range.width] = '\0';
260         pr("%4d %s %-4d\n", yval, wmap[i], yval);
261         if (y >= WORLD_Y)
262             y -= WORLD_Y;
263     }
264     border(&range, "     ", "");
265     return RET_OK;
266 }
267
268 /*
269  * get the next sector in the range
270  */
271 static int
272 bmnxtsct(struct nstr_sect *np)
273 {
274     while (1) {
275         np->dx++;
276         np->x++;
277         if (np->x >= WORLD_X)
278             np->x = 0;
279         if (np->dx >= np->range.width) {
280             np->dx = 0;
281             np->x = np->range.lx;
282             np->dy++;
283             if (np->dy >= np->range.height)
284                 return 0;
285             np->y++;
286             if (np->y >= WORLD_Y)
287                 np->y = 0;
288         }
289         if ((np->y + np->x) & 01)
290             continue;
291         if (np->type == NS_DIST) {
292             np->curdist = mapdist(np->x, np->y, np->cx, np->cy);
293             if (np->curdist > np->dist)
294                 continue;
295         }
296         np->id = sctoff(np->x, np->y);
297         return 1;
298     }
299     /*NOTREACHED*/
300 }
301
302 /*
303  * Return character to use in maps for sector type TYPE owned by OWN.
304  * If OWNER_OR_GOD, the map is for the sector's owner or a deity.
305  */
306 static char
307 map_char(unsigned char type, natid own, int owner_or_god)
308 {
309     if (CANT_HAPPEN(type > SCT_TYPE_MAX || !dchr[type].d_mnem))
310         return '?';
311     if (owner_or_god
312         || type == SCT_WATER || type == SCT_MOUNT || type == SCT_WASTE
313         || (!own && (type == SCT_RURAL || type == SCT_PLAINS)))
314         return dchr[type].d_mnem;
315     return '?';
316 }
317
318 int
319 unit_map(int unit_type, int uid, struct nstr_sect *nsp, char *originp)
320 {
321     struct shpstr origs;
322     struct lndstr origl;
323     struct plnstr origp;
324     struct nukstr orign;
325     struct genitem *gp;
326     struct range range;
327
328     if (unit_type == EF_LAND) {
329         if (!getland(uid, &origl) || !player->owner || origl.lnd_own == 0)
330             return RET_FAIL;
331         gp = (struct genitem *)&origl;
332         *originp = *lchr[(int)origl.lnd_type].l_name;
333     } else if (unit_type == EF_PLANE) {
334         if (!getplane(uid, &origp) || !player->owner || origp.pln_own == 0)
335             return RET_FAIL;
336         gp = (struct genitem *)&origp;
337         *originp = *plchr[(int)origp.pln_type].pl_name;
338     } else if (unit_type == EF_NUKE) {
339         if (!getnuke(uid, &orign) || !player->owner || orign.nuk_own == 0)
340             return RET_FAIL;
341         gp = (struct genitem *)&orign;
342         *originp = 'n';
343     } else {
344         if (!getship(uid, &origs) || !player->owner || origs.shp_own == 0)
345             return RET_FAIL;
346         gp = (struct genitem *)&origs;
347         *originp = *mchr[(int)origs.shp_type].m_name;
348     }
349
350     range.lx = xnorm(gp->x - 10);
351     range.hx = xnorm(gp->x + 11);
352     range.ly = ynorm(gp->y - 5);
353     range.hy = ynorm(gp->y + 6);
354     xysize_range(&range);
355     snxtsct_area(nsp, &range);
356     return RET_OK;
357 }
358
359 int
360 bmaps_intersect(natid a, natid b)
361 {
362     char *mapa = ef_ptr(EF_MAP, a);
363     char *mapb = ef_ptr(EF_MAP, b);
364     int i;
365
366     for (i = 0; i < WORLD_X * WORLD_Y / 2; ++i, ++mapa, ++mapb)
367         if (*mapa && *mapa != ' ' && *mapb && *mapb != ' ')
368             return 1;
369     return 0;
370 }
371
372 /* Note that this requires that the BMAP is mapped into memory */
373
374 int
375 share_bmap(natid from, natid to, struct nstr_sect *ns, char des,
376            char *from_name)
377 {
378     char *from_bmap = ef_ptr(EF_BMAP, from);
379     char *to_bmap = ef_ptr(EF_BMAP, to);
380     int n = 0;
381     struct sctstr sect;
382     char fromdes;
383     char todes;
384     char from_des = *from_name;
385
386     if (isalpha(from_des))
387         from_des &= ~0x20;
388
389     while (nxtsct(ns, &sect)) {
390         if (!(fromdes = from_bmap[sctoff(ns->x, ns->y)]))
391             continue;
392         todes = to_bmap[sctoff(ns->x, ns->y)];
393         if (todes &&
394             todes != '?' &&
395             todes != '.' && todes != ' ' && todes != from_des)
396             continue;
397         if (sect.sct_own == from) {
398             if (fromdes != '=' && fromdes != 'h' && fromdes != des)
399                 fromdes = from_des;
400         }
401         if (todes == fromdes)
402             continue;
403         n += map_set(to, ns->x, ns->y, fromdes, 1);
404     }
405
406     if (n)
407         writebmap(to);
408     return n;
409 }