1 /*
2 	swcollsn -	SW collision resolution
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-02-02	Development
19 			84-06-12	PCjr Speed-up
20 			84-10-31	Atari
21 			87-03-09	Microsoft compiler.
22 			87-03-11	No explosion on bird-plane collision
23 			87-03-12	Wounded airplanes.
24 			87-03-12	More than 1 bullet to kill target.
25 			87-03-13	Splatted bird symbol.
26 			87-03-31	Missiles.
27 			87-04-05	Missile and starburst support
28 			2003-01-27	GNU General Public License
29 */
30 #include	"sw.h"
31 
32 
33 extern	OBJECTS topobj, botobj;
34 extern	OBJECTS oobjects[];		/* Original plane object description*/
35 extern	OBJECTS *nobjects;		/* Objects list.		    */
36 extern	GRNDTYPE ground[];		/*  Ground height by pixel	    */
37 extern	GRNDTYPE orground[];		/* Original ground height by pixel  */
38 extern	int	playmode;
39 extern	int	player;
40 extern	int	shothole;		/* Number of window shots to dislay */
41 extern	int	splatbird;		/* Number of splatted birds	    */
42 extern	int	splatox;		/* Display a splatted OX	    */
43 extern	int	numtarg[];		/*  Number of active targets	    */
44 extern	MULTIO	*multbuff;
45 extern	int	gamenum;		/* Current game number		    */
46 extern	int	endsts[];		/* End of game status and move count*/
47 extern	int	forcdisp;		/* Force display of ground	    */
48 extern	int	gmaxspeed,gminspeed;	/* Speed range based on game number */
49 extern	int	counttick, countmove;	/* Performance counters 	   */
50 
51 static	OBJECTS *killed[MAX_OBJS << 1],
52 		*killer[MAX_OBJS << 1];
53 static	int	killptr;
54 
55 static	int	collsdx[MAX_PLYR];
56 static	int	collsdy[MAX_PLYR];
57 static	OBJECTS *collsno[MAX_PLYR];
58 static	int	collptr;
59 static	int	collxadj, collyadj;
60 
61 
62 
63 swcollsn()
64 {
65 register OBJECTS *ob, *obp, **obkd, **obkr;
66 register int	 xmax, ymin, ymax, otype, i;
67 int		 prevx1, prevx2;
68 
69 	collptr = killptr = 0;
70 	collxadj = 2;
71 	collyadj = 1;
72 	if ( countmove & 1 ) {
73 		collxadj = -collxadj;
74 		collyadj = -collyadj;
75 	}
76 	setadisp();
77 	prevx1 = topobj.ob_x;
78 	for ( ob = topobj.ob_xnext; ob != &botobj; ob = ob->ob_xnext ) {
79 		prevx2 = prevx1 = ob->ob_x;
80 
81 		xmax = ob->ob_x + ob->ob_symwdt - 1;
82 		ymin = ( ymax = ob->ob_y ) - ob->ob_symhgt + 1;
83 
84 		for ( obp = ob->ob_xnext;
85 			( obp != &botobj ) && ( obp->ob_x <= xmax );
86 			obp = obp->ob_xnext ) {
87 			prevx2 = obp->ob_x;
88 
89 			if ( ( obp->ob_y >= ymin )
90 			  && ( ( obp->ob_y - obp->ob_symhgt + 1 ) <= ymax ) )
91 				colltest( ob, obp );
92 		}
93 
94 		if ( ( ( ( otype = ob->ob_type ) == PLANE )
95 			    && ( ob->ob_state != FINISHED )
96 			    && ( ob->ob_state != WAITING )
97 			    && ( ob->ob_y < ( ground[ob->ob_x + 8] + 24 ) ) )
98 			  || ( ( ( otype == BOMB ) || ( otype == MISSILE ) )
99 			    && ( ob->ob_y < ( ground[ob->ob_x + 4] + 12 ) ) ) )
100 			tstcrash( ob );
101 	}
102 
103 	obkd = killed;
104 	obkr = killer;
105 	for ( i = 0; i < killptr; ++i, ++obkd, ++obkr )
106 	       kill( *obkd, *obkr );
107 
108 	obkd = collsno;
109 	for ( i = 0; i < collptr; ++i, ++obkd ) {
110 		( ob = *obkd )->ob_dx = collsdx[i];
111 		ob->ob_dy = collsdy[i];
112 	}
113 }
114 
115 
116 
117 
118 colltest( ob1, ob2 )
119 OBJECTS *ob1, *ob2;
120 {
121 register OBJECTS *obt, *ob, *obp;
122 register int	 otype, ttype;
123 
124 	ob = ob1;
125 	obp = ob2;
126 	otype = ob->ob_type;
127 	ttype = obp->ob_type;
128 	if ( ( ( otype == PLANE ) && ( ob->ob_state >= FINISHED ) )
129 		|| ( ( ttype == PLANE ) && ( obp->ob_state >= FINISHED ) )
130 		|| ( ( otype == EXPLOSION ) && ( ttype == EXPLOSION ) ) )
131 		return;
132 
133 	if ( ob->ob_y < obp->ob_y ) {
134 		obt = ob;
135 		ob = obp;
136 		obp = obt;
137 	}
138 
139 	swputsym( 15, 15, ob );
140 	if ( swputcol( obp->ob_x - ob->ob_x + 15,
141 		   obp->ob_y - ob->ob_y + 15,
142 		   obp ) )
143 		if ( killptr < ( ( MAX_OBJS << 1 ) - 1 ) ) {
144 			killed[killptr] = ob;
145 			killer[killptr++] = obp;
146 			killed[killptr] = obp;
147 			killer[killptr++] = ob;
148 		}
149 	swclrcol();
150 }
151 
152 
153 
154 tstcrash( obp )
155 OBJECTS *obp;
156 {
157 register OBJECTS *ob;
158 register int	 x, xmax, y;
159 register BOOL	 hit = FALSE;
160 
161 	ob = obp;
162 	swputsym( 15, 15, ob );
163 
164 	xmax = ob->ob_x + ob->ob_symwdt - 1;
165 	for ( x = ob->ob_x; x <= xmax; ++x ) {
166 		if ( ( y = (int) ground[x] - ob->ob_y + 15 ) > 15 ) {
167 			hit = TRUE;
168 			break;
169 		}
170 		if ( y < 0 )
171 			continue;
172 		if ( hit = swpntcol( x - ob->ob_x + 15, y, 0x80 ) )
173 			break;
174 	}
175 	swclrcol();
176 
177 	if ( ( hit ) && ( killptr < ( MAX_OBJS << 1 ) ) ){
178 		killed[killptr] = ob;
179 		killer[killptr++] = NULL;
180 	}
181 }
182 
183 
184 
185 kill( ob1, ob2 )
186 OBJECTS *ob1, *ob2;
187 {
188 register OBJECTS *ob, *obt;
189 register int	 state, ttype, i;
190 
191 	ob = ob1;
192 	obt = ob2;
193 	ttype = obt ? obt->ob_type : GROUND;
194 	if ( ( ( ttype == BIRD ) || ( ttype == FLOCK ) )
195 		&& ( ob->ob_type != PLANE ) )
196 		return;
197 
198 	switch ( ob->ob_type ) {
199 
200 		case BOMB:
201 		case MISSILE:
202 			initexpl( ob, 0 );
203 			ob->ob_life = -1;
204 			if ( !obt )
205 				crater( ob );
206 			stopsound( ob );
207 			return;
208 
209 		case SHOT:
210 			ob->ob_life = 1;
211 			return;
212 
213 		case STARBURST:
214 			if ( ( ttype == MISSILE ) || ( ttype == BOMB ) || !obt )
215 				ob->ob_life = 1;
216 			return;
217 
218 		case EXPLOSION:
219 			if ( !obt ) {
220 				ob->ob_life = 1;
221 				stopsound( ob );
222 			}
223 			return;
224 
225 		case TARGET:
226 			if ( ob->ob_state != STANDING )
227 				return;
228 			if ( ( ttype == EXPLOSION ) || ( ttype == STARBURST ) )
229 				return;
230 
231 			if ( ( ttype == SHOT )
232 				&& ( ( ob->ob_hitcount += TARGHITCOUNT )
233 				   <= ( TARGHITCOUNT * ( gamenum + 1 ) ) ) )
234 				   return;
235 
236 			ob->ob_state = FINISHED;
237 			initexpl( ob, 0 );
238 
239 			setvdisp();
240 			dispwobj( ob );
241 			setadisp();
242 
243 			scoretarg( ob, ( ob->ob_orient == 2 ) ? 200 : 100 );
244 			if ( !--numtarg[ob->ob_clr - 1] )
245 				endgame( ob->ob_clr );
246 			return;
247 
248 		case PLANE:
249 			if ( ( ( state = ob->ob_state ) == CRASHED )
250 				|| ( state == GHOSTCRASHED ) )
251 				return;
252 
253 			if ( endsts[ob->ob_index] == WINNER )
254 				return;
255 
256 			if ( ( ttype == STARBURST )
257 				|| ( ( ttype == BIRD ) && ob->ob_athome ) )
258 				return;
259 
260 			if ( !obt ) {
261 				if ( state == FALLING ) {
262 					stopsound( ob );
263 					initexpl( ob, 1 );
264 					crater( ob );
265 				}  else
266 					if ( state < FINISHED ) {
267 						scorepln( ob );
268 						initexpl( ob, 1 );
269 						crater( ob );
270 					}
271 
272 				crashpln( ob );
273 				return;
274 			}
275 
276 			if ( state >= FINISHED )
277 				return;
278 
279 			if ( state == FALLING ) {
280 				if ( ob->ob_index == player )
281 					if ( ttype == SHOT )
282 						++shothole;
283 					else if ( ( ttype == BIRD )
284 						|| ( ttype == FLOCK ) )
285 						++splatbird;
286 				return;
287 			}
288 
289 			if ( ( ttype == SHOT ) || ( ttype == BIRD )
290 				|| ( ttype == OX ) || ( ttype == FLOCK ) ) {
291 				if ( ob->ob_index == player )
292 					if ( ttype == SHOT )
293 						++shothole;
294 					else if ( ttype == OX )
295 						++splatox;
296 					else
297 						++splatbird;
298 				if ( state == FLYING ) {
299 					ob->ob_state = WOUNDED;
300 					return;
301 				}
302 				if ( state == STALLED ) {
303 					ob->ob_state = WOUNDSTALL;
304 					return;
305 				}
306 			} else {
307 				initexpl( ob, 1 );
308 				if ( ttype == PLANE ) {
309 					collsdx[collptr]
310 					    = ( ( ob->ob_dx + obt->ob_dx ) >> 1)
311 					    + ( collxadj = -collxadj );
312 					collsdy[collptr]
313 					    = ( ( ob->ob_dy + obt->ob_dy ) >> 1)
314 					    + ( collyadj = -collyadj );
315 					collsno[collptr++] = ob;
316 				}
317 			}
318 
319 			hitpln( ob );
320 			scorepln( ob );
321 			return;
322 
323 		case BIRD:
324 			ob->ob_life = scorepenalty( ttype, obt, 25 ) ? -1 : -2;
325 			return;
326 
327 		case FLOCK:
328 			if ( ( ttype != FLOCK ) && ( ttype != BIRD )
329 				&& ( ob->ob_state == FLYING ) ) {
330 				for ( i = 0; i < 8; ++i )
331 					initbird( ob, i );
332 				ob->ob_life = -1;
333 				ob->ob_state = FINISHED;
334 				}
335 			return;
336 
337 		case OX:
338 			if ( ob->ob_state != STANDING )
339 				return;
340 			if ( ( ttype == EXPLOSION ) || ( ttype == STARBURST ) )
341 				return;
342 			scorepenalty( ttype, obt, 200 );
343 			ob->ob_state = FINISHED;
344 			return;
345 	}
346 }
347 
348 
349 
350 static	scorepenalty( ttype, ob, score )
351 int	ttype;
352 OBJECTS *ob;
353 int	score;
354 {
355 register OBJECTS *obt;
356 
357 	obt = ob;
358 	if ( ( ttype == SHOT ) || ( ttype == BOMB ) || ( ttype ==  MISSILE )
359 		|| ( ( ttype == PLANE )
360 		    && ( ( obt->ob_state == FLYING )
361 			|| ( obt->ob_state == WOUNDED )
362 			|| ( ( obt->ob_state == FALLING )
363 				&& ( obt->ob_hitcount == FALLCOUNT ) ) )
364 		    && ( !obt->ob_athome ) ) ) {
365 		scoretarg( obt, score );
366 		return( TRUE );
367 	}
368 	return( FALSE );
369 }
370 
371 
372 
373 
374 static	scoretarg( obp, score )
375 OBJECTS *obp;
376 int	score;
377 {
378 register OBJECTS *ob;
379 
380 	ob = obp;
381 	if ( ( ( playmode != MULTIPLE ) && ( playmode != ASYNCH ) )
382 		|| ( multbuff->mu_maxplyr == 1 ) ) {
383 		if ( ob->ob_clr == 1 )
384 			nobjects[0].ob_score -= score;
385 		else
386 			nobjects[0].ob_score += score;
387 		dispscore( &nobjects[0] );
388 	} else {
389 		nobjects[2 - ob->ob_clr].ob_score += score;
390 		dispscore( &nobjects[2 - ob->ob_clr] );
391 	}
392 }
393 
394 
395 
396 
397 
398 scorepln( ob )
399 OBJECTS *ob;
400 {
401 
402 	scoretarg( ob, 50 );
403 }
404 
405 
406 
407 
408 dispscore( obp )
409 OBJECTS *obp;
410 {
411 register OBJECTS *ob;
412 
413 	swposcur( ( ( ob = obp )->ob_clr - 1 ) * 7 + 2, 24 );
414 	swcolour( ob->ob_clr );
415 	dispd( ob->ob_score, 6 );
416 }
417 
418 
419 
420 
421 dispd( n, size )
422 int	n, size;
423 {
424 register int   i     = 0;
425 register int   d, t;
426 register BOOL  first = TRUE;
427 
428 	if ( n < 0 ) {
429 		n = -n;
430 		swputc( '-' );
431 		++i;
432 	}
433 	for ( t = 10000; t > 1; n %= t, t /= 10 )
434 		if ( ( d = n / t ) || ( !first ) ){
435 			first = FALSE;
436 			swputc( d + '0' );
437 			++i;
438 		}
439 	swputc( n + '0' );
440 	++i;
441 	while( ++i <= size )
442 		swputc( ' ' );
443 }
444 
445 
446 
447 
448 
449 
450 static crtdepth[8] = { 1, 2, 2, 3, 3, 2, 2, 1 };
451 
452 static crater( ob )
453 OBJECTS *ob;
454 {
455 register int	i, x, y, ymin, ymax;
456 int		xmin, xmax;
457 
458 	xmin = ob->ob_x + ( ob->ob_symwdt - 8 ) / 2;
459 	xmax = xmin + 7;
460 
461 	for ( x = xmin, i = 0; x <= xmax; ++x, ++i ) {
462 		ymax = ground[x];
463 		if ( ( y = orground[x] - 20 ) < 20 )
464 			y = 20;
465 		if ( ( ymin = ymax - crtdepth[i] + 1 ) <= y )
466 			ymin = y + 1;
467 		ground[x] = ymin - 1;
468 	}
469 	forcdisp = TRUE;
470 }
471 
472 
473 
474 
475 equal( x, y )
476 int	( *x )(), ( *y )();
477 {
478 	return ( x == y );
479 }
480 