]> git.pond.sub.org Git - empserver/blob - src/lib/subs/move.c
Indented with src/scripts/indent-emp.
[empserver] / src / lib / subs / move.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  *  move.c: Move something somewhere.
29  * 
30  *  Known contributors to this file:
31  *     
32  */
33
34 #include "misc.h"
35 #include "player.h"
36 #include "var.h"
37 #include "sect.h"
38 #include "item.h"
39 #include "file.h"
40 #include "deity.h"
41 #include "xy.h"
42 #include "path.h"
43 #include "nat.h"
44 #include "map.h"
45 #include "nsc.h"
46 #include "damage.h"
47 #include "prototypes.h"
48
49 extern int move_map(s_char *what, coord curx, coord cury, s_char *arg);
50
51 int
52 move_ground(s_char *what, struct sctstr *start, struct sctstr *end,
53             double mobility, double weight, s_char *path,
54             int (*map) (s_char *, coord, coord, s_char *), int exploring,
55             int *dam)
56
57
58                                 /* RESULT */
59 {
60     struct sctstr sect, ending_sect;
61     struct sctstr next, dsect;
62     int vec[I_MAX + 1];
63     coord curx, cury, oldx, oldy;
64     coord tmpx, tmpy;
65     coord dx, dy;
66     s_char *movstr, *BestLandPath(s_char *, struct sctstr *,
67                                   struct sctstr *, double *, int);
68     double sect_mcost;
69     double total_mcost;
70     double mv_cost;
71     int dir;
72     int intcost;
73     int takedam = (*dam), out = 0;
74     s_char bpath[512];
75     s_char buf2[512];
76     s_char prompt[128];
77     s_char buf[1024];
78
79     if (mobility <= 0.0)
80         return -1;
81     *dam = 0;
82     if (path && sarg_xy(path, &dx, &dy) && getsect(dx, dy, &ending_sect)) {
83         if ((ending_sect.sct_x == start->sct_x) &&
84             (ending_sect.sct_y == start->sct_y)) {
85             pr("Start sector is ending sector!\n");
86             return -1;
87         }
88         pr("Looking for best path to %s\n", path);
89         path =
90             BestLandPath(buf2, start, &ending_sect, &total_mcost,
91                          MOB_ROAD);
92         if (exploring && (path != (s_char *)0)) /* take off the 'h' */
93             *(path + strlen(path) - 1) = '\0';
94         if (path == (s_char *)0)
95             pr("No owned path exists!\n");
96         else {
97             pr("Using best path '%s', movement cost %1.3f\n",
98                path, total_mcost);
99             bzero(bpath, 512);
100             bcopy(path, bpath, strlen(path));
101             path = bpath;
102         }
103         if ((total_mcost * weight) > mobility) {
104             pr("Not enough mobility to go all the way. Nothing moved.\n");
105             *end = *start;
106             return -1;
107         }
108     }
109     movstr = path;
110     tmpx = start->sct_x;
111     curx = tmpx;
112     tmpy = start->sct_y;
113     cury = tmpy;
114     total_mcost = 0.0;
115     if (getsect(curx, cury, &sect) < 0) {
116         logerror("move_path: getsect %d,%d", curx, cury);
117         return -1;
118     }
119     for (;;) {
120         tmpx = curx;
121         tmpy = cury;
122         oldx = curx;
123         oldy = cury;
124         if (movstr == 0 || *movstr == 0) {
125             if (exploring) {
126                 map(what, curx, cury, (s_char *)0);
127             } else {
128                 move_map(what, curx, cury, (s_char *)0);
129             }
130             sprintf(prompt, "<%.1f: %c %s> ", mobility,
131                     dchr[sect.sct_type].d_mnem,
132                     xyas(sect.sct_x, sect.sct_y, player->cnum));
133             movstr = getstring(prompt, buf);
134         }
135         if (movstr && sarg_xy(movstr, &dx, &dy)) {
136             if (getsect(dx, dy, &dsect)) {
137                 movstr =
138                     BestLandPath(buf2, &sect, &dsect, &mv_cost, MOB_ROAD);
139             } else {
140                 pr("Invalid destination sector!\n");
141                 movstr = (s_char *)0;
142             }
143
144             if (movstr == (s_char *)0) {
145                 pr("Can't get to %s from here!\n",
146                    xyas(dx, dy, player->cnum));
147                 movstr = (s_char *)0;
148             } else {
149                 if ((mv_cost * weight) > mobility) {
150                     pr("Not enough mobility to go all the way. Nothing moved.\n");
151                     movstr = (s_char *)0;
152                 } else {
153                     pr("Using best path '%s', movement cost %1.3f\n",
154                        movstr, mv_cost);
155                     bzero(bpath, 512);
156                     bcopy(movstr, bpath, strlen(movstr));
157                     movstr = bpath;
158                 }
159             }
160         }
161         if (movstr == 0 || *movstr == 0)
162             movstr = dirch;
163         if ((dir = chkdir(*movstr, DIR_STOP, DIR_MAP)) < 0) {
164             pr("\"%c\" is not legal...", *movstr);
165             direrr("'%c' to stop ", "'%c' to view ", "& '%c' to map\n");
166             *movstr = 0;
167             continue;
168         }
169         movstr++;
170         if (dir == DIR_MAP) {
171             if (!exploring)
172                 map(what, curx, cury, movstr + 1);
173             *movstr = 0;
174             continue;
175         } else if (dir == DIR_STOP)
176             break;
177         else if (dir == DIR_VIEW) {
178             pr("%d%% %s with %d civilians.\n", sect.sct_effic,
179                dchr[sect.sct_type].d_name,
180                getvar(V_CIVIL, (s_char *)&sect, EF_SECTOR));
181             continue;
182         }
183         /*
184          * now see if we can move into the
185          * next sector.  Mobility, terrain,
186          * or ownership may prevent us.
187          */
188         tmpx += diroff[dir][0];
189         tmpy += diroff[dir][1];
190         if (getsect(tmpx, tmpy, &next) < 0) {
191             pr("You can't go there...\n");
192             *movstr = 0;
193             continue;
194         }
195         if (!player->god) {
196             if ((next.sct_type == SCT_SANCT) &&
197                 (next.sct_own != player->cnum)) {
198                 pr("Converts, huh?\n");
199                 *end = next;
200                 intcost = (int)total_mcost;
201                 if (chance(total_mcost - intcost))
202                     intcost++;
203                 return intcost;
204             }
205             getvec(VT_ITEM, vec, (s_char *)&next, EF_SECTOR);
206             sect_mcost = sector_mcost(&next, MOB_ROAD);
207             if ((!player->owner && (!exploring ||
208                                     (vec[I_MILIT] || vec[I_CIVIL]))) ||
209                 sect_mcost == -1.0) {
210                 /* already-owned, or prohibited terrain */
211                 pr("You can't go there...\n");
212                 *movstr = 0;
213                 continue;
214             }
215             sect_mcost *= weight;
216             if (sect_mcost > mobility) {
217                 pr("Not enough mobility.  ");
218                 pr("You can't go there...\n");
219                 *movstr = 0;
220                 continue;
221             }
222             mobility -= sect_mcost;
223             total_mcost += sect_mcost;
224         }
225         curx = tmpx;
226         cury = tmpy;
227         if (cury != start->sct_y)
228             out = 1;
229         if (curx != start->sct_x)
230             out = 1;
231
232         sect = next;
233
234         if (takedam)
235             *dam += check_lmines(sect.sct_x, sect.sct_y, weight);
236         if (*dam >= 100)
237             break;
238         /*
239          * Check and see if anyone will interdict us
240          */
241         if (takedam && chance(weight / 100.0) &&
242             ((curx != oldx) || (cury != oldy)))
243             (*dam) +=
244                 ground_interdict(curx, cury, player->cnum, "commodities");
245         if (*dam >= 100)
246             break;
247     }
248     *end = sect;
249     intcost = (int)total_mcost;
250     if (intcost < 0)
251         return -1;
252     if ((start->sct_x == end->sct_x) && (start->sct_y == end->sct_y)
253         && !out)
254         return -1;
255
256     if (chance(total_mcost - intcost))
257         intcost++;
258     return intcost;
259 }
260
261
262 /*ARGSUSED*/
263 int
264 move_map(s_char *what, coord curx, coord cury, s_char *arg)
265 {
266     struct nstr_sect ns;
267     struct natstr *np;
268     struct sctstr sect;
269     coord rel_x, rel_y;
270     s_char range[128];
271     s_char view[7];
272     int i;
273     int vec[I_MAX + 1];
274     int changed = 0;
275
276     np = getnatp(player->cnum);
277     rel_x = xrel(np, curx);
278     rel_y = yrel(np, cury);
279     sprintf(range, "%d:%d,%d:%d", rel_x - 2, rel_x + 2, rel_y - 1,
280             rel_y + 1);
281     player->condarg = 0;
282     /* This is necessary, otherwise move_map would attempt to pay */
283     /* attention to the conditional arguments left behind by such */
284     /* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
285     /* 100% efficienct sects, and get all screwed up         --ts */
286     if (!snxtsct(&ns, range))
287         return RET_FAIL;
288     i = 0;
289     while (i < 7 && nxtsct(&ns, &sect)) {
290         view[i] = dchr[sect.sct_type].d_mnem;
291         switch (sect.sct_type) {
292         case SCT_WATER:
293         case SCT_RURAL:
294         case SCT_MOUNT:
295         case SCT_WASTE:
296         case SCT_PLAINS:
297             break;
298         default:
299             if (sect.sct_own != player->cnum && !player->god)
300                 view[i] = '?';
301             break;
302         }
303         changed += map_set(player->cnum, ns.x, ns.y, view[i], 0);
304         i++;
305     }
306     if (changed)
307         writemap(player->cnum);
308     if (!getsect(curx, cury, &sect))
309         return RET_FAIL;
310     getvec(VT_ITEM, vec, (s_char *)&sect, EF_SECTOR);
311     pr("    %c %c      eff   mob   civ  mil   uw food  work  avail\n",
312        view[0], view[1]);
313     pr("   %c %c %c     %3d   %3d  %4d %4d %4d %4d   %3d   %3d\n",
314        view[2], view[3], view[4],
315        sect.sct_effic, sect.sct_mobil, vec[I_CIVIL], vec[I_MILIT],
316        vec[I_UW], vec[I_FOOD], sect.sct_work, sect.sct_avail);
317     pr("    %c %c\n", view[5], view[6]);
318     return RET_OK;
319 }
320
321 int
322 fly_map(coord curx, coord cury)
323 {
324     struct nstr_sect ns;
325     struct natstr *np;
326     struct sctstr sect;
327     coord rel_x, rel_y;
328     s_char view[7];
329     int i;
330     s_char range[128];
331
332     np = getnatp(player->cnum);
333     rel_x = xrel(np, curx);
334     rel_y = yrel(np, cury);
335     sprintf(range, "%d:%d,%d:%d", rel_x - 2, rel_x + 2, rel_y - 1,
336             rel_y + 1);
337     player->condarg = 0;
338     /* This is necessary, otherwise move_map would attempt to pay */
339     /* attention to the conditional arguments left behind by such */
340     /* a command as "tran p -1,-1 ?eff=100".. It'd then only see  */
341     /* 100% efficienct sects, and get all screwed up         --ts */
342
343     if (!snxtsct(&ns, range))
344         return RET_FAIL;
345     i = 0;
346     while (i < 7 && nxtsct(&ns, &sect)) {
347         if (!(view[i] = player->bmap[sctoff(ns.x, ns.y)]))
348             view[i] = ' ';
349         i++;
350     }
351
352     pr("    %c %c\n", view[0], view[1]);
353     pr("   %c %c %c\n", view[2], view[3], view[4]);
354     pr("    %c %c\n", view[5], view[6]);
355     return RET_OK;
356 }
357
358 int
359 check_lmines(coord x, coord y, double weight)
360 {
361     struct sctstr sect;
362     int mines;
363     int dam = 0;
364
365     getsect(x, y, &sect);
366     mines = getvar(V_MINE, (s_char *)&sect, EF_SECTOR);
367     if (mines > 0 &&
368         sect.sct_oldown != player->cnum &&
369         chance(DMINE_LHITCHANCE(mines)) && chance(weight / 100.0)) {
370         pr_beep();
371         pr("Blammo! Landmines detected! in %s  ",
372            xyas(sect.sct_x, sect.sct_y, player->cnum));
373         dam = roll(20);
374         --mines;
375         putvar(V_MINE, mines, (s_char *)&sect, EF_SECTOR);
376         putsect(&sect);
377         pr("%d damage sustained.\n", dam);
378     }
379     return dam;
380 }