]> git.pond.sub.org Git - empserver/blob - src/lib/commands/navi.c
Break inclusion cycle: prototypes.h and commands.h included each
[empserver] / src / lib / commands / navi.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  *  navi.c: Navigate ships and such
29  * 
30  *  Known contributors to this file:
31  *     Ken Stevens, 1995 (rewritten)
32  */
33
34 #include <config.h>
35
36 #include <ctype.h>
37 #include "commands.h"
38 #include "map.h"
39 #include "optlist.h"
40 #include "path.h"
41 #include "ship.h"
42
43 static int set_flagship(struct emp_qelem *list, struct shpstr **flagshipp);
44 static void switch_flagship(struct emp_qelem *list, int ship_uid);
45
46 int
47 navi(void)
48 {
49     struct nstr_item ni_ship;
50     struct emp_qelem ship_list;
51     double minmob, maxmob;
52     int together;
53     char *cp = NULL;
54     struct shpstr *shp = NULL;  /* flagship */
55     struct nstr_sect ns;
56     char origin;
57     int dir;
58     int stopping = 0;
59     int skip = 0;
60     char buf[1024];
61     char prompt[128];
62     char scanspace[1024];
63     char pathtaken[1024];       /* Doubtful we'll have a path longer than this */
64     char *pt = pathtaken;
65     char bmap_flag;
66     int ac;
67
68     if (!snxtitem(&ni_ship, EF_SHIP, player->argp[1]))
69         return RET_SYN;
70     shp_sel(&ni_ship, &ship_list);
71     shp_nav(&ship_list, &minmob, &maxmob, &together, player->cnum);
72     if (QEMPTY(&ship_list)) {
73         pr("No ships\n");
74         return RET_FAIL;
75     }
76     set_flagship(&ship_list, &shp);
77     if (player->argp[2]) {
78         strcpy(buf, player->argp[2]);
79         if (!(cp = shp_path(together, shp, buf)))
80             cp = player->argp[2];
81     }
82
83     *pt = '\0';
84     while (!QEMPTY(&ship_list)) {
85         char dp[80];
86
87         if (cp == NULL || *cp == '\0' || stopping) {
88             stopping = 0;
89             shp_nav(&ship_list, &minmob, &maxmob, &together, player->cnum);
90             if (QEMPTY(&ship_list)) {
91                 pr("No ships left\n");
92                 if (strlen(pathtaken) > 0) {
93                     pathtaken[strlen(pathtaken) - 1] = '\0';
94                     if (strlen(pathtaken) > 0)
95                         pr("Path taken: %s\n", pathtaken);
96                 }
97                 return RET_OK;
98             }
99             if (set_flagship(&ship_list, &shp)) {
100                 stopping = 1;
101                 continue;
102             }
103             if (!skip)
104                 nav_map(shp->shp_x, shp->shp_y,
105                         !(mchr[(int)shp->shp_type].m_flags & M_SUB));
106             else
107                 skip = 0;
108             sprintf(prompt, "<%.1f:%.1f: %s> ", maxmob,
109                     minmob, xyas(shp->shp_x, shp->shp_y, player->cnum));
110             cp = getstring(prompt, buf);
111             /* Just in case any of our ships were shelled while we were
112              * at the prompt, we call shp_nav() again.
113              */
114             shp_nav(&ship_list, &minmob, &maxmob, &together, player->cnum);
115             if (QEMPTY(&ship_list)) {
116                 pr("No ships left\n");
117                 if (strlen(pathtaken) > 0) {
118                     pathtaken[strlen(pathtaken) - 1] = '\0';
119                     if (strlen(pathtaken) > 0)
120                         pr("Path taken: %s\n", pathtaken);
121                 }
122                 return RET_OK;
123             }
124             if (set_flagship(&ship_list, &shp)) {
125                 stopping = 1;
126                 continue;
127             }
128             if (cp && !(cp = shp_path(together, shp, buf)))
129                 cp = buf;
130         }
131         radmapnopr(shp->shp_x, shp->shp_y, (int)shp->shp_effic,
132                    (int)techfact(shp->shp_tech,
133                                  mchr[(int)shp->shp_type].m_vrnge),
134                    (mchr[(int)shp->shp_type].m_flags & M_SONAR)
135                    ? techfact(shp->shp_tech, 1.0) : 0.0);
136         if (cp == NULL || *cp == '\0')
137             cp = &dirch[DIR_STOP];
138         dir = chkdir(*cp, DIR_STOP, DIR_VIEW);
139         if (dir >= 0) {
140             if (dir == DIR_VIEW)
141                 shp_view(&ship_list);
142             else {
143                 stopping |= shp_nav_one_sector(&ship_list, dir, player->cnum, together);
144                 if (stopping != 2) {
145                     *pt++ = dirch[dir];
146                     *pt = '\0';
147                 }
148             }
149             cp++;
150             continue;
151         }
152         ac = parse(cp, player->argp, NULL, scanspace, NULL);
153         if (ac <= 1) {
154             sprintf(dp, "%d", shp->shp_uid);
155             player->argp[1] = dp;
156             cp++;
157         } else
158             cp = NULL;
159         bmap_flag = 0;
160         switch (*player->argp[0]) {
161         case 'B':
162             bmap_flag = 'b';
163             /*
164              * fall through
165              */
166         case 'M':
167             unit_map(EF_SHIP, atoi(player->argp[1]), &ns, &origin);
168             draw_map(bmap_flag, origin, MAP_SHIP, &ns);
169             skip = 1;
170             break;
171         case 'f':
172             if (ac <= 1) 
173                 switch_flagship(&ship_list, -1);
174             else
175                 switch_flagship(&ship_list, atoi(player->argp[1]));
176             set_flagship(&ship_list, &shp);
177             break;
178         case 'i':
179             shp_list(&ship_list);
180             break;
181         case 'm':
182             stopping |= shp_sweep(&ship_list, 1, 0, player->cnum);
183             break;
184         case 'r':
185             rada();
186             skip = 1;
187             player->btused++;
188             break;
189         case 'l':
190             look();
191             player->btused++;
192             break;
193         case 's':
194             sona();
195             player->btused++;
196             skip = 1;
197             break;
198         case 'd':
199             if (ac == 2) {
200                 player->argp[2] = player->argp[1];
201                 sprintf(dp, "%d", shp->shp_uid);
202                 player->argp[1] = dp;
203             }
204             mine();
205             skip = 1;
206             player->btused++;
207             break;
208         default:
209             direrr("`%c' to stop", ", `%c' to view, ", 0);
210             pr("`i' to list ships, `f' to change flagship,\n");
211             pr("`r' to radar, `s' to sonar, `l' to look, `M' to map, `B' to bmap,\n");
212             pr("`d' to drop mines, and `m' to minesweep\n");
213             stopping = 1;
214         }
215     }
216     if (strlen(pathtaken) > 0) {
217         pathtaken[strlen(pathtaken) - 1] = '\0';
218         if (strlen(pathtaken) > 0)
219             pr("Path taken: %s\n", pathtaken);
220     }
221     return RET_OK;
222 }
223
224 int
225 nav_map(int x, int y, int show_designations)
226 {
227     char *ptr;
228     struct nstr_sect ns;
229     struct natstr *np;
230     struct sctstr sect;
231     struct range range;
232     int i;
233     /* Note this is not re-entrant anyway, so we keep the buffers
234        around */
235     static unsigned char *bitmap = NULL;
236     static char *wmapbuf = NULL;
237     static char **wmap = NULL;
238     int changed = 0;
239
240     if (!wmapbuf)
241         wmapbuf = malloc(WORLD_Y * MAPWIDTH(1));
242     if (!wmap) {
243         wmap = malloc(WORLD_Y * sizeof(*wmap));
244         if (wmap && wmapbuf) {
245             for (i = 0; i < WORLD_Y; i++)
246                 wmap[i] = &wmapbuf[MAPWIDTH(1) * i];
247         } else if (wmap) {
248             free(wmap);
249             wmap = NULL;
250         }
251     }
252     if (!bitmap)
253         bitmap = malloc((WORLD_X * WORLD_Y) / 8);
254     if (!wmapbuf || !wmap || !bitmap) {
255         pr("Memory error, tell the deity.\n");
256         logerror("malloc failed in navi\n");
257         return RET_FAIL;
258     }
259     memset(bitmap, 0, (WORLD_X * WORLD_Y) / 8);
260     snxtsct_dist(&ns, x, y, 1);
261     np = getnatp(player->cnum);
262     xyrelrange(np, &ns.range, &range);
263     blankfill(wmapbuf, &ns.range, 1);
264     while (nxtsct(&ns, &sect)) {
265         ptr = &wmap[ns.dy][ns.dx];
266         *ptr = dchr[sect.sct_type].d_mnem;
267         if (!show_designations &&
268             sect.sct_own != player->cnum &&
269             sect.sct_type != SCT_WATER &&
270             sect.sct_type != SCT_BSPAN && sect.sct_type != SCT_HARBR)
271             *ptr = '?';
272         changed += map_set(player->cnum, sect.sct_x, sect.sct_y, *ptr, 0);
273         /*
274          * We do it this way so that 'x' and 'X'
275          * bdesignations will show up. This can
276          * be used to mark mined sectors. So, the
277          * player will see the current des, UNLESS
278          * they've marked the sector 'x' or 'X',
279          * in which case they'll see that.
280          * --ts
281          */
282         *ptr = player->bmap[sctoff(sect.sct_x, sect.sct_y)];
283     }
284     if (changed)
285         writemap(player->cnum);
286     for (i = 0; i < ns.range.height; i++)
287         pr("%s\n", wmap[i]);
288     return RET_OK;
289 }
290
291 static int
292 set_flagship(struct emp_qelem *list, struct shpstr **flagshipp)
293 {
294     struct mlist *mlp = (struct mlist *)(list->q_back);
295
296     if (!*flagshipp)
297         pr("Flagship is ");
298     else if ((*flagshipp)->shp_uid != mlp->ship.shp_uid)
299         pr("Changing flagship to ");
300     else
301         return 0;
302     *flagshipp = &mlp->ship;
303     pr("%s\n", prship(&mlp->ship));
304     return 1;
305 }
306
307 static void
308 switch_flagship(struct emp_qelem *list, int ship_uid)
309 {
310     struct emp_qelem *qp, *save;
311     struct mlist *mlp;
312
313     if (QEMPTY(list))
314         return;
315
316     save = qp = list->q_back;
317     do {
318         emp_remque(qp);
319         emp_insque(qp, list);
320         qp = list->q_back;
321         mlp = (struct mlist *)qp;
322         if (mlp->ship.shp_uid == ship_uid || ship_uid == -1)
323             break;
324     } while (list->q_back != save);
325 }
326