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