]> git.pond.sub.org Git - empserver/blob - src/lib/common/maps.c
(get_empobjp): New. Returns a pointer an empobj.
[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 <ctype.h>
38 #include "com.h"
39 #include "empobj.h"
40 #include "file.h"
41 #include "land.h"
42 #include "map.h"
43 #include "misc.h"
44 #include "nat.h"
45 #include "nsc.h"
46 #include "nuke.h"
47 #include "optlist.h"
48 #include "plane.h"
49 #include "player.h"
50 #include "prototypes.h"
51 #include "sect.h"
52 #include "ship.h"
53 #include "xy.h"
54
55 static int bmnxtsct(struct nstr_sect *);
56 static char map_char(unsigned char type, natid own, int owner_or_god);
57
58 int
59 do_map(int bmap, int unit_type, char *arg, char *map_flags_arg)
60 {
61     struct nstr_sect ns;
62     char origin = '\0';
63     char *b;
64     int map_flags = 0;
65
66     if (!snxtsct(&ns, arg)) {
67         if (unit_map(unit_type, atoi(arg), &ns, &origin))
68             return RET_FAIL;
69     }
70     for (b = map_flags_arg; b && *b; b++) {
71         switch (*b) {
72         case 's':
73         case 'S':
74             map_flags |= MAP_SHIP;
75             break;
76         case 'l':
77         case 'L':
78             map_flags |= MAP_LAND;
79             break;
80         case 'p':
81         case 'P':
82             map_flags |= MAP_PLANE;
83             break;
84         case 'n':
85         case 'N':
86             map_flags |= MAP_NUKE;
87             break;
88         case 'h':
89         case 'H':
90             map_flags |= MAP_HIGH;
91             break;
92         case '*':
93             map_flags |= MAP_ALL;
94             break;
95         case 't':
96             if (bmap != 'b')
97                 goto bad_flag;
98             bmap = 't';
99             *(b + 1) = 0;
100             break;
101         case 'r':
102             if (bmap != 'b')
103                 goto bad_flag;
104             bmap = 'r';
105             *(b + 1) = 0;
106             break;
107         default:
108         bad_flag:
109             pr("Bad flag %c!\n", *b);
110             break;
111         }
112     }
113     return draw_map(bmap, origin, map_flags, &ns);
114 }
115
116 int
117 draw_map(int bmap, char origin, int map_flags, struct nstr_sect *nsp)
118 {
119     struct natstr *np;
120     struct range range;
121     struct nstr_item ni;
122     struct shpstr ship;
123     struct lndstr land;
124     struct plnstr plane;
125     struct nukstr nuke;
126     coord x, y;
127     int i;
128     /* Note this is not re-entrant anyway, so we keep the buffers
129        around */
130     static unsigned char *bitmap = NULL;
131     static char *wmapbuf = NULL;
132     static char **wmap = NULL;
133
134     if (!wmapbuf)
135         wmapbuf = malloc(WORLD_Y * MAPWIDTH(1));
136     if (!wmap) {
137         wmap = malloc(WORLD_Y * sizeof(char *));
138         if (wmap && wmapbuf) {
139             for (i = 0; i < WORLD_Y; i++)
140                 wmap[i] = &wmapbuf[MAPWIDTH(1) * i];
141         } else if (wmap) {
142             free(wmap);
143             wmap = NULL;
144         }
145     }
146     if (!bitmap)
147         bitmap = malloc((WORLD_X * WORLD_Y) / 8);
148     if (!wmapbuf || !wmap || !bitmap) {
149         pr("Memory error, tell the deity.\n");
150         logerror("malloc failed in draw_map\n");
151         return RET_FAIL;
152     }
153
154     if (bmap == 'r') {
155         if (!confirm("Are you sure you want to revert your bmap? "))
156             return RET_OK;
157     }
158     if (!(player->command->c_flags & C_MOD)) {
159         logerror("%s command needs C_MOD flag set",
160                  player->command->c_form);
161         player->command->c_flags |= C_MOD;
162     }
163     np = getnatp(player->cnum);
164     /* zap any conditionals */
165     nsp->ncond = 0;
166     xyrelrange(np, &nsp->range, &range);
167     border(&range, "     ", "");
168     blankfill(wmapbuf, &nsp->range, 1);
169     if (bmap) {
170         int c;
171         switch (bmap) {
172         default:
173             CANT_REACH();
174             bmap = 'b';
175             /* fall through */
176         case 'b':
177             while (bmnxtsct(nsp) && !player->aborted) {
178                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
179                     wmap[nsp->dy][nsp->dx] = c;
180             }
181             break;
182         case 't':
183             while (bmnxtsct(nsp) && !player->aborted) {
184                 if (0 != (c = player->map[sctoff(nsp->x, nsp->y)]))
185                     wmap[nsp->dy][nsp->dx] = c;
186             }
187             break;
188         case 'r':
189             while (bmnxtsct(nsp) && !player->aborted) {
190                 player->bmap[sctoff(nsp->x, nsp->y)] =
191                     player->map[sctoff(nsp->x, nsp->y)];
192                 if (0 != (c = player->bmap[sctoff(nsp->x, nsp->y)]))
193                     wmap[nsp->dy][nsp->dx] = c;
194             }
195             ef_write(EF_BMAP, player->cnum, player->bmap);
196             break;
197         case 'n':
198             {
199                 struct sctstr sect;
200
201                 if (!player->god) {
202                     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
203                     bitinit2(nsp, bitmap, player->cnum);
204                 }
205                 while (nxtsct(nsp, &sect) && !player->aborted) {
206                     if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
207                         continue;
208                     wmap[nsp->dy][nsp->dx]
209                         = map_char(sect.sct_newtype, sect.sct_own,
210                                    player->owner);
211                 }
212                 break;
213             }
214         }
215     } else {
216         struct sctstr sect;
217         char mapch;
218         int changed = 0;
219
220         if (!player->god) {
221             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
222             bitinit2(nsp, bitmap, player->cnum);
223         }
224         while (nxtsct(nsp, &sect) && !player->aborted) {
225             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
226                 continue;
227             mapch = map_char(sect.sct_type, sect.sct_own, player->owner);
228             wmap[nsp->dy][nsp->dx] = mapch;
229             changed |= map_set(player->cnum, nsp->x, nsp->y, mapch, 0);
230         }
231         if (changed)
232             writemap(player->cnum);
233     }
234     if (player->aborted)
235         return RET_OK;
236     if (map_flags & MAP_PLANE) {
237         snxtitem_all(&ni, EF_PLANE);
238         while (nxtitem(&ni, &plane)) {
239             if (plane.pln_own == 0)
240                 continue;
241             if (plane.pln_own != player->cnum && !player->god)
242                 continue;
243             if (!xyinrange(plane.pln_x, plane.pln_y, &nsp->range))
244                 continue;
245
246             x = xnorm(plane.pln_x - nsp->range.lx);
247             y = ynorm(plane.pln_y - nsp->range.ly);
248             wmap[y][x] = (*plchr[(int)plane.pln_type].pl_name) & ~0x20;
249         }
250     }
251     if (map_flags & MAP_SHIP) {
252         snxtitem_all(&ni, EF_SHIP);
253         while (nxtitem(&ni, &ship)) {
254             if (ship.shp_own == 0)
255                 continue;
256             if (ship.shp_own != player->cnum && !player->god)
257                 continue;
258             if (!xyinrange(ship.shp_x, ship.shp_y, &nsp->range))
259                 continue;
260
261             x = xnorm(ship.shp_x - nsp->range.lx);
262             y = ynorm(ship.shp_y - nsp->range.ly);
263             wmap[y][x] = (*mchr[(int)ship.shp_type].m_name) & ~0x20;
264         }
265     }
266     if (map_flags & MAP_LAND) {
267         snxtitem_all(&ni, EF_LAND);
268         while (nxtitem(&ni, &land)) {
269             if (land.lnd_own == 0)
270                 continue;
271             if (land.lnd_own != player->cnum && !player->god)
272                 continue;
273             if (!xyinrange(land.lnd_x, land.lnd_y, &nsp->range))
274                 continue;
275
276             x = xnorm(land.lnd_x - nsp->range.lx);
277             y = ynorm(land.lnd_y - nsp->range.ly);
278             wmap[y][x] = (*lchr[(int)land.lnd_type].l_name) & ~0x20;
279         }
280     }
281     if (map_flags & MAP_NUKE) {
282         snxtitem_all(&ni, EF_NUKE);
283         while (nxtitem(&ni, &nuke)) {
284             if (nuke.nuk_own == 0)
285                 continue;
286             if (nuke.nuk_own != player->cnum && !player->god)
287                 continue;
288             if (!xyinrange(nuke.nuk_x, nuke.nuk_y, &nsp->range))
289                 continue;
290
291             x = xnorm(nuke.nuk_x - nsp->range.lx);
292             y = ynorm(nuke.nuk_y - nsp->range.ly);
293             wmap[y][x] = 'N';
294         }
295     }
296     if (map_flags & MAP_HIGH) {
297         struct sctstr sect;
298
299         snxtsct_rewind(nsp);
300         if (!player->god) {
301             memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
302             bitinit2(nsp, bitmap, player->cnum);
303         }
304         while (nxtsct(nsp, &sect) && !player->aborted) {
305             if (!player->god && !emp_getbit(nsp->x, nsp->y, bitmap))
306                 continue;
307             if (sect.sct_own == player->cnum)
308                  wmap[nsp->dy][nsp->dx] |= 0x80;
309         }
310     }
311     if (origin)
312         wmap[5][10] = origin & ~0x20;
313     for (y = nsp->range.ly, i = 0; i < nsp->range.height; y++, i++) {
314         int yval;
315
316         yval = yrel(np, y);
317         wmap[i][nsp->range.width] = '\0';
318         pr("%4d %s %-4d\n", yval, wmap[i], yval);
319         if (y >= WORLD_Y)
320             y -= WORLD_Y;
321     }
322     border(&range, "     ", "");
323     return RET_OK;
324 }
325
326 /*
327  * get the next sector in the range
328  */
329 static int
330 bmnxtsct(struct nstr_sect *np)
331 {
332     while (1) {
333         np->dx++;
334         np->x++;
335         if (np->x >= WORLD_X)
336             np->x = 0;
337         if (np->dx >= np->range.width) {
338             np->dx = 0;
339             np->x = np->range.lx;
340             np->dy++;
341             if (np->dy >= np->range.height)
342                 return 0;
343             np->y++;
344             if (np->y >= WORLD_Y)
345                 np->y = 0;
346         }
347         if ((np->y + np->x) & 01)
348             continue;
349         if (np->type == NS_DIST) {
350             np->curdist = mapdist(np->x, np->y, np->cx, np->cy);
351             if (np->curdist > np->dist)
352                 continue;
353         }
354         np->id = sctoff(np->x, np->y);
355         return 1;
356     }
357     /*NOTREACHED*/
358 }
359
360 /*
361  * Return character to use in maps for sector type TYPE owned by OWN.
362  * If OWNER_OR_GOD, the map is for the sector's owner or a deity.
363  */
364 static char
365 map_char(unsigned char type, natid own, int owner_or_god)
366 {
367     if (CANT_HAPPEN(type > SCT_TYPE_MAX || !dchr[type].d_mnem))
368         return '?';
369     if (owner_or_god
370         || type == SCT_WATER || type == SCT_MOUNT || type == SCT_WASTE
371         || (!own && (type == SCT_RURAL || type == SCT_PLAINS)))
372         return dchr[type].d_mnem;
373     return '?';
374 }
375
376 int
377 unit_map(int unit_type, int uid, struct nstr_sect *nsp, char *originp)
378 {
379     struct empobj *gp;
380     struct range range;
381     char *name;
382
383     gp = get_empobjp(unit_type, uid);
384     if (!gp || !player->owner || gp->own == 0)
385         return RET_FAIL;
386
387     if (unit_type == EF_NUKE)
388         *originp = 'n';
389     else {
390         if ((name = emp_obj_chr_name(gp)) == NULL)
391             return RET_FAIL;
392         *originp = *name;
393     }
394
395     range.lx = xnorm(gp->x - 10);
396     range.hx = xnorm(gp->x + 11);
397     range.ly = ynorm(gp->y - 5);
398     range.hy = ynorm(gp->y + 6);
399     xysize_range(&range);
400     snxtsct_area(nsp, &range);
401     return RET_OK;
402 }
403
404 int
405 display_region_map(int bmap, int unit_type, coord curx, coord cury,
406                    char *arg)
407 {
408     char coordinates[80];
409     char *map_flag_arg;
410
411     if (!arg || !*arg) {
412         struct natstr *np;
413
414         np = getnatp(player->cnum);
415         sprintf(coordinates, "%d:%d,%d:%d",
416             xrel(np, curx - 10), xrel(np, curx + 11),
417             yrel(np, cury - 5), yrel(np, cury + 6));
418         arg = coordinates;
419         map_flag_arg = NULL;
420     } else {
421         map_flag_arg = strchr(arg, ' ');
422         if (map_flag_arg != NULL) {
423             *map_flag_arg++  = '\0';
424             while (isspace(*map_flag_arg)) map_flag_arg++;
425         }
426     }
427     player->condarg = NULL;
428     return do_map(bmap, unit_type, arg, map_flag_arg);
429 }
430
431 int
432 bmaps_intersect(natid a, natid b)
433 {
434     char *mapa = ef_ptr(EF_MAP, a);
435     char *mapb = ef_ptr(EF_MAP, b);
436     int i;
437
438     for (i = 0; i < WORLD_X * WORLD_Y / 2; ++i, ++mapa, ++mapb)
439         if (*mapa && *mapa != ' ' && *mapb && *mapb != ' ')
440             return 1;
441     return 0;
442 }
443
444 /* Note that this requires that the BMAP is mapped into memory */
445
446 int
447 share_bmap(natid from, natid to, struct nstr_sect *ns, char des,
448            char *from_name)
449 {
450     char *from_bmap = ef_ptr(EF_BMAP, from);
451     char *to_bmap = ef_ptr(EF_BMAP, to);
452     int n = 0;
453     struct sctstr sect;
454     char fromdes;
455     char todes;
456     char from_des = *from_name;
457
458     if (isalpha(from_des))
459         from_des &= ~0x20;
460
461     while (nxtsct(ns, &sect)) {
462         if (!(fromdes = from_bmap[sctoff(ns->x, ns->y)]))
463             continue;
464         todes = to_bmap[sctoff(ns->x, ns->y)];
465         if (todes &&
466             todes != '?' &&
467             todes != '.' && todes != ' ' && todes != from_des)
468             continue;
469         if (sect.sct_own == from) {
470             if (fromdes != '=' && fromdes != 'h' && fromdes != des)
471                 fromdes = from_des;
472         }
473         if (todes == fromdes)
474             continue;
475         n += map_set(to, ns->x, ns->y, fromdes, 1);
476     }
477
478     if (n)
479         writebmap(to);
480     return n;
481 }