1286438Sbapt/*	$NetBSD: dr_3.c,v 1.18 2009/03/14 20:04:43 dholland Exp $	*/
2286438Sbapt
3286438Sbapt/*
4286438Sbapt * Copyright (c) 1983, 1993
5286438Sbapt *	The Regents of the University of California.  All rights reserved.
6286438Sbapt *
7286438Sbapt * Redistribution and use in source and binary forms, with or without
8286438Sbapt * modification, are permitted provided that the following conditions
9286438Sbapt * are met:
10286438Sbapt * 1. Redistributions of source code must retain the above copyright
11286438Sbapt *    notice, this list of conditions and the following disclaimer.
12286438Sbapt * 2. Redistributions in binary form must reproduce the above copyright
13286438Sbapt *    notice, this list of conditions and the following disclaimer in the
14286438Sbapt *    documentation and/or other materials provided with the distribution.
15286438Sbapt * 3. Neither the name of the University nor the names of its contributors
16286438Sbapt *    may be used to endorse or promote products derived from this software
17286438Sbapt *    without specific prior written permission.
18286438Sbapt *
19286438Sbapt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20286438Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21286438Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22286438Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23286438Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24286438Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25286438Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26286438Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27286438Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28286438Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29286438Sbapt * SUCH DAMAGE.
30286438Sbapt */
31286438Sbapt
32286438Sbapt#include <sys/cdefs.h>
33286438Sbapt#ifndef lint
34286438Sbapt#if 0
35286438Sbaptstatic char sccsid[] = "@(#)dr_3.c	8.1 (Berkeley) 5/31/93";
36286438Sbapt#else
37286438Sbapt__RCSID("$NetBSD: dr_3.c,v 1.18 2009/03/14 20:04:43 dholland Exp $");
38286438Sbapt#endif
39286438Sbapt#endif /* not lint */
40286438Sbapt
41286438Sbapt#include <stdlib.h>
42286438Sbapt#include <string.h>
43286438Sbapt#include "extern.h"
44286438Sbapt#include "driver.h"
45286438Sbapt
46286438Sbaptstatic int stillmoving(int);
47286438Sbaptstatic int is_isolated(struct ship *);
48286438Sbaptstatic int push(struct ship *, struct ship *);
49286438Sbaptstatic void step(struct ship *, int, char *);
50325928Sbapt
51325928Sbapt/* move all comp ships */
52325928Sbaptvoid
53286438Sbaptmoveall(void)
54286438Sbapt{
55312336Sbapt	struct ship *sp, *sq;
56312336Sbapt	int n;
57312336Sbapt	int k, l;
58312336Sbapt	int row[NSHIP], col[NSHIP], dir[NSHIP], drift[NSHIP];
59312336Sbapt	char moved[NSHIP];
60312336Sbapt
61312336Sbapt	/*
62312336Sbapt	 * first try to create moves for OUR ships
63312336Sbapt	 */
64312336Sbapt	foreachship(sp) {
65312336Sbapt		struct ship *closest;
66312336Sbapt		int ma, ta;
67312336Sbapt		bool af;
68312336Sbapt
69312336Sbapt		if (sp->file->captain[0] || sp->file->dir == 0)
70286438Sbapt			continue;
71286438Sbapt		if (!sp->file->struck && windspeed && !snagged(sp)
72286438Sbapt		    && sp->specs->crew3) {
73286438Sbapt			ta = maxturns(sp, &af);
74286438Sbapt			ma = maxmove(sp, sp->file->dir, 0);
75286438Sbapt			closest = closestenemy(sp, 0, 0);
76312336Sbapt			if (closest == 0)
77312336Sbapt				*sp->file->movebuf = '\0';
78312336Sbapt			else
79312336Sbapt				closeon(sp, closest, sp->file->movebuf,
80312336Sbapt					sizeof(sp->file->movebuf),
81312336Sbapt					ta, ma, af);
82312336Sbapt		} else
83325928Sbapt			*sp->file->movebuf = '\0';
84286438Sbapt	}
85286438Sbapt	/*
86286438Sbapt	 * Then execute the moves for ALL ships (dead ones too),
87286438Sbapt	 * checking for collisions and snags at each step.
88286438Sbapt	 * The old positions are saved in row[], col[], dir[].
89286438Sbapt	 * At the end, we compare and write out the changes.
90286438Sbapt	 */
91286438Sbapt	n = 0;
92286438Sbapt	foreachship(sp) {
93286438Sbapt		if (snagged(sp))
94286438Sbapt			strcpy(sp->file->movebuf, "d");
95286438Sbapt		else
96286438Sbapt			if (*sp->file->movebuf != 'd')
97286438Sbapt				strcat(sp->file->movebuf, "d");
98286438Sbapt		row[n] = sp->file->row;
99286438Sbapt		col[n] = sp->file->col;
100286438Sbapt		dir[n] = sp->file->dir;
101286438Sbapt		drift[n] = sp->file->drift;
102286438Sbapt		moved[n] = 0;
103286438Sbapt		n++;
104286438Sbapt	}
105286438Sbapt	/*
106286438Sbapt	 * Now resolve collisions.
107286438Sbapt	 * This is the tough part.
108286438Sbapt	 */
109286438Sbapt	for (k = 0; stillmoving(k); k++) {
110286438Sbapt		/*
111286438Sbapt		 * Step once.
112286438Sbapt		 * And propagate the nulls at the end of sp->file->movebuf.
113286438Sbapt		 */
114286438Sbapt		n = 0;
115286438Sbapt		foreachship(sp) {
116286438Sbapt			if (!sp->file->movebuf[k])
117286438Sbapt				sp->file->movebuf[k+1] = '\0';
118286438Sbapt			else if (sp->file->dir)
119286438Sbapt				step(sp, sp->file->movebuf[k], &moved[n]);
120286438Sbapt			n++;
121286438Sbapt		}
122286438Sbapt		/*
123286438Sbapt		 * The real stuff.
124286438Sbapt		 */
125286438Sbapt		n = 0;
126286438Sbapt		foreachship(sp) {
127286438Sbapt			if (sp->file->dir == 0 || is_isolated(sp))
128286438Sbapt				goto cont1;
129286438Sbapt			l = 0;
130286438Sbapt			foreachship(sq) {
131286438Sbapt				char snap = 0;
132286438Sbapt
133286438Sbapt				if (sp == sq)
134286438Sbapt					goto cont2;
135286438Sbapt				if (sq->file->dir == 0)
136286438Sbapt					goto cont2;
137286438Sbapt				if (!push(sp, sq))
138286438Sbapt					goto cont2;
139286438Sbapt				if (snagged2(sp, sq) && range(sp, sq) > 1)
140286438Sbapt					snap++;
141286438Sbapt				if (!range(sp, sq) && !fouled2(sp, sq)) {
142286438Sbapt					makesignal(sp, "collision with $$", sq);
143286438Sbapt					if (dieroll() < 4) {
144286438Sbapt						makesignal(sp, "fouled with $$",
145286438Sbapt						    sq);
146286438Sbapt						send_foul(sp, l);
147286438Sbapt						send_foul(sq, n);
148286438Sbapt					}
149286438Sbapt					snap++;
150286438Sbapt				}
151286438Sbapt				if (snap) {
152286438Sbapt					sp->file->movebuf[k + 1] = 0;
153286438Sbapt					sq->file->movebuf[k + 1] = 0;
154286438Sbapt					sq->file->row = sp->file->row - 1;
155286438Sbapt					if (sp->file->dir == 1
156286438Sbapt					    || sp->file->dir == 5)
157286438Sbapt						sq->file->col =
158286438Sbapt							sp->file->col - 1;
159286438Sbapt					else
160286438Sbapt						sq->file->col = sp->file->col;
161286438Sbapt					sq->file->dir = sp->file->dir;
162286438Sbapt				}
163286438Sbapt			cont2:
164286438Sbapt				l++;
165286438Sbapt			}
166286438Sbapt		cont1:
167286438Sbapt			n++;
168286438Sbapt		}
169286438Sbapt	}
170286438Sbapt	/*
171286438Sbapt	 * Clear old moves.  And write out new pos.
172286438Sbapt	 */
173286438Sbapt	n = 0;
174286438Sbapt	foreachship(sp) {
175286438Sbapt		if (sp->file->dir != 0) {
176286438Sbapt			*sp->file->movebuf = 0;
177286438Sbapt			if (row[n] != sp->file->row)
178286438Sbapt				send_row(sp, sp->file->row);
179286438Sbapt			if (col[n] != sp->file->col)
180286438Sbapt				send_col(sp, sp->file->col);
181286438Sbapt			if (dir[n] != sp->file->dir)
182286438Sbapt				send_dir(sp, sp->file->dir);
183286438Sbapt			if (drift[n] != sp->file->drift)
184286438Sbapt				send_drift(sp, sp->file->drift);
185286438Sbapt		}
186286438Sbapt		n++;
187286438Sbapt	}
188286438Sbapt}
189286438Sbapt
190286438Sbaptstatic int
191286438Sbaptstillmoving(int k)
192286438Sbapt{
193286438Sbapt	struct ship *sp;
194286438Sbapt
195286438Sbapt	foreachship(sp)
196286438Sbapt		if (sp->file->movebuf[k])
197286438Sbapt			return 1;
198286438Sbapt	return 0;
199286438Sbapt}
200286438Sbapt
201286438Sbaptstatic int
202286438Sbaptis_isolated(struct ship *ship)
203286438Sbapt{
204286438Sbapt	struct ship *sp;
205286438Sbapt
206286438Sbapt	foreachship(sp) {
207286438Sbapt		if (ship != sp && range(ship, sp) <= 10)
208286438Sbapt			return 0;
209325928Sbapt	}
210325928Sbapt	return 1;
211325928Sbapt}
212286438Sbapt
213286438Sbaptstatic int
214312336Sbaptpush(struct ship *from, struct ship *to)
215312336Sbapt{
216312336Sbapt	int bs, sb;
217312336Sbapt
218312336Sbapt	sb = to->specs->guns;
219312336Sbapt	bs = from->specs->guns;
220312336Sbapt	if (sb > bs)
221312336Sbapt		return 1;
222312336Sbapt	if (sb < bs)
223312336Sbapt		return 0;
224312336Sbapt	return from < to;
225312336Sbapt}
226312336Sbapt
227312336Sbaptstatic void
228312336Sbaptstep(struct ship *sp, int com, char *moved)
229286438Sbapt{
230286438Sbapt	int dist;
231286438Sbapt
232286438Sbapt	switch (com) {
233286438Sbapt	case 'r':
234286438Sbapt		if (++sp->file->dir == 9)
235312336Sbapt			sp->file->dir = 1;
236312336Sbapt		break;
237312336Sbapt	case 'l':
238312336Sbapt		if (--sp->file->dir == 0)
239312336Sbapt			sp->file->dir = 8;
240312336Sbapt		break;
241312336Sbapt		case '0': case '1': case '2': case '3':
242325928Sbapt		case '4': case '5': case '6': case '7':
243286438Sbapt		if (sp->file->dir % 2 == 0)
244286438Sbapt			dist = dtab[com - '0'];
245286438Sbapt		else
246286438Sbapt			dist = com - '0';
247286438Sbapt		sp->file->row -= dr[sp->file->dir] * dist;
248286438Sbapt		sp->file->col -= dc[sp->file->dir] * dist;
249286438Sbapt		*moved = 1;
250286438Sbapt		break;
251286438Sbapt	case 'b':
252286438Sbapt		break;
253286438Sbapt	case 'd':
254286438Sbapt		if (!*moved) {
255286438Sbapt			if (windspeed != 0 && ++sp->file->drift > 2 &&
256286438Sbapt			    ((sp->specs->class >= 3 && !snagged(sp))
257286438Sbapt			     || (turn & 1) == 0)) {
258286438Sbapt				sp->file->row -= dr[winddir];
259286438Sbapt				sp->file->col -= dc[winddir];
260286438Sbapt			}
261286438Sbapt		} else {
262286438Sbapt			sp->file->drift = 0;
263286438Sbapt		}
264286438Sbapt		break;
265286438Sbapt	}
266286438Sbapt}
267286438Sbapt
268286438Sbaptvoid
269286438Sbaptsendbp(struct ship *from, struct ship *to, int sections, int isdefense)
270286438Sbapt{
271286438Sbapt	int n;
272286438Sbapt	struct BP *bp;
273286438Sbapt
274286438Sbapt	bp = isdefense ? from->file->DBP : from->file->OBP;
275286438Sbapt	for (n = 0; n < NBP && bp[n].turnsent; n++)
276286438Sbapt		;
277286438Sbapt	if (n < NBP && sections) {
278286438Sbapt		if (isdefense) {
279286438Sbapt			send_dbp(from, n, turn, to->file->index, sections);
280286438Sbapt		} else {
281286438Sbapt			send_obp(from, n, turn, to->file->index, sections);
282286438Sbapt		}
283286438Sbapt		if (isdefense)
284286438Sbapt			makemsg(from, "repelling boarders");
285286438Sbapt		else
286286438Sbapt			makesignal(from, "boarding the $$", to);
287286438Sbapt	}
288286438Sbapt}
289286438Sbapt
290286438Sbaptint
291286438Sbaptis_toughmelee(struct ship *ship, struct ship *to, int isdefense, int count)
292286438Sbapt{
293286438Sbapt	struct BP *bp;
294286438Sbapt	int obp = 0;
295286438Sbapt	int n, OBP = 0, DBP = 0, dbp = 0;
296286438Sbapt	int qual;
297286438Sbapt
298286438Sbapt	qual = ship->specs->qual;
299286438Sbapt	bp = isdefense ? ship->file->DBP : ship->file->OBP;
300286438Sbapt	for (n = 0; n < NBP; n++, bp++) {
301286438Sbapt		if (bp->turnsent && (to == bp->toship || isdefense)) {
302286438Sbapt			obp += bp->mensent / 100
303286438Sbapt				? ship->specs->crew1 * qual : 0;
304286438Sbapt			obp += (bp->mensent % 100)/10
305286438Sbapt				? ship->specs->crew2 * qual : 0;
306286438Sbapt			obp += bp->mensent % 10
307286438Sbapt				? ship->specs->crew3 * qual : 0;
308286438Sbapt		}
309286438Sbapt	}
310286438Sbapt	if (count || isdefense)
311286438Sbapt		return obp;
312286438Sbapt	OBP = is_toughmelee(to, ship, 0, count + 1);
313286438Sbapt	dbp = is_toughmelee(ship, to, 1, count + 1);
314286438Sbapt	DBP = is_toughmelee(to, ship, 1, count + 1);
315286438Sbapt	if (OBP > obp + 10 || OBP + DBP >= obp + dbp + 10)
316286438Sbapt		return 1;
317286438Sbapt	else
318286438Sbapt		return 0;
319286438Sbapt}
320286438Sbapt
321286438Sbaptvoid
322286438Sbaptreload(void)
323286438Sbapt{
324286438Sbapt	struct ship *sp;
325286438Sbapt
326286438Sbapt	foreachship(sp) {
327286438Sbapt		sp->file->loadwith = 0;
328286438Sbapt	}
329286438Sbapt}
330286438Sbapt
331286438Sbaptvoid
332286438Sbaptchecksails(void)
333286438Sbapt{
334286438Sbapt	struct ship *sp;
335286438Sbapt	int rig, full;
336286438Sbapt	struct ship *close;
337286438Sbapt
338286438Sbapt	foreachship(sp) {
339286438Sbapt		if (sp->file->captain[0] != 0)
340286438Sbapt			continue;
341286438Sbapt		rig = sp->specs->rig1;
342286438Sbapt		if (windspeed == 6 || (windspeed == 5 && sp->specs->class > 4))
343286438Sbapt			rig = 0;
344286438Sbapt		if (rig && sp->specs->crew3) {
345286438Sbapt			close = closestenemy(sp, 0, 0);
346286438Sbapt			if (close != 0) {
347286438Sbapt				if (range(sp, close) > 9)
348286438Sbapt					full = 1;
349286438Sbapt				else
350286438Sbapt					full = 0;
351286438Sbapt			} else {
352286438Sbapt				full = 0;
353286438Sbapt			}
354286438Sbapt		} else {
355286438Sbapt			full = 0;
356286438Sbapt		}
357286438Sbapt		if ((sp->file->FS != 0) != full)
358286438Sbapt			send_fs(sp, full);
359286438Sbapt	}
360286438Sbapt}
361286438Sbapt