Merge from vendor branch OPENPAM:
[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  * @(#)dr_1.c   8.1 (Berkeley) 5/31/93
34  * $FreeBSD: src/games/sail/dr_1.c,v 1.7 1999/11/30 03:49:32 billf Exp $
35  * $DragonFly: src/games/sail/dr_1.c,v 1.2 2003/06/17 04:25:25 dillon Exp $
36  */
37
38 #include "driver.h"
39
40 unfoul()
41 {
42         struct ship *sp;
43         struct ship *to;
44         int nat;
45         int i;
46
47         foreachship(sp) {
48                 if (sp->file->captain[0])
49                         continue;
50                 nat = capship(sp)->nationality;
51                 foreachship(to) {
52                         if (nat != capship(to)->nationality &&
53                             !toughmelee(sp, to, 0, 0))
54                                 continue;
55                         for (i = fouled2(sp, to); --i >= 0;)
56                                 if (die() <= 2)
57                                         cleanfoul(sp, to, 0);
58                 }
59         }
60 }
61
62 boardcomp()
63 {
64         int crew[3];
65         struct ship *sp, *sq;
66
67         foreachship(sp) {
68                 if (*sp->file->captain)
69                         continue;
70                 if (sp->file->dir == 0)
71                         continue;
72                 if (sp->file->struck || sp->file->captured != 0)
73                         continue;
74                 if (!snagged(sp))
75                         continue;
76                 crew[0] = sp->specs->crew1 != 0;
77                 crew[1] = sp->specs->crew2 != 0;
78                 crew[2] = sp->specs->crew3 != 0;
79                 foreachship(sq) {
80                         if (!Xsnagged2(sp, sq))
81                                 continue;
82                         if (meleeing(sp, sq))
83                                 continue;
84                         if (!sq->file->dir
85                                 || sp->nationality == capship(sq)->nationality)
86                                 continue;
87                         switch (sp->specs->class - sq->specs->class) {
88                         case -3: case -4: case -5:
89                                 if (crew[0]) {
90                                         /* OBP */
91                                         sendbp(sp, sq, crew[0]*100, 0);
92                                         crew[0] = 0;
93                                 } else if (crew[1]){
94                                         /* OBP */
95                                         sendbp(sp, sq, crew[1]*10, 0);
96                                         crew[1] = 0;
97                                 }
98                                 break;
99                         case -2:
100                                 if (crew[0] || crew[1]) {
101                                         /* OBP */
102                                         sendbp(sp, sq, crew[0]*100+crew[1]*10,
103                                                 0);
104                                         crew[0] = crew[1] = 0;
105                                 }
106                                 break;
107                         case -1: case 0: case 1:
108                                 if (crew[0]) {
109                                         /* OBP */
110                                         sendbp(sp, sq, crew[0]*100+crew[1]*10,
111                                                 0);
112                                         crew[0] = crew[1] = 0;
113                                 }
114                                 break;
115                         case 2: case 3: case 4: case 5:
116                                 /* OBP */
117                                 sendbp(sp, sq, crew[0]*100+crew[1]*10+crew[2],
118                                         0);
119                                 crew[0] = crew[1] = crew[2] = 0;
120                                 break;
121                         }
122                 }
123         }
124 }
125
126 fightitout(from, to, key)
127 struct ship *from, *to;
128 int key;
129 {
130         struct ship *fromcap, *tocap;
131         int crewfrom[3], crewto[3], menfrom, mento;
132         int pcto, pcfrom, fromstrength, strengthto, frominjured, toinjured;
133         int topoints;
134         int index, totalfrom = 0, totalto = 0;
135         int count;
136         char message[60];
137
138         menfrom = mensent(from, to, crewfrom, &fromcap, &pcfrom, key);
139         mento = mensent(to, from, crewto, &tocap, &pcto, 0);
140         if (fromcap == 0)
141                 fromcap = from;
142         if (tocap == 0)
143                 tocap = to;
144         if (key) {
145                 if (!menfrom) {          /* if crew surprised */
146                         if (fromcap == from)
147                                 menfrom = from->specs->crew1
148                                         + from->specs->crew2
149                                         + from->specs->crew3;
150                         else
151                                 menfrom = from->file->pcrew;
152                 } else {
153                         menfrom *= 2;   /* DBP's fight at an advantage */
154                 }
155         }
156         fromstrength = menfrom * fromcap->specs->qual;
157         strengthto = mento * tocap->specs->qual;
158         for (count = 0;
159              (fromstrength < strengthto * 3 && strengthto < fromstrength * 3
160               || fromstrength == -1) && count < 4;
161              count++) {
162                 index = fromstrength/10;
163                 if (index > 8)
164                         index = 8;
165                 toinjured = MT[index][2 - die() / 3];
166                 totalto += toinjured;
167                 index = strengthto/10;
168                 if (index > 8)
169                         index = 8;
170                 frominjured = MT[index][2 - die() / 3];
171                 totalfrom += frominjured;
172                 menfrom -= frominjured;
173                 mento -= toinjured;
174                 fromstrength = menfrom * fromcap->specs->qual;
175                 strengthto = mento * tocap->specs->qual;
176         }
177         if (fromstrength >= strengthto * 3 || count == 4) {
178                 unboard(to, from, 0);
179                 subtract(from, totalfrom, crewfrom, fromcap, pcfrom);
180                 subtract(to, totalto, crewto, tocap, pcto);
181                 makesignal(from, "boarders from %s repelled", to);
182                 (void) sprintf(message, "killed in melee: %d.  %s: %d",
183                         totalto, from->shipname, totalfrom);
184                 Write(W_SIGNAL, to, 1, (long) message, 0, 0, 0);
185                 if (key)
186                         return 1;
187         } else if (strengthto >= fromstrength * 3) {
188                 unboard(from, to, 0);
189                 subtract(from, totalfrom, crewfrom, fromcap, pcfrom);
190                 subtract(to, totalto, crewto, tocap, pcto);
191                 if (key) {
192                         if (fromcap != from)
193                                 Write(W_POINTS, fromcap, 0,
194                                         fromcap->file->points -
195                                                 from->file->struck
196                                                 ? from->specs->pts
197                                                 : 2 * from->specs->pts,
198                                         0, 0, 0);
199
200 /* ptr1 points to the shipspec for the ship that was just unboarded.
201    I guess that what is going on here is that the pointer is multiplied
202    or something. */
203
204                         Write(W_CAPTURED, from, 0, to->file->index, 0, 0, 0);
205                         topoints = 2 * from->specs->pts + to->file->points;
206                         if (from->file->struck)
207                                 topoints -= from->specs->pts;
208                         Write(W_POINTS, to, 0, topoints, 0, 0, 0);
209                         mento = crewto[0] ? crewto[0] : crewto[1];
210                         if (mento) {
211                                 subtract(to, mento, crewto, tocap, pcto);
212                                 subtract(from, - mento, crewfrom, to, 0);
213                         }
214                         (void) sprintf(message, "captured by the %s!",
215                                 to->shipname);
216                         Write(W_SIGNAL, from, 1, (long) message, 0, 0, 0);
217                         (void) sprintf(message, "killed in melee: %d.  %s: %d",
218                                 totalto, from->shipname, totalfrom);
219                         Write(W_SIGNAL, to, 1, (long) message, 0, 0, 0);
220                         mento = 0;
221                         return 0;
222                 }
223         }
224         return 0;
225 }
226
227 resolve()
228 {
229         int thwart;
230         struct ship *sp, *sq;
231
232         foreachship(sp) {
233                 if (sp->file->dir == 0)
234                         continue;
235                 for (sq = sp + 1; sq < ls; sq++)
236                         if (sq->file->dir && meleeing(sp, sq) && meleeing(sq, sp))
237                                 (void) fightitout(sp, sq, 0);
238                 thwart = 2;
239                 foreachship(sq) {
240                         if (sq->file->dir && meleeing(sq, sp))
241                                 thwart = fightitout(sp, sq, 1);
242                         if (!thwart)
243                                 break;
244                 }
245                 if (!thwart) {
246                         foreachship(sq) {
247                                 if (sq->file->dir && meleeing(sq, sp))
248                                         unboard(sq, sp, 0);
249                                 unboard(sp, sq, 0);
250                         }
251                         unboard(sp, sp, 1);
252                 } else if (thwart == 2)
253                         unboard(sp, sp, 1);
254         }
255 }
256
257 compcombat()
258 {
259         int n;
260         struct ship *sp;
261         struct ship *closest;
262         int crew[3], men = 0, target, temp;
263         int r, guns, ready, load, car;
264         int index, rakehim, sternrake;
265         int shootat, hit;
266
267         foreachship(sp) {
268                 if (sp->file->captain[0] || sp->file->dir == 0)
269                         continue;
270                 crew[0] = sp->specs->crew1;
271                 crew[1] = sp->specs->crew2;
272                 crew[2] = sp->specs->crew3;
273                 for (n = 0; n < 3; n++) {
274                         if (sp->file->OBP[n].turnsent)
275                                 men += sp->file->OBP[n].mensent;
276                 }
277                 for (n = 0; n < 3; n++) {
278                         if (sp->file->DBP[n].turnsent)
279                                 men += sp->file->DBP[n].mensent;
280                 }
281                 if (men){
282                         crew[0] = men/100 ? 0 : crew[0] != 0;
283                         crew[1] = (men%100)/10 ? 0 : crew[1] != 0;
284                         crew[2] = men%10 ? 0 : crew[2] != 0;
285                 }
286                 for (r = 0; r < 2; r++) {
287                         if (!crew[2])
288                                 continue;
289                         if (sp->file->struck)
290                                 continue;
291                         if (r) {
292                                 ready = sp->file->readyR;
293                                 guns = sp->specs->gunR;
294                                 car = sp->specs->carR;
295                         } else {
296                                 ready = sp->file->readyL;
297                                 guns = sp->specs->gunL;
298                                 car = sp->specs->carL;
299                         }
300                         if (!guns && !car)
301                                 continue;
302                         if ((ready & R_LOADED) == 0)
303                                 continue;
304                         closest = closestenemy(sp, r ? 'r' : 'l', 0);
305                         if (closest == 0)
306                                 continue;
307                         if (range(closest, sp) > range(sp, closestenemy(sp, r ? 'r' : 'l', 1)))
308                                 continue;
309                         if (closest->file->struck)
310                                 continue;
311                         target = range(sp, closest);
312                         if (target > 10)
313                                 continue;
314                         if (!guns && target >= 3)
315                                 continue;
316                         load = L_ROUND;
317                         if (target == 1 && sp->file->loadwith == L_GRAPE)
318                                 load = L_GRAPE;
319                         if (target <= 3 && closest->file->FS)
320                                 load = L_CHAIN;
321                         if (target == 1 && load != L_GRAPE)
322                                 load = L_DOUBLE;
323                         if (load > L_CHAIN && target < 6)
324                                 shootat = HULL;
325                         else
326                                 shootat = RIGGING;
327                         rakehim = gunsbear(sp, closest)
328                                 && !gunsbear(closest, sp);
329                         temp = portside(closest, sp, 1)
330                                 - closest->file->dir + 1;
331                         if (temp < 1)
332                                 temp += 8;
333                         if (temp > 8)
334                                 temp -= 8;
335                         sternrake = temp > 4 && temp < 6;
336                         index = guns;
337                         if (target < 3)
338                                 index += car;
339                         index = (index - 1) / 3;
340                         index = index > 8 ? 8 : index;
341                         if (!rakehim)
342                                 hit = HDT[index][target-1];
343                         else
344                                 hit = HDTrake[index][target-1];
345                         if (rakehim && sternrake)
346                                 hit++;
347                         hit += QUAL[index][capship(sp)->specs->qual - 1];
348                         for (n = 0; n < 3 && sp->file->captured == 0; n++)
349                                 if (!crew[n]) {
350                                         if (index <= 5)
351                                                 hit--;
352                                         else
353                                                 hit -= 2;
354                                 }
355                         if (ready & R_INITIAL) {
356                                 if (!r)
357                                         sp->file->readyL &= ~R_INITIAL;
358                                 else
359                                         sp->file->readyR &= ~R_INITIAL;
360                                 if (index <= 3)
361                                         hit++;
362                                 else
363                                         hit += 2;
364                         }
365                         if (sp->file->captured != 0) {
366                                 if (index <= 1)
367                                         hit--;
368                                 else
369                                         hit -= 2;
370                         }
371                         hit += AMMO[index][load - 1];
372                         temp = sp->specs->class;
373                         if ((temp >= 5 || temp == 1) && windspeed == 5)
374                                 hit--;
375                         if (windspeed == 6 && temp == 4)
376                                 hit -= 2;
377                         if (windspeed == 6 && temp <= 3)
378                                 hit--;
379                         if (hit >= 0) {
380                                 if (load != L_GRAPE)
381                                         hit = hit > 10 ? 10 : hit;
382                                 table(shootat, load, hit, closest, sp, die());
383                         }
384                 }
385         }
386 }
387
388 next()
389 {
390         if (++turn % 55 == 0) {
391                 if (alive)
392                         alive = 0;
393                 else
394                         people = 0;
395         }
396         if (people <= 0 || windspeed == 7) {
397                 struct ship *s;
398                 struct ship *bestship;
399                 float net, best = 0.0;
400                 foreachship(s) {
401                         if (*s->file->captain)
402                                 continue;
403                         net = (float)s->file->points / s->specs->pts;
404                         if (net > best) {
405                                 best = net;
406                                 bestship = s;
407                         }
408                 }
409                 if (best > 0.0) {
410                         char *p = getenv("WOTD");
411                         if (p == 0)
412                                 p = "Driver";
413                         if (islower(*p))
414                                 *p = toupper(*p);
415                         (void) strncpy(bestship->file->captain, p,
416                                 sizeof bestship->file->captain);
417                         bestship->file->captain
418                                 [sizeof bestship->file->captain - 1] = 0;
419                         log(bestship);
420                 }
421                 return -1;
422         }
423         Write(W_TURN, SHIP(0), 0, turn, 0, 0, 0);
424         if (turn % 7 == 0 && (die() >= cc->windchange || !windspeed)) {
425                 switch (die()) {
426                 case 1:
427                         winddir = 1;
428                         break;
429                 case 2:
430                         break;
431                 case 3:
432                         winddir++;
433                         break;
434                 case 4:
435                         winddir--;
436                         break;
437                 case 5:
438                         winddir += 2;
439                         break;
440                 case 6:
441                         winddir -= 2;
442                         break;
443                 }
444                 if (winddir > 8)
445                         winddir -= 8;
446                 if (winddir < 1)
447                         winddir += 8;
448                 if (windspeed)
449                         switch (die()) {
450                         case 1:
451                         case 2:
452                                 windspeed--;
453                                 break;
454                         case 5:
455                         case 6:
456                                 windspeed++;
457                                 break;
458                         }
459                 else
460                         windspeed++;
461                 Write(W_WIND, SHIP(0), 0, winddir, windspeed, 0, 0);
462         }
463         return 0;
464 }