1 /*
2 	swmove	 -	SW move all objects and players
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-07	Development
19 			85-10-31	Atari
20 			87-03-09	Microsoft compiler.
21 			87-03-12	Wounded airplanes.
22 			87-03-12	Crashed planes stay longer at home.
23 			87-03-12	Proper ASYCHRONOUS end of game.
24 			87-03-12	Prioritize bombs/shots over flaps.
25 			87-03-12	Computer plane heads home at end.
26 			87-03-30	Novice Player
27 			87-03-31	Allow wounded plane to fly home
28 			87-04-01	Missiles.
29 			87-04-04	Missile and starburst support.
30 			87-04-09	Delay between starbursts.
31 			2003-01-27	GNU General Public License
32 */
33 #include	"sw.h"
34 
35 
36 
37 extern	int	displx, disprx; 	/*  Display left and right bounds */
38 extern	int	dispdx; 		/*  Display shift		  */
39 extern	OBJECTS *objtop,		/*  Start of object list.	  */
40 		*objfree,		/*  Free object list.		  */
41 		*deltop, *delbot;	/*  Newly deallocated objects	  */
42 extern	OBJECTS oobjects[];		/* Original plane object description*/
43 extern	OBJECTS *nobjects;		/* Objects list.		    */
44 extern	OBJECTS *compnear[];		/*  Array of planes near computers*/
45 extern	int	lcompter[];		/* Computer plane territory	  */
46 extern	int	rcompter[];		/* Computer plane territory	  */
47 extern	int	playmode;		/*  Play mode			  */
48 extern	MULTIO	*multbuff;		/*  Communications buffer	  */
49 extern	int	sintab[];		/*  sine table based on angles	  */
50 extern	GRNDTYPE ground[];		/*  Ground height by pixel	  */
51 extern	int	keydelay;		/*  Number of displays per keystr */
52 extern	int	multkey;		/* Keystroke to be passed	  */
53 extern	char	swplnsym[][ANGLES][SYMBYTES];/* plane pixel array	  */
54 extern	char	swhitsym[][SYMBYTES];	/*  Hit plane pixel array	  */
55 extern	char	swbmbsym[][BOMBBYTES];	/* Bomb pixel array		  */
56 extern	char	swmscsym[][MISCBYTES];	/* Missile pixel array		  */
57 extern	char	swbstsym[][BRSTBYTES];	/* Statburst symbol array	  */
58 extern	char	swtrgsym[][TARGBYTES];	/* Target Pixel array		  */
59 extern	char	swwinsym[][WINBYTES];	/* Winner Pixel Array		  */
60 extern	char	swhtrsym[];		/*  Hit target pixel array	   */
61 extern	char	swexpsym[][EXPBYTES];	/*  Explosion pixel array	   */
62 extern	char	swflksym[][FLKBYTES];	/*  Flock pixel array		   */
63 extern	char	swbrdsym[][BRDBYTES];	/*  Bird pixel array		   */
64 extern	char	swoxsym[][OXBYTES];	/*  Ox pixel array		   */
65 extern	int	dispcomp();
66 extern	int	counttick, countmove;	/* Performance counters 	   */
67 extern	BOOL	compplane;		/* Moving computer plane flag	   */
68 extern	BOOL	plyrplane;		/* Moving player plane flag	   */
69 extern	int	currobx;		/* Current object index 	    */
70 extern	int	player;
71 extern	int	soundflg;		/*  Sound flag			    */
72 extern	int	endsts[];		/* End of game status and move count*/
73 extern	int	endcount;
74 extern	BOOL	goingsun;		/* Heading for the sun flag	    */
75 extern	int	gamenum;		/* Game number			    */
76 extern	int	gmaxspeed,gminspeed;	/* Speed range based on game number */
77 extern	int	targrnge;		/* Target range based on game number*/
78 extern	int	dispcnt;		/* Displays to delay keyboard	    */
79 extern	int	endstat;		/* End of game status for curr. move*/
80 
81 extern	int	missok; 		/* Missiles supported		    */
82 
83 static	BOOL	quit;
84 
85 
86 
87 
88 swmove()
89 {
90 register OBJECTS *ob, *obn;
91 
92 	if ( deltop ) {
93 		delbot->ob_next = objfree;
94 		objfree = deltop;
95 		deltop = delbot = NULL;
96 	}
97 
98 	if ( ++dispcnt >= keydelay )
99 		dispcnt = 0;
100 
101 	ob = objtop;
102 	while ( ob ) {
103 		obn = ob->ob_next;
104 		ob->ob_delflg = ob->ob_drwflg;
105 		ob->ob_oldsym = ob->ob_newsym;
106 		ob->ob_drwflg = ( *ob->ob_movef )( ob );
107 		if ( ( ( playmode == MULTIPLE ) || ( playmode == ASYNCH ) )
108 			&& ( ob->ob_index == multbuff->mu_maxplyr )
109 			&& ( !dispcnt ) )
110 			if ( playmode == MULTIPLE )
111 				multput();
112 			else
113 				asynput();
114 		ob = obn;
115 	}
116 	++countmove;
117 
118 }
119 
120 
121 
122 moveplyr( obp )
123 OBJECTS *obp;
124 {
125 register OBJECTS *ob;
126 register BOOL	 rc;
127 register oldx;
128 
129 	compplane = FALSE;
130 	plyrplane = TRUE;
131 
132 	ob = obp;
133 	currobx = ob->ob_index;
134 
135 	if ( endstat = endsts[player] )
136 		if ( --endcount <= 0 ) {
137 			if ( ( playmode != MULTIPLE )
138 				&& ( playmode != ASYNCH )
139 				&& ( !quit ) )
140 				swrestart();
141 			swend( NULL, YES );
142 		}
143 
144 	if ( !dispcnt ) {
145 		if ( playmode == MULTIPLE )
146 			multkey = multget( ob );
147 		else if ( playmode == ASYNCH )
148 			multkey = asynget( ob );
149 		else {
150 			multkey = swgetc();
151 			swflush();
152 		}
153 		interpret( ob, multkey );
154 	} else {
155 		ob->ob_flaps = 0;
156 		ob->ob_bfiring = ob->ob_bombing = FALSE;
157 		ob->ob_mfiring = NULL;
158 	}
159 
160 	if ( ( ( ob->ob_state == CRASHED ) || ( ob->ob_state == GHOSTCRASHED ))
161 		&& ( ob->ob_hitcount <= 0 ) ) {
162 		++ob->ob_crashcnt;
163 		if ( ( endstat != WINNER )
164 			&& ( ( ob->ob_life <= QUIT )
165 			|| ( ( playmode != MULTIPLE )
166 			&& ( playmode != ASYNCH )
167 			&& ( ob->ob_crashcnt >= MAXCRASH ) ) ) ) {
168 			if ( !endstat )
169 				loser( ob );
170 		} else {
171 			initplyr( ob );
172 			initdisp( YES );
173 			if ( endstat == WINNER ) {
174 				if ( ctlbreak() )
175 					swend( NULL, YES );
176 				winner( ob );
177 			}
178 		}
179 	}
180 
181 	oldx = ob->ob_x;
182 	rc = movepln( ob );
183 	if ( ( oldx <= SCR_LIMIT ) || ( oldx >= ( MAX_X - SCR_LIMIT ) ) )
184 		dispdx = 0;
185 	else {
186 		displx += ( dispdx = ob->ob_x - oldx );
187 		disprx += dispdx;
188 	}
189 
190 	if ( !ob->ob_athome ) {
191 		setvdisp();
192 		if ( ob->ob_firing )
193 			dispsgge( ob );
194 		if ( ob->ob_bombing )
195 			dispbgge( ob );
196 		if ( ob->ob_mfiring )
197 			dispmgge( ob );
198 		if ( ob->ob_bfiring )
199 			dispsbgge( ob );
200 	}
201 
202 	return( rc );
203 }
204 
205 
206 
207 
208 interpret( obp, key )
209 OBJECTS *obp;
210 int	key;
211 {
212 register OBJECTS *ob;
213 register int	 state;
214 
215 	ob = obp;
216 	ob->ob_flaps = 0;
217 	ob->ob_bombing = ob->ob_bfiring = 0;
218 	ob->ob_mfiring = ob->ob_firing = NULL;
219 	if ( ( ( state = ob->ob_state ) != FLYING )
220 		&& ( state != STALLED )
221 		&& ( state != FALLING )
222 		&& ( state != WOUNDED )
223 		&& ( state != WOUNDSTALL )
224 		&& ( state != GHOST )
225 		&& ( state != GHOSTSTALLED ) )
226 		return;
227 
228 	if ( state != FALLING ) {
229 		if ( endstat ) {
230 			if ( ( endstat == LOSER ) && plyrplane )
231 				gohome( ob );
232 			return;
233 		}
234 
235 		if ( key & K_BREAK ) {
236 			ob->ob_life = QUIT;
237 			ob->ob_home = FALSE;
238 			if ( ob->ob_athome ) {
239 				ob->ob_state = state = ( state >= FINISHED )
240 					? GHOSTCRASHED : CRASHED;
241 				ob->ob_hitcount = 0;
242 			}
243 			if ( plyrplane )
244 				quit = TRUE;
245 		}
246 
247 		if ( key & K_HOME )
248 			if ( ( state == FLYING )
249 				|| ( state == GHOST )
250 				|| ( state == WOUNDED ) )
251 				ob->ob_home = TRUE;
252 	}
253 
254 	if ( ( countmove & 1 )
255 		|| ( ( state != WOUNDED ) && ( state != WOUNDSTALL ) ) ) {
256 		if ( key & K_FLAPU ) {
257 			++ob->ob_flaps;
258 			ob->ob_home = FALSE;
259 		}
260 
261 		if ( key & K_FLAPD ) {
262 			--ob->ob_flaps;
263 			ob->ob_home = FALSE;
264 		}
265 
266 		if ( key & K_FLIP ) {
267 			ob->ob_orient = !ob->ob_orient;
268 			ob->ob_home = FALSE;
269 		}
270 
271 		if ( key & K_DEACC ) {
272 			if ( ob->ob_accel )
273 				--ob->ob_accel;
274 			ob->ob_home = FALSE;
275 		}
276 
277 		if ( key & K_ACCEL ) {
278 			if ( ob->ob_accel < MAX_THROTTLE )
279 				++ob->ob_accel;
280 			ob->ob_home = FALSE;
281 		}
282 	}
283 
284 	if ( ( key & K_SHOT ) && ( state < FINISHED ) )
285 		ob->ob_firing = ob;
286 
287 	if ( ( key & K_MISSILE ) && ( state < FINISHED ) )
288 		ob->ob_mfiring = ob;
289 
290 	if ( ( key & K_BOMB ) && ( state < FINISHED ) )
291 		ob->ob_bombing = TRUE;
292 
293 	if ( ( key & K_STARBURST ) && ( state < FINISHED ) )
294 		ob->ob_bfiring = TRUE;
295 
296 	if ( key & K_SOUND )
297 		if ( plyrplane ) {
298 			if ( soundflg ) {
299 				sound( 0, 0, NULL );
300 				swsound();
301 			}
302 			soundflg = !soundflg;
303 		}
304 
305 	if ( ob->ob_home )
306 		gohome( ob );
307 }
308 
309 
310 
311 movecomp( obp )
312 OBJECTS *obp;
313 {
314 register OBJECTS *ob;
315 
316 	compplane = TRUE;
317 	plyrplane = FALSE;
318 
319 	ob = obp;
320 	ob->ob_flaps = 0;
321 	ob->ob_bfiring = ob->ob_bombing = FALSE;
322 	ob->ob_mfiring = NULL;
323 
324 	endstat = endsts[currobx = ob->ob_index];
325 
326 	if ( !dispcnt )
327 		ob->ob_firing = NULL;
328 
329 	switch ( ob->ob_state) {
330 
331 		case WOUNDED:
332 		case WOUNDSTALL:
333 			if ( countmove & 1 )
334 				break;
335 
336 		case FLYING:
337 		case STALLED:
338 			if ( endstat ) {
339 				gohome( ob );
340 				break;
341 			}
342 			if ( !dispcnt )
343 				swauto( ob );
344 			break;
345 
346 		case CRASHED:
347 			ob->ob_firing = NULL;
348 			if ( ( ob->ob_hitcount <= 0 ) && ( !endstat ) )
349 				initcomp( ob );
350 			break;
351 
352 		default:
353 			ob->ob_firing = NULL;
354 			break;
355 	}
356 
357 	return( movepln( ob ) );
358 }
359 
360 
361 
362 movepln( obp )
363 OBJECTS *obp;
364 {
365 register OBJECTS *ob;
366 register int	nangle, nspeed, state, limit, update;
367 int		x, y, newstate, stalled, grv;
368 static	 char	gravity[] = { 0,-1,-2,-3,-4,-3,-2,-1,
369 			      0, 1, 2, 3, 4, 3, 2, 1 };
370 
371 	ob = obp;
372 	switch ( state = ob->ob_state ) {
373 		case FINISHED:
374 		case WAITING:
375 			return( FALSE );
376 
377 		case CRASHED:
378 		case GHOSTCRASHED:
379 			--ob->ob_hitcount;
380 			break;
381 
382 		case FALLING:
383 			ob->ob_hitcount -= 2;
384 			if ( ( ob->ob_dy < 0 ) && ob->ob_dx )
385 				if ( ob->ob_orient ^ ( ob->ob_dx < 0 ) )
386 					ob->ob_hitcount -= ob->ob_flaps;
387 				else
388 					ob->ob_hitcount += ob->ob_flaps;
389 
390 			if ( ob->ob_hitcount <= 0 ) {
391 				if ( ob->ob_dy < 0 )
392 					if ( ob->ob_dx < 0 )
393 						++ob->ob_dx;
394 					else if ( ob->ob_dx > 0 )
395 						--ob->ob_dx;
396 					else
397 						ob->ob_orient = !ob->ob_orient;
398 
399 				if ( ob->ob_dy > -10 )
400 					--ob->ob_dy;
401 				ob->ob_hitcount = FALLCOUNT;
402 			}
403 			ob->ob_angle = symangle( ob ) << 1;
404 			if ( ob->ob_dy <= 0 )
405 				initsound( ob, S_FALLING );
406 			break;
407 
408 		case STALLED:
409 			newstate = FLYING;
410 			goto commonstall;
411 
412 		case GHOSTSTALLED:
413 			newstate = GHOST;
414 			goto commonstall;
415 
416 		case WOUNDSTALL:
417 			newstate = WOUNDED;
418 
419 		commonstall:
420 			if ( !( stalled = ( ob->ob_angle != ( 3 * ANGLES / 4 ) )
421 					  || ( ob->ob_speed < gminspeed ) ) )
422 				ob->ob_state = state = newstate;
423 			goto controlled;
424 
425 		case FLYING:
426 		case WOUNDED:
427 		case GHOST:
428 			if ( stalled = ( ob->ob_y >= MAX_Y ) ) {
429 				if ( playmode == NOVICE ) {
430 					ob->ob_angle = ( 3 * ANGLES / 4 );
431 					stalled = FALSE;
432 				} else {
433 					stallpln( ob );
434 					state = ob->ob_state;
435 				}
436 			}
437 
438 		controlled:
439 			if ( goingsun && plyrplane )
440 				break;
441 
442 			if ( ( ob->ob_life <= 0 ) && !ob->ob_athome
443 				&& ( ( state == FLYING )
444 				  || ( state == STALLED )
445 				  || ( state == WOUNDED )
446 				  || ( state == WOUNDSTALL ) ) ) {
447 				hitpln( ob );
448 				scorepln( ob );
449 				return( movepln( ob ) );
450 			}
451 
452 			if ( ob->ob_firing )
453 				initshot( ob, NULL );
454 
455 			if ( ob->ob_bombing )
456 				initbomb( ob );
457 
458 			if ( ob->ob_mfiring )
459 				initmiss( ob );
460 
461 			if ( ob->ob_bfiring )
462 				initburst( ob );
463 
464 			nangle = ob->ob_angle;
465 			nspeed = ob->ob_speed;
466 			update = FALSE;
467 
468 			if ( update = ob->ob_flaps ) {
469 				if ( ob->ob_orient )
470 					nangle -= update;
471 				else
472 					nangle += update;
473 				nangle = ( nangle + ANGLES ) % ANGLES;
474 			}
475 
476 			if ( !( countmove & 0x0003 ) ){
477 				if ( ( !stalled ) && ( nspeed < gminspeed )
478 					&& ( playmode != NOVICE ) ) {
479 					--nspeed;
480 					update = TRUE;
481 				} else {
482 					limit = gminspeed
483 						+ ob->ob_accel
484 						+ gravity[nangle];
485 					if ( nspeed < limit ) {
486 						++nspeed;
487 						update = TRUE;
488 					} else if ( nspeed > limit ) {
489 						--nspeed;
490 						update = TRUE;
491 					}
492 				}
493 			}
494 
495 			if ( update ) {
496 				if ( ob->ob_athome )
497 					if ( ob->ob_accel || ob->ob_flaps )
498 						nspeed = gminspeed;
499 					else
500 						nspeed = 0;
501 
502 				else if ( ( nspeed <= 0 ) && !stalled ) {
503 					if ( playmode == NOVICE )
504 						nspeed = 1;
505 					else {
506 						stallpln( ob );
507 						return( movepln( ob ) );
508 					}
509 				}
510 
511 				ob->ob_speed = nspeed;
512 				ob->ob_angle = nangle;
513 
514 				if ( stalled ) {
515 					ob->ob_dx = ob->ob_ldx = ob->ob_ldy = 0;
516 					ob->ob_dy = -nspeed;
517 				} else
518 					setdxdy( ob,
519 					   nspeed * COS( nangle ),
520 					   nspeed * SIN( nangle )
521 					);
522 			}
523 
524 			if ( stalled ){
525 				if ( !--ob->ob_hitcount ) {
526 					ob->ob_orient = !ob->ob_orient;
527 					ob->ob_angle = ( ( 3 * ANGLES / 2 )
528 							 - ob->ob_angle )
529 						       % ANGLES;
530 					ob->ob_hitcount = STALLCOUNT;
531 				}
532 			}
533 
534 			if ( !compplane ) {
535 				if ( plyrplane
536 					&& ( ob->ob_speed >
537 					( ob->ob_life % ( MAXFUEL/10 ) ) ) ){
538 					setvdisp();
539 					dispfgge( ob );
540 				}
541 				ob->ob_life -= ob->ob_speed;
542 			}
543 
544 			if ( ob->ob_speed )
545 				ob->ob_athome = FALSE;
546 			break;
547 	}
548 
549 	if ( ( endstat == WINNER ) && plyrplane && goingsun )
550 		ob->ob_newsym = swwinsym[endcount / 18];
551 	else
552 		ob->ob_newsym = ( ob->ob_state == FINISHED )
553 				? NULL
554 				: ( ( ( ob->ob_state == FALLING )
555 				    && ( !ob->ob_dx ) && ( ob->ob_dy < 0 ) )
556 				    ? swhitsym[ob->ob_orient]
557 				    : swplnsym[ob->ob_orient][ob->ob_angle]);
558 
559 	movexy( ob, &x, &y );
560 
561 	if ( x < 0 )
562 		x = ob->ob_x = 0;
563 	else
564 		if ( x >= ( MAX_X - 16 ) )
565 			x = ob->ob_x = MAX_X - 16;
566 
567 	if ( ( !compplane )
568 		&& ( ( ob->ob_state == FLYING )
569 		  || ( ob->ob_state == STALLED )
570 		  || ( ob->ob_state == WOUNDED )
571 		  || ( ob->ob_state == WOUNDSTALL ) )
572 		&& !endsts[player] )
573 		nearpln( ob );
574 
575 	deletex( ob );
576 	insertx( ob, ob->ob_xnext );
577 
578 	if ( ob->ob_bdelay )
579 		--ob->ob_bdelay;
580 	if ( ob->ob_mdelay )
581 		--ob->ob_mdelay;
582 	if ( ob->ob_bsdelay )
583 		--ob->ob_bsdelay;
584 
585 	if ( ( !compplane ) && ob->ob_athome && ( ob->ob_state == FLYING ) )
586 		refuel( ob );
587 
588 	if ( ( y < MAX_Y ) && ( y >= 0 ) ) {
589 		if ( ( ob->ob_state == FALLING )
590 			|| ( ob->ob_state == WOUNDED )
591 			|| ( ob->ob_state == WOUNDSTALL ) )
592 			initsmok( ob );
593 		setvdisp();
594 		dispwobj( ob );
595 		return( plyrplane || ( ob->ob_state < FINISHED ) );
596 	}
597 
598 	return( FALSE );
599 }
600 
601 
602 
603 static	nearpln( obp )
604 OBJECTS *obp;
605 {
606 register OBJECTS *ob, *obt, *obc;
607 register int	 i, obx, r, obclr;
608 
609 	ob = obp;
610 	obt = objtop + 1;
611 
612 	obx = ob->ob_x;
613 	obclr = ob->ob_owner->ob_clr;
614 
615 	for ( i = 1; obt->ob_type == PLANE; ++i, ++obt ) {
616 		if ( obclr == obt->ob_owner->ob_clr )
617 			continue;
618 
619 		if ( equal( obt->ob_drawf, dispcomp ) )
620 
621 			if ( ( playmode != COMPUTER )
622 				|| ( ( obx >= lcompter[i] )
623 				  && ( obx <= rcompter[i] ) ) )
624 				if ( ( !( obc = compnear[i] ) )
625 					|| ( abs( obx - obt->ob_x )
626 					< abs( obc->ob_x - obt->ob_x ) ) )
627 					compnear[i] = ob;
628 	}
629 }
630 
631 
632 
633 
634 
635 
636 static	refuel( obp )
637 OBJECTS *obp;
638 {
639 register OBJECTS *ob;
640 
641 	ob = obp;
642 	setvdisp();
643 	if ( topup( &ob->ob_life, MAXFUEL ) )
644 		dispfgge( ob );
645 	if ( topup( &ob->ob_rounds, MAXROUNDS ) )
646 		dispsgge( ob );
647 	if ( topup( &ob->ob_bombs, MAXBOMBS ) )
648 		dispbgge( ob );
649 	if ( topup( &ob->ob_missiles, MAXMISSILES ) )
650 		dispmgge( ob );
651 	if ( topup( &ob->ob_bursts, MAXBURSTS ) )
652 		dispsbgge( ob );
653 }
654 
655 
656 
657 
658 static	topup( counter, max )
659 int	*counter, max;
660 {
661 BOOL	rc;
662 
663 	rc = FALSE;
664 	if ( *counter == max )
665 		return( rc );
666 	if ( max < 20 ) {
667 		if ( !( countmove % 20 ) ) {
668 			++*counter;
669 			rc = plyrplane;
670 		}
671 	} else {
672 		*counter += max / 100;
673 		rc = plyrplane;
674 	}
675 	if ( *counter > max )
676 		*counter = max;
677 	return( rc );
678 }
679 
680 
681 
682 
683 
684 moveshot( obp )
685 OBJECTS *obp;
686 {
687 register OBJECTS *ob;
688 int		 x, y;
689 
690 	ob = obp;
691 	deletex( ob );
692 	if ( !--ob->ob_life ){
693 		deallobj( ob );
694 		return( FALSE );
695 	}
696 
697 	movexy( ob, &x, &y );
698 
699 	if ( ( y >= MAX_Y ) || ( y <= (int) ground[x] )
700 		|| ( x < 0 ) || ( x >= MAX_X ) ) {
701 		deallobj( ob );
702 		return( FALSE );
703 	}
704 
705 	insertx( ob, ob->ob_xnext );
706 	ob->ob_newsym = (char *) 0x83;
707 	return( TRUE );
708 }
709 
710 
711 
712 movebomb( obp )
713 OBJECTS *obp;
714 {
715 register OBJECTS *ob;
716 int		 x, y;
717 
718 	ob = obp;
719 
720 	deletex( ob );
721 
722 	if ( ob->ob_life < 0 ) {
723 		deallobj( ob );
724 		ob->ob_state = FINISHED;
725 		setvdisp();
726 		dispwobj( ob );
727 		return( FALSE );
728 	}
729 
730 	adjustfall( ob );
731 
732 	if ( ob->ob_dy <= 0 )
733 		initsound( ob, S_BOMB );
734 
735 	movexy( ob, &x, &y );
736 
737 	if ( ( y < 0 ) || ( x < 0 ) || ( x >= MAX_X ) ) {
738 		deallobj( ob );
739 		stopsound( ob );
740 		ob->ob_state = FINISHED;
741 		setvdisp();
742 		dispwobj( ob );
743 		return( FALSE );
744 	}
745 
746 	ob->ob_newsym = swbmbsym[symangle( ob )];
747 	insertx( ob, ob->ob_xnext );
748 
749 	if ( y >= MAX_Y )
750 		return( FALSE );
751 
752 	setvdisp();
753 	dispwobj( ob );
754 	return( TRUE );
755 }
756 
757 
758 
759 static	adjustfall( obp )
760 OBJECTS *obp;
761 {
762 register OBJECTS *ob;
763 
764 	ob = obp;
765 	if ( !--ob->ob_life ) {
766 		if ( ob->ob_dy < 0 )
767 			if ( ob->ob_dx < 0 )
768 				++ob->ob_dx;
769 			else
770 				if ( ob->ob_dx > 0 )
771 					--ob->ob_dx;
772 		if ( ob->ob_dy > -10 )
773 			--ob->ob_dy;
774 		ob->ob_life = BOMBLIFE;
775 	}
776 }
777 
778 
779 
780 static	symangle( ob )
781 OBJECTS *ob;
782 {
783 register int	 dx, dy;
784 
785 	dx = ob->ob_dx;
786 	dy = ob->ob_dy;
787 	if ( dx == 0 )
788 		if ( dy < 0 )
789 			return( 6 );
790 		else
791 			if ( dy > 0 )
792 				return( 2 );
793 			else
794 				return( 6 );
795 	else
796 		if ( dx > 0 )
797 			if ( dy < 0 )
798 				return( 7 );
799 			else
800 				if ( dy > 0 )
801 					return( 1 );
802 				else
803 					return( 0 );
804 		else
805 			if ( dy < 0 )
806 				return( 5 );
807 			else
808 				if ( dy > 0 )
809 					return( 3 );
810 				else
811 					return( 4 );
812 }
813 
814 
815 
816 movemiss( obp )
817 OBJECTS *obp;
818 {
819 register OBJECTS *ob;
820 int		 x, y, angle;
821 OBJECTS 	 *obt;
822 
823 	ob = obp;
824 
825 	deletex( ob );
826 
827 	if ( ob->ob_life < 0 ) {
828 		deallobj( ob );
829 		ob->ob_state = FINISHED;
830 		setvdisp();
831 		dispwobj( ob );
832 		return( FALSE );
833 	}
834 
835 	if ( ob->ob_state == FLYING ) {
836 		if ( ( ( obt = ob->ob_target ) != ob->ob_owner )
837 			&& ( ob->ob_life & 1 ) ) {
838 			if ( obt->ob_target )
839 				obt = obt->ob_target;
840 			aim( ob, obt->ob_x, obt->ob_y, NULL, NO );
841 			angle = ob->ob_angle
842 			      = ( ob->ob_angle + ob->ob_flaps + ANGLES )%ANGLES;
843 			setdxdy( ob, ob->ob_speed * COS( angle ),
844 				 ob->ob_speed * SIN( angle ) );
845 		}
846 		movexy( ob, &x, &y );
847 		if ( ( !--ob->ob_life ) || ( y >= ((MAX_Y*3)/2) ) ) {
848 			ob->ob_state = FALLING;
849 			++ob->ob_life;
850 		}
851 	} else	{
852 		adjustfall( ob );
853 		ob->ob_angle = ( ob->ob_angle + 1 ) % ANGLES;
854 		movexy( ob, &x, &y );
855 	}
856 
857 	if ( ( y < 0 ) || ( x < 0 ) || ( x >= MAX_X ) ) {
858 		deallobj( ob );
859 		ob->ob_state = FINISHED;
860 		setvdisp();
861 		dispwobj( ob );
862 		return( FALSE );
863 	}
864 
865 	ob->ob_newsym = swmscsym[ob->ob_angle];
866 	insertx( ob, ob->ob_xnext );
867 
868 	if ( y >= MAX_Y )
869 		return( FALSE );
870 
871 	setvdisp();
872 	dispwobj( ob );
873 	return( TRUE );
874 }
875 
876 
877 
878 moveburst( obp )
879 OBJECTS *obp;
880 {
881 register OBJECTS *ob;
882 int		 x, y;
883 
884 	ob = obp;
885 	deletex( ob );
886 	if ( ob->ob_life < 0 ) {
887 		ob->ob_owner->ob_target = NULL;
888 		deallobj( ob );
889 		return( FALSE );
890 	}
891 
892 	adjustfall( ob );
893 	movexy( ob, &x, &y );
894 
895 	if ( ( y <= (int) ground[x] ) || ( x < 0 ) || ( x >= MAX_X ) ) {
896 		ob->ob_owner->ob_target = NULL;
897 		deallobj( ob );
898 		return( FALSE );
899 	}
900 
901 	ob->ob_owner->ob_target = ob;
902 	ob->ob_newsym = swbstsym[ob->ob_life & 1];
903 	insertx( ob, ob->ob_xnext );
904 	return( y < MAX_Y );
905 }
906 
907 
908 
909 
910 movetarg( obt )
911 OBJECTS *obt;
912 {
913 int		 r;
914 register OBJECTS *obp, *ob;
915 
916 	ob = obt;
917 	obp = objtop;
918 	ob->ob_firing = NULL;
919 	if ( gamenum && ( ob->ob_state == STANDING )
920 		&& ( ( obp->ob_state == FLYING )
921 		  || ( obp->ob_state == STALLED )
922 		  || ( obp->ob_state == WOUNDED )
923 		  || ( obp->ob_state == WOUNDSTALL ) )
924 		&& ( ob->ob_clr != obp->ob_clr )
925 		&& ( ( gamenum > 1 ) || ( countmove & 0x0001 ) )
926 		&& ( ( r = range( ob->ob_x, ob->ob_y,
927 				 obp->ob_x, obp->ob_y ) ) > 0 )
928 		&& ( r < targrnge ) )
929 		initshot( ob, ob->ob_firing = obp );
930 
931 	if ( --ob->ob_hitcount < 0 )
932 		ob->ob_hitcount = 0;
933 
934 	ob->ob_newsym = ( ob->ob_state == STANDING )
935 		 ? swtrgsym[ob->ob_orient]
936 		 : swhtrsym;
937 	return( TRUE );
938 }
939 
940 
941 
942 moveexpl( obp )
943 OBJECTS *obp;
944 {
945 register OBJECTS *ob;
946 int		 x, y;
947 register int	 orient;
948 
949 	ob = obp;
950 	orient = ob->ob_orient;
951 	deletex( ob );
952 	if ( ob->ob_life < 0 ) {
953 		if ( orient )
954 			stopsound( ob );
955 		deallobj( ob );
956 		return( FALSE );
957 	}
958 
959 	if ( !--ob->ob_life ) {
960 		if ( ob->ob_dy < 0 )
961 			if ( ob->ob_dx < 0 )
962 				++ob->ob_dx;
963 			else
964 				if ( ob->ob_dx > 0 )
965 					--ob->ob_dx;
966 		if ( ( ob->ob_orient && ( ob->ob_dy > -10 ) )
967 			|| ( ( !ob->ob_orient ) && ( ob->ob_dy > -gminspeed )))
968 			--ob->ob_dy;
969 		ob->ob_life = EXPLLIFE;
970 	}
971 
972 	movexy( ob, &x, &y );
973 
974 	if ( ( y <= (int) ground[x] )
975 		|| ( x < 0 ) || ( x >= MAX_X ) ) {
976 		if ( orient )
977 			stopsound( ob );
978 		deallobj( ob );
979 		return( FALSE );
980 	}
981 	++ob->ob_hitcount;
982 
983 	insertx( ob, ob->ob_xnext );
984 	ob->ob_newsym = swexpsym[ob->ob_orient];
985 	return( y < MAX_Y );
986 }
987 
988 
989 
990 movesmok( obp )
991 OBJECTS *obp;
992 {
993 register OBJECTS *ob;
994 register int	 state;
995 
996 	ob = obp;
997 	if ( ( !--ob->ob_life )
998 		|| ( ( ( state = ob->ob_owner->ob_state ) != FALLING )
999 		    && ( state != WOUNDED )
1000 		    && ( state != WOUNDSTALL )
1001 		    && ( state != CRASHED ) ) ) {
1002 		deallobj( ob );
1003 		return( FALSE );
1004 	}
1005 	ob->ob_newsym = (char *)( 0x80 + ob->ob_clr );
1006 
1007 	return( TRUE );
1008 }
1009 
1010 
1011 
1012 moveflck( obp )
1013 OBJECTS *obp;
1014 {
1015 register OBJECTS *ob;
1016 int	 x, y;
1017 
1018 	ob = obp;
1019 	deletex( ob );
1020 
1021 	if ( ob->ob_life == -1 ) {
1022 		setvdisp();
1023 		dispwobj( ob );
1024 		deallobj( ob );
1025 		return( FALSE );
1026 	}
1027 
1028 	if ( !--ob->ob_life ) {
1029 		ob->ob_orient = !ob->ob_orient;
1030 		ob->ob_life = FLOCKLIFE;
1031 	}
1032 
1033 	if ( ( ob->ob_x < MINFLCKX ) || ( ob->ob_x > MAXFLCKX ) )
1034 		ob->ob_dx = -ob->ob_dx;
1035 
1036 	movexy( ob, &x, &y );
1037 	insertx( ob, ob->ob_xnext );
1038 	ob->ob_newsym = swflksym[ob->ob_orient];
1039 	setvdisp();
1040 	dispwobj( ob );
1041 	return( TRUE );
1042 }
1043 
1044 
1045 
1046 movebird( obp )
1047 OBJECTS *obp;
1048 {
1049 register OBJECTS *ob;
1050 int		 x, y;
1051 
1052 	ob = obp;
1053 
1054 	deletex( ob );
1055 
1056 	if ( ob->ob_life == -1 ) {
1057 		deallobj( ob );
1058 		return( FALSE );
1059 	}
1060 	else if ( ob->ob_life == -2 ) {
1061 		ob->ob_dy = -ob->ob_dy;
1062 		ob->ob_dx = ( countmove & 7 ) - 4;
1063 		ob->ob_life = BIRDLIFE;
1064 	}
1065 	else if ( !--ob->ob_life ) {
1066 		ob->ob_orient = !ob->ob_orient;
1067 		ob->ob_life = BIRDLIFE;
1068 	}
1069 
1070 	movexy( ob, &x, &y );
1071 
1072 	insertx( ob, ob->ob_xnext );
1073 	ob->ob_newsym = swbrdsym[ob->ob_orient];
1074 	if ( ( y >= MAX_Y ) || ( y <= (int) ground[x] )
1075 		|| ( x < 0 ) || ( x >= MAX_X ) ) {
1076 		ob->ob_y -= ob->ob_dy;
1077 		ob->ob_life = -2;
1078 		return( FALSE );
1079 	}
1080 	return( TRUE );
1081 }
1082 
1083 
1084 
1085 
1086 moveox( ob )
1087 OBJECTS *ob;
1088 {
1089 
1090 	ob->ob_newsym = swoxsym[ ob->ob_state != STANDING ];
1091 	return( TRUE );
1092 }
1093 
1094 
1095 
1096 
1097 BOOL crashpln( obp )
1098 OBJECTS *obp;
1099 {
1100 register OBJECTS *ob, *obo;
1101 
1102 	ob = obp;
1103 
1104 	if ( ob->ob_dx < 0 )
1105 		ob->ob_angle = ( ob->ob_angle + 2 ) % ANGLES;
1106 	else
1107 		ob->ob_angle = ( ob->ob_angle + ANGLES - 2 ) % ANGLES;
1108 
1109 	ob->ob_state = ( ob->ob_state >= GHOST ) ? GHOSTCRASHED : CRASHED;
1110 	ob->ob_athome = FALSE;
1111 	ob->ob_dx = ob->ob_dy = ob->ob_ldx = ob->ob_ldy = ob->ob_speed = 0;
1112 
1113 	obo = &oobjects[ob->ob_index];
1114 	ob->ob_hitcount = ( ( abs( obo->ob_x - ob->ob_x ) < SAFERESET )
1115 			 && ( abs( obo->ob_y - ob->ob_y ) < SAFERESET ) )
1116 			 ? ( MAXCRCOUNT << 1 ) : MAXCRCOUNT;
1117 
1118 }
1119 
1120 
1121 
1122 BOOL hitpln( obp )
1123 OBJECTS *obp;
1124 {
1125 register OBJECTS *ob;
1126 
1127 	ob = obp;
1128 	ob->ob_ldx = ob->ob_ldy = 0;
1129 	ob->ob_hitcount = FALLCOUNT;
1130 	ob->ob_state = FALLING;
1131 	ob->ob_athome = FALSE;
1132 }
1133 
1134 
1135 
1136 BOOL stallpln( obp )
1137 OBJECTS *obp;
1138 {
1139 register OBJECTS *ob;
1140 
1141 	ob = obp;
1142 	ob->ob_ldx = ob->ob_ldy = ob->ob_orient = ob->ob_dx = 0;
1143 	ob->ob_angle = 7 * ANGLES / 8;
1144 	ob->ob_speed = 0;
1145 	ob->ob_dy = 0;
1146 	ob->ob_hitcount = STALLCOUNT;
1147 	ob->ob_state = ( ob->ob_state >= GHOST ) ? GHOSTSTALLED :
1148 		       ( ( ob->ob_state == WOUNDED ) ? WOUNDSTALL : STALLED );
1149 	ob->ob_athome = FALSE;
1150 }
1151 
1152 
1153 
1154 
1155 insertx( ob, obp )
1156 OBJECTS *ob, *obp;
1157 {
1158 register OBJECTS *obs;
1159 register int	  obx;
1160 
1161 	obs = obp;
1162 	obx = ob->ob_x;
1163 	if ( obx < obs->ob_x )
1164 		do {
1165 			obs = obs->ob_xprev;
1166 		} while ( obx < obs->ob_x );
1167 	else {
1168 		while ( obx >= obs->ob_x )
1169 			obs = obs->ob_xnext;
1170 		obs = obs->ob_xprev;
1171 	}
1172 	ob->ob_xnext = obs->ob_xnext;
1173 	ob->ob_xprev = obs;
1174 	obs->ob_xnext->ob_xprev = ob;
1175 	obs->ob_xnext = ob;
1176 }
1177 
1178 
1179 
1180 
1181 deletex( obp )
1182 OBJECTS *obp;
1183 {
1184 register OBJECTS *ob;
1185 
1186 	ob = obp;
1187 	ob->ob_xnext->ob_xprev = ob->ob_xprev;
1188 	ob->ob_xprev->ob_xnext = ob->ob_xnext;
1189 }
1190 