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