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