]> git.pond.sub.org Git - empserver/blob - src/lib/update/sail.c
s_char purge directed by compiler warnings.
[empserver] / src / lib / update / sail.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, 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  *  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 <config.h>
38
39 #include "misc.h"
40 #include "sect.h"
41 #include "path.h"
42 #include "ship.h"
43 #include "file.h"
44 #include "nat.h"
45 #include "xy.h"
46 #include "nsc.h"
47 #include "update.h"
48 #include "subs.h"
49 #include "common.h"
50 #include <math.h>
51 #include <stdlib.h>
52
53 static void fltp_to_list(struct fltheadstr *, struct emp_qelem *);
54
55 static void
56 cost_ship(struct shpstr *sp, struct fltelemstr *ep, struct fltheadstr *fp)
57 {
58     double mobcost;
59     int howfar;
60
61     mobcost = 0.0;
62     if (sp->shp_effic > 0) {
63         mobcost = sp->shp_effic * sp->shp_speed * 0.01;
64         mobcost = 480.0 / (mobcost * (1 + (50 + sp->shp_tech) /
65                                       (double)(200 + sp->shp_tech)));
66     }
67 /* the next two lines are not necessary since shp_mobquota is unsigned
68 and therefore cannot be less than 0. 
69         if (sp->shp_mobquota<0)
70                 sp->shp_mobquota=0;
71 */
72
73     howfar = 0;
74     if (mobcost > 0) {
75         howfar = (int)sp->shp_mobil - (int)sp->shp_mobquota;
76         howfar = ceil((howfar / mobcost));
77     }
78     if (howfar < 0)
79         howfar = 0;
80 #ifdef SAILDEBUG
81     wu(0, fp->own,
82        "Ship #%d can move %d spaces on mobility %d (cost/sect %f)\n",
83        sp->shp_uid, howfar, sp->shp_mobil, mobcost);
84 #endif
85     if ((unsigned int)howfar < fp->maxmoves)
86         fp->maxmoves = howfar;
87
88     ep->mobil = sp->shp_mobil;
89     ep->mobcost = mobcost;
90 }
91
92 static int
93 sail_find_fleet(struct fltheadstr **head, struct shpstr *sp)
94 {
95     struct fltheadstr *fltp;
96     struct shpstr *ap;
97     struct fltelemstr *this;
98     int len = 0;
99     int follow = -1;
100     int stop;
101     char *cp;
102
103     if (sp->shp_own == 0)
104         return 0;
105
106
107
108     /* If this ship is following, find the head of the follow list. */
109     for (ap = sp; ap; len++, ap = getshipp(follow)) {
110         follow = ap->shp_follow;
111         /* Not same owner */
112         if (ap->shp_own != sp->shp_own) {
113             wu(0, sp->shp_own,
114                "Ship #%d, following #%d, which you don't own.\n",
115                sp->shp_uid, ap->shp_uid);
116             return 0;
117         }
118         /* Not a follower. */
119         if (ap->shp_path[0] != 'f')
120             break;
121         /* Following itself */
122         if (follow == ap->shp_uid || follow == sp->shp_uid)
123             break;
124     }
125     if (!ap) {
126         wu(0, sp->shp_own,
127            "Ship #%d, following #%d, which you don't own.\n",
128            sp->shp_uid, follow);
129         return 0;
130     }
131
132     /* This should prevent infinite loops. */
133     if (len >= 10) {
134         wu(0, sp->shp_own,
135            "Ship #%d, too many follows (circular follow?).\n",
136            sp->shp_uid);
137         return 0;
138     }
139
140     for (stop = 0, cp = ap->shp_path; !stop && *cp; cp++) {
141         switch (*cp) {
142         case 'y':
143         case 'u':
144         case 'g':
145         case 'j':
146         case 'b':
147         case 'n':
148         case 'h':
149         case 't':
150             break;
151         default:
152             stop = 1;
153         }
154     }
155
156     /* we found a non-valid char in the path. */
157     if (*cp) {
158         wu(0, ap->shp_own, "invalid char '\\%03o' in path of ship %d\n",
159            (unsigned char)*cp, ap->shp_uid);
160         *cp = 0;
161     }
162
163     /* if this ship is not sailing anywhere then ignore it. */
164     if (!*ap->shp_path)
165         return 0;
166
167     /* Find the fleet structure we belong to. */
168     for (fltp = *head; fltp && fltp->leader != follow; fltp = fltp->next) ;
169
170     if (!fltp) {
171         fltp = 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 = 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     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     for (fe = fltp->head; fe; fe = fe->next) {
242         sp = getshipp(fe->num);
243         if (sp->shp_item[I_MILIT] == 0 && sp->shp_item[I_CIVIL] == 0) {
244             wu(0, fltp->own,
245                "   ship #%d (%s) is crewless and can't go on\n",
246                fe->num, cname(fe->own));
247             error = 1;
248         }
249         if ((shp_check_nav(sectp, sp) == CN_LANDLOCKED) &&
250             (dchr[sectp->sct_type].d_nav == NAV_CANAL)) {
251             wu(0, fltp->own,
252                "Your ship #%d (%s) is too big to fit through the canal.\n",
253                fe->num, cname(fe->own));
254             error = 1;
255         }
256     }
257     if (error)
258         return 0;
259     sp = getshipp(fltp->leader);
260     sectp = getsectp(fltp->x, fltp->y);
261     if (shp_check_nav(sectp, sp) != CN_NAVIGABLE)
262         wu(0, fltp->own, "Your fleet lead by %d is trapped by land.\n",
263            fltp->leader);
264     sp = getshipp(fltp->leader);
265     own = sp->shp_own;
266     fltp_to_list(fltp, &ship_list);     /* hack -KHS 1995 */
267     for (s = sp->shp_path; *s && fltp->maxmoves > 0; s++) {
268         dir = diridx(*s);
269         if (0 != shp_nav_one_sector(&ship_list, dir, own, 0))
270             fltp->maxmoves = 1;
271         --fltp->maxmoves;
272     }
273     shp_put(&ship_list, own);
274     getship(sp->shp_uid, &ship);
275     fltp->x = ship.shp_x;
276     fltp->y = ship.shp_y;
277     for (p = &ship.shp_path[0]; *s; p++, s++)
278         *p = *s;
279     *p = 0;
280     putship(ship.shp_uid, &ship);
281 #ifdef SAILDEBUG
282     if (sp->shp_path[0]) {
283         wu(0, fltp->own,
284            "Fleet lead by #%d nav'd to %s, path left = %s\n",
285            fltp->leader, xyas(fltp->x, fltp->y, fltp->own), &sp->shp_path);
286     } else
287         wu(0, fltp->own,
288            "Fleet lead by #%d nav'd to %s, finished.\n",
289            fltp->leader, xyas(fltp->x, fltp->y, fltp->own));
290     wu(0, sp->shp_own, "Ship #%d has %d mobility now.\n",
291        fe->num, (int)fe->mobil);
292 #endif
293     return 1;
294 }
295
296 void
297 sail_ship(natid cn)
298 {
299     struct shpstr *sp;
300     struct fltheadstr *head = 0;
301     struct fltheadstr *fltp;
302     int n;
303
304
305     for (n = 0; NULL != (sp = getshipp(n)); n++)
306         if (sp->shp_own == cn) {
307             sail_find_fleet(&head, sp);
308         }
309
310     /* see what the fleets fall out into */
311     for (fltp = head; fltp; fltp = fltp->next) {
312         if (sail_nav_fleet(fltp))
313             wu(0, fltp->own, "Your fleet lead by ship #%d has reached %s.\n",
314                fltp->leader, xyas(fltp->x, fltp->y, fltp->own));
315     }
316
317     /* Free up the memory, 'cause I want to. */
318     for (fltp = head; fltp != 0;) {
319         struct fltelemstr *fe;
320         struct fltheadstr *saveh;
321         saveh = fltp->next;
322         for (fe = fltp->head; fe != 0;) {
323             struct fltelemstr *saveel;
324             saveel = fe->next;
325             free(fe);
326             fe = saveel;
327         }
328         free(fltp);
329         fltp = saveh;
330     }
331 }
332
333 /* The following is a total hack by Ken Stevens to cut down dramatically on repeated code 1995 */
334
335 static void
336 fltp_to_list(struct fltheadstr *fltp, struct emp_qelem *list)
337 {
338     struct fltelemstr *fe;
339     struct mlist *mlp;
340     struct shpstr *sp;
341
342     emp_initque(list);
343     for (fe = fltp->head; fe; fe = fe->next) {
344         mlp = malloc(sizeof(struct mlist));
345         sp = getshipp(fe->num);
346         mlp->mcp = mchr + sp->shp_type;
347         mlp->ship = *sp;
348         mlp->mobil = fe->mobil;
349         emp_insque(&mlp->queue, list);
350     }
351 }