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