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