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