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