Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / sail / dr_1.c
1 /*
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)dr_1.c      8.1 (Berkeley) 5/31/93";
37 #endif
38 static const char rcsid[] =
39  "$FreeBSD: src/games/sail/dr_1.c,v 1.7 1999/11/30 03:49:32 billf Exp $";
40 #endif /* not lint */
41
42 #include "driver.h"
43
44 unfoul()
45 {
46         struct ship *sp;
47         struct ship *to;
48         int nat;
49         int i;
50
51         foreachship(sp) {
52                 if (sp->file->captain[0])
53                         continue;
54                 nat = capship(sp)->nationality;
55                 foreachship(to) {
56                         if (nat != capship(to)->nationality &&
57                             !toughmelee(sp, to, 0, 0))
58                                 continue;
59                         for (i = fouled2(sp, to); --i >= 0;)
60                                 if (die() <= 2)
61                                         cleanfoul(sp, to, 0);
62                 }
63         }
64 }
65
66 boardcomp()
67 {
68         int crew[3];
69         struct ship *sp, *sq;
70
71         foreachship(sp) {
72                 if (*sp->file->captain)
73                         continue;
74                 if (sp->file->dir == 0)
75                         continue;
76                 if (sp->file->struck || sp->file->captured != 0)
77                         continue;
78                 if (!snagged(sp))
79                         continue;
80                 crew[0] = sp->specs->crew1 != 0;
81                 crew[1] = sp->specs->crew2 != 0;
82                 crew[2] = sp->specs->crew3 != 0;
83                 foreachship(sq) {
84                         if (!Xsnagged2(sp, sq))
85                                 continue;
86                         if (meleeing(sp, sq))
87                                 continue;
88                         if (!sq->file->dir
89                                 || sp->nationality == capship(sq)->nationality)
90                                 continue;
91                         switch (sp->specs->class - sq->specs->class) {
92                         case -3: case -4: case -5:
93                                 if (crew[0]) {
94                                         /* OBP */
95                                         sendbp(sp, sq, crew[0]*100, 0);
96                                         crew[0] = 0;
97                                 } else if (crew[1]){
98                                         /* OBP */
99                                         sendbp(sp, sq, crew[1]*10, 0);
100                                         crew[1] = 0;
101                                 }
102                                 break;
103                         case -2:
104                                 if (crew[0] || crew[1]) {
105                                         /* OBP */
106                                         sendbp(sp, sq, crew[0]*100+crew[1]*10,
107                                                 0);
108                                         crew[0] = crew[1] = 0;
109                                 }
110                                 break;
111                         case -1: case 0: case 1:
112                                 if (crew[0]) {
113                                         /* OBP */
114                                         sendbp(sp, sq, crew[0]*100+crew[1]*10,
115                                                 0);
116                                         crew[0] = crew[1] = 0;
117                                 }
118                                 break;
119                         case 2: case 3: case 4: case 5:
120                                 /* OBP */
121                                 sendbp(sp, sq, crew[0]*100+crew[1]*10+crew[2],
122                                         0);
123                                 crew[0] = crew[1] = crew[2] = 0;
124                                 break;
125                         }
126                 }
127         }
128 }
129
130 fightitout(from, to, key)
131 struct ship *from, *to;
132 int key;
133 {
134         struct ship *fromcap, *tocap;
135         int crewfrom[3], crewto[3], menfrom, mento;
136         int pcto, pcfrom, fromstrength, strengthto, frominjured, toinjured;
137         int topoints;
138         int index, totalfrom = 0, totalto = 0;
139         int count;
140         char message[60];
141
142         menfrom = mensent(from, to, crewfrom, &fromcap, &pcfrom, key);
143         mento = mensent(to, from, crewto, &tocap, &pcto, 0);
144         if (fromcap == 0)
145                 fromcap = from;
146         if (tocap == 0)
147                 tocap = to;
148         if (key) {
149                 if (!menfrom) {          /* if crew surprised */
150                         if (fromcap == from)
151                                 menfrom = from->specs->crew1
152                                         + from->specs->crew2
153                                         + from->specs->crew3;
154                         else
155                                 menfrom = from->file->pcrew;
156                 } else {
157                         menfrom *= 2;   /* DBP's fight at an advantage */
158                 }
159         }
160         fromstrength = menfrom * fromcap->specs->qual;
161         strengthto = mento * tocap->specs->qual;
162         for (count = 0;
163              (fromstrength < strengthto * 3 && strengthto < fromstrength * 3
164               || fromstrength == -1) && count < 4;
165              count++) {
166                 index = fromstrength/10;
167                 if (index > 8)
168                         index = 8;
169                 toinjured = MT[index][2 - die() / 3];
170                 totalto += toinjured;
171                 index = strengthto/10;
172                 if (index > 8)
173                         index = 8;
174                 frominjured = MT[index][2 - die() / 3];
175                 totalfrom += frominjured;
176                 menfrom -= frominjured;
177                 mento -= toinjured;
178                 fromstrength = menfrom * fromcap->specs->qual;
179                 strengthto = mento * tocap->specs->qual;
180         }
181         if (fromstrength >= strengthto * 3 || count == 4) {
182                 unboard(to, from, 0);
183                 subtract(from, totalfrom, crewfrom, fromcap, pcfrom);
184                 subtract(to, totalto, crewto, tocap, pcto);
185                 makesignal(from, "boarders from %s repelled", to);
186                 (void) sprintf(message, "killed in melee: %d.  %s: %d",
187                         totalto, from->shipname, totalfrom);
188                 Write(W_SIGNAL, to, 1, (long) message, 0, 0, 0);
189                 if (key)
190                         return 1;
191         } else if (strengthto >= fromstrength * 3) {
192                 unboard(from, to, 0);
193                 subtract(from, totalfrom, crewfrom, fromcap, pcfrom);
194                 subtract(to, totalto, crewto, tocap, pcto);
195                 if (key) {
196                         if (fromcap != from)
197                                 Write(W_POINTS, fromcap, 0,
198                                         fromcap->file->points -
199                                                 from->file->struck
200                                                 ? from->specs->pts
201                                                 : 2 * from->specs->pts,
202                                         0, 0, 0);
203
204 /* ptr1 points to the shipspec for the ship that was just unboarded.
205    I guess that what is going on here is that the pointer is multiplied
206    or something. */
207
208                         Write(W_CAPTURED, from, 0, to->file->index, 0, 0, 0);
209                         topoints = 2 * from->specs->pts + to->file->points;
210                         if (from->file->struck)
211                                 topoints -= from->specs->pts;
212                         Write(W_POINTS, to, 0, topoints, 0, 0, 0);
213                         mento = crewto[0] ? crewto[0] : crewto[1];
214                         if (mento) {
215                                 subtract(to, mento, crewto, tocap, pcto);
216                                 subtract(from, - mento, crewfrom, to, 0);
217                         }
218                         (void) sprintf(message, "captured by the %s!",
219                                 to->shipname);
220                         Write(W_SIGNAL, from, 1, (long) message, 0, 0, 0);
221                         (void) sprintf(message, "killed in melee: %d.  %s: %d",
222                                 totalto, from->shipname, totalfrom);
223                         Write(W_SIGNAL, to, 1, (long) message, 0, 0, 0);
224                         mento = 0;
225                         return 0;
226                 }
227         }
228         return 0;
229 }
230
231 resolve()
232 {
233         int thwart;
234         struct ship *sp, *sq;
235
236         foreachship(sp) {
237                 if (sp->file->dir == 0)
238                         continue;
239                 for (sq = sp + 1; sq < ls; sq++)
240                         if (sq->file->dir && meleeing(sp, sq) && meleeing(sq, sp))
241                                 (void) fightitout(sp, sq, 0);
242                 thwart = 2;
243                 foreachship(sq) {
244                         if (sq->file->dir && meleeing(sq, sp))
245                                 thwart = fightitout(sp, sq, 1);
246                         if (!thwart)
247                                 break;
248                 }
249                 if (!thwart) {
250                         foreachship(sq) {
251                                 if (sq->file->dir && meleeing(sq, sp))
252                                         unboard(sq, sp, 0);
253                                 unboard(sp, sq, 0);
254                         }
255                         unboard(sp, sp, 1);
256                 } else if (thwart == 2)
257                         unboard(sp, sp, 1);
258         }
259 }
260
261 compcombat()
262 {
263         int n;
264         struct ship *sp;
265         struct ship *closest;
266         int crew[3], men = 0, target, temp;
267         int r, guns, ready, load, car;
268         int index, rakehim, sternrake;
269         int shootat, hit;
270
271         foreachship(sp) {
272                 if (sp->file->captain[0] || sp->file->dir == 0)
273                         continue;
274                 crew[0] = sp->specs->crew1;
275                 crew[1] = sp->specs->crew2;
276                 crew[2] = sp->specs->crew3;
277                 for (n = 0; n < 3; n++) {
278                         if (sp->file->OBP[n].turnsent)
279                                 men += sp->file->OBP[n].mensent;
280                 }
281                 for (n = 0; n < 3; n++) {
282                         if (sp->file->DBP[n].turnsent)
283                                 men += sp->file->DBP[n].mensent;
284                 }
285                 if (men){
286                         crew[0] = men/100 ? 0 : crew[0] != 0;
287                         crew[1] = (men%100)/10 ? 0 : crew[1] != 0;
288                         crew[2] = men%10 ? 0 : crew[2] != 0;
289                 }
290                 for (r = 0; r < 2; r++) {
291                         if (!crew[2])
292                                 continue;
293                         if (sp->file->struck)
294                                 continue;
295                         if (r) {
296                                 ready = sp->file->readyR;
297                                 guns = sp->specs->gunR;
298                                 car = sp->specs->carR;
299                         } else {
300                                 ready = sp->file->readyL;
301                                 guns = sp->specs->gunL;
302                                 car = sp->specs->carL;
303                         }
304                         if (!guns && !car)
305                                 continue;
306                         if ((ready & R_LOADED) == 0)
307                                 continue;
308                         closest = closestenemy(sp, r ? 'r' : 'l', 0);
309                         if (closest == 0)
310                                 continue;
311                         if (range(closest, sp) > range(sp, closestenemy(sp, r ? 'r' : 'l', 1)))
312                                 continue;
313                         if (closest->file->struck)
314                                 continue;
315                         target = range(sp, closest);
316                         if (target > 10)
317                                 continue;
318                         if (!guns && target >= 3)
319                                 continue;
320                         load = L_ROUND;
321                         if (target == 1 && sp->file->loadwith == L_GRAPE)
322                                 load = L_GRAPE;
323                         if (target <= 3 && closest->file->FS)
324                                 load = L_CHAIN;
325                         if (target == 1 && load != L_GRAPE)
326                                 load = L_DOUBLE;
327                         if (load > L_CHAIN && target < 6)
328                                 shootat = HULL;
329                         else
330                                 shootat = RIGGING;
331                         rakehim = gunsbear(sp, closest)
332                                 && !gunsbear(closest, sp);
333                         temp = portside(closest, sp, 1)
334                                 - closest->file->dir + 1;
335                         if (temp < 1)
336                                 temp += 8;
337                         if (temp > 8)
338                                 temp -= 8;
339                         sternrake = temp > 4 && temp < 6;
340                         index = guns;
341                         if (target < 3)
342                                 index += car;
343                         index = (index - 1) / 3;
344                         index = index > 8 ? 8 : index;
345                         if (!rakehim)
346                                 hit = HDT[index][target-1];
347                         else
348                                 hit = HDTrake[index][target-1];
349                         if (rakehim && sternrake)
350                                 hit++;
351                         hit += QUAL[index][capship(sp)->specs->qual - 1];
352                         for (n = 0; n < 3 && sp->file->captured == 0; n++)
353                                 if (!crew[n]) {
354                                         if (index <= 5)
355                                                 hit--;
356                                         else
357                                                 hit -= 2;
358                                 }
359                         if (ready & R_INITIAL) {
360                                 if (!r)
361                                         sp->file->readyL &= ~R_INITIAL;
362                                 else
363                                         sp->file->readyR &= ~R_INITIAL;
364                                 if (index <= 3)
365                                         hit++;
366                                 else
367                                         hit += 2;
368                         }
369                         if (sp->file->captured != 0) {
370                                 if (index <= 1)
371                                         hit--;
372                                 else
373                                         hit -= 2;
374                         }
375                         hit += AMMO[index][load - 1];
376                         temp = sp->specs->class;
377                         if ((temp >= 5 || temp == 1) && windspeed == 5)
378                                 hit--;
379                         if (windspeed == 6 && temp == 4)
380                                 hit -= 2;
381                         if (windspeed == 6 && temp <= 3)
382                                 hit--;
383                         if (hit >= 0) {
384                                 if (load != L_GRAPE)
385                                         hit = hit > 10 ? 10 : hit;
386                                 table(shootat, load, hit, closest, sp, die());
387                         }
388                 }
389         }
390 }
391
392 next()
393 {
394         if (++turn % 55 == 0) {
395                 if (alive)
396                         alive = 0;
397                 else
398                         people = 0;
399         }
400         if (people <= 0 || windspeed == 7) {
401                 struct ship *s;
402                 struct ship *bestship;
403                 float net, best = 0.0;
404                 foreachship(s) {
405                         if (*s->file->captain)
406                                 continue;
407                         net = (float)s->file->points / s->specs->pts;
408                         if (net > best) {
409                                 best = net;
410                                 bestship = s;
411                         }
412                 }
413                 if (best > 0.0) {
414                         char *p = getenv("WOTD");
415                         if (p == 0)
416                                 p = "Driver";
417                         if (islower(*p))
418                                 *p = toupper(*p);
419                         (void) strncpy(bestship->file->captain, p,
420                                 sizeof bestship->file->captain);
421                         bestship->file->captain
422                                 [sizeof bestship->file->captain - 1] = 0;
423                         log(bestship);
424                 }
425                 return -1;
426         }
427         Write(W_TURN, SHIP(0), 0, turn, 0, 0, 0);
428         if (turn % 7 == 0 && (die() >= cc->windchange || !windspeed)) {
429                 switch (die()) {
430                 case 1:
431                         winddir = 1;
432                         break;
433                 case 2:
434                         break;
435                 case 3:
436                         winddir++;
437                         break;
438                 case 4:
439                         winddir--;
440                         break;
441                 case 5:
442                         winddir += 2;
443                         break;
444                 case 6:
445                         winddir -= 2;
446                         break;
447                 }
448                 if (winddir > 8)
449                         winddir -= 8;
450                 if (winddir < 1)
451                         winddir += 8;
452                 if (windspeed)
453                         switch (die()) {
454                         case 1:
455                         case 2:
456                                 windspeed--;
457                                 break;
458                         case 5:
459                         case 6:
460                                 windspeed++;
461                                 break;
462                         }
463                 else
464                         windspeed++;
465                 Write(W_WIND, SHIP(0), 0, winddir, windspeed, 0, 0);
466         }
467         return 0;
468 }