]> git.pond.sub.org Git - empserver/blob - src/lib/update/sail.c
Import of Empire 4.2.12
[empserver] / src / lib / update / sail.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 "var.h"
39 #include "sect.h"
40 #include "path.h"
41 #include "ship.h"
42 #include "var.h"
43 #include "news.h"
44 #include "file.h"
45 #include "nat.h"
46 #include "xy.h"
47 #include "nsc.h"
48 #include "update.h"
49 #include "subs.h"
50 #include "common.h"
51 #include <stdlib.h>
52
53 static void
54 cost_ship(struct shpstr *sp, struct fltelemstr *ep, struct fltheadstr *fp)
55 {
56         double  mobcost,ceil(double);
57         int     howfar;
58
59         mobcost = 0.0;
60         if (sp->shp_effic > 0) {
61                 mobcost = sp->shp_effic * sp->shp_speed * 0.01;
62                 mobcost = 480.0 / ( mobcost*(1 + (50+sp->shp_tech)/
63                                         (double)(200+sp->shp_tech)));
64         }
65 /* the next two lines are not necessary since shp_mobquota is unsigned
66 and therefore cannot be less than 0. 
67         if (sp->shp_mobquota<0)
68                 sp->shp_mobquota=0;
69 */
70
71         howfar = 0;
72         if (mobcost > 0) {
73                 howfar = (int)sp->shp_mobil - (int)sp->shp_mobquota;
74                 howfar = ceil((howfar / mobcost));
75         }
76         if (howfar<0)
77                 howfar=0;
78 #ifdef SAILDEBUG
79         wu(0,fp->own,
80                 "Ship #%d can move %d spaces on mobility %d (cost/sect %f)\n",
81                 sp->shp_uid, howfar, sp->shp_mobil, mobcost);
82 #endif
83         if ((unsigned int)howfar < fp->maxmoves)
84                 fp->maxmoves = howfar;
85
86         ep->mobil = sp->shp_mobil;
87         ep->mobcost = mobcost;
88 }
89
90 static int
91 sail_find_fleet(struct fltheadstr **head, struct shpstr *sp)
92 {
93         struct fltheadstr *fltp;
94         struct shpstr   *ap;
95         struct fltelemstr *this;
96         int  len=0;
97         int  follow = -1;
98         int  stop;
99         s_char *cp;
100
101         if (sp->shp_own==0)
102                 return(0);
103
104
105
106         /* If this ship is following, find the head of the follow list. */
107         for (ap=sp; ap; len++, ap=getshipp(follow)) {
108                 follow = ap->shp_follow;
109                 /* Not same owner */
110                 if (ap->shp_own != sp->shp_own) {
111                         wu(0, sp->shp_own, 
112                                 "Ship #%d, following #%d, which you don't own.\n",
113                                 sp->shp_uid, ap->shp_uid);
114                         return(0);
115                 }
116                 /* Not a follower. */
117                 if (ap->shp_path[0] != 'f')
118                         break;
119                 /* Following itself */
120                 if (follow==ap->shp_uid ||
121                     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); fltp = fltp->next)
168                 ;
169
170         if (!fltp) {
171                 fltp = (struct fltheadstr *) malloc(sizeof(*fltp));
172                 bzero((s_char *)fltp, 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         bzero((s_char *)this, 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         int     vec[I_MAX+1];
213         struct sctstr *sectp;
214         int     error=0;
215         s_char  *s, *p;
216         natid   own;
217         struct  emp_qelem ship_list;
218         int     dir;
219
220 #ifdef SAILDEBUG
221         switch (fltp->real_q) {
222         case LEADER_VIRTUAL:
223                 s = "leaderless";
224                 break;
225         case LEADER_REAL:
226                 s = "real";
227                 break;
228         case LEADER_WRONGSECT:
229                 s = "scattered";
230                 break;
231         default:
232                 s = "inconsistent";
233         }
234         wu(0,fltp->own,
235                 "Fleet lead by %d is %s, can go %d spaces\n  contains ships:",
236                 fltp->leader, s, fltp->maxmoves);
237         for (fe=fltp->head; fe; fe = fe->next)
238                 wu(0, fltp->own, " %d", fe->num);
239         wu(0, fltp->own, "\n");
240 #endif
241         sectp = getsectp(fltp->x, fltp->y);
242         switch (check_nav(sectp)) {
243         case CN_NAVIGABLE:
244                 break;
245         case CN_CONSTRUCTION:
246         case CN_LANDLOCKED:
247         default:
248                 wu(0,fltp->own, "Your fleet lead by %d is trapped by land.\n",
249                         fltp->leader);
250                 return(0);
251         }
252         for (fe=fltp->head; fe; fe = fe->next) {
253                 sp = getshipp(fe->num);
254                 getvec(VT_ITEM, vec, (s_char *)sp, EF_SHIP);
255                 if (vec[I_MILIT]==0 && vec[I_CIVIL]==0) {
256                         wu(0,fltp->own,
257                         "   ship #%d (%s) is crewless and can't go on\n",
258                                 fe->num, cname(fe->own));
259                         error = 1;
260                 }
261         }
262         if (error)
263                 return(0);
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 = chkdir(*s, DIR_STOP, DIR_LAST);
269                 if (0 != (error = 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),
286                         &sp->shp_path);
287         } else
288                 wu(0,fltp->own,
289                         "Fleet lead by #%d nav'd to %s, finished.\n",
290                         fltp->leader, xyas(fltp->x,fltp->y,fltp->own));
291                 wu(0,sp->shp_own, "Ship #%d has %d mobility now.\n",
292                         fe->num, (int)fe->mobil);
293 #endif
294         return 1;
295 }
296
297 void
298 sail_ship(natid cn)
299 {  
300         struct shpstr   *sp;
301         struct fltheadstr *head=0;
302         struct fltheadstr *fltp;
303         int     n;
304
305
306         for (n=0; NULL != (sp = getshipp(n)); n++) 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                 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 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 = (struct mlist *) malloc(sizeof(struct mlist));
345                 sp = getshipp(fe->num);
346                 mlp->mcp = mchr + sp->shp_type;
347                 bcopy((s_char *)sp, (s_char *)&mlp->ship,
348                         sizeof(struct shpstr));
349                 mlp->mobil = fe->mobil;
350                 emp_insque(&mlp->queue, list);
351         }
352 }