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