]> git.pond.sub.org Git - empserver/blob - src/lib/subs/paths.c
Indented with src/scripts/indent-emp.
[empserver] / src / lib / subs / paths.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  *  path.c: Routines associated with paths, directions, etc.
29  * 
30  *  Known contributors to this file:
31  *   
32  */
33
34 #include "misc.h"
35 #include "player.h"
36 #include "xy.h"
37 #include "path.h"
38 #include "nat.h"
39 #include "sect.h"
40 #include "file.h"
41 #include "prototypes.h"
42
43 int
44 getdir(s_char *prompt, s_char *stop_msg, s_char *view_msg,
45        s_char *bomb_msg)
46 {
47     register int max_dir;
48     register int min_dir;
49     register int dir_num;
50     s_char buf[1024];
51
52     if (stop_msg != 0)
53         min_dir = DIR_STOP;
54     else
55         min_dir = DIR_FIRST;
56     if (view_msg == 0)
57         max_dir = DIR_LAST;
58     else
59         max_dir = DIR_VIEW;
60     while (1) {
61         if (getstring(prompt, buf) == 0 || *buf == 0)
62             return -1;
63         dir_num = chkdir(buf[0], min_dir, max_dir);
64         if (dir_num >= min_dir)
65             break;
66         direrr(stop_msg, view_msg, bomb_msg);
67     }
68     return dir_num;
69 }
70
71 int
72 chkdir(s_char dir_char, int min_dir, int max_dir)
73 {
74     register int i;
75
76     for (i = min_dir; i <= max_dir; i++)
77         if (dir_char == dirch[i])
78             return i;
79     return -1;
80 }
81
82 void
83 direrr(s_char *stop_msg, s_char *view_msg, s_char *map_msg)
84 {
85     pr("Legal directions are:\n");
86     pr(" %c %c\n", dirch[DIR_UL], dirch[DIR_UR]);
87     pr("%c   %c\n", dirch[DIR_L], dirch[DIR_R]);
88     pr(" %c %c\n", dirch[DIR_DL], dirch[DIR_DR]);
89     if (stop_msg != 0)
90         pr(stop_msg, dirch[DIR_STOP]);
91     if (view_msg != 0)
92         pr(view_msg, dirch[DIR_VIEW]);
93     if (map_msg != 0)
94         pr(map_msg, dirch[DIR_MAP]);
95 }
96
97 /*
98  * return pointer to path; prompt user until a stop char
99  * or a bomb char have been entered.  A "bomb" char in
100  * this context is actually "execute" for the partial
101  * move commands, and isn't valid for those commands
102  * which do not accept partial moves.
103  */
104 s_char *
105 getpath(s_char *buf, s_char *arg, coord x, coord y, int onlyown,
106         int showdes, int showxy, int destinations)
107 {
108     s_char *p = buf;
109     s_char *bp;
110     s_char prompt[128];
111     coord dx, dy;
112     struct sctstr sect, dsect;
113     coord nx, ny;
114     int dir;
115     s_char *execute;
116     double mv_cost;
117
118     if (arg) {
119         strncpy(buf, arg, MAX_PATH_LEN - 1);
120         buf[MAX_PATH_LEN - 1] = 0;
121     } else {
122         *p = 0;
123     }
124
125     if (showxy)
126         execute = " & '%c' to execute\n";
127     else
128         execute = "\n";
129
130     getsect(x, y, &sect);
131     nx = x;
132     ny = y;
133
134   more:
135     while (*p) {
136         if (sarg_xy(p, &dx, &dy)) {
137             bp = 0;
138             if (destinations == P_NONE) {
139                 pr("Destination sectors not allowed here!\n");
140                 *p = 0;
141             }
142             if (getsect(dx, dy, &dsect)) {
143                 if (destinations == P_WALKING) {
144                     bp = BestLandPath(p, &sect, &dsect,
145                                       &mv_cost, MOB_ROAD);
146                 } else if (destinations == P_FLYING) {
147                     bp = BestAirPath(p, nx, ny, dx, dy);
148                 }
149             } else {
150                 pr("Invalid destination sector!\n");
151                 *p = 0;
152             }
153             if (bp) {
154                 pr("Using best path  '%s'\n", p);
155                 pr("Using total path '%s'\n", buf);
156                 return buf;
157             } else {
158                 pr("Can't get to %s from here!\n",
159                    xyas(nx, ny, player->cnum));
160                 *p = 0;
161             }
162             break;
163         }
164         dir = chkdir(*p, DIR_STOP, DIR_LAST);
165         if (dir < 0) {
166             pr("\"%c\" is not legal...", *p);
167             direrr("'%c' to stop", (s_char *)0, execute);
168             *p = 0;
169             break;
170         }
171         nx = x + diroff[dir][0];
172         ny = y + diroff[dir][1];
173         getsect(nx, ny, &sect);
174         if (onlyown && sect.sct_own != player->cnum) {
175             *p = 0;
176             pr("You don't own %s; you can't go there!\n",
177                xyas(nx, ny, player->cnum));
178             break;
179         }
180         if (dir == DIR_STOP || dir == DIR_MAP) {
181             p[1] = 0;
182             return buf;
183         }
184         if (++p - buf == MAX_PATH_LEN) {
185             pr("Path length may not exceed %d.\n", MAX_PATH_LEN);
186             pr("Aborting...\n");
187             *buf = 0;
188             return buf;
189         }
190         x = nx;
191         y = ny;
192     }
193     fly_map(x, y);
194     if (showdes) {
195         getsect(x, y, &sect);
196         sprintf(prompt, "<%c: %s> ", dchr[sect.sct_type].d_mnem,
197                 xyas(x, y, player->cnum));
198     } else {
199         sprintf(prompt, "<%d: %s> ", (int)(p - buf),
200                 xyas(x, y, player->cnum));
201     }
202     if (!(bp = getstring(prompt, p)) || !*bp) {
203         if (player->aborted)
204             *buf = 0;
205         return buf;
206     }
207     goto more;
208 }
209
210 /* ARGSUSED */
211 double
212 mcost(struct sctstr *sp, int own)
213 {
214     return sector_mcost(sp, MOB_ROAD);
215
216 /*
217         int     m_cost;
218
219         if (!(m_cost = dchr[sp->sct_type].d_mcst))
220                 return -1.0;
221         if (m_cost < 25)
222                 return (200.0 + (m_cost - 3.0) * sp->sct_effic) / 500.0;
223         else
224                 return (m_cost * 5.0 - (double)sp->sct_effic) / 25.0;
225  */
226 }
227
228 /*
229  * fly move cost
230  */
231 /* ARGSUSED */
232 double
233 fcost(struct sctstr *sp, natid own)
234 {
235     return 1.0;
236 }
237
238 /*
239  * nav move cost
240  */
241 /* ARGSUSED */
242 double
243 ncost(struct sctstr *sp, natid own)
244 {
245     return 1.0;
246 }
247
248 /*
249  * return end x,y of path, and the base
250  * movement cost it takes to get there.
251  */
252 double
253 pathtoxy(s_char *path, coord *xp, coord *yp,
254          double (*cost) (struct sctstr *, natid))
255 {
256     struct sctstr s;
257     s_char *pp;
258     coord x;
259     coord y;
260     int val;
261     double m;
262     int c;
263
264     x = *xp;
265     y = *yp;
266     m = 0.0;
267     for (pp = path; *pp; pp++) {
268         if ((val = chkdir(*pp, DIR_STOP, DIR_LAST)) == 0)
269             break;
270         x += diroff[val][0];
271         y += diroff[val][1];
272         c = dirch[val];
273         if (c == DIR_STOP)
274             break;
275         if (!getsect(x, y, &s))
276             return -1.0;
277         m += cost(&s, s.sct_own);
278     }
279     *xp = xnorm(x);
280     *yp = ynorm(y);
281     return m;
282 }
283
284 /*
285  * return true if "who" owns the path starting at x,y
286  */
287 int
288 chkpath(natid who, s_char *path, coord x, coord y)
289 {
290     s_char *pp;
291     int val;
292     struct sctstr sect;
293
294     for (pp = path; *pp; pp++) {
295         if ((val = chkdir(*pp, DIR_STOP, DIR_LAST)) == 0)
296             break;
297         x += diroff[val][0];
298         y += diroff[val][1];
299         if (!getsect(x, y, &sect) || sect.sct_own != who)
300             return 0;
301     }
302     return 1;
303 }
304
305 void
306 pathrange(register coord cx, register coord cy, register s_char *pp,
307           int border, struct range *range)
308 {
309     int dir;
310
311     range->lx = cx;
312     range->hx = cx;
313     range->ly = cy;
314     range->hy = cy;
315     range->width = 0;
316     range->height = 0;
317     while ((dir = chkdir(*pp, DIR_FIRST, DIR_LAST)) >= 0) {
318         pp++;
319         cx += diroff[dir][0];
320         cy += diroff[dir][1];
321         if (cx < range->lx)
322             range->lx = cx;
323         if (cx > range->hx)
324             range->hx = cx;
325         if (cy < range->ly)
326             range->ly = cy;
327         if (cy > range->hy)
328             range->hy = cy;
329     }
330     range->lx = xnorm(range->lx - border * 2);
331     range->ly = ynorm(range->ly - border);
332     range->hx = xnorm(range->hx + border * 2 + 1);
333     range->hy = ynorm(range->hy + border + 1);
334     xysize_range(range);
335 }