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