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