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