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