/* Copyright (C) 1993, 1992 Nathan Sidwell */
/* RCS $Id: apple.c,v 4.10 1993/12/10 11:52:23 nathan Stable $ */
#include "xmris.h"
/*{{{  prototypes*/
static APPLE *apple_search PROTOARG((int, int, unsigned, unsigned, unsigned));
/*}}}*/
/*{{{  APPLE *apple_search(x, y, width, height, found)*/
static APPLE *apple_search
FUNCARG((x, y, width, height, found),
	int       x       /* x coord start */
ARGSEP  int       y       /* y coord start */
ARGSEP  unsigned  width   /* width of box */
ARGSEP  unsigned  height  /* height of box */
ARGSEP  unsigned  found   /* already found ones */
)
/*
 * looks for an apple in the specified box
 * and returns a ptr to it, if found
 */
{
  unsigned  i;
  APPLE     *aptr;
  
  for(aptr = apple.list, i = 0; i != apple.apples; i++, aptr++, found >>= 1)
    if(!(found & 1) && INRANGE(aptr->pixel.x + aptr->push - x, 0, width) &&
	INRANGE(aptr->pixel.y - y, 0, height))
      return aptr;
  return NULL;
}
/*}}}*/
/*{{{  int apple_stop(mptr, cptr)*/
extern int apple_stop
FUNCARG((mptr, cptr),
	MONSTER   *mptr
ARGSEP  CELL      *cptr
)
/*
 * sees if the monster is about to walk into an apple
 * returns 0 if clear, 1 if stopped
 * sets mptr->pause & mptr->stop as required
 * the apples and other monsters are altered
 * if they're pushed about
 * called before we've moved the monster
 */
{
  unsigned  stop;
  unsigned  pause;
  
  pause = stop = 0;
  switch(mptr->dir)
  {
    /*{{{  case 0: (up)*/
    case 0:
    {
      unsigned  i;
      APPLE     *aptr;
      int       px, py;
    
      px = mptr->pixel.x;
      py = mptr->pixel.y;
      for(aptr = apple.list, i = apple.apples; i--; aptr++)
	{
	  if(INRANGE(aptr->pixel.x + aptr->push - px,
		1 - CELL_WIDTH, CELL_WIDTH) &&
	      INRANGE(py - aptr->pixel.y, CELL_HEIGHT / 2,
	      CELL_HEIGHT + VEL_Y) && !aptr->ghost)
	    {
	      stop = 1;
	      break;
	    }
	}
      break;
    }
    /*}}}*/
    /*{{{  case 1: (down)*/
    case 1:
    {
      unsigned  i;
      APPLE     *aptr;
      int       px, py;
	
      px = mptr->pixel.x;
      py = mptr->pixel.y;
      for(aptr = apple.list, i = apple.apples; i--; aptr++)
	{
	  if(INRANGE(aptr->pixel.x + aptr->push - px,
	      1 - CELL_WIDTH, CELL_WIDTH) &&
	      INRANGE(aptr->pixel.y + apple_sizes[aptr->state].offset.y - py,
	      CELL_HEIGHT / 2, CELL_HEIGHT + VEL_Y) && !aptr->ghost)
	    {
	      stop = 1;
	      break;
	    }
	}
      break;
    }
    /*}}}*/
    /*{{{  case 2: (left)*/
    case 2:
    {
      unsigned  found;
      int       x, y;
      int       width;
      APPLE     *final;
	  
      found = 0;
      final = NULL;
      width = VEL_X;
      x = mptr->pixel.x - CELL_WIDTH + 1 - width;
      y = mptr->pixel.y - CELL_HEIGHT + VEL_Y;
      /*{{{  look for apple*/
      for(;;)
      {
	APPLE     *aptr;
	CELL      *cptr;
	      
	aptr = apple_search(x, y, (unsigned)width + CELL_WIDTH / 2,
	    2 * (CELL_HEIGHT - VEL_Y), found);
	if(!aptr)
	  break;
	else if(aptr->push || aptr->pixel.x - width < PIXELX(0, 0))
	  {
	    stop = 1;
	    break;
	  }
	else if(aptr->state == 2 &&
	    ((mptr->type != 1 && mptr->type != 4) ||
	    (aptr->offset.x < (cptr = BOARDCELL(aptr->cell.x, aptr->cell.y +
		(aptr->offset.y <= 0)))->depths[2] &&
		  !cptr[-1].visit)))
	  break;
	else
	  {
	    final = aptr;
	    found |= 1 << (aptr - apple.list);
	    width = aptr->pixel.x - x + 1;
	    width = (width + APPLE_VEL_X - 1) / APPLE_VEL_X * APPLE_VEL_X;
	    aptr->maypush = width;
	    x = aptr->pixel.x - CELL_WIDTH + 1 - width;
	    if(aptr->state != 2 && aptr->offset.y > 0 &&
		apple_search(x, aptr->pixel.y - aptr->offset.y + CELL_HEIGHT,
		  (unsigned)width, (unsigned)aptr->offset.y, found))
	      {
		stop = 1;
		break;
	      }
	    y = aptr->pixel.y - CELL_HEIGHT + VEL_Y;
	    if(!width || aptr->state == 2)
	      break;
	  }
      }
      /*}}}*/
      if(found && !stop)
	{
	  /*{{{  check if against monster*/
	  if(width)
	    {
	      unsigned  i;
	      MONSTER   *mptr;
	      MONSTER   *list;
	  
	      list = NULL;
	      for(mptr = monster.list, i = monster.monsters; i--; mptr++)
		{
		  if(!mptr->squished && !mptr->shot &&
		      INRANGE(mptr->pixel.x - x, 0, width + CELL_WIDTH) &&
		      INRANGE(mptr->pixel.y - y, 0, 2 * (CELL_HEIGHT - VEL_Y)))
		    {
		      if(mptr->type == 4)
			stop = 1;
		      else if(mptr->type == 1)
			{
			  if(mptr->dir & 2 ||
			      mptr->pixel.x - x >= width + CELL_WIDTH / 2)
			    stop = 1;
			}
		      else if(final->state < 2 && (!mptr->type || mptr->chew))
			{
			  CELL      *cptr;
			
			  cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
			  if(cptr->depths[2] <= mptr->offset.x - width ||
			      ((cptr->depths[1] || cptr->depths[0]) &&
			      mptr->offset.x >= 0))
			    {
			      mptr->list = list;
			      list = mptr;
			      mptr->push = -1;
			    }
			  else
			    stop = 1;
			}
		    }
		}
	      if(final->state < 2)
		final->list = list;
	    }
	  /*}}}*/
	  if(!stop)
	  {
	    pause = 1;
	    /*{{{  push the apples*/
	    {
	      unsigned  i;
	      APPLE     *aptr;
	    
	      for(aptr = apple.list, i = apple.apples;
		  i--; aptr++, found >>= 1)
		if(found & 1)
		  aptr->push = -aptr->maypush;
	    }
	    /*}}}*/
	  }
	}
      break;
    }
    /*}}}*/
    /*{{{  case 3: (right)*/
    case 3:
    {
      unsigned  found;
      int       x, y;
      int       width;
      APPLE     *final;
	  
      found = 0;
      final = NULL;
      width = VEL_X;
      x = mptr->pixel.x + CELL_WIDTH;
      y = mptr->pixel.y - CELL_HEIGHT + VEL_Y;
      /*{{{  look for apple*/
      for(;;)
      {
	APPLE       *aptr;
	      
	aptr = apple_search(x - CELL_WIDTH / 2, y,
	    (unsigned)width + CELL_WIDTH / 2,
	    2 * (CELL_HEIGHT - VEL_Y), found);
	if(!aptr)
	  break;
	else if(aptr->push ||
	    aptr->pixel.x + width > PIXELX(CELLS_ACROSS - 1, 0))
	  {
	    stop = 1;
	    break;
	  }
	else if(aptr->state == 2 && ((mptr->type != 1 && mptr->type != 4) ||
	    (aptr->offset.x > (cptr = BOARDCELL(aptr->cell.x, aptr->cell.y +
		(aptr->offset.y <= 0)))->depths[3] &&
		  !cptr[1].visit)))
	  break;
	else
	  {
	    final = aptr;
	    found |= 1 << (aptr - apple.list);
	    width -= aptr->pixel.x - x;
	    width = (width + APPLE_VEL_X - 1) / APPLE_VEL_X * APPLE_VEL_X;
	    aptr->maypush = width;
	    x = aptr->pixel.x + CELL_WIDTH;
	    if(aptr->state != 2 && aptr->offset.y > 0 &&
		apple_search(x, aptr->pixel.y - aptr->offset.y + CELL_HEIGHT,
		    (unsigned)width, (unsigned)aptr->offset.y, found))
	      {
		stop = 1;
		break;
	      }
	    y = aptr->pixel.y - CELL_HEIGHT + VEL_Y;
	    if(!width || aptr->state == 2)
	      break;
	  }
      }
      /*}}}*/
      if(found && !stop)
	{
	  /*{{{  check if against monster*/
	  if(width)
	    {
	      unsigned  i;
	      MONSTER   *mptr;
	      MONSTER   *list;
	      
	      list = NULL;
	      for(mptr = monster.list, i = monster.monsters; i--; mptr++)
		{
		  if(!mptr->squished && !mptr->shot &&
		      INRANGE(mptr->pixel.x - x, -CELL_WIDTH, width) &&
		      INRANGE(mptr->pixel.y - y, 0, 2 * (CELL_HEIGHT - VEL_Y)))
		    {
		      if(mptr->type == 4)
			stop = 1;
		      else if(mptr->type == 1)
			{
			  if(mptr->dir & 2 ||
			      mptr->pixel.x - x < -CELL_WIDTH / 2)
			    stop = 1;
			}
		      else if(final->state < 2 && (!mptr->type || mptr->chew))
			{
			  CELL      *cptr;
			
			  cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
			  if(cptr->depths[3] >= mptr->offset.x + width ||
			      ((cptr->depths[1] || cptr->depths[0]) &&
			      mptr->offset.x <= 0))
			    {
			      mptr->list = list;
			      list = mptr;
			      mptr->push = 1;
			    }
			  else
			    stop = 1;
			}
		    }
		}
	      if(final->state < 2)
		final->list = list;
	    }
	  /*}}}*/
	  if(!stop)
	    {
	      pause = 1;
	      /*{{{  push the apples*/
	      {
		unsigned  i;
		APPLE     *aptr;
	      
		for(aptr = apple.list, i = apple.apples; i--; aptr++, found >>= 1)
		  if(found & 1)
		    aptr->push = aptr->maypush;
	      }
	      /*}}}*/
	    }
	}
      break;
    }
    /*}}}*/
  }
  mptr->stop = stop;
  mptr->pause = pause;
  return (int)stop;
}
/*}}}*/
/*{{{  void move_apples()*/
extern VOIDFUNC move_apples FUNCARGVOID
/*
 * moves all the apples
 */
{
  APPLE     *aptr;
  unsigned  i;

  apple.moving = 0;
  for(aptr = apple.list, i = apple.apples; i--; aptr++)
    {
      CELL      *cptr;
  
      cptr = BOARDCELL(aptr->cell.x, aptr->cell.y);
      if(aptr->chewed)
	{
	  assert(!aptr->monsters);
	  aptr->state = 6;
	}
      else
	{
	  if(aptr->ghost)
	    aptr->ghost--;
	  /*{{{  pushed?*/
	  if(aptr->push)
	    {
	      aptr->pixel.x += aptr->push;
	      aptr->offset.x += aptr->push;
	      assert(!(aptr->offset.x % APPLE_VEL_X));
	      if(aptr->offset.x < -(CELL_WIDTH / 2))
		{
		  aptr->offset.x += CELL_WIDTH + GAP_WIDTH;
		  aptr->cell.x -= 1;
		  cptr -= 1;
		}
	      else if(aptr->offset.x > (CELL_WIDTH / 2))
		{
		  aptr->offset.x -= CELL_WIDTH + GAP_WIDTH;
		  aptr->cell.x += 1;
		  cptr += 1;
		}
	    }
	  /*}}}*/
	  switch(aptr->state)
	  {
	    /*{{{  case 0: (static) case 1: (rock)*/
	    case 0: case 1:
	    {
	      unsigned  old;
	      unsigned  new;
	      int       offset;
	    
	      old = aptr->state;
	      new = 0;
	      offset = 0;
	      if(aptr->offset.y < cptr->depths[1])
		new = 2;
	      else if(aptr->cell.y == CELLS_DOWN - 1)
		{
		  new = 3;
		  aptr->ghost = 0;
		}
	      else if(cptr[CELL_STRIDE].visit)
		new = 1;
	      else if(aptr->offset.y - cptr[CELL_STRIDE*2].depths[0] >=
		  CELL_HEIGHT + GAP_HEIGHT)
		new = 1;
	      else if(cptr[CELL_STRIDE + 1].visit &&
		  cptr[CELL_STRIDE + 1].depths[2] - aptr->offset.x <
		  -(CELL_WIDTH / 2))
		{
		  new = 1;
		  offset = 1;
		}
	      else if(cptr[CELL_STRIDE - 1].visit &&
		  cptr[CELL_STRIDE - 1].depths[3] - aptr->offset.x >
		  CELL_WIDTH / 2)
		{
		  new = 1;
		  offset = -1;
		}
	      if(new == 1 && old == 1 && !aptr->count--)
		new = 2;
	      if(new)
		/*{{{  check for supporting monster*/
		{
		  MONSTER   *mptr;
		  unsigned  count;
		  int       x, y;
		
		  x = aptr->pixel.x;
		  y = aptr->pixel.y;
		  for(mptr = monster.list, count = monster.monsters;
		      count--; mptr++)
		    if((mptr->type == 4 || mptr->type == 1) && !mptr->shot &&
			INRANGE(mptr->pixel.x - x, 1 + VEL_X - CELL_WIDTH,
			  CELL_WIDTH - VEL_X) &&
			INRANGE(mptr->pixel.y - y, CELL_HEIGHT / 2,
			  CELL_HEIGHT + GAP_HEIGHT + 1))
		      {
			new = 0;
			break;
		      }
		    else if(mptr->type & 2 && !mptr->dir &&
			INRANGE(mptr->pixel.y - y, 0, CELL_HEIGHT + 1) &&
			INRANGE(mptr->pixel.x - x, 1 - CELL_WIDTH / 2,
			  CELL_WIDTH / 2))
		      {
			new = 0;
			break;
		      }
		}
		/*}}}*/
	      aptr->state = new;
	      if(new == 0)
		/*{{{  doesn't fall*/
		{
		  aptr->list = NULL;
		  if(aptr->offset.y)
		    {
		      aptr->offset.y += APPLE_SINK_Y;
		      aptr->pixel.y += APPLE_SINK_Y;
		      if(aptr->offset.y >= CELL_HEIGHT + GAP_HEIGHT)
			{
			  aptr->pixel.y -= aptr->offset.y -
			      (CELL_HEIGHT + GAP_HEIGHT);
			  aptr->offset.y = 0;
			  aptr->cell.y++;
			}
		    }
		}
		/*}}}*/
	      else if(new == 1)
		/*{{{  rock*/
		{
		  aptr->list = NULL;
		  if(old != new)
		    aptr->count = APPLE_ROCK_DELAY;
		}
		/*}}}*/
	      else if(new == 2)
		/*{{{  start to fall*/
		{
		  MONSTER   *mptr;
		  MONSTER   *prev;
		
		  aptr->count = APPLE_ACC;
		  aptr->distance = 0;
		  if(!cptr[offset].visit || aptr->offset.y > 0)
		    {
		      aptr->cell.y += 1;
		      aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT;
		    }
		  aptr->cell.x += offset;
		  aptr->offset.x -= offset * (CELL_WIDTH + GAP_WIDTH);
		  for(prev = NULL, mptr = aptr->list; mptr;
		      prev = mptr, mptr = mptr->list)
		    if(mptr->squished)
		      /*{{{  already put on a squish list*/
		      {
			if(prev)
			  prev->list = NULL;
			else
			  aptr->list = NULL;
			break;
		      }
		      /*}}}*/
		    else
		      {
			squish_monster(mptr);
			if(mptr->pixel.y > aptr->pixel.y)
			  mptr->pixel.y = aptr->pixel.y;
			mptr->pixel.y += CELL_HEIGHT - CELL_HEIGHT / 4;
			aptr->monsters++;
			aptr->distance = APPLE_FALL_SPLIT + 1;
		      }
		  panic_monsters(aptr->cell.x, aptr->cell.y,
		      BOARDCELL(aptr->cell.x, aptr->cell.y));
		}
		/*}}}*/
	      else
		aptr->count = APPLE_SPLIT_DELAY;
	      break;
	    }
	    /*}}}*/
	    /*{{{  case 2: (fall)*/
	    case 2:
	    {
	      int       j;
	      APPLE     *optr;
	    
	      /*{{{  horizontal movement*/
	      if(!aptr->push)
		{
		  int     shift;
		  int     x;
		  
		  shift = x = 0;
		  /*{{{  desired direction*/
		  if(aptr->offset.x < 0)
		    {
		      if(aptr->offset.x < cptr->depths[2])
		       {
			  shift = APPLE_VEL_X;
			  x = aptr->pixel.x + CELL_WIDTH;
			}
		    }
		  else if(aptr->offset.x > 0)
		    {
		      if(aptr->offset.x > cptr->depths[3])
			{
			  shift = -APPLE_VEL_X;
			  x = aptr->pixel.x - CELL_WIDTH - APPLE_VEL_X;
			}
		    }
		  /*}}}*/
		  if(shift)
		    /*{{{  move if not blocked*/
		    {
		      MONSTER   *mptr;
		      unsigned  count;
		      
		      for(mptr = monster.list, count = monster.monsters;
			  count--; mptr++)
			if((mptr->type == 1 || mptr->type == 2) &&
			    !mptr->shot && !mptr->squished &&
			    INRANGE(mptr->pixel.x - x, 0, APPLE_VEL_X) &&
			    INRANGE(mptr->pixel.y - aptr->pixel.y,
			      VEL_Y - CELL_HEIGHT + 1, CELL_HEIGHT - VEL_Y))
			  {
			    shift = 0;
			    break;
			  }
		      if(shift)
			{
			  aptr->offset.x += shift;
			  aptr->pixel.x += shift;
			}
		    }
		    /*}}}*/
		}
	      /*}}}*/
	      /*{{{  bashes into another?*/
	      {
		int       x, y;
	      
		x = aptr->pixel.x;
		y = aptr->pixel.y + aptr->count;
		for(optr = apple.list, j = apple.apples; j--; optr++)
		  if(optr != aptr && INRANGE(optr->pixel.x - x,
			1 - CELL_WIDTH, CELL_WIDTH) &&
		      INRANGE(optr->pixel.y +
			apple_sizes[optr->state].offset.y - y, 1,
			CELL_HEIGHT - APPLE_VEL_Y) &&
		      (optr->state ||
			BOARDCELL(optr->cell.x, optr->cell.y)->visit))
		    {
		      if(optr->ghost || aptr->ghost)
			/* EMPTY */;
		      else if(optr->state < 2)
			{
			  optr->list = NULL;
			  optr->state = 3;
			  optr->count = APPLE_SPLIT_DELAY;
			}
		      else if(optr->state == 2)
			optr->distance = APPLE_FALL_SPLIT + 1;
		      break;
		    }
	      }
	      /*}}}*/
	      if(j >= 0)
		{
		  aptr->count = 0;
		  if(aptr->distance > APPLE_FALL_SPLIT)
		    {
		      aptr->state = 3;
		      aptr->count = APPLE_SPLIT_DELAY;
		    }
		  else
		    aptr->distance = 0;
		}
	      else
		{
		  CELL      *nptr;
	    
		  aptr->offset.y += aptr->count;
		  aptr->pixel.y += aptr->count;
		  aptr->distance += aptr->count;
		  aptr->count += APPLE_ACC;
		  if(aptr->count > APPLE_VEL_Y)
		    aptr->count = APPLE_VEL_Y;
		  nptr = drop_apple(aptr, cptr);
		  if(nptr)
		    panic_monsters(aptr->cell.x, aptr->cell.y, nptr);
		  else if(aptr->offset.y <= cptr[0].depths[1])
		    /*{{{  not broken*/
		    {
		      if(aptr->offset.y > 0 && cptr[CELL_STRIDE].visit)
			{
			  aptr->cell.y += 1;
			  aptr->offset.y -= CELL_HEIGHT + GAP_HEIGHT;
			}
		    }
		    /*}}}*/
		  else
		    /*{{{  stop falling*/
		    {
		      aptr->pixel.y += cptr[0].depths[1] - aptr->offset.y;
		      aptr->offset.y = cptr[0].depths[1];
		      assert(aptr->offset.y < CELL_HEIGHT + GAP_HEIGHT);
		      if(aptr->distance > APPLE_FALL_SPLIT ||
			  aptr->cell.y == CELLS_DOWN - 1)
			{
			  aptr->state = 3;
			  aptr->count = APPLE_SPLIT_DELAY;
			  aptr->ghost = 0;
			}
		      else
			{
			  assert(!aptr->list);
			  aptr->state = 0;
			}
		    }
		    /*}}}*/
		}
	      if(aptr->state < 6)
		/*{{{  crushed someone?*/
		{
		  unsigned  i;
		  MONSTER   *mptr;
		  int       x, y;
		
		  x = aptr->pixel.x;
		  y = aptr->pixel.y;
		  for(mptr = monster.list, i = monster.monsters; i--; mptr++)
		    if(!mptr->squished && !mptr->shot && mptr->type < 5 &&
			(mptr->type != 4 ||
			(global.state != 4 && !aptr->ghost)) &&
			INRANGE(mptr->pixel.x - x, VEL_X - CELL_WIDTH,
			  CELL_WIDTH - VEL_X + 1) && INRANGE(mptr->pixel.y - y,
			    mptr->type & 2 && mptr->dir != 1 ?
			      -CELL_HEIGHT / 2 : VEL_Y,
			  CELL_HEIGHT / 2 + VEL_Y + 1))
		      {
			unsigned  squish;
			
			if(!(mptr->type & 2) || mptr->chew ||
			    aptr->monsters || mptr->dir == 1 ||
			    global.state == 4)
			  squish = mptr->pixel.y - y >= VEL_Y;
			else if(!mptr->dir)
			  /*{{{  going up*/
			  {
			    squish = 0;
			    if(mptr->pixel.y - y >= -APPLE_VEL_Y &&
				INRANGE(mptr->pixel.x - x,
				  -VEL_X * 2, VEL_X * 2 + 1))
			      {
				aptr->chewed = 1;
				mptr->chew = 1;
				break;
			      }
			  }
			  /*}}}*/
			else if(mptr->dir == 2)
			  /*{{{  going left*/
			  {
			    squish = mptr->pixel.x - x + y - mptr->pixel.y <
				  CELL_WIDTH / 2;
			    if(!squish && mptr->pixel.x - x <= 2 * VEL_X)
			      {
				aptr->chewed = 1;
				mptr->chew = 1;
				break;
			      }
			  }
			  /*}}}*/
			else
			  /*{{{  going right*/
			  {
			    squish = x - mptr->pixel.x + y - mptr->pixel.y <
				  CELL_WIDTH /2;
			    if(!squish && x - mptr->pixel.x <= 2 * VEL_X)
			      {
				aptr->chewed = 1;
				mptr->chew = 1;
				break;
			      }
			  }
			  /*}}}*/
			if(squish)
			  /*{{{  squish it*/
			  {
			    mptr->list = aptr->list;
			    aptr->list = mptr;
			    if(mptr != &monster.list[0])
			      aptr->monsters++;
			    aptr->distance = APPLE_FALL_SPLIT + 1;
			    if(!aptr->state)
			      {
				aptr->state = 3;
				aptr->count = APPLE_SPLIT_DELAY;
			      }
			    squish_monster(mptr);
			  }
			  /*}}}*/
		      }
		}
		/*}}}*/
	      /*{{{  move the crushed monsters*/
	      {
		MONSTER   *mptr;
		unsigned  count;
		  
		count = 0; /* XXX DEBUG */
		for(mptr = aptr->list; mptr; mptr = mptr->list)
		  {
		    mptr->pixel.y = aptr->pixel.y + CELL_HEIGHT;
		    count += mptr->type != 4;
		  }
		assert(count == aptr->monsters);
	      }
	      /*}}}*/
	      break;
	    }
	    /*}}}*/
	    /*{{{  case 3: (split)*/
	    case 3:
	      if(!aptr->count--)
		{
		  aptr->state = 4;
		  aptr->count = APPLE_DECAY_DELAY;
		  assert(!aptr->monsters || aptr->list);
		  /*{{{  delete the crushed monsters*/
		  {
		    MONSTER   *mptr;
		    unsigned  count;
		      
		    count = 0; /* XXX */
		    for(mptr = aptr->list; mptr; mptr = mptr->list)
		      if(mptr->type != 4)
			{
			  mptr->type = 5;
			  count++;
			}
		    assert(count == aptr->monsters);
		  }
		  /*}}}*/
		  aptr->list = NULL;
		  if(aptr->monsters)
		    add_score(squish_scores[aptr->monsters >= SQUISH_SCORES ?
			SQUISH_SCORES - 1 : aptr->monsters],
			aptr->pixel.x + CELL_WIDTH / 2,
			aptr->pixel.y + (int)(apple_sizes[4].size.y / 2));
		  if(!aptr->offset.x && !aptr->offset.y && !global.diamond &&
		      global.state != 4 && chaotic() < DIAMOND_PROB)
		    {
		      global.diamond = 1;
		      spawn_monster(1, 6, 1, 1, aptr->cell.x, aptr->cell.y,
			  0, 0)->count = DIAMOND_DELAY;
		    }
		}
	      break;
	    /*}}}*/
	    /*{{{  case 4: (decay)*/
	    case 4:
	      if(!aptr->count--)
		{
		  aptr->state = 5;
		  aptr->count = APPLE_ROT_DELAY;
		}
	      break;
	    /*}}}*/
	    /*{{{  case 5: (rot)*/
	    case 5:
	      if(!aptr->count--)
		aptr->state = 6;
	      break;
	    /*}}}*/
	    /*{{{  default:*/
	    default:
	      assert(0);
	    /*}}}*/
	  }
	  apple.moving |= aptr->state;
	}
      aptr->push = 0;
    }
  return;
}
/*}}}*/
/*{{{  void panic_monsters(cx, cy, cptr)*/
extern VOIDFUNC panic_monsters
FUNCARG((cx, cy, cptr),
	int       cx
ARGSEP  int       cy
ARGSEP  CELL      *cptr
)
/*
 * looks underneath a newly falling apple and
 * sees if there are any normal monsters to panic
 */
{
  MONSTER   *mptr;
  unsigned  count;
  unsigned  by;
  
  for(by = ++cy; cptr->depths[1] >= GAP_HEIGHT; cptr++)
    by++;
  for(mptr = &monster.list[1], count = monster.monsters - 1; count--; mptr++)
    if(!mptr->squished && !mptr->shot && !mptr->type && !mptr->panic &&
	mptr->cell.x == cx && INRANGE(mptr->cell.y, cy, by) &&
	(mptr->offset.x >= 0 || mptr->dir != 2) &&
	(mptr->offset.x <= 0 || mptr->dir != 3))
      mptr->panic = 1;
  return;
}
/*}}}*/
/*{{{  APPLE *spawn_apple(cx, cy, ox, oy)*/
extern APPLE *spawn_apple
FUNCARG((cx, cy, ox, oy),
	int       cx
ARGSEP  int       cy
ARGSEP  int       ox
ARGSEP  int       oy
)
/*
 * spawns a new apple in state 0
 */
{
  APPLE     *aptr;

  assert(apple.apples != APPLES);
  aptr = &apple.list[apple.apples++];
  aptr->cell.x = cx;
  aptr->cell.y = cy;
  aptr->offset.x = ox = ox / APPLE_VEL_X * APPLE_VEL_X;
  aptr->offset.y = oy;
  aptr->old_pixel.x = aptr->pixel.x = PIXELX(cx, ox);
  aptr->old_pixel.y = aptr->pixel.y = PIXELY(cy, oy);
  aptr->ghost = aptr->state = 0;
  aptr->count = 1;
  aptr->distance = 0;
  aptr->monsters = 0;
  aptr->list = NULL;
  aptr->push = 0;
  aptr->chewed = 0;
  aptr->old_state = 7;
  aptr->back = 0;
  return aptr;
}
/*}}}*/
/*{{{  void squish_monster(mptr)*/
extern VOIDFUNC squish_monster
FUNCARG((mptr),
	MONSTER   *mptr
)
/*
 * oh no, I've been squashed!
 */
{
  mptr->squished = 1;
  new_face(mptr);
  if(mptr == &monster.list[0])
    mptr->shot = 1;
  else
    {
      mptr->chew = 0;
      if(mptr->type < 2)
	monster.normals--;
      else if(mptr->type == 2)
	extra_dies();
      else if(mptr->type == 3)
	monster.drones--;
    }
  return;
}
/*}}}*/
