1 /*
2 	swauto	 -	SW control of computer player
3 
4 	Copyright (C) 1984-2003 David L. Clark.
5 	This program is free software; you can redistribute it and/or modify it under
6 	the terms of the GNU General Public License as published by the Free Software
7 	Foundation; either version 2 of the License, or (at your option) any later
8 	version. This program is distributed in the hope that it will be useful,
9 	but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 	more details. You should have received a copy of the GNU General Public
12 	License along with this program; if not, write to the Free Software Foundation,
13 	Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
14 
15 			Author: Dave Clark
16 
17 	Modification History:
18 			84-03-05	Development
19 			84-06-12	PCjr Speed-up
20 			84-10-31	Atari
21 			87-03-09	Microsoft compiler.
22 			87-03-12	Wounded airplanes.
23 			87-03-12	Smarter shooting.
24 			87-03-31	Missiles.
25 			87-04-05	Missile and starburst support
26 			87-04-06	Computer plane avoiding oxen.
27 			87-04-09	Don't attack until closer.
28 			2003-01-27	GNU General Public License
29 */
30 #include	"sw.h"
31 
32 extern	int	sintab[];		/* sine table based on angles	 */
33 extern	GRNDTYPE ground[];		/* Ground height by pixel	 */
34 extern	GRNDTYPE orground[];		/* Minimum ground height in craters */
35 extern	OBJECTS *nobjects;		/* Objects list.		    */
36 extern	OBJECTS oobjects[];		/* Original plane object description*/
37 extern	OBJECTS *compnear[];		/* Array of planes near computers   */
38 extern	OBJECTS *targets[];		/* Target status array		    */
39 extern	int	lcompter[];		/* Computer plane territory	  */
40 extern	int	rcompter[];		/* Computer plane territory	  */
41 extern	OBJECTS topobj, botobj;
42 extern	int	dispcomp(), dispplyr();
43 extern	int	keydelay;		/*  Number of displays per keystr   */
44 extern	int	playmode;		/*  Play mode			    */
45 extern	BOOL	goingsun;		/* Heading for the sun flag	    */
46 extern	int	endcount;
47 extern	int	gmaxspeed,gminspeed;	/* Speed range based on game number */
48 extern	BOOL	compplane;		/* Moving computer plane flag	    */
49 extern	BOOL	plyrplane;		/* Moving player plane flag	    */
50 extern	int	currobx;		/* Current object index 	    */
51 extern	int	counttick, countmove;	/* Performance counters 	   */
52 
53 
54 static	BOOL	correction;		/*  Course correction flag	  */
55 static	BOOL	goinghome;		/*  Going home flag		  */
56 static	OBJECTS obs;			/*  Saved computer object	  */
57 static	int	courseadj;		/*  Course adjustment		  */
58 
59 
60 
61 
62 swauto( ob )
63 OBJECTS *ob;
64 {
65 register OBJECTS *obt;
66 
67 	goinghome = FALSE;
68 
69 	if ( obt = compnear[currobx] )
70 		attack( ob, obt );
71 	else
72 		if ( !ob->ob_athome )
73 		       cruise( ob );
74 
75 	compnear[currobx] = NULL;
76 }
77 
78 
79 
80 
81 
82 attack( obp, obt )
83 OBJECTS *obp, *obt;
84 {
85 register OBJECTS *ob;
86 
87 	courseadj = ( ( countmove & 0x001F ) < 16 ) << 4;
88 	ob = obt;
89 	if ( ob->ob_speed )
90 		aim( obp,
91 		     ob->ob_x - ( ( CLOSE * COS( ob->ob_angle ) ) >> 8 ),
92 		     ob->ob_y - ( ( CLOSE * SIN( ob->ob_angle ) ) >> 8 ),
93 		     ob, NO );
94 	else
95 		aim( obp, ob->ob_x, ob->ob_y + 4, ob, NO );
96 }
97 
98 
99 
100 
101 static	cruise( ob )
102 OBJECTS *ob;
103 {
104 register int	 orgx;
105 
106 	courseadj = ( ( countmove & 0x001F ) < 16 ) << 4;
107 	orgx = oobjects[currobx].ob_x;
108 	aim( ob, ( ( orgx < ( MAX_X / 3 ) )
109 		? ( MAX_X / 3 )
110 		: ( ( orgx > ( 2 * MAX_X / 3 ) )
111 		? ( 2 * MAX_X / 3 )
112 		: orgx ) ) + courseadj,
113 		MAX_Y - 50 - ( courseadj >> 1 ),
114 		NULL, NO );
115 }
116 
117 
118 
119 
120 gohome( obpt )
121 OBJECTS *obpt;
122 {
123 register OBJECTS *ob, *obp;
124 
125 	if ( ( obp = obpt )->ob_athome )
126 		return( 0 );
127 
128 	ob = &oobjects[currobx];
129 
130 	courseadj = ( ( countmove & 0x001F ) < 16 ) << 4;
131 	if ( ( abs( obp->ob_x - ob->ob_x ) < HOME )
132 		&& ( abs( obp->ob_y - ob->ob_y ) < HOME ) ) {
133 		if ( plyrplane ) {
134 			initplyr( obp );
135 			initdisp( YES );
136 		} else
137 			if ( compplane )
138 				initcomp( obp );
139 			else
140 				initpln( obp );
141 		return( 0 );
142 	}
143 	goinghome = TRUE;
144 	return( aim( obp, ob->ob_x, ob->ob_y, NULL, NO ) );
145 }
146 
147 
148 
149 
150 
151 shoot( obt )
152 OBJECTS *obt;
153 {
154 static		OBJECTS obsp, obtsp;
155 int		obx, oby, obtx, obty;
156 int		nspeed, nangle;
157 int		rprev;
158 register int	r, i;
159 
160 
161 	movmem( &obs, &obsp, sizeof( OBJECTS ) );
162 	movmem( obt, &obtsp, sizeof( OBJECTS ) );
163 	nspeed = obsp.ob_speed + BULSPEED;
164 	setdxdy( &obsp, nspeed * COS( obsp.ob_angle ),
165 			nspeed * SIN( obsp.ob_angle ) );
166 	obsp.ob_x += SYM_WDTH / 2;
167 	obsp.ob_y -= SYM_HGHT / 2;
168 
169 	nangle = obtsp.ob_angle;
170 	nspeed = obtsp.ob_speed;
171 	rprev = NEAR;
172 	for ( i = 0; i < BULLIFE; ++i ) {
173 		movexy( &obsp, &obx, &oby );
174 		if ( ( ( obtsp.ob_state == FLYING )
175 			|| ( obtsp.ob_state == WOUNDED ) )
176 			&& ( r = obtsp.ob_flaps ) ) {
177 			if ( obtsp.ob_orient )
178 				nangle -= r;
179 			else
180 				nangle += r;
181 			nangle = ( nangle + ANGLES ) % ANGLES;
182 			setdxdy( &obtsp, nspeed * COS( nangle ),
183 					 nspeed * SIN( nangle ) );
184 		}
185 		movexy( &obtsp, &obtx, &obty );
186 		r = range( obx, oby, obtx, obty );
187 		if ( ( r < 0 ) || ( r > rprev ) )
188 			return( 0 );
189 		if ( ( obx >= obtx )
190 			&& ( obx <= ( obtx + SYM_WDTH - 1 ) )
191 			&& ( oby <= obty )
192 			&& ( oby >= ( obty - SYM_HGHT + 1 ) ) )
193 			return( 1 + ( i > ( BULLIFE / 3 ) ) );
194 
195 	}
196 	return( 0 );
197 }
198 
199 
200 
201 
202 abs( x )
203 int	x;
204 {
205 	return( ( x < 0 ) ? -x : x );
206 }
207 
208 
209 
210 
211 
212 
213 
214 aim( obo, ax, ay, obt, longway )
215 OBJECTS *obo, *obt;
216 int	ax, ay;
217 BOOL	longway;
218 {
219 register OBJECTS *ob, *obp;
220 register int	 r, rmin, i, n;
221 int	x, y, dx, dy, nx, ny;
222 int	nangle, nspeed;
223 static	int	cflaps[3] = { 0, -1, 1 };
224 static	int	crange[3],ccrash[3], calt[3];
225 
226 	ob = obo;
227 
228 	correction = FALSE;
229 
230 	if ( ( ( ob->ob_state == STALLED ) || ( ob->ob_state == WOUNDSTALL ) )
231 		&& ( ob->ob_angle != ( 3*ANGLES/4 ))){
232 		ob->ob_flaps = -1;
233 		ob->ob_accel = MAX_THROTTLE;
234 		return;
235 	}
236 
237 	x = ob->ob_x;
238 	y = ob->ob_y;
239 	if ( abs( dx = x - ax ) > 160 ) {
240 		if ( ob->ob_dx && ( ( dx < 0 ) == ( ob->ob_dx < 0 ) ) ) {
241 			if ( !ob->ob_hitcount )
242 				ob->ob_hitcount = 1 + ( y > ( MAX_Y - 50 ) );
243 			return( aim( ob, x, ( ob->ob_hitcount == 1 )
244 				? ( y + 25 ) : ( y - 25 ), NULL, YES ) );
245 		}
246 		ob->ob_hitcount = 0;
247 		return( aim( ob, x + ( ( dx < 0 ) ? 150 : -150 ),
248 			     ( ( ( y += 100 ) > ( MAX_Y - 50 - courseadj ) )
249 			     ? ( MAX_Y - 50 - courseadj ) : y ), NULL, YES ) );
250 	} else
251 		if ( !longway )
252 			ob->ob_hitcount = 0;
253 
254 	if ( ob->ob_speed )
255 		if ( correction = ( dy = y - ay ) && ( abs( dy ) < 6 ) )
256 			ob->ob_y = ( dy < 0 ) ? ++y : --y;
257 		else
258 			if ( correction = dx && ( abs( dx ) < 6 ) )
259 				ob->ob_x = ( dx < 0 ) ? ++x : --x;
260 
261 	movmem( ob, &obs, sizeof( OBJECTS ) );
262 	if ( ( ( nspeed = obs.ob_speed + 1 ) > gmaxspeed )
263 		&& ( obs.ob_type == PLANE ) )
264 		nspeed = gmaxspeed;
265 	else
266 		if ( nspeed < gminspeed )
267 			nspeed = gminspeed;
268 
269 	cleartargs();
270 	for ( i = 0; i < 3; ++i ) {
271 		nangle = ( obs.ob_angle
272 			 + ( obs.ob_orient ? -( cflaps[i] ) : cflaps[i] )
273 			 + ANGLES ) % ANGLES;
274 		setdxdy( &obs, nspeed * COS( nangle ), nspeed * SIN( nangle ) );
275 		movexy( &obs, &nx, &ny );
276 		crange[i] = range( nx, ny, ax, ay );
277 		calt[i] = ny - orground[nx + 8];
278 		ccrash[i] = tstcrash( ob, nx, ny, calt[i] );
279 		movmem( ob, &obs, sizeof( OBJECTS ) );
280 	}
281 
282 
283 	if ( obt && ( i = shoot( obt ) ) )
284 		if ( ob->ob_missiles && ( i == 2 ) )
285 			ob->ob_mfiring = obt->ob_athome ? ob : obt;
286 		else
287 			ob->ob_firing = obt;
288 
289 	rmin = 32767;
290 	for ( i = 0; i < 3; ++i )
291 		if ( ( ( r = crange[i] ) >= 0 )
292 			&& ( r < rmin )
293 			&& !ccrash[i] ) {
294 			rmin = r;
295 			n = i;
296 		}
297 	if ( rmin == 32767 ) {
298 		rmin = -32767;
299 		for ( i = 0; i < 3; ++i )
300 			if ( ( ( r = crange[i] ) < 0 )
301 				&& ( r > rmin )
302 				&& !ccrash[i] ) {
303 				rmin = r;
304 				n = i;
305 			}
306 	}
307 
308 	if ( ob->ob_speed < gminspeed )
309 		ob->ob_accel = MAX_THROTTLE;
310 
311 	if ( rmin != -32767 ) {
312 		if ( ob->ob_accel < MAX_THROTTLE )
313 			++ob->ob_accel;
314 	} else {
315 		if ( ob->ob_accel )
316 			--ob->ob_accel;
317 
318 		n = 0;
319 		if ( calt[1] > ( dy = calt[0] ) ) {
320 			dy = calt[1];
321 			n = 1;
322 		}
323 		if ( calt[2] > dy )
324 			n = 2;
325 	}
326 
327 	ob->ob_flaps = cflaps[n];
328 	if ( ( ob->ob_type == PLANE ) && !ob->ob_flaps )
329 		if ( ob->ob_speed )
330 			ob->ob_orient = ( ob->ob_dx < 0 );
331 
332 }
333 
334 
335 
336 static	int	tl, tr;
337 
338 
339 
340 static	cleartargs()
341 {
342 	tl = -2;
343 }
344 
345 
346 
347 static	testtargs( x, y )
348 int	x, y;
349 {
350 register int	i, xl, xr;
351 
352 	xl = x - 32 - gmaxspeed;
353 	xr = x + 32 + gmaxspeed;
354 
355 	tl = -1;
356 	tr = 0;
357 	for ( i = 0; i < ( MAX_TARG + MAX_OXEN ); ++i )
358 		if ( targets[i] && ( targets[i]->ob_x >= xl ) ) {
359 			tl = i;
360 			break;
361 		}
362 
363 	if ( tl == -1 )
364 		return;
365 
366 	for ( ; ( i < ( MAX_TARG + MAX_OXEN ) ) && targets[i]
367 		&& ( targets[i]->ob_x < xr ); ++i );
368 	tr = i - 1;
369 }
370 
371 
372 
373 
374 static	tstcrash( obp, x, y, alt )
375 int	x, y, alt;
376 OBJECTS *obp;
377 {
378 register OBJECTS *ob;
379 register int	 i, xl, xr, xt, yt;
380 
381 	if ( alt > 50 )
382 		return( FALSE );
383 
384 	if ( alt < 22 )
385 		return( TRUE );
386 
387 	ob = obp;
388 	if ( tl == -2 )
389 		testtargs( ob->ob_x, ob->ob_y );
390 
391 	xl = x - 32;
392 	xr = x + 32;
393 
394 	for ( i = tl; i <= tr; ++i ) {
395 		if ( ( xt = ( ob = targets[i] )->ob_x ) < xl )
396 			continue;
397 		if ( xt > xr )
398 			return( FALSE );
399 		yt = ob->ob_y + ( ob->ob_state == STANDING ? 16 : 8 );
400 		if ( y <= yt )
401 			return( TRUE );
402 	}
403 	return( FALSE );
404 }
405 
406 
407 
408 
409 
410 range( x, y, ax, ay )
411 int	x, y, ax, ay;
412 {
413 register int	 dx, dy;
414 register int	 t;
415 
416 	dy = abs( y - ay );
417 	dy += dy >> 1;
418 	if ( ( ( dx = abs( x - ax ) ) < 125 ) && ( dy < 125 ) )
419 		return ( dx * dx + dy * dy );
420 
421 	if ( dx < dy ) {
422 		t = dx;
423 		dx = dy;
424 		dy = t;
425 	}
426 
427 	return( - ( ( ( 7 * dx ) + ( dy << 2 ) ) >> 3 ) );
428 }
429 