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