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