]> git.pond.sub.org Git - empserver/blob - src/lib/update/sail.c
Cleanup #includes of (mostly a long time) unused header files.
[empserver] / src / lib / update / sail.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, 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  *  sail.c: Sail ships during the update
29  * 
30  *  Known contributors to this file:
31  *     Doug Hay
32  *     Robert Forsman
33  *     Ken Stevens, 1995
34  *     Steve McClure, 1998-2000
35  */
36
37 #include "misc.h"
38 #include "sect.h"
39 #include "path.h"
40 #include "ship.h"
41 #include "file.h"
42 #include "nat.h"
43 #include "xy.h"
44 #include "nsc.h"
45 #include "update.h"
46 #include "subs.h"
47 #include "common.h"
48 #include <math.h>
49 #include <stdlib.h>
50
51 static void fltp_to_list(struct fltheadstr *, struct emp_qelem *);
52
53 static void
54 cost_ship(struct shpstr *sp, struct fltelemstr *ep, struct fltheadstr *fp)
55 {
56     double mobcost;
57     int howfar;
58
59     mobcost = 0.0;
60     if (sp->shp_effic > 0) {
61         mobcost = sp->shp_effic * sp->shp_speed * 0.01;
62         mobcost = 480.0 / (mobcost * (1 + (50 + sp->shp_tech) /
63                                       (double)(200 + sp->shp_tech)));
64     }
65 /* the next two lines are not necessary since shp_mobquota is unsigned
66 and therefore cannot be less than 0. 
67         if (sp->shp_mobquota<0)
68                 sp->shp_mobquota=0;
69 */
70
71     howfar = 0;
72     if (mobcost > 0) {
73         howfar = (int)sp->shp_mobil - (int)sp->shp_mobquota;
74         howfar = ceil((howfar / mobcost));
75     }
76     if (howfar < 0)
77         howfar = 0;
78 #ifdef SAILDEBUG
79     wu(0, fp->own,
80        "Ship #%d can move %d spaces on mobility %d (cost/sect %f)\n",
81        sp->shp_uid, howfar, sp->shp_mobil, mobcost);
82 #endif
83     if ((unsigned int)howfar < fp->maxmoves)
84         fp->maxmoves = howfar;
85
86     ep->mobil = sp->shp_mobil;
87     ep->mobcost = mobcost;
88 }
89
90 static int
91 sail_find_fleet(struct fltheadstr **head, struct shpstr *sp)
92 {
93     struct fltheadstr *fltp;
94     struct shpstr *ap;
95     struct fltelemstr *this;
96     int len = 0;
97     int follow = -1;
98     int stop;
99     s_char *cp;
100
101     if (sp->shp_own == 0)
102         return (0);
103
104
105
106     /* If this ship is following, find the head of the follow list. */
107     for (ap = sp; ap; len++, ap = getshipp(follow)) {
108         follow = ap->shp_follow;
109         /* Not same owner */
110         if (ap->shp_own != sp->shp_own) {
111             wu(0, sp->shp_own,
112                "Ship #%d, following #%d, which you don't own.\n",
113                sp->shp_uid, ap->shp_uid);
114             return (0);
115         }
116         /* Not a follower. */
117         if (ap->shp_path[0] != 'f')
118             break;
119         /* Following itself */
120         if (follow == ap->shp_uid || follow == sp->shp_uid)
121             break;
122     }
123     if (!ap) {
124         wu(0, sp->shp_own,
125            "Ship #%d, following #%d, which you don't own.\n",
126            sp->shp_uid, follow);
127         return (0);
128     }
129
130     /* This should prevent infinite loops. */
131     if (len >= 10) {
132         wu(0, sp->shp_own,
133            "Ship #%d, too many follows (circular follow?).\n",
134            sp->shp_uid);
135         return (0);
136     }
137
138     for (stop = 0, cp = ap->shp_path; (!stop) && (*cp); cp++) {
139         switch (*cp) {
140         case 'y':
141         case 'u':
142         case 'g':
143         case 'j':
144         case 'b':
145         case 'n':
146         case 'h':
147         case 't':
148             break;
149         default:
150             stop = 1;
151         }
152     }
153
154     /* we found a non-valid char in the path. */
155     if (*cp) {
156         wu(0, ap->shp_own, "invalid char '\\%03o' in path of ship %d\n",
157            (unsigned char)*cp, ap->shp_uid);
158         *cp = 0;
159     }
160
161     /* if this ship is not sailing anywhere then ignore it. */
162     if (!*ap->shp_path)
163         return (0);
164
165     /* Find the fleet structure we belong to. */
166     for (fltp = (*head); (fltp && fltp->leader != follow);
167          fltp = fltp->next) ;
168
169     if (!fltp) {
170         fltp = (struct fltheadstr *)malloc(sizeof(*fltp));
171         memset(fltp, 0, sizeof(*fltp));
172
173         /* Fix the links. */
174         fltp->next = (*head);
175         *head = fltp;
176
177         /* Set the leader. */
178         fltp->leader = ap->shp_uid;
179         fltp->real_q = LEADER_REAL;
180         fltp->x = ap->shp_x;
181         fltp->y = ap->shp_y;
182         fltp->own = ap->shp_own;
183         fltp->maxmoves = 500;
184     }
185
186     /* If the fleet is not in the same sector as us, no go. */
187     if ((fltp->x != sp->shp_x) || (fltp->y != sp->shp_y)) {
188         wu(0, sp->shp_own,
189            "Ship %d not in same sector as its sailing fleet\n",
190            sp->shp_uid);
191         fltp->real_q = LEADER_WRONGSECT;
192         return (0);
193     }
194
195     this = (struct fltelemstr *)malloc(sizeof(*this));
196     memset(this, 0, sizeof(*this));
197     this->num = sp->shp_uid;
198     this->own = sp->shp_own;
199     this->next = fltp->head;
200     fltp->head = this;
201     cost_ship(sp, this, fltp);
202
203     return 1;
204 }
205
206 static int
207 sail_nav_fleet(struct fltheadstr *fltp)
208 {
209     struct fltelemstr *fe;
210     struct shpstr *sp, ship;
211     struct sctstr *sectp;
212     int error = 0;
213     s_char *s, *p;
214     natid own;
215     struct emp_qelem ship_list;
216     int dir;
217
218 #ifdef SAILDEBUG
219     switch (fltp->real_q) {
220     case LEADER_VIRTUAL:
221         s = "leaderless";
222         break;
223     case LEADER_REAL:
224         s = "real";
225         break;
226     case LEADER_WRONGSECT:
227         s = "scattered";
228         break;
229     default:
230         s = "inconsistent";
231     }
232     wu(0, fltp->own,
233        "Fleet lead by %d is %s, can go %d spaces\n  contains ships:",
234        fltp->leader, s, fltp->maxmoves);
235     for (fe = fltp->head; fe; fe = fe->next)
236         wu(0, fltp->own, " %d", fe->num);
237     wu(0, fltp->own, "\n");
238 #endif
239     sectp = getsectp(fltp->x, fltp->y);
240     switch (check_nav(sectp)) {
241     case CN_NAVIGABLE:
242         break;
243     case CN_CONSTRUCTION:
244     case CN_LANDLOCKED:
245     default:
246         wu(0, fltp->own, "Your fleet lead by %d is trapped by land.\n",
247            fltp->leader);
248         return (0);
249     }
250     for (fe = fltp->head; fe; fe = fe->next) {
251         sp = getshipp(fe->num);
252         if (sp->shp_item[I_MILIT] == 0 && sp->shp_item[I_CIVIL] == 0) {
253             wu(0, fltp->own,
254                "   ship #%d (%s) is crewless and can't go on\n",
255                fe->num, cname(fe->own));
256             error = 1;
257         }
258     }
259     if (error)
260         return (0);
261     sp = getshipp(fltp->leader);
262     own = sp->shp_own;
263     fltp_to_list(fltp, &ship_list);     /* hack -KHS 1995 */
264     for (s = sp->shp_path; (*s) && (fltp->maxmoves > 0); s++) {
265         dir = chkdir(*s, DIR_STOP, DIR_LAST);
266         if (0 != (error = shp_nav_one_sector(&ship_list, dir, own, 0)))
267             fltp->maxmoves = 1;
268         --(fltp->maxmoves);
269     }
270     shp_put(&ship_list, own);
271     getship(sp->shp_uid, &ship);
272     fltp->x = ship.shp_x;
273     fltp->y = ship.shp_y;
274     for (p = &ship.shp_path[0]; *s; p++, s++)
275         *p = *s;
276     *p = 0;
277     putship(ship.shp_uid, &ship);
278 #ifdef SAILDEBUG
279     if (sp->shp_path[0]) {
280         wu(0, fltp->own,
281            "Fleet lead by #%d nav'd to %s, path left = %s\n",
282            fltp->leader, xyas(fltp->x, fltp->y, fltp->own), &sp->shp_path);
283     } else
284         wu(0, fltp->own,
285            "Fleet lead by #%d nav'd to %s, finished.\n",
286            fltp->leader, xyas(fltp->x, fltp->y, fltp->own));
287     wu(0, sp->shp_own, "Ship #%d has %d mobility now.\n",
288        fe->num, (int)fe->mobil);
289 #endif
290     return 1;
291 }
292
293 void
294 sail_ship(natid cn)
295 {
296     struct shpstr *sp;
297     struct fltheadstr *head = 0;
298     struct fltheadstr *fltp;
299     int n;
300
301
302     for (n = 0; NULL != (sp = getshipp(n)); n++)
303         if (sp->shp_own == cn) {
304             sail_find_fleet(&head, sp);
305         }
306
307     /* see what the fleets fall out into */
308     for (fltp = head; fltp; fltp = fltp->next) {
309         sail_nav_fleet(fltp);
310         wu(0, fltp->own, "Your fleet lead by ship #%d has reached %s.\n",
311            fltp->leader, xyas(fltp->x, fltp->y, fltp->own));
312     }
313
314     /* Free up the memory, 'cause I want to. */
315     for (fltp = head; fltp != 0;) {
316         struct fltelemstr *fe;
317         struct fltheadstr *saveh;
318         saveh = fltp->next;
319         for (fe = fltp->head; fe != 0;) {
320             struct fltelemstr *saveel;
321             saveel = fe->next;
322             free(fe);
323             fe = saveel;
324         }
325         free(fltp);
326         fltp = saveh;
327     }
328 }
329
330 /* The following is a total hack by Ken Stevens to cut down dramatically on repeated code 1995 */
331
332 static void
333 fltp_to_list(struct fltheadstr *fltp, struct emp_qelem *list)
334 {
335     struct fltelemstr *fe;
336     struct mlist *mlp;
337     struct shpstr *sp;
338
339     emp_initque(list);
340     for (fe = fltp->head; fe; fe = fe->next) {
341         mlp = (struct mlist *)malloc(sizeof(struct mlist));
342         sp = getshipp(fe->num);
343         mlp->mcp = mchr + sp->shp_type;
344         mlp->ship = *sp;
345         mlp->mobil = fe->mobil;
346         emp_insque(&mlp->queue, list);
347     }
348 }