//========================================================================
EnemyTYPE :: EnemyTYPE ( )
:	num_enemies_left    		( 0 ),
	num_enemies_attacking   ( 0 ),
   num_enemies_per_level 	( 0 ),
   most_recent 				( NULL ),
   enemy_list        		( NULL ),
   enemy_bullets     		( )
{  }
//========================================================================
EnemyTYPE :: ~EnemyTYPE ( )
{
	DestroyEnemies ();
}
//========================================================================
void EnemyTYPE :: DestroyEnemies ( )
{
	EnemyNodeTYPE * scan;
	while ( enemy_list != NULL )
   {
     	scan = enemy_list;
      enemy_list = enemy_list -> next;
  		delete scan;
  	}
   most_recent = enemy_list = NULL;
   num_enemies_left = num_enemies_attacking = num_enemies_per_level = 0;
}
//========================================================================
void EnemyTYPE :: UpdateAI ( int plane_x, int plane_y )
{
	EnemyNodeTYPE * scan = enemy_list;
   for (; scan != NULL; scan = scan -> next)
   {
      if ( scan -> health <= 0 && scan->explode_stage == ENEMY_EXPLODE_STAGES - 1 )
      	DeleteNode ( scan );
      else
      {
			if ( scan -> attacking )
	      {
   	    	if ( (scan -> xpos >= plane_x && scan -> xpos < plane_x + PLANE_WIDTH) || (scan -> xpos + EnemyWidths [scan->TypeOfEnemy] >= plane_x && scan -> xpos + EnemyWidths [scan->TypeOfEnemy] < plane_x + PLANE_WIDTH))
      	   {
         		if ( timer - scan -> TimeOfLastFired > BULLET_PAUSE && (plane_y > scan -> ypos + EnemyHeights [scan->TypeOfEnemy] && timer - scan -> TimeOfLastFired >= BULLET_PAUSE))
            	{
	            	scan -> TimeOfLastFired = timer;
		         	enemy_bullets.Fire (	scan -> xpos, scan->ypos, XBulletVelocities [scan->weapon], -(YBulletVelocities [scan->weapon]), scan->weapon );
					}
				}

   	      switch ( scan->state )
      	   {
   				case ATTACKING_1 : Attack_1 ( scan );
	          							 break;
            	case ATTACKING_2 : Attack_2 ( scan );
	              						 break;
   	         case ATTACKING_3 : Attack_3 ( scan,plane_x );
      	        						 break;
         	   case ATTACKING_4   : Attack_4 ( scan );
            	  						 break;
	            case ATTACKING_5   : Attack_5 ( scan );
   	           					    break;
      	      case ATTACKING_6   : Attack_5 ( scan );
         	     						 break;
	            default          : break;
				}
      	   scan -> state_stage ++;
            if ( (scan -> ypos < -80 || scan -> ypos > SCREEN_HEIGHT) ||
            (scan -> xpos + EnemyWidths [scan->TypeOfEnemy] < 0 || scan -> xpos > SCREEN_WIDTH ) )
         	{
					scan -> attacking = false;
         		num_enemies_attacking --;
				}
         }
		}
   }
}
//========================================================================
void EnemyTYPE :: LoadEnemies ( char * level_file, char * sprite_file, char * bullet_file, char * explode_file )
{
	DestroyEnemies ();
   explode_images.LoadImages ( explode_file );
   enemy_images.LoadImages ( sprite_file );
   enemy_bullets.LoadWeapon ( bullet_file );
   ifstream enemy_file;
   enemy_file.open ( level_file );
   enemy_file >> num_enemies_per_level;
   num_enemies_left = num_enemies_per_level;

   enemy_list = new EnemyNodeTYPE;
   EnemyNodeTYPE * scan = enemy_list;

   int enemy_int;
   enemy_file >> enemy_int >> scan->health;
   scan->TypeOfEnemy = IntToEnemy(enemy_int);
   scan->weapon = IntToWeapon (enemy_int);
   scan -> health = EnemyLifeValues [ scan->TypeOfEnemy ];

  	for ( int index = 1; index < num_enemies_per_level; index++ )
	{
		scan -> next = new EnemyNodeTYPE (scan,NULL);
      scan = scan -> next;
	   enemy_file >> enemy_int >> scan->health;
      scan->TypeOfEnemy = IntToEnemy(enemy_int);
	   scan->weapon = IntToWeapon (enemy_int);
      scan -> health = EnemyLifeValues [ scan->TypeOfEnemy ];
   }
   enemy_file.close (  );

   myEnemyMasks.resize ( enemy_images.Length() );
   init_sp_bb ( myEnemyMasks );

   for ( int i = 0; i < myEnemyMasks.length(); i++ )
	   mk_spr_mask (enemy_images.GetImage(i), myEnemyMasks[i] );

}
//========================================================================
void EnemyTYPE :: AddAttacker (  )
{
	if  (num_enemies_left == num_enemies_per_level && num_enemies_attacking == 0 )
   	most_recent = enemy_list;

	while ( most_recent != NULL && most_recent -> attacking )
		most_recent = most_recent -> next;

   if ( most_recent != NULL )
   {
	   most_recent->xpos = rand () % ( SCREEN_WIDTH - 72) ;
   	most_recent->ypos = INIT_ENEMY_Y;
     	num_enemies_attacking++;
		most_recent -> attacking = true;
	}
   else
     most_recent = enemy_list;
}
//========================================================================
void EnemyTYPE :: SetHealth ( int index, int new_health )
{
	EnemyNodeTYPE * scan = enemy_list;
	for ( int i = 0; i < index ; i++)
   	scan = scan -> next;
   scan -> health = new_health;
}
//========================================================================
int EnemyTYPE :: GetHealth ( int index )
{
	EnemyNodeTYPE * scan = enemy_list;
	for ( int i = 0; i < index ; i++)
   	scan = scan -> next;
	return ( scan -> health );
}
//========================================================================
void EnemyTYPE :: Display ( BITMAP * buffer )
{
   for ( EnemyNodeTYPE * scan = enemy_list; scan != NULL; scan = scan -> next )
   {
   	if ( scan -> attacking )
			draw_sprite ( buffer,enemy_images.GetImage(scan->TypeOfEnemy), scan->xpos, scan->ypos );
      else if ( scan -> dead && scan -> explode_stage != ENEMY_EXPLODE_STAGES - 1 )
     	{
         draw_sprite ( buffer,explode_images.GetImage ( scan -> explode_stage ), scan->xpos, scan->ypos );
			scan -> explode_stage ++;
     	}
	}
   enemy_bullets.UpdateAndDisplayShot (buffer);
}
//========================================================================
int EnemyTYPE :: GetNumEnemiesLeft   ( )
{
	return ( num_enemies_left );
}
//========================================================================
int EnemyTYPE :: GetTotalNumEnemies  ( )
{
   return ( num_enemies_per_level );
}
//========================================================================
EnemyNodeTYPE * EnemyTYPE :: GetEnemyList ( )
{
	return enemy_list;
}
//========================================================================
BulletTYPE * EnemyTYPE ::  GetBullets ()
{
	return &enemy_bullets;
}
//========================================================================
void EnemyTYPE :: Attack_1 ( EnemyNodeTYPE * enemy )
{
   if ( (enemy->xpos >= SCREEN_WIDTH - 75 && enemy->dx > 0 )|| (enemy->xpos <= 5 && enemy->dx < 0))
   	enemy->dx = -(enemy->dx) ;
	else if ( enemy -> state_stage % 20 == 0 )
   {
	   if( enemy->xpos < SCREEN_WIDTH / 2 )
   	{
      	if ( enemy -> xpos <= 160 && enemy -> dx < 0 )
				enemy->dx /= 2;
         else if ( enemy ->dx < 8 && enemy ->dx > -8 )
            enemy->dx *= 2;
         if ( enemy->dx == 0 )
         	enemy-> dx = 1;
		}
   	else
	   {
			if ( enemy -> xpos >= SCREEN_WIDTH - 160 && enemy -> dx > 0 )
				enemy->dx /= 2;
         else if ( enemy ->dx < 8 && enemy ->dx > -8 )
            enemy->dx *= 2;
         if ( enemy->dx == 0 )
         	enemy-> dx = 1;
	   }
	}
	enemy->ypos += enemy->dy;
	enemy->xpos += enemy->dx;
}
//=============================================================================
void EnemyTYPE :: Attack_2 ( EnemyNodeTYPE * enemy )
{
	if ( enemy -> ypos == INIT_ENEMY_Y )
   {
   	enemy -> dy = 4;
		if ( enemy -> xpos < SCREEN_WIDTH / 2 )
      	enemy -> dx = 3;
		else
			enemy -> dx = -3;
   }

   if ( (enemy -> ypos) % 160 == 0)
		enemy->dx = -(enemy->dx);

	enemy->ypos += enemy->dy;
	enemy->xpos += enemy->dx;
}
//=============================================================================
void EnemyTYPE :: Attack_3 ( EnemyNodeTYPE * enemy, int plane_x )
{
	if ( enemy -> ypos == INIT_ENEMY_Y )
   {
  		enemy -> dy = 6;
   	if ( enemy -> xpos < SCREEN_WIDTH / 2 )
      	enemy -> dx = 3;
		else
			enemy -> dx = -3;
   }
	else if ( enemy -> ypos > 175 )
   {
   	if ( enemy -> dy == 6)
      {
      	enemy -> dy = 4;
			if ( enemy -> xpos > plane_x  )
  	      	enemy -> dx = -10;
		   else
  	      	enemy -> dx = 10;
		}
      if ( enemy -> state_stage % 20 == 0 )
	      enemy -> dx /= 2;
   }
	enemy->ypos += enemy->dy;
	enemy->xpos += enemy->dx;
}
//=============================================================================
void EnemyTYPE :: Attack_4  ( EnemyNodeTYPE * enemy )
{
	if ( enemy -> ypos == INIT_ENEMY_Y )
   {
   	enemy -> dy = 4;
		if ( enemy -> xpos < SCREEN_WIDTH / 2 )
      	enemy -> dx = 3;
		else
			enemy -> dx = -3;
   }

   if ( (enemy -> ypos) % 160 == 0)
		enemy->dx = -(enemy->dx);

   if ( enemy-> ypos > 0 )
   {
   	if ( enemy -> state_stage % 40 == 0 )
      {
		   enemy-> dx = rand() % 13;
		   enemy-> dy = rand () %13;
      }

	   if ( enemy->dx > 7 )
	  	   enemy->dx = -rand ()%7;
		if ( enemy->dy > 7 )
			enemy->dy = -rand ()%7;
   }
   else
     	enemy-> dy = 4 ;

	enemy->ypos += enemy->dy;
	enemy->xpos += enemy->dx;

}
//=============================================================================
void EnemyTYPE :: Attack_5  ( EnemyNodeTYPE * enemy )
{
	if ( enemy -> ypos == INIT_ENEMY_Y )
   {
   	enemy -> dy = 4;
		if ( enemy -> xpos < SCREEN_WIDTH / 2 )
      	enemy -> dx = 3;
		else
			enemy -> dx = -3;
   }

   if ( (enemy -> ypos) % 160 == 0)
		enemy->dx = -(enemy->dx);

   if ( enemy-> ypos > 0 )
   {
   	if ( enemy -> state_stage % 30 == 0 )
      {
		   enemy-> dx = rand() % 13;
		   enemy-> dy = rand () %13;
      }

	   if ( enemy->dx > 6 )
	  	   enemy->dx = -rand ()%6;
		if ( enemy->dy > 6 )
			enemy->dy = -rand ()%6;
   }
   else
     	enemy-> dy = 3 ;

   if ( enemy->xpos + enemy->dx < 0 || enemy->xpos + enemy->dx + EnemyWidths [enemy->TypeOfEnemy] > SCREEN_WIDTH )
		enemy->dx = -(enemy->dx);
     
	enemy->xpos += enemy->dx;
	enemy->ypos += enemy->dy;
}
//=============================================================================
void EnemyTYPE :: Attack_6 ( EnemyNodeTYPE * enemy )
{

}
//=============================================================================
void EnemyTYPE :: DeleteNode ( EnemyNodeTYPE * scan )
{
	if ( scan == NULL )
   	return;

   if ( scan == most_recent )
   {
   	if ( most_recent -> next == NULL )
      	most_recent = enemy_list;
		else
	 	  most_recent = most_recent -> next;
	}

	if ( scan -> back == NULL )
   {
   	enemy_list = scan -> next;
      if ( scan -> next != NULL )
      	scan -> next -> back = NULL;
	}
   else
   {
   	if ( scan -> next == NULL )
     	  scan -> back -> next = NULL;
      else
      {
      	scan->back->next = scan -> next;
         scan->next->back = scan -> back;
      }
   }
	num_enemies_left --;
 	num_enemies_attacking --;
   delete scan;
}
//=============================================================================
int EnemyTYPE :: GetNumAttackers     ( )
{
	return num_enemies_attacking;
}
//=============================================================================
