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