]> git.pond.sub.org Git - empserver/blob - src/lib/update/nav_ship.c
Update copyright notice.
[empserver] / src / lib / update / nav_ship.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2007, 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  *  nav_ship.c: Navigate ships and such
29  * 
30  *  Known contributors to this file:
31  *     Chad Zabel, 1994
32  *     Ken Stevens, 1995
33  */
34
35 #include <config.h>
36
37
38 #include <ctype.h>
39 #include "nsc.h"
40 #include "path.h"
41 #include "update.h"
42 #include "empobj.h"
43 #include "unit.h"
44
45 static void swap(struct shpstr *);
46
47 static void
48 scuttle_it(struct shpstr *sp)
49 {
50     struct sctstr *sectp;
51
52     sp->shp_autonav &= ~AN_SCUTTLE;
53     if (!(sectp = getsectp(sp->shp_x, sp->shp_y))) {
54         wu(0, 0, "bad sector (%d,%d) ship %d\n",
55            sp->shp_x, sp->shp_y, sp->shp_uid);
56         return;
57     }
58     if (sectp->sct_type != SCT_HARBR || sectp->sct_effic < 2) {
59         wu(0, sp->shp_own,
60            "%s is not in a harbor at least 2%% eff!  Not scuttling.\n",
61            prship(sp));
62         return;
63     }
64     if (opt_TRADESHIPS) {
65         if (!(mchr[(int)sp->shp_type].m_flags & M_TRADE)) {
66             wu(0, sp->shp_own, "You can only autoscuttle trade ships!\n");
67             return;
68         }
69     }
70     wu(0, sp->shp_own, "Scuttling %s in sector %s\n",
71        prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
72     if (opt_TRADESHIPS) {
73         scuttle_tradeship(sp, 0);
74     }
75     scuttle_ship(sp);
76 }
77
78 static void
79 nav_check_atdest(struct shpstr *sp)
80 {
81     if ((sp->shp_x == sp->shp_destx[0]) && (sp->shp_y == sp->shp_desty[0])) {
82         if ((sp->shp_destx[0] == sp->shp_destx[1]) &&
83             (sp->shp_desty[0] == sp->shp_desty[1])) {
84
85             /* End of road */
86
87             sp->shp_autonav &= ~AN_AUTONAV;
88             wu(0, sp->shp_own, "%s arrived at %s, finished\n",
89                prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
90             if (sp->shp_autonav & AN_SCUTTLE) {
91                 scuttle_it(sp);
92             }
93         } else {
94             /* unload all cargo */
95             unload_it(sp);
96             wu(0, sp->shp_own, "%s arrived at %s\n",
97                prship(sp), xyas(sp->shp_x, sp->shp_y, sp->shp_own));
98             /* Swap */
99             swap(sp);
100         }
101     } else
102         sp->shp_autonav &= ~AN_LOADING;
103 }
104
105 /* flip the 2 fields that deal with autonav movement. */
106 /* CZ 6/1/94                                          */
107
108 static void
109 swap(struct shpstr *sp)
110 {
111     coord tcord;
112     i_type tcomm[TMAX];
113     short lev[TMAX];
114     int i;
115
116     tcord = sp->shp_destx[0];
117     sp->shp_destx[0] = sp->shp_destx[1];
118     sp->shp_destx[1] = tcord;
119     tcord = sp->shp_desty[0];
120     sp->shp_desty[0] = sp->shp_desty[1];
121     sp->shp_desty[1] = tcord;
122
123     for (i = 0; i < TMAX; ++i) {
124         lev[i] = sp->shp_lstart[i];
125         tcomm[i] = sp->shp_tstart[i];
126     }
127
128     for (i = 0; i < TMAX; ++i) {
129         sp->shp_lstart[i] = sp->shp_lend[i];
130         sp->shp_tstart[i] = sp->shp_tend[i];
131     }
132
133     for (i = 0; i < TMAX; ++i) {
134         sp->shp_lend[i] = lev[i];
135         sp->shp_tend[i] = tcomm[i];
136     }
137
138     /* set load bit */
139     sp->shp_autonav |= AN_LOADING;
140 }
141
142 /*  New Autonav code.
143  *  Chad Zabel
144  *  6-1-94
145  */
146
147 static int
148 nav_loadship(struct shpstr *sp, natid cnum)
149 {
150     struct sctstr *sectp;
151     int i, landown, shipown, didsomething[TMAX], rel;
152
153     for (i = 0; i < TMAX; i++)
154         didsomething[i] = 0;
155
156     /* Turn off the loading flag.
157      * if any of the loads fail on the ship
158      * it will be turned back on.
159      */
160
161     sp->shp_autonav &= ~AN_LOADING;
162
163     if (!(sectp = getsectp(sp->shp_x, sp->shp_y)))
164         return RET_SYS;         /* safety */
165     /* I suspect RET_SYS isn't really what you want here --dfp */
166
167
168     landown = sectp->sct_own;
169     shipown = sp->shp_own;
170     rel = getrel(getnatp(sectp->sct_own), cnum);
171
172     /* loop through each field for that ship */
173     for (i = 0; i < TMAX; ++i) {
174         /* check and see if the data fields have been set. */
175
176         if (sp->shp_tend[i] == I_NONE || sp->shp_lend[i] == 0) {
177             /* nothing to do move on. */
178             didsomething[i] = 1;
179             continue;
180         }
181         if (landown == 0) {
182             /* either sea or deity harbor */
183             didsomething[i] = 1;
184             continue;
185         }
186         if (!sect_has_dock(sectp)) {
187             /* we can only load in harbors */
188             didsomething[i] = 1;
189             continue;
190         }
191         if (landown == shipown || rel >= FRIENDLY)
192             didsomething[i] = load_it(sp, sectp, i);
193     }
194
195     /* check for any unsucessful loads */
196     /* if we have any return 0 to stop */
197     /* the nav_ship loop.              */
198
199     for (i = 0; i < TMAX; i++) {
200         if (didsomething[i] == 0)
201             return 0;
202     }
203     /* All loads were succesful */
204     return 1;
205 }
206
207 /* new autonav code.
208  * 
209  * 1. Try and move to the next sector/harbor given by the player.
210  * 2. Once we reach a harbor try and load all cargo holds for that ship.
211  * 3. If the ship reaches its max levels set by the player try to use
212  *    up all mobility getting to the next harbor.
213  * Continue to loop until the ship runs out of mobility, a load fails,
214  * the ship gets sunk (forts,ect..), the ship hits a mine.
215  *
216  * A check has been added for fuel so ships don't end up running
217  * out of mobility in the ocean.
218  *
219  * Questions, bugs (fixes) , or new ideas should be directed at
220  * Chad Zabel.  
221  * 6-1-94   
222  * Modified to use shp_nav by Ken Stevens 1995
223  */
224 int
225 nav_ship(struct shpstr *sp)
226 {
227     struct sctstr *sectp;
228     char *cp;
229     int stopping;
230     int quit;
231     int didsomething = 0;
232     int max_amt, food_amt;
233     char buf[1024];
234     struct emp_qelem ship_list;
235     struct emp_qelem *qp, *newqp;
236     struct ulist *mlp;
237     int dummyint;
238     double dummydouble;
239     int dir;
240     natid cnum;
241     struct mchrstr *mcp, *vship;
242
243     /* just return if no autonaving to do for this ship */
244     if (!(sp->shp_autonav & AN_AUTONAV) || (sp->shp_autonav & AN_STANDBY))
245         return RET_OK;
246
247     cnum = sp->shp_own;
248     vship = mcp = &mchr[(int)sp->shp_type];
249
250     /* Make a list of one ships so we can use the navi.c code */
251     emp_initque(&ship_list);
252     mlp = malloc(sizeof(struct ulist));
253     mlp->chrp = (struct empobj_chr *)(mchr + sp->shp_type);
254     mlp->unit.ship = *sp;
255     mlp->mobil = sp->shp_mobil;
256     emp_insque(&mlp->queue, &ship_list);
257
258     quit = 1;                   /* setup loop, we want to check it 1 time. */
259
260     do {
261         if ((sp->shp_mobil > 0) && (!(sp->shp_autonav & AN_LOADING)) &&
262             (!(sp->shp_autonav & AN_STANDBY))) {
263             shp_nav(&ship_list, &dummydouble, &dummydouble, &dummyint,
264                     sp->shp_own);
265             if (QEMPTY(&ship_list))
266                 return RET_OK;
267             /* before we move check to see if ship needs fuel. */
268             sectp = getsectp(sp->shp_x, sp->shp_y);
269             if (opt_FUEL &&
270                 sectp->sct_own != 0 &&
271                 sp->shp_fuel <= 0 &&
272                 ((struct mchrstr *)mlp->chrp)->m_fuelu != 0)
273                 auto_fuel_ship(sp);
274             mlp->unit.ship.shp_fuel = sp->shp_fuel;
275
276             cp = BestShipPath(buf, sp->shp_x, sp->shp_y,
277                               sp->shp_destx[0], sp->shp_desty[0],
278                               sp->shp_own);
279             if (cp == 0) {
280                 wu(0, cnum,
281                    "%s bad path, ship put on standby\n", prship(sp));
282                 sp->shp_autonav |= AN_STANDBY;
283                 putship(sp->shp_uid, sp);
284
285                 /* We need to free the ship list */
286                 qp = ship_list.q_forw;
287                 while (qp != &ship_list) {
288                     newqp = qp->q_forw;
289                     emp_remque(qp);
290                     free(qp);
291                     qp = newqp;
292                 }
293                 return RET_SYN;
294             }
295             stopping = 0;
296
297             while (*cp && !stopping && sp->shp_own && mlp->mobil > 0.0) {
298                 dir = diridx(*cp++);
299                 stopping |= shp_nav_one_sector(&ship_list, dir,
300                                                sp->shp_own, 0);
301             }
302
303             /* Ship not sunk */
304             if (sp->shp_own)
305                 nav_check_atdest(sp);
306         }
307
308         quit = 0;               /* stop loop */
309
310         /* Try to load the ship */
311         if (sp->shp_autonav & AN_LOADING) {
312             didsomething = nav_loadship(sp, cnum);
313             if (didsomething)
314                 quit = 1;
315         }
316         /* special case for fishing boats */
317         if ((mchr[(int)sp->shp_type].m_flags & M_FOOD) == 1) {
318             food_amt = sp->shp_item[I_FOOD];
319             max_amt = vship->m_item[I_FOOD];
320             sectp = getsectp(sp->shp_x, sp->shp_y);
321
322             if (food_amt < max_amt && (sectp->sct_own == 0))
323                 quit = 0;
324         }
325         /* reset flag and check if we can move. */
326
327     } while (quit);             /* end loop */
328
329     putship(sp->shp_uid, sp);
330
331     /* We need to free the ship list (just in case) */
332     qp = ship_list.q_forw;
333     while (qp != &ship_list) {
334         newqp = qp->q_forw;
335         emp_remque(qp);
336         free(qp);
337         qp = newqp;
338     }
339     return RET_OK;
340 }