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