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