1 /* Copyright (C) 1993, 1992 Nathan Sidwell */
2 /* RCS $Id: apple.c,v 4.10 1993/12/10 11:52:23 nathan Stable $ */
3 #include "xmris.h"
4 /*{{{  prototypes*/
5 static APPLE *apple_search PROTOARG((int, int, unsigned, unsigned, unsigned));
6 /*}}}*/
7 /*{{{  APPLE *apple_search(x, y, width, height, found)*/
8 static APPLE *apple_search
9 FUNCARG((x, y, width, height, found),
10 	int       x       /* x coord start */
11 ARGSEP  int       y       /* y coord start */
12 ARGSEP  unsigned  width   /* width of box */
13 ARGSEP  unsigned  height  /* height of box */
14 ARGSEP  unsigned  found   /* already found ones */
15 )
16 /*
17  * looks for an apple in the specified box
18  * and returns a ptr to it, if found
19  */
20 {
21   unsigned  i;
22   APPLE     *aptr;
23 
24   for(aptr = apple.list, i = 0; i != apple.apples; i++, aptr++, found >>= 1)
25     if(!(found & 1) && INRANGE(aptr->pixel.x + aptr->push - x, 0, width) &&
26 	INRANGE(aptr->pixel.y - y, 0, height))
27       return aptr;
28   return NULL;
29 }
30 /*}}}*/
31 /*{{{  int apple_stop(mptr, cptr)*/
32 extern int apple_stop
33 FUNCARG((mptr, cptr),
34 	MONSTER   *mptr
35 ARGSEP  CELL      *cptr
36 )
37 /*
38  * sees if the monster is about to walk into an apple
39  * returns 0 if clear, 1 if stopped
40  * sets mptr->pause & mptr->stop as required
41  * the apples and other monsters are altered
42  * if they're pushed about
43  * called before we've moved the monster
44  */
45 {
46   unsigned  stop;
47   unsigned  pause;
48 
49   pause = stop = 0;
50   switch(mptr->dir)
51   {
52     /*{{{  case 0: (up)*/
53     case 0:
54     {
55       unsigned  i;
56       APPLE     *aptr;
57       int       px, py;
58 
59       px = mptr->pixel.x;
60       py = mptr->pixel.y;
61       for(aptr = apple.list, i = apple.apples; i--; aptr++)
62 	{
63 	  if(INRANGE(aptr->pixel.x + aptr->push - px,
64 		1 - CELL_WIDTH, CELL_WIDTH) &&
65 	      INRANGE(py - aptr->pixel.y, CELL_HEIGHT / 2,
66 	      CELL_HEIGHT + VEL_Y) && !aptr->ghost)
67 	    {
68 	      stop = 1;
69 	      break;
70 	    }
71 	}
72       break;
73     }
74     /*}}}*/
75     /*{{{  case 1: (down)*/
76     case 1:
77     {
78       unsigned  i;
79       APPLE     *aptr;
80       int       px, py;
81 
82       px = mptr->pixel.x;
83       py = mptr->pixel.y;
84       for(aptr = apple.list, i = apple.apples; i--; aptr++)
85 	{
86 	  if(INRANGE(aptr->pixel.x + aptr->push - px,
87 	      1 - CELL_WIDTH, CELL_WIDTH) &&
88 	      INRANGE(aptr->pixel.y + apple_sizes[aptr->state].offset.y - py,
89 	      CELL_HEIGHT / 2, CELL_HEIGHT + VEL_Y) && !aptr->ghost)
90 	    {
91 	      stop = 1;
92 	      break;
93 	    }
94 	}
95       break;
96     }
97     /*}}}*/
98     /*{{{  case 2: (left)*/
99     case 2:
100     {
101       unsigned  found;
102       int       x, y;
103       int       width;
104       APPLE     *final;
105 
106       found = 0;
107       final = NULL;
108       width = VEL_X;
109       x = mptr->pixel.x - CELL_WIDTH + 1 - width;
110       y = mptr->pixel.y - CELL_HEIGHT + VEL_Y;
111       /*{{{  look for apple*/
112       for(;;)
113       {
114 	APPLE     *aptr;
115 	CELL      *cptr;
116 
117 	aptr = apple_search(x, y, (unsigned)width + CELL_WIDTH / 2,
118 	    2 * (CELL_HEIGHT - VEL_Y), found);
119 	if(!aptr)
120 	  break;
121 	else if(aptr->push || aptr->pixel.x - width < PIXELX(0, 0))
122 	  {
123 	    stop = 1;
124 	    break;
125 	  }
126 	else if(aptr->state == 2 &&
127 	    ((mptr->type != 1 && mptr->type != 4) ||
128 	    (aptr->offset.x < (cptr = BOARDCELL(aptr->cell.x, aptr->cell.y +
129 		(aptr->offset.y <= 0)))->depths[2] &&
130 		  !cptr[-1].visit)))
131 	  break;
132 	else
133 	  {
134 	    final = aptr;
135 	    found |= 1 << (aptr - apple.list);
136 	    width = aptr->pixel.x - x + 1;
137 	    width = (width + APPLE_VEL_X - 1) / APPLE_VEL_X * APPLE_VEL_X;
138 	    aptr->maypush = width;
139 	    x = aptr->pixel.x - CELL_WIDTH + 1 - width;
140 	    if(aptr->state != 2 && aptr->offset.y > 0 &&
141 		apple_search(x, aptr->pixel.y - aptr->offset.y + CELL_HEIGHT,
142 		  (unsigned)width, (unsigned)aptr->offset.y, found))
143 	      {
144 		stop = 1;
145 		break;
146 	      }
147 	    y = aptr->pixel.y - CELL_HEIGHT + VEL_Y;
148 	    if(!width || aptr->state == 2)
149 	      break;
150 	  }
151       }
152       /*}}}*/
153       if(found && !stop)
154 	{
155 	  /*{{{  check if against monster*/
156 	  if(width)
157 	    {
158 	      unsigned  i;
159 	      MONSTER   *mptr;
160 	      MONSTER   *list;
161 
162 	      list = NULL;
163 	      for(mptr = monster.list, i = monster.monsters; i--; mptr++)
164 		{
165 		  if(!mptr->squished && !mptr->shot &&
166 		      INRANGE(mptr->pixel.x - x, 0, width + CELL_WIDTH) &&
167 		      INRANGE(mptr->pixel.y - y, 0, 2 * (CELL_HEIGHT - VEL_Y)))
168 		    {
169 		      if(mptr->type == 4)
170 			stop = 1;
171 		      else if(mptr->type == 1)
172 			{
173 			  if(mptr->dir & 2 ||
174 			      mptr->pixel.x - x >= width + CELL_WIDTH / 2)
175 			    stop = 1;
176 			}
177 		      else if(final->state < 2 && (!mptr->type || mptr->chew))
178 			{
179 			  CELL      *cptr;
180 
181 			  cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
182 			  if(cptr->depths[2] <= mptr->offset.x - width ||
183 			      ((cptr->depths[1] || cptr->depths[0]) &&
184 			      mptr->offset.x >= 0))
185 			    {
186 			      mptr->list = list;
187 			      list = mptr;
188 			      mptr->push = -1;
189 			    }
190 			  else
191 			    stop = 1;
192 			}
193 		    }
194 		}
195 	      if(final->state < 2)
196 		final->list = list;
197 	    }
198 	  /*}}}*/
199 	  if(!stop)
200 	  {
201 	    pause = 1;
202 	    /*{{{  push the apples*/
203 	    {
204 	      unsigned  i;
205 	      APPLE     *aptr;
206 
207 	      for(aptr = apple.list, i = apple.apples;
208 		  i--; aptr++, found >>= 1)
209 		if(found & 1)
210 		  aptr->push = -aptr->maypush;
211 	    }
212 	    /*}}}*/
213 	  }
214 	}
215       break;
216     }
217     /*}}}*/
218     /*{{{  case 3: (right)*/
219     case 3:
220     {
221       unsigned  found;
222       int       x, y;
223       int       width;
224       APPLE     *final;
225 
226       found = 0;
227       final = NULL;
228       width = VEL_X;
229       x = mptr->pixel.x + CELL_WIDTH;
230       y = mptr->pixel.y - CELL_HEIGHT + VEL_Y;
231       /*{{{  look for apple*/
232       for(;;)
233       {
234 	APPLE       *aptr;
235 
236 	aptr = apple_search(x - CELL_WIDTH / 2, y,
237 	    (unsigned)width + CELL_WIDTH / 2,
238 	    2 * (CELL_HEIGHT - VEL_Y), found);
239 	if(!aptr)
240 	  break;
241 	else if(aptr->push ||
242 	    aptr->pixel.x + width > PIXELX(CELLS_ACROSS - 1, 0))
243 	  {
244 	    stop = 1;
245 	    break;
246 	  }
247 	else if(aptr->state == 2 && ((mptr->type != 1 && mptr->type != 4) ||
248 	    (aptr->offset.x > (cptr = BOARDCELL(aptr->cell.x, aptr->cell.y +
249 		(aptr->offset.y <= 0)))->depths[3] &&
250 		  !cptr[1].visit)))
251 	  break;
252 	else
253 	  {
254 	    final = aptr;
255 	    found |= 1 << (aptr - apple.list);
256 	    width -= aptr->pixel.x - x;
257 	    width = (width + APPLE_VEL_X - 1) / APPLE_VEL_X * APPLE_VEL_X;
258 	    aptr->maypush = width;
259 	    x = aptr->pixel.x + CELL_WIDTH;
260 	    if(aptr->state != 2 && aptr->offset.y > 0 &&
261 		apple_search(x, aptr->pixel.y - aptr->offset.y + CELL_HEIGHT,
262 		    (unsigned)width, (unsigned)aptr->offset.y, found))
263 	      {
264 		stop = 1;
265 		break;
266 	      }
267 	    y = aptr->pixel.y - CELL_HEIGHT + VEL_Y;
268 	    if(!width || aptr->state == 2)
269 	      break;
270 	  }
271       }
272       /*}}}*/
273       if(found && !stop)
274 	{
275 	  /*{{{  check if against monster*/
276 	  if(width)
277 	    {
278 	      unsigned  i;
279 	      MONSTER   *mptr;
280 	      MONSTER   *list;
281 
282 	      list = NULL;
283 	      for(mptr = monster.list, i = monster.monsters; i--; mptr++)
284 		{
285 		  if(!mptr->squished && !mptr->shot &&
286 		      INRANGE(mptr->pixel.x - x, -CELL_WIDTH, width) &&
287 		      INRANGE(mptr->pixel.y - y, 0, 2 * (CELL_HEIGHT - VEL_Y)))
288 		    {
289 		      if(mptr->type == 4)
290 			stop = 1;
291 		      else if(mptr->type == 1)
292 			{
293 			  if(mptr->dir & 2 ||
294 			      mptr->pixel.x - x < -CELL_WIDTH / 2)
295 			    stop = 1;
296 			}
297 		      else if(final->state < 2 && (!mptr->type || mptr->chew))
298 			{
299 			  CELL      *cptr;
300 
301 			  cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
302 			  if(cptr->depths[3] >= mptr->offset.x + width ||
303 			      ((cptr->depths[1] || cptr->depths[0]) &&
304 			      mptr->offset.x <= 0))
305 			    {
306 			      mptr->list = list;
307 			      list = mptr;
308 			      mptr->push = 1;
309 			    }
310 			  else
311 			    stop = 1;
312 			}
313 		    }
314 		}
315 	      if(final->state < 2)
316 		final->list = list;
317 	    }
318 	  /*}}}*/
319 	  if(!stop)
320 	    {
321 	      pause = 1;
322 	      /*{{{  push the apples*/
323 	      {
324 		unsigned  i;
325 		APPLE     *aptr;
326 
327 		for(aptr = apple.list, i = apple.apples; i--; aptr++, found >>= 1)
328 		  if(found & 1)
329 		    aptr->push = aptr->maypush;
330 	      }
331 	      /*}}}*/
332 	    }
333 	}
334       break;
335     }
336     /*}}}*/
337   }
338   mptr->stop = stop;
339   mptr->pause = pause;
340   return stop;
341 }
342 /*}}}*/
343 /*{{{  void move_apples()*/
344 extern VOIDFUNC move_apples FUNCARGVOID
345 /*
346  * moves all the apples
347  */
348 {
349   APPLE     *aptr;
350   unsigned  i;
351 
352   apple.moving = 0;
353   for(aptr = apple.list, i = apple.apples; i--; aptr++)
354     {
355       CELL      *cptr;
356 
357       cptr = BOARDCELL(aptr->cell.x, aptr->cell.y);
358       if(aptr->chewed)
359 	{
360 	  assert(!aptr->monsters);
361 	  aptr->state = 6;
362 	}
363       else
364 	{
365 	  if(aptr->ghost)
366 	    aptr->ghost--;
367 	  /*{{{  pushed?*/
368 	  if(aptr->push)
369 	    {
370 	      aptr->pixel.x += aptr->push;
371 	      aptr->offset.x += aptr->push;
372 	      assert(!(aptr->offset.x % APPLE_VEL_X));
373 	      if(aptr->offset.x < -(CELL_WIDTH / 2))
374 		{
375 		  aptr->offset.x += CELL_WIDTH + GAP_WIDTH;
376 		  aptr->cell.x -= 1;
377 		  cptr -= 1;
378 		}
379 	      else if(aptr->offset.x > (CELL_WIDTH / 2))
380 		{
381 		  aptr->offset.x -= CELL_WIDTH + GAP_WIDTH;
382 		  aptr->cell.x += 1;
383 		  cptr += 1;
384 		}
385 	    }
386 	  /*}}}*/
387 	  switch(aptr->state)
388 	  {
389 	    /*{{{  case 0: (static) case 1: (rock)*/
390 	    case 0: case 1:
391 	    {
392 	      unsigned  old;
393 	      unsigned  new;
394 	      int       offset;
395 
396 	      old = aptr->state;
397 	      new = 0;
398 	      offset = 0;
399 	      if(aptr->offset.y < cptr->depths[1])
400 		new = 2;
401 	      else if(aptr->cell.y == CELLS_DOWN - 1)
402 		{
403 		  new = 3;
404 		  aptr->ghost = 0;
405 		}
406 	      else if(cptr[CELL_STRIDE].visit)
407 		new = 1;
408 	      else if(aptr->offset.y - cptr[CELL_STRIDE*2].depths[0] >=
409 		  CELL_HEIGHT + GAP_HEIGHT)
410 		new = 1;
411 	      else if(cptr[CELL_STRIDE + 1].visit &&
412 		  cptr[CELL_STRIDE + 1].depths[2] - aptr->offset.x <
413 		  -(CELL_WIDTH / 2))
414 		{
415 		  new = 1;
416 		  offset = 1;
417 		}
418 	      else if(cptr[CELL_STRIDE - 1].visit &&
419 		  cptr[CELL_STRIDE - 1].depths[3] - aptr->offset.x >
420 		  CELL_WIDTH / 2)
421 		{
422 		  new = 1;
423 		  offset = -1;
424 		}
425 	      if(new == 1 && old == 1 && !aptr->count--)
426 		new = 2;
427 	      if(new)
428 		/*{{{  check for supporting monster*/
429 		{
430 		  MONSTER   *mptr;
431 		  unsigned  count;
432 		  int       x, y;
433 
434 		  x = aptr->pixel.x;
435 		  y = aptr->pixel.y;
436 		  for(mptr = monster.list, count = monster.monsters;
437 		      count--; mptr++)
438 		    if((mptr->type == 4 || mptr->type == 1) && !mptr->shot &&
439 			INRANGE(mptr->pixel.x - x, 1 + VEL_X - CELL_WIDTH,
440 			  CELL_WIDTH - VEL_X) &&
441 			INRANGE(mptr->pixel.y - y, CELL_HEIGHT / 2,
442 			  CELL_HEIGHT + GAP_HEIGHT + 1))
443 		      {
444 			new = 0;
445 			break;
446 		      }
447 		    else if(mptr->type & 2 && !mptr->dir &&
448 			INRANGE(mptr->pixel.y - y, 0, CELL_HEIGHT + 1) &&
449 			INRANGE(mptr->pixel.x - x, 1 - CELL_WIDTH / 2,
450 			  CELL_WIDTH / 2))
451 		      {
452 			new = 0;
453 			break;
454 		      }
455 		}
456 		/*}}}*/
457 	      aptr->state = new;
458 	      if(new == 0)
459 		/*{{{  doesn't fall*/
460 		{
461 		  aptr->list = NULL;
462 		  if(aptr->offset.y)
463 		    {
464 		      aptr->offset.y += APPLE_SINK_Y;
465 		      aptr->pixel.y += APPLE_SINK_Y;
466 		      if(aptr->offset.y >= CELL_HEIGHT + GAP_HEIGHT)
467 			{
468 			  aptr->pixel.y -= aptr->offset.y -
469 			      (CELL_HEIGHT + GAP_HEIGHT);
470 			  aptr->offset.y = 0;
471 			  aptr->cell.y++;
472 			}
473 		    }
474 		}
475 		/*}}}*/
476 	      else if(new == 1)
477 		/*{{{  rock*/
478 		{
479 		  aptr->list = NULL;
480 		  if(old != new)
481 		    aptr->count = APPLE_ROCK_DELAY;
482 		}
483 		/*}}}*/
484 	      else if(new == 2)
485 		/*{{{  start to fall*/
486 		{
487 		  MONSTER   *mptr;
488 		  MONSTER   *prev;
489 
490 		  aptr->count = APPLE_ACC;
491 		  aptr->distance = 0;
492 		  if(!cptr[offset].visit || aptr->offset.y > 0)
493 		    {
494 		      aptr->cell.y += 1;
495 		      aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT;
496 		    }
497 		  aptr->cell.x += offset;
498 		  aptr->offset.x -= offset * (CELL_WIDTH + GAP_WIDTH);
499 		  for(prev = NULL, mptr = aptr->list; mptr;
500 		      prev = mptr, mptr = mptr->list)
501 		    if(mptr->squished)
502 		      /*{{{  already put on a squish list*/
503 		      {
504 			if(prev)
505 			  prev->list = NULL;
506 			else
507 			  aptr->list = NULL;
508 			break;
509 		      }
510 		      /*}}}*/
511 		    else
512 		      {
513 			squish_monster(mptr);
514 			if(mptr->pixel.y > aptr->pixel.y)
515 			  mptr->pixel.y = aptr->pixel.y;
516 			mptr->pixel.y += CELL_HEIGHT - CELL_HEIGHT / 4;
517 			aptr->monsters++;
518 			aptr->distance = APPLE_FALL_SPLIT + 1;
519 		      }
520 		  panic_monsters(aptr->cell.x, aptr->cell.y,
521 		      BOARDCELL(aptr->cell.x, aptr->cell.y));
522 		}
523 		/*}}}*/
524 	      else
525 		aptr->count = APPLE_SPLIT_DELAY;
526 	      break;
527 	    }
528 	    /*}}}*/
529 	    /*{{{  case 2: (fall)*/
530 	    case 2:
531 	    {
532 	      int       j;
533 	      APPLE     *optr;
534 
535 	      /*{{{  horizontal movement*/
536 	      if(!aptr->push)
537 		{
538 		  int     shift;
539 		  int     x;
540 
541 		  shift = x = 0;
542 		  /*{{{  desired direction*/
543 		  if(aptr->offset.x < 0)
544 		    {
545 		      if(aptr->offset.x < cptr->depths[2])
546 		       {
547 			  shift = APPLE_VEL_X;
548 			  x = aptr->pixel.x + CELL_WIDTH;
549 			}
550 		    }
551 		  else if(aptr->offset.x > 0)
552 		    {
553 		      if(aptr->offset.x > cptr->depths[3])
554 			{
555 			  shift = -APPLE_VEL_X;
556 			  x = aptr->pixel.x - CELL_WIDTH - APPLE_VEL_X;
557 			}
558 		    }
559 		  /*}}}*/
560 		  if(shift)
561 		    /*{{{  move if not blocked*/
562 		    {
563 		      MONSTER   *mptr;
564 		      unsigned  count;
565 
566 		      for(mptr = monster.list, count = monster.monsters;
567 			  count--; mptr++)
568 			if((mptr->type == 1 || mptr->type == 2) &&
569 			    !mptr->shot && !mptr->squished &&
570 			    INRANGE(mptr->pixel.x - x, 0, APPLE_VEL_X) &&
571 			    INRANGE(mptr->pixel.y - aptr->pixel.y,
572 			      VEL_Y - CELL_HEIGHT + 1, CELL_HEIGHT - VEL_Y))
573 			  {
574 			    shift = 0;
575 			    break;
576 			  }
577 		      if(shift)
578 			{
579 			  aptr->offset.x += shift;
580 			  aptr->pixel.x += shift;
581 			}
582 		    }
583 		    /*}}}*/
584 		}
585 	      /*}}}*/
586 	      /*{{{  bashes into another?*/
587 	      {
588 		int       x, y;
589 
590 		x = aptr->pixel.x;
591 		y = aptr->pixel.y + aptr->count;
592 		for(optr = apple.list, j = apple.apples; j--; optr++)
593 		  if(optr != aptr && INRANGE(optr->pixel.x - x,
594 			1 - CELL_WIDTH, CELL_WIDTH) &&
595 		      INRANGE(optr->pixel.y +
596 			apple_sizes[optr->state].offset.y - y, 1,
597 			CELL_HEIGHT - APPLE_VEL_Y) &&
598 		      (optr->state ||
599 			BOARDCELL(optr->cell.x, optr->cell.y)->visit))
600 		    {
601 		      if(optr->ghost || aptr->ghost)
602 			/* EMPTY */;
603 		      else if(optr->state < 2)
604 			{
605 			  optr->list = NULL;
606 			  optr->state = 3;
607 			  optr->count = APPLE_SPLIT_DELAY;
608 			}
609 		      else if(optr->state == 2)
610 			optr->distance = APPLE_FALL_SPLIT + 1;
611 		      break;
612 		    }
613 	      }
614 	      /*}}}*/
615 	      if(j >= 0)
616 		{
617 		  aptr->count = 0;
618 		  if(aptr->distance > APPLE_FALL_SPLIT)
619 		    {
620 		      aptr->state = 3;
621 		      aptr->count = APPLE_SPLIT_DELAY;
622 		    }
623 		  else
624 		    aptr->distance = 0;
625 		}
626 	      else
627 		{
628 		  CELL      *nptr;
629 
630 		  aptr->offset.y += aptr->count;
631 		  aptr->pixel.y += aptr->count;
632 		  aptr->distance += aptr->count;
633 		  aptr->count += APPLE_ACC;
634 		  if(aptr->count > APPLE_VEL_Y)
635 		    aptr->count = APPLE_VEL_Y;
636 		  nptr = drop_apple(aptr, cptr);
637 		  if(nptr)
638 		    panic_monsters(aptr->cell.x, aptr->cell.y, nptr);
639 		  else if(aptr->offset.y <= cptr[0].depths[1])
640 		    /*{{{  not broken*/
641 		    {
642 		      if(aptr->offset.y > 0 && cptr[CELL_STRIDE].visit)
643 			{
644 			  aptr->cell.y += 1;
645 			  aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT;
646 			}
647 		    }
648 		    /*}}}*/
649 		  else
650 		    /*{{{  stop falling*/
651 		    {
652 		      aptr->pixel.y += cptr[0].depths[1] - aptr->offset.y;
653 		      aptr->offset.y = cptr[0].depths[1];
654 		      assert(aptr->offset.y < CELL_HEIGHT + GAP_HEIGHT);
655 		      if(aptr->distance > APPLE_FALL_SPLIT ||
656 			  aptr->cell.y == CELLS_DOWN - 1)
657 			{
658 			  aptr->state = 3;
659 			  aptr->count = APPLE_SPLIT_DELAY;
660 			  aptr->ghost = 0;
661 			}
662 		      else
663 			{
664 			  assert(!aptr->list);
665 			  aptr->state = 0;
666 			}
667 		    }
668 		    /*}}}*/
669 		}
670 	      if(aptr->state < 6)
671 		/*{{{  crushed someone?*/
672 		{
673 		  unsigned  i;
674 		  MONSTER   *mptr;
675 		  int       x, y;
676 
677 		  x = aptr->pixel.x;
678 		  y = aptr->pixel.y;
679 		  for(mptr = monster.list, i = monster.monsters; i--; mptr++)
680 		    if(!mptr->squished && !mptr->shot && mptr->type < 5 &&
681 			(mptr->type != 4 ||
682 			(global.state != 4 && !aptr->ghost)) &&
683 			INRANGE(mptr->pixel.x - x, VEL_X - CELL_WIDTH,
684 			  CELL_WIDTH - VEL_X + 1) && INRANGE(mptr->pixel.y - y,
685 			    mptr->type & 2 && mptr->dir != 1 ?
686 			      -CELL_HEIGHT / 2 : VEL_Y,
687 			  CELL_HEIGHT / 2 + VEL_Y + 1))
688 		      {
689 			unsigned  squish;
690 
691 			if(!(mptr->type & 2) || mptr->chew ||
692 			    aptr->monsters || mptr->dir == 1 ||
693 			    global.state == 4)
694 			  squish = mptr->pixel.y - y >= VEL_Y;
695 			else if(!mptr->dir)
696 			  /*{{{  going up*/
697 			  {
698 			    squish = 0;
699 			    if(mptr->pixel.y - y >= -APPLE_VEL_Y &&
700 				INRANGE(mptr->pixel.x - x,
701 				  -VEL_X * 2, VEL_X * 2 + 1))
702 			      {
703 				aptr->chewed = 1;
704 				mptr->chew = 1;
705 				break;
706 			      }
707 			  }
708 			  /*}}}*/
709 			else if(mptr->dir == 2)
710 			  /*{{{  going left*/
711 			  {
712 			    squish = mptr->pixel.x - x + y - mptr->pixel.y <
713 				  CELL_WIDTH / 2;
714 			    if(!squish && mptr->pixel.x - x <= 2 * VEL_X)
715 			      {
716 				aptr->chewed = 1;
717 				mptr->chew = 1;
718 				break;
719 			      }
720 			  }
721 			  /*}}}*/
722 			else
723 			  /*{{{  going right*/
724 			  {
725 			    squish = x - mptr->pixel.x + y - mptr->pixel.y <
726 				  CELL_WIDTH /2;
727 			    if(!squish && x - mptr->pixel.x <= 2 * VEL_X)
728 			      {
729 				aptr->chewed = 1;
730 				mptr->chew = 1;
731 				break;
732 			      }
733 			  }
734 			  /*}}}*/
735 			if(squish)
736 			  /*{{{  squish it*/
737 			  {
738 			    mptr->list = aptr->list;
739 			    aptr->list = mptr;
740 			    if(mptr != &monster.list[0])
741 			      aptr->monsters++;
742 			    aptr->distance = APPLE_FALL_SPLIT + 1;
743 			    if(!aptr->state)
744 			      {
745 				aptr->state = 3;
746 				aptr->count = APPLE_SPLIT_DELAY;
747 			      }
748 			    squish_monster(mptr);
749 			  }
750 			  /*}}}*/
751 		      }
752 		}
753 		/*}}}*/
754 	      /*{{{  move the crushed monsters*/
755 	      {
756 		MONSTER   *mptr;
757 		unsigned  count;
758 
759 		count = 0; /* XXX DEBUG */
760 		for(mptr = aptr->list; mptr; mptr = mptr->list)
761 		  {
762 		    mptr->pixel.y = aptr->pixel.y + CELL_HEIGHT;
763 		    count += mptr->type != 4;
764 		  }
765 		assert(count == aptr->monsters);
766 	      }
767 	      /*}}}*/
768 	      break;
769 	    }
770 	    /*}}}*/
771 	    /*{{{  case 3: (split)*/
772 	    case 3:
773 	      if(!aptr->count--)
774 		{
775 		  aptr->state = 4;
776 		  aptr->count = APPLE_DECAY_DELAY;
777 		  assert(!aptr->monsters || aptr->list);
778 		  /*{{{  delete the crushed monsters*/
779 		  {
780 		    MONSTER   *mptr;
781 		    unsigned  count;
782 
783 		    count = 0; /* XXX */
784 		    for(mptr = aptr->list; mptr; mptr = mptr->list)
785 		      if(mptr->type != 4)
786 			{
787 			  mptr->type = 5;
788 			  count++;
789 			}
790 		    assert(count == aptr->monsters);
791 		  }
792 		  /*}}}*/
793 		  aptr->list = NULL;
794 		  if(aptr->monsters)
795 		    add_score(squish_scores[aptr->monsters >= SQUISH_SCORES ?
796 			SQUISH_SCORES - 1 : aptr->monsters],
797 			aptr->pixel.x + CELL_WIDTH / 2,
798 			aptr->pixel.y + (int)(apple_sizes[4].size.y / 2));
799 		  if(!aptr->offset.x && !aptr->offset.y && !global.diamond &&
800 		      global.state != 4 && chaotic() < DIAMOND_PROB)
801 		    {
802 		      global.diamond = 1;
803 		      spawn_monster(1, 6, 1, 1, aptr->cell.x, aptr->cell.y,
804 			  0, 0)->count = DIAMOND_DELAY;
805 		    }
806 		}
807 	      break;
808 	    /*}}}*/
809 	    /*{{{  case 4: (decay)*/
810 	    case 4:
811 	      if(!aptr->count--)
812 		{
813 		  aptr->state = 5;
814 		  aptr->count = APPLE_ROT_DELAY;
815 		}
816 	      break;
817 	    /*}}}*/
818 	    /*{{{  case 5: (rot)*/
819 	    case 5:
820 	      if(!aptr->count--)
821 		aptr->state = 6;
822 	      break;
823 	    /*}}}*/
824 	    /*{{{  default:*/
825 	    default:
826 	      assert(0);
827 	    /*}}}*/
828 	  }
829 	  apple.moving |= aptr->state;
830 	}
831       aptr->push = 0;
832     }
833   return;
834 }
835 /*}}}*/
836 /*{{{  void panic_monsters(cx, cy, cptr)*/
837 extern VOIDFUNC panic_monsters
838 FUNCARG((cx, cy, cptr),
839 	int       cx
840 ARGSEP  int       cy
841 ARGSEP  CELL      *cptr
842 )
843 /*
844  * looks underneath a newly falling apple and
845  * sees if there are any normal monsters to panic
846  */
847 {
848   MONSTER   *mptr;
849   unsigned  count;
850   unsigned  by;
851 
852   for(by = ++cy; cptr->depths[1] >= GAP_HEIGHT; cptr++)
853     by++;
854   for(mptr = &monster.list[1], count = monster.monsters - 1; count--; mptr++)
855     if(!mptr->squished && !mptr->shot && !mptr->type && !mptr->panic &&
856 	mptr->cell.x == cx && INRANGE(mptr->cell.y, cy, by) &&
857 	(mptr->offset.x >= 0 || mptr->dir != 2) &&
858 	(mptr->offset.x <= 0 || mptr->dir != 3))
859       mptr->panic = 1;
860   return;
861 }
862 /*}}}*/
863 /*{{{  APPLE *spawn_apple(cx, cy, ox, oy)*/
864 extern APPLE *spawn_apple
865 FUNCARG((cx, cy, ox, oy),
866 	int       cx
867 ARGSEP  int       cy
868 ARGSEP  int       ox
869 ARGSEP  int       oy
870 )
871 /*
872  * spawns a new apple in state 0
873  */
874 {
875   APPLE     *aptr;
876 
877   assert(apple.apples != APPLES);
878   aptr = &apple.list[apple.apples++];
879   aptr->cell.x = cx;
880   aptr->cell.y = cy;
881   aptr->offset.x = ox = ox / APPLE_VEL_X * APPLE_VEL_X;
882   aptr->offset.y = oy;
883   aptr->old_pixel.x = aptr->pixel.x = PIXELX(cx, ox);
884   aptr->old_pixel.y = aptr->pixel.y = PIXELY(cy, oy);
885   aptr->ghost = aptr->state = 0;
886   aptr->count = 1;
887   aptr->distance = 0;
888   aptr->monsters = 0;
889   aptr->list = NULL;
890   aptr->push = 0;
891   aptr->chewed = 0;
892   aptr->old_state = 7;
893   aptr->back = 0;
894   return aptr;
895 }
896 /*}}}*/
897 /*{{{  void squish_monster(mptr)*/
898 extern VOIDFUNC squish_monster
899 FUNCARG((mptr),
900 	MONSTER   *mptr
901 )
902 /*
903  * oh no, I've been squashed!
904  */
905 {
906   mptr->squished = 1;
907   new_face(mptr);
908   if(mptr == &monster.list[0])
909     mptr->shot = 1;
910   else
911     {
912       mptr->chew = 0;
913       if(mptr->type < 2)
914 	monster.normals--;
915       else if(mptr->type == 2)
916 	extra_dies();
917       else if(mptr->type == 3)
918 	monster.drones--;
919     }
920   return;
921 }
922 /*}}}*/
923