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