]> git.pond.sub.org Git - empserver/blob - src/lib/commands/orde.c
deity.h is redundant, remove it.
[empserver] / src / lib / commands / orde.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  *  orde.c: Turn on/off autonavigation
29  * 
30  *  Known contributors to this file:
31  *     Chad Zabel, 1994
32  *     Steve McClure, 2000
33  */
34
35 #include <string.h>
36 #include <ctype.h>
37 #include "misc.h"
38 #include "player.h"
39 #include "var.h"
40 #include "ship.h"
41 #include "sect.h"
42 #include "news.h"
43 #include "xy.h"
44 #include "nsc.h"
45 #include "nat.h"
46 #include "path.h"
47 #include "file.h"
48 #include "item.h"
49 #include "commands.h"
50 #include "optlist.h"
51
52 /*
53 **  Command syntax:
54 **
55 **  ORDER <ship>                                  Show orders
56 **  ORDER <ship> c[ancel]                         Cancel orders
57 **  ORDER <ship> s[top]                           Suspend orders
58 **  ORDER <ship> r[esume]                         Resume orders
59 **  ORDER <ship> d[eclare] <dest1>                Set destination
60 **               d[eclare] <dest1> <dest2>
61 **  ORDER <ship> l[evel]   <field> <start/end> <comm> <level>
62 **
63 **
64 ** New syntax:
65 **  qorder <ship>    display cargo levels     
66 **  sorder <ship>    display statistical info 
67  */
68
69 int
70 orde(void)
71 {
72     int nships = 0;
73     int diffeachship = 0;
74     int orders, sub, level;
75     int scuttling = 0;
76     struct nstr_item nb;
77     struct shpstr ship;
78     struct shpstr start;        /* Used for checking database */
79     struct ichrstr *i1;
80     coord p0x, p0y, p1x, p1y;
81     int i;
82     s_char *p, *p1, *dest;
83     s_char buf1[128];
84     s_char buf[1024];
85     s_char prompt[128];
86
87     if (!snxtitem(&nb, EF_SHIP, player->argp[1]))
88         return RET_SYN;
89     while (!player->aborted && nxtitem(&nb, (s_char *)(&ship))) {
90         if (!player->owner || ship.shp_own == 0)
91             continue;
92         if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
93             pr("bad ship type %d (#%d)\n", ship.shp_type, nb.cur);
94             continue;
95         }
96         if (opt_SAIL) {
97             if (*ship.shp_path) {
98                 if (!diffeachship)
99                     pr("Ship #%d has a \"sail\" path!\n", ship.shp_uid);
100                 continue;
101             }
102         }
103         memcpy(&start, &ship, sizeof(struct shpstr));
104         sprintf(prompt,
105                 "Ship #%d, declare, cancel, suspend, resume, level? ",
106                 ship.shp_uid);
107         p = getstarg(player->argp[2], prompt, buf);
108         if (player->aborted || !p)
109             return RET_FAIL;
110         if (!*p) {
111             if (!diffeachship)
112                 return RET_FAIL;
113             else
114                 continue;
115         }
116         switch (*p) {
117         default:
118             pr("Bad order type!\n");
119             return RET_SYN;
120         case 'c':               /* clear ship fields  */
121             ship.shp_mission = 0;
122             ship.shp_autonav &= ~(AN_AUTONAV + AN_STANDBY + AN_LOADING);
123             for (i = 0; i < TMAX; i++) {
124                 ship.shp_tstart[i] = ' ';
125                 ship.shp_tend[i] = ' ';
126                 ship.shp_lstart[i] = 0;
127                 ship.shp_lend[i] = 0;
128             }
129             break;
130         case 's':               /* suspend ship movement  */
131             ship.shp_mission = 0;
132             ship.shp_autonav |= AN_STANDBY;
133             break;
134         case 'r':               /* resume ship movement   */
135             ship.shp_mission = 0;
136             ship.shp_autonav &= ~AN_STANDBY;
137             break;
138         case 'd':               /* declare path */
139             orders = 0;
140             scuttling = 0;
141             /* Need location */
142             if ((p = getstarg(player->argp[3], "Destination? ", buf)) == 0
143                 || *p == 0)
144                 return RET_SYN;
145             if (!sarg_xy(p, &p0x, &p0y))
146                 return RET_SYN;
147             p1x = p0x;
148             p1y = p0y;
149
150
151
152             if (!orders) {
153                 p = getstarg(player->argp[4], "Second dest? ", buf);
154                 if (!p || !*p || !strcmp(p, "-")) {
155                     orders = 1;
156                     pr("A one-way order has been accepted.\n");
157                 } else if (!strncmp(p, "s", 1)) {
158                     if (opt_TRADESHIPS) {
159                         if (!(mchr[(int)ship.shp_type].m_flags & M_TRADE)) {
160                             pr("You can't auto-scuttle that ship!\n");
161                             return RET_SYN;
162                         }
163                     } else {
164                         pr("You can't auto-scuttle that ship!\n");
165                         return RET_SYN;
166                     }
167                     pr("A scuttle order has been accepted.\n");
168                     scuttling = 1;
169                 } else {
170                     if (!sarg_xy(p, &p1x, &p1y))
171                         return RET_SYN;
172                     pr("A circular order has been accepted.\n");
173                 }
174             }
175
176             /*
177              *  Set new destination and trade type fields.
178              */
179             ship.shp_mission = 0;
180             ship.shp_destx[1] = p1x;
181             ship.shp_desty[1] = p1y;
182             ship.shp_destx[0] = p0x;
183             ship.shp_desty[0] = p0y;
184
185             ship.shp_autonav &= ~(AN_STANDBY + AN_SAILDIR + AN_LOADING);
186             ship.shp_autonav |= AN_AUTONAV;
187
188             if (scuttling)
189                 ship.shp_autonav |= AN_SCUTTLE;
190             break;
191
192             /* set cargo levels on the ship */
193
194         case 'l':
195             /* convert player->argp[3] to an integer */
196             if (player->argp[3])
197                 sub = atoi(player->argp[3]);
198             else {
199                 sprintf(buf1, "Field (1-%d) ", TMAX);
200                 if (getstarg(player->argp[3], buf1, buf) == 0)
201                     return RET_SYN;
202                 sub = atoi(buf);
203             }
204             /* check to make sure value in within range. */
205             if (sub > TMAX || sub < 1) {
206                 pr("Value must range from 1 to %d\n", TMAX);
207                 break;
208             }
209
210             /* to keep sub in range of our arrays 
211                subtract 1 so the new range is 0-(TMAX-1)
212              */
213             sub = sub - 1;;
214
215             if (ship.shp_autonav & AN_AUTONAV) {
216                 orders = 1;
217                 dest = getstarg(player->argp[4], "Start or End? ", buf);
218                 if (orders) {   /* before dest check */
219                     if (!dest)
220                         break;
221                     switch (*dest) {
222                     default:
223                         pr("You must enter 'start' or 'end'\n");
224                         return RET_SYN;
225                     case 'e':
226                     case 'E':
227                         i1 = whatitem(player->argp[5], "Commodity? ");
228                         if (!i1)
229                             break;
230                         else {
231                             p1 = getstarg(player->argp[6], "Amount? ",
232                                           buf);
233                             if (!p1)
234                                 return RET_SYN;
235                             level = atoi(p1);
236                         }
237                         if (level < 0) {
238                             level = 0;  /* prevent negatives. */
239                             pr("You must use positive number! Level set to 0.\n");
240                         }
241                         ship.shp_tstart[sub] = (s_char)i1->i_mnem;
242                         ship.shp_lstart[sub] = level;
243                         pr("Order Set \n");
244                         break;
245                     case 's':
246                     case 'S':
247                         i1 = whatitem(player->argp[5], "Commodity? ");
248                         if (!i1)
249                             break;
250                         else {
251                             p1 = getstarg(player->argp[6], "Amount? ",
252                                           buf);
253                             if (!p1)
254                                 return RET_SYN;
255                             level = atoi(p1);
256                         }
257                         if (level < 0) {
258                             level = 0;
259                             pr("You must use positive number! Level set to 0.\n");
260                         }
261                         ship.shp_tend[sub] = (s_char)i1->i_mnem;
262                         ship.shp_lend[sub] = level;
263                         pr("Order Set \n");
264                         break;
265                     }
266                 }
267             } else
268                 pr("You need to 'declare' a ship path first, see 'info order'\n");
269
270             break;
271         }                       /* end of switch (*p) */
272
273
274
275         /*
276          *  Set loading flag if ship is already in one
277          *  of the specified harbors and a cargo has been
278          *  specified.
279          */
280
281         if (((ship.shp_x == ship.shp_destx[0])
282              && (ship.shp_y == ship.shp_desty[0])
283              && (ship.shp_lstart[0] != ' '))
284             || ((ship.shp_x == ship.shp_desty[1])
285                 && (ship.shp_y == ship.shp_desty[1])
286                 && (ship.shp_lstart[1] != ' '))) {
287
288             coord tcord;
289             s_char tcomm[TMAX];
290             short lev[TMAX];
291             int i;
292
293             ship.shp_autonav |= AN_LOADING;
294
295             /*  swap variables, this keeps 
296                the load_it() procedure happy. CZ
297              */
298             tcord = ship.shp_destx[0];
299             ship.shp_destx[0] = ship.shp_destx[1];
300             ship.shp_destx[1] = tcord;
301             tcord = ship.shp_desty[0];
302             ship.shp_desty[0] = ship.shp_desty[1];
303             ship.shp_desty[1] = tcord;
304
305             for (i = 0; i < TMAX; i++) {
306                 lev[i] = ship.shp_lstart[i];
307                 ship.shp_lstart[i] = ship.shp_lend[i];
308                 ship.shp_lend[i] = lev[i];
309                 tcomm[i] = ship.shp_tstart[i];
310                 ship.shp_tstart[i] = ship.shp_tend[i];
311                 ship.shp_tend[i] = tcomm[i];
312             }
313         }
314         /*
315            **  Write ship back to database, then give it
316            **  a kick down the autonav route if necessary.
317          */
318
319
320         /* Now do a sanity check. */
321         if (!check_ship_ok(&start))
322             return RET_SYN;
323
324         putship(ship.shp_uid, &ship);
325         nships++;
326     }
327     return RET_OK;
328 }
329
330 static void
331 eta_calc(struct shpstr *sp, s_char *path, int *len, int *nupdates)
332 {
333     struct mchrstr *mcp;
334     double mobcost, mobil;
335     int i;
336
337     i = strlen(path);
338     *len = i;
339     *nupdates = 1;
340
341     mcp = &mchr[(int)sp->shp_type];
342     mobcost = sp->shp_effic * 0.01 * sp->shp_speed;
343     mobcost = 480.0 / (mobcost + techfact(sp->shp_tech, mobcost));
344     mobil = sp->shp_mobil;
345     while (i) {
346         if (mobil > 0) {
347             mobil -= mobcost;
348             i--;
349         } else {
350             mobil += (ship_mob_scale * (float)etu_per_update);
351             (*nupdates)++;
352         }
353     }
354 }
355
356 int
357 qorde(void)
358 {
359     int nships = 0;
360     int i;
361     struct nstr_item nb;
362     struct shpstr ship;
363
364     if (!snxtitem(&nb, EF_SHIP, player->argp[1]))
365         return RET_SYN;
366     while (nxtitem(&nb, (s_char *)(&ship))) {
367         if (!player->owner || ship.shp_own == 0)
368             continue;
369         if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
370             pr("bad ship type %d (#%d)\n", ship.shp_type, nb.cur);
371             continue;
372         }
373
374         if ((ship.shp_autonav & AN_AUTONAV) ||
375             (ship.shp_path[0] && opt_SAIL)) {
376             if (!nships) {      /* 1st ship, print banner */
377                 if (player->god)
378                     pr("own ");
379                 pr("shp#     ship type    ");
380                 pr("[Starting]       (Ending)    \n");
381             }
382             nships++;
383             if (player->god)
384                 pr("%3d ", ship.shp_own);
385             pr("%4d", nb.cur);
386             pr(" %-16.16s", mchr[(int)ship.shp_type].m_name);
387         }
388         if (ship.shp_autonav & AN_AUTONAV) {
389
390             pr(" [");
391             for (i = 0; i < TMAX; i++) {
392                 if (ship.shp_tend[i] != ' ' && ship.shp_lend[i] != 0) {
393                     pr("%d-", i + 1);
394                     pr("%c", ship.shp_tend[i]);
395                     pr(":");
396                     pr("%d ", ship.shp_lend[i]);
397                 }
398             }
399             pr("] , (");
400             for (i = 0; i < TMAX; i++) {
401                 if (ship.shp_tstart[i] != ' ' && ship.shp_lstart[i] != 0) {
402                     pr("%d-", i + 1);
403                     pr("%c", ship.shp_tstart[i]);
404                     pr(":");
405                     pr("%d ", ship.shp_lstart[i]);
406                 }
407             }
408             pr(")");
409             if (ship.shp_autonav & AN_SCUTTLE)
410                 pr(" scuttling");
411             pr("\n");
412         }
413
414         if (opt_SHIPNAMES) {
415             if ((ship.shp_autonav & AN_AUTONAV) ||
416                 (ship.shp_path[0] && opt_SAIL)) {
417                 if (ship.shp_name[0] != 0) {
418                     if (player->god)
419                         pr("    ");
420                     pr("       %s\n", ship.shp_name);
421                 }
422             }
423         }
424     }
425     if (!nships) {
426         if (player->argp[1])
427             pr("%s: No ship(s)\n", player->argp[1]);
428         else
429             pr("%s: No ship(s)\n", "");
430         return RET_FAIL;
431     } else
432         pr("%d ship%s\n", nships, splur(nships));
433     return RET_OK;
434 }
435
436 /*  Chad Zabel 1-15-94
437  *  New command added to display autonav stats.
438  */
439
440 int
441 sorde(void)
442 {
443     int nships = 0;
444     int len, updates;
445     s_char *c;
446     struct nstr_item nb;
447     struct shpstr ship;
448     s_char buf[1024];
449
450     if (!snxtitem(&nb, EF_SHIP, player->argp[1]))
451         return RET_SYN;
452     while (nxtitem(&nb, (s_char *)(&ship))) {
453         if (!player->owner || ship.shp_own == 0)
454             continue;
455         if (ship.shp_type < 0 || ship.shp_type > shp_maxno) {
456             pr("bad ship type %d (#%d)\n", ship.shp_type, nb.cur);
457             continue;
458         }
459         if ((ship.shp_autonav & AN_AUTONAV) ||
460             (ship.shp_path[0] && opt_SAIL)) {
461             if (!nships) {      /* 1st ship, print banner */
462                 if (player->god)
463                     pr("own ");
464                 pr("shp#     ship type      x,y    ");
465                 pr("start    end   ");
466                 pr("len  eta\n");
467             }
468             nships++;
469             if (player->god)
470                 pr("%3d ", ship.shp_own);
471             pr("%4d", nb.cur);
472             pr(" %-16.16s", mchr[(int)ship.shp_type].m_name);
473             prxy(" %3d,%-3d", ship.shp_x, ship.shp_y, player->cnum);
474         }
475         if (ship.shp_autonav & AN_AUTONAV) {
476             /* Destination 1 */
477             prxy(" %3d,%-3d", ship.shp_destx[1],
478                  ship.shp_desty[1], player->cnum);
479
480             /* Destination 2 */
481             if ((ship.shp_destx[1] != ship.shp_destx[0])
482                 || (ship.shp_desty[1] != ship.shp_desty[0])) {
483                 prxy(" %3d,%-3d", ship.shp_destx[0],
484                      ship.shp_desty[0], player->cnum);
485             } else
486                 pr("        ");
487
488             if (ship.shp_autonav & AN_STANDBY)
489                 pr(" suspended");
490             else if (ship.shp_autonav & AN_LOADING)
491                 pr(" loading");
492             else {
493                 /* ETA calculation */
494
495                 c = BestShipPath(buf, ship.shp_x,
496                                  ship.shp_y, ship.shp_destx[0],
497                                  ship.shp_desty[0], ship.shp_own);
498                 if (!c || !*c)
499                     pr(" no route possible");
500                 else if (*c == 'h')
501                     pr(" has arrived");
502                 else if (*c == '?')
503                     pr(" route too long");
504                 else {
505                     /* distance to destination */
506                     eta_calc(&ship, c, &len, &updates);
507                     pr(" %3d %4d", len, updates);
508                 }
509             }
510             if (ship.shp_autonav & AN_SCUTTLE)
511                 pr(" (scuttling)");
512             pr("\n");
513         }
514         if (opt_SHIPNAMES) {
515             if ((ship.shp_autonav & AN_AUTONAV) ||
516                 (ship.shp_path[0] && opt_SAIL)) {
517                 if (!(ship.shp_autonav & AN_AUTONAV))
518                     pr("\n");
519                 if (ship.shp_name[0] != 0) {
520                     if (player->god)
521                         pr("    ");
522                     pr("       %s\n", ship.shp_name);
523                 }
524             }
525         }
526     }
527     if (!nships) {
528         if (player->argp[1])
529             pr("%s: No ship(s)\n", player->argp[1]);
530         else
531             pr("%s: No ship(s)\n", "");
532         return RET_FAIL;
533     } else
534         pr("%d ship%s\n", nships, splur(nships));
535     return RET_OK;
536 }