/*
 * Level.c - Level handling crap
 * By: Odis
 */
#include <windows.h>
#include <math.h>
#include <ctype.h>
#include "main.h"
#include "game.h"

/* externs */
unsigned char level_buf[LEVELS][MSL];

/* levels */
/******* LEVELS ********/

unsigned char level_buf[LEVELS][MSL]={
"\
#LEVEL \
Num 0 \
Screen 640 480 \
Bounds 0 0 PRGW PRGH \
End \
\
#BITMAP \
GENERIC \
Width 10 \
Height 10 \
RGB 240 120 60 \
Name bmp1 \
End \
\
#BITMAP \
GENERIC \
Width 10 \
Height 10 \
RGB 150 150 150 \
Name bmp2 \
End \
\
#BITMAP \
GENERIC \
Width 10 \
Height 10 \
RGB 60 200 90 \
Name bmp3 \
End \
\
#BITMAP \
GENERIC \
Width 10 \
Height 10 \
RGB 10 0 200 \
Name bmp4 \
End \
\
#SPRITE \
Name square1 \
Bitmap bmp1 \
Velocity 1-1 5-5 \
Position POINT 235 296 \
Type PLAYER \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 1 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square2 \
Bitmap bmp2 \
Velocity 3-3 8-8 \
Position POINT 100 300 \
Type ENEMY \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 0 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square3 \
Bitmap bmp3 \
Velocity 3-3 2-2 \
Position POINT 250 5 \
Type BOSS \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 2 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square4 \
Bitmap bmp4 \
Velocity 4-4 2-2 \
Position POINT 90 100 \
Type PROJECTILE \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 3 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square5 \
Bitmap bmp1 \
Velocity 2-2 5-5 \
Position POINT 130 17 \
Type PROJECTILE \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 3 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square6 \
Bitmap bmp2 \
Velocity 1-7 1-3 \
Position POINT 400 400 \
Type PROJECTILE \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 3 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square7 \
Bitmap bmp3 \
Velocity 3-3 1-9 \
Position POINT 600 100 \
Type PROJECTILE \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 3 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#SPRITE \
Name square8 \
Bitmap bmp4 \
Velocity 5-6 7-9 \
Position POINT 620 400 \
Type PROJECTILE \
Bounds 0 0 PRGW PRGH \
Hidden FALSE \
Drag TRUE \
Gravity FALSE \
Z 3 \
Action WRAP \
Direction LEFT \
Proto FALSE \
Dims 10 10 \
Frames 1 \
Delay 0 \
End \
\
#BG \
COLOR 0 0 0 \
Simmune n/a \
End \
\
#END \
"
/* end of level0 */
};
/* end levels */

/*
example bitmap
#BITMAP \
GENERIC \
Width 500 \
Height 400 \
RGB 250 120 10 \
Name bg \
End \

example level

#BG \
IMAGE \
bg \
End \
\
\
#SPRITE \
Name basket \
Bitmap basket \
Velocity 0-0 0-0 \
Position POINT 235 296 \
Type PLAYER \
Bounds 0 50 500 360 \
Hidden FALSE \
Drag FALSE \
Gravity FALSE \
Z 2 \
Action STOP \
Direction LEFT \
Proto FALSE \
Dims 29 8 \
Frames 1 \
Delay 0 \
End \
\
#LEVEL \
Num 0 \
Bounds 0 0 500 400 \
End \
\
#END \
*/

/*...local functions?!?! */
LEVEL *parse_level( char *obuf );
char *read_level( int level );

/* supports! */
int get_obj_state( char *word );

/*** Support Functions ***/
int get_obj_state( char *word )
{
   switch( tolower( word[0] ) )
   {
      default:
      case 'n':
         return NONE;

      case 's':
         return SOLID;
         
      case 'k':
         return KILL;
         
      case 'c':
         if ( !stricmp( word, "CLICK" ) )
            return CLICK;
         else
            return CLIMB;

      case 'e':
           return EXIT;
   }
}

/* if we are managing the population of this sprite, lets subtract */
void subtract_from_population( char *name, LEVEL *level )
{
    SPRITE_INFO *info = NULL;
    
    for ( info = level->first_info; info != NULL; info = info->next )
    {
        if ( !stricmp( name, info->name ) )
        {
            info->sprites[CURRENT]--;
            return;
        }
    }
}

OBJ *is_point_in_obj(int x, int y, LEVEL *level)
{
  OBJ *obj;
  POINT pt;
  
  pt.x = x+lvl->pos.x;
  pt.y = y+lvl->pos.y;

  for ( obj = level->first_obj; obj != NULL; obj = obj->next )
  {
    if ( PtInRect(&obj->bounds, pt ) != 0 )
     return obj;
  }

  return NULL;
}
/* End Support Functions */

/**************/
LEVEL *change_level( LEVEL *level, int num )
{
  LEVEL *l = NULL;
  
  clean_level( level, FALSE ); /* get rid of old level */
  
  l = load_level( num );
  
  populate_level( l );
  
  if ( l->pos.x == 0 && l->pos.y == 0 && (psprite != NULL))
  {
   POINT pos;
   SPRITE *bskt = psprite; /* player sprite */
   
   pos.x = (bskt->position.x-(PRG_WIDTH/2));
   pos.y = (bskt->position.y-(PRG_HEIGHT/2));

        if ( pos.x < 0 )
         pos.x = 0;
        else if ( pos.x+PRG_WIDTH > level->bounds.right )
         pos.x = level->bounds.right-PRG_WIDTH;

        if ( pos.y < 0 )
         pos.y = 0;
        else if ( pos.y+PRG_HEIGHT > level->bounds.bottom )
         pos.y = level->bounds.bottom-PRG_HEIGHT;

    l->pos.x = pos.x;
    l->pos.y = pos.y;
  }

  return l;
}

void populate_level( LEVEL *level )
{
  SPRITE_INFO *info;
  bool add = FALSE;
  bool remove = FALSE;

  for ( info = level->first_info; info != NULL; info = info->next )
  {
     add = FALSE;
     remove = FALSE;
     
     if ( info == NULL )
      continue;
     
     if ( info->sprites[CURRENT] < info->sprites[MIN] )
       add = TRUE;
       
     if ( (info->sprites[CURRENT] >= info->sprites[MIN]) && (info->sprites[CURRENT] < info->sprites[MAX]) && add == FALSE)
     {
/* for historical purposes
        int num = random(info->sprites[MIN],info->sprites[MAX]);

        if ( num == info->sprites[CURRENT] )
*/
         int num = random(1,1000);
         
         if ( num == 1 || num == 1000 )
          add = TRUE;
     }
     
     if ( info->sprites[CURRENT] > info->sprites[MAX] )
      remove = TRUE;

     if ( remove == TRUE )
     {
        int times = (info->sprites[CURRENT] - info->sprites[MAX]);
        int i;
        
        for ( i = 0; i < times; i++ )
        {
          SPRITE *sprite = get_sprite( info->name, level );

          if ( sprite == NULL )
           continue;

          level->num_sprites--;                       /* subtract from total */
          sprite->bitmap = NULL;
          UNLINK( sprite, level->first_sprite, level->last_sprite, next, prev ); /* remove from list */
          sprite->next = sprite->prev = NULL;

          subtract_from_population( sprite->name, level );

          DISPOSE( sprite->name );
          DISPOSE( sprite );                         /* unalloc */
        }
     }
     
     if ( add == TRUE )
     {
        int times = (info->sprites[CURRENT] < info->sprites[MIN] ? (info->sprites[MIN] - info->sprites[CURRENT]) : 1 );
        int i;
        
        if ( times < 0 )
         times = 1;
        
        for ( i = 0; i < times; i++ )
        {
           SPRITE *sprite = NULL;
           SPRITE *proto = get_proto( info->name, level );
           BMP *bmp = NULL;
           POINT pos = { 0, 0 };
           POINT velo = { 0, 0 };
           RECT bounds = { 0, 0, level->bounds.right, level->bounds.bottom };
           
           if ( proto == NULL )
            continue;

           if ( info->action == aNONE )
            break;

           bmp = proto->bitmap;
           
           velo.x = proto->velocity.x;
           velo.y = proto->velocity.y;
           
           CopyRect(&bounds, &proto->bounds );
           
           if ( info->action == POS_ONLY )
           {
               pos.x = info->pos_pt.x;
               pos.y = info->pos_pt.y;
           }
           else if ( info->action == RANDOM )
           {
             pos.x = random(info->pos_rect.left, info->pos_rect.right );
             pos.y = random(info->pos_rect.top, info->pos_rect.bottom);
           }

           sprite = sprite_from_initial( bmp, pos, velo, proto->z, bounds, proto->action, proto->width, proto->height, proto->name, proto->type );
           
           sprite->gravity = proto->gravity;

           sprite->frames = proto->frames;
           sprite->delay = proto->delay;
           info->sprites[CURRENT]++;
        } /* end for */
     } /* end if ( add ) */
  }
}

LEVEL *load_level( int level )
{
   if ( level < 0 )
    return NULL;

   LEVEL *l;
   char *buf = read_level( level ); /* get a pointer to memory holding directions for this levels creation */

   l = parse_level( buf ); /* analyze and read/create objects/sprites */
   
   return l;
}

LEVEL *parse_level( char *obuf )
{
  LEVEL *level = NULL;
  char buf[4000];
  char *word = NULL;

  buf[0] = '\0';

  CREATE( level, LEVEL, 1 );
  
  /* default none! */
  level->song = MAX_SOUND;


  strcpy(buf, strip_spaces(obuf));

  for ( ; ; )
  {
    char cEnd = buf[0];
    
    while ( isspace( cEnd ) )
    {
       strcpy(buf, strip_leading_spaces(buf));
       cEnd = buf[0];
    }

    if ( buf[0] == '#' ) /* should always be true */
    {
       strcpy( buf, (strrep(buf, "#", " ",buf)));
       word = read_word(buf);

       if ( !stricmp( word, "LEVEL") )
       {
        for ( ; ; )
        {
             strcpy( buf, strrep( buf, word, " ",buf));
             word = read_word(buf);

             if ( !stricmp( word, "Start" ) )
             {
                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
                level->pos.x = (LONG)atoi(word);

                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
                level->pos.y = (LONG)atoi(word);
                continue;
             }

             if ( !stricmp( word, "Sprite" ) )
             {
               SPRITE_INFO *info = NULL;
               CREATE( info, SPRITE_INFO, 1 );
               
               strcpy(buf, strrep( buf, word, " ",buf));
               word = read_word(buf);

               info->name = (char *)strdup(word);
               
               for ( ; ; )
               {
                 strcpy(buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( !stricmp( word, "End" ) )
                 {
                   LINK( info, level->first_info, level->last_info, next, prev );
                   break;
                 }

                 if ( !stricmp( word, "Num" ) )
                 {
                    strcpy(buf, strrep( buf, word, " ",buf));
                    word = read_word(buf);
                    
                    char temp[20] = { '\0' };
                    int min,max;
                    strcpy(temp, word );
                    sscanf( temp, "%d-%d", &min, &max );
                    
                    info->sprites[MIN] = min;
                    info->sprites[CURRENT] = 0;
                    info->sprites[MAX] = max;
                    continue;
                 }
                 
                 if ( !stricmp( word, "Position" ) )
                 {
                    strcpy(buf, strrep( buf, word, " ",buf));
                    word = read_word(buf);
                    
                    if ( !stricmp( word, "RANDOM" ) )
                     info->action = RANDOM;
                    else if ( !stricmp( word,"POS_ONLY" ) )
                     info->action = POS_ONLY;
                    else
                     info->action = aNONE;

                    strcpy(buf, strrep( buf, word, " ",buf));
                    word = read_word(buf);

                    if ( !stricmp( word, "RECT" ) )
                    {
                       strcpy(buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);

                       char temp[50] = { '\0' };
                       int x1,x2,y1,y2;
                       int i;
                       
                       strcpy( temp, word );
                       sscanf( temp, "%d-%d-%d-%d", &x1, &x2, &y1, &y2 );
                       SetRect( &info->pos_rect, x1, x2, y1, y2 );
                    }
                    else /* point */
                    {
                       strcpy(buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);

                       char temp[20] = { '\0' };
                       int x1,x2;
                       int i;

                       strcpy( temp, word );
                       sscanf( temp, "%d-%d", &x1, &x2);

                       info->pos_pt.x = x1;
                       info->pos_pt.y = x2;
                    }
                    continue;
                 }
               } /* end for */
               continue;
             }

             if ( !stricmp( word, "Num") )
             {
               strcpy(buf, strrep( buf, word, " ",buf));
               word = read_word(buf);

               if ( word != NULL )
                level->num = atoi(word);
                
               continue;
             }

             if ( !stricmp( word, "Song" ) )
             {
               strcpy(buf, strrep( buf, word, " ",buf));
               word = read_word(buf);
#ifdef DX
               if ( is_number(word) )
                 level->song = atoi(word);
               else
                 level->song = get_sound( word );
#else
               level->song = MAX_SOUND;
#endif
                 
               continue;
             }
             
             if ( !stricmp( word, "Screen" ) )
             {
                LONG width, height;
                width = height = 0;
                
                strcpy(buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
               if ( word != NULL )
                width = (LONG)atoi(word);
                
                strcpy(buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
               
               if ( word != NULL )
                height = (LONG)atoi(word);
                
                /* 500 x 400 minimum */
                if ( width < 500 )
                 width = 500;

                if ( height < 400 )
                 height = 400;
                 
                /* change the size */
                game_size( width, height, level );
                 
                continue;
             }

             if ( !stricmp( word, "Bounds" ) )
             {
               int num[4];
               int loop;

               for ( loop = 0; loop < 4; loop++ )
               {
                   strcpy(buf, strrep( buf, word, " ",buf));
                   word = read_word(buf);
                   
                   if ( is_number(word) == FALSE )
                   {
                     if ( !stricmp(word, "PRGW") )
                      num[loop] = PRG_WIDTH;
                     else if ( !stricmp(word, "PRGH") )
                      num[loop] = PRG_HEIGHT;
                   }
                   else
                     num[loop] = atoi(word);
               }

               SetRect( &level->bounds, num[0], num[1], num[2], num[3] );
               continue;
             }

             if ( !stricmp( word, "End" ) )
             {
              strcpy(buf, strrep( buf, word, " ",buf));
              break;
             }
        } /* end for */
        continue;
       }/* end LEVEL */
       
       if ( !stricmp( word, "BITMAP" ) )
       {
              strcpy( buf, strrep( buf, word, " ",buf));
              word = read_word(buf);
              
              if ( !stricmp( word, "FILE" ) )
              {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 BMP *b = bitmap_from_file( game->hInstance, word );
#ifdef LEVEL_LOG
                 if ( b == NULL )
                 {
#ifdef XLOG
                   LT( "Parse_Level", WARNING, "Script: Bitmap -> File: File not found", 0 );
#else
                   glog( "Script: Bitmap -> File: File not found!" );
#endif
                 }
#endif

                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

#ifdef LEVEL_LOG
                 if ( !stricmp( word, "End" ) )
                 {
#ifdef XLOG
                   LT( "Parse_Level", ERR, "Script: Bitmap -> File: Missing 'end'", 0 )
#else
                   glog( "Script: Bitmap -> File: Missing 'end'" );
#endif
                 }
#endif

                strcpy(buf, strrep( buf, word, " ",buf));
                continue;
              } /* end "file" */
              
              if ( !stricmp( word, "GENERIC" ) )
              {
                int height = 0, width = 0;
                int color[3] = {0,0,0};
                char *name;

                for ( ; ; )
                {
                   strcpy( buf, strrep( buf, word, " ",buf));
                   word = read_word(buf);

                   if ( !stricmp( word, "Name" ) )
                   {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       name = (char *)strdup(word); /* unalloced later */
                       continue;
                   }

                   if ( !stricmp( word, "RGB" ) )
                   {
                     int i;
                     
                     for ( i = 0; i < 3; i++ )
                     {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       color[i] = atoi(word);
                     }
                     continue;
                   }
                   
                   if ( !stricmp( word, "Width" ) )
                   {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       width = atoi(word);
                       continue;
                   }
                   
                   if ( !stricmp( word, "Height" ) )
                   {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       height = atoi(word);
                       continue;
                   }
                   
                   if ( !stricmp( word, "End" ) )
                   {
#ifdef LEVEL_LOG
                     if ( name[0] == '\0' )
                     {
#ifdef XLOG
                        LT( "Parse_Level", ERR, "Bitmap->Generic->End: Bad name! Exiting...", 0 );
#else
                        glog( "Parse_level: Bitamp->Generic->End: Bad name!" );
#endif
                        exit(1);
                     }
                     
                     if ( width < 1 )
                     {
#ifdef XLOG
                        LT( "Parse_Level", ERR, "Bitmap->Generic->End: Bad width (%d)! Default 1.", width );
#else
                        glog( "Parse_level: Bitamp->Generic->End: Bad width! (%d)", width);
#endif
                        width = 1;
                     }

                     if ( height < 1 )
                     {
#ifdef XLOG
                        LT( "Parse_Level", ERR, "Bitmap->Generic->End: Bad height (%d)! Default 1.", height );
#else
                        glog( "Parse_level: Bitamp->Generic->End: Bad height! (%d)", height);
#endif
                        height = 1;
                     }
                     
                     if ( (color[0] < 0) || (color[1] < 0) || (color[2] < 0) )
                     {
#ifdef XLOG
                        LT( "Prase_Level", ERR, "Bitmap->Generic->End: Bad color set! (%d %d %d)   Defaulting to black", color[0], color[1], color[2] );
#else
                        glog( "Parse_level: Bitap->Generic->End: Bad color set! (%d %d %d)", color[0], color[1], color[2] );
#endif

                        int i;
                        for ( i = 0; i < 3; i++ )
                         color[i] = 0;
                     }
#endif

                     /* create the bitmap */
                     bitmap_from_generic(GetDC(game->hWindow), width, height, RGB(color[0],color[1],color[2]), name, TRUE );
                     
                     strcpy(buf, strrep( buf, word, " ",buf));
                     break;
                   }
#ifdef LEVEL_LOG
                   {
#ifdef XLOG
                      LT( "Parse_Level", ERR, "Bitmap -> Generic: no match for word %s", word );
#else
                      glog( "Parse_level: Bitmap -> Generic: no match for word %s", word );
#endif
                      exit(1);
                   }
#endif
                } /* end for */

                DISPOSE( name );
              } /* end "generic" */
          continue;
       } /* end bitmap */
       
       if ( !stricmp( word, "BG" ) )
       {
        strcpy( buf, strrep( buf, word, " ",buf));
        word = read_word(buf);

        for ( ; ; )
        {
         if ( !stricmp( word, "Stretch") )
         {
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            
           if ( level && level->bg )
            if ( !stricmp( word, "true" ) )
             level->bg->stretch = TRUE;
            else
             level->bg->stretch = FALSE;
             
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            continue;
         }
         
         if ( !stricmp( word, "Simmune") )
         {
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            
            if ( level && level->bg )
             if ( !stricmp( word, "true" ) )
               level->bg->simmune = TRUE;
             else if ( !stricmp( word, "n/a" ) )
               level->bg->simmune = -1; /* not applicable */
             else
               level->bg->simmune = FALSE;

            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            continue;
         }

         if ( !stricmp( word, "IMAGE" ) )
         {
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);

            BG *bg;
            BMP *bmp = get_bmp( word );
            bg = bg_from_bitmap( bmp );

            bg->type = IMAGE;
            level->bg = bg;
            
            level->pos.x =  0;
            level->pos.y = 0;
            
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            continue;
         }
         
         if ( !stricmp( word, "COLOR" ) )
         {
            int num[3];
            int loop;

            for ( loop = 0; loop < 3; loop++ )
            {
                 strcpy(buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);
                 num[loop] = atoi(word);
            }

            BG *bg = NULL;
            bg = bg_from_init( PRG_WIDTH, PRG_HEIGHT, RGB(num[0],num[1],num[2]) );
            bg->type = COLOR;
            
            level->bg = bg;
           
            level->pos.x = 0;
            level->pos.y = 0;
           
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);

            continue;
         }
         
         if ( !stricmp( word, "End" ) )
         {
            strcpy(buf, strrep( buf, word, " ",buf));
            break;
         }
        } /* end for */
        continue;
       }/* end BG */
       
       if ( !stricmp( word, "OBJ" ) )
       {
         OBJ *obj = NULL;
         CREATE( obj, OBJ, 1 );
         
         for ( ; ; )
         {
           strcpy(buf, strrep( buf, word, " ",buf));
           word = read_word(buf);

           if ( !is_number(word) ) /* we have our state */
           {
             if ( !stricmp( word, "End" ) )
               break;
               
             if ( !stricmp( word, "Name" ) )
             {
               strcpy( buf, strrep( buf, word, " ",buf));
               word = read_word(buf);

               obj->name = (char *)strdup(word);
               continue;
             }

             obj->state = get_obj_state(word);
             continue;
           }
           else
           {
             int loop;
             int num[4];
             
             for ( loop = 0; loop < 4; loop++ )
             {
                 num[loop] = atoi(word);
                 
                if ( loop <= 2 )
                {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);
                }
             }

               SetRect( &obj->bounds, num[0], num[1], num[2], num[3] );
               continue;
           }

         } /* end for */
         
         if ( !stricmp( word, "End" ) )
         {
          LINK( obj, level->first_obj, level->last_obj, next, prev );
          
          if ( obj->name == NULL )
           obj->name = (char *)strdup("");
           
          strcpy(buf, strrep( buf, word, " ",buf));
          continue;
         }
       } /* end obj */
       
       if ( !stricmp( word, "END" ) ) /* level loading complete */
       {
        strcpy(buf, strrep( buf, word, " ",buf));
#ifdef LEVEL_LOG
#ifdef XLOG
        LT( "Parse_Level", EVENT, "#END: Level Loading complete!", 0 );
#else
        glog( "Parse_Level->#END: Level Loading complete!" );
#endif
#endif
        /* if we have no song, make sure we have no song */
        if ( level->song < 0 || level->song > MAX_SOUND )
         level->song = MAX_SOUND;
         
        break;
       }
       
       if ( !stricmp( word, "SPRITE" ) ) /* load some sprite data */
       {
          SPRITE *sprite = NULL;
          CREATE( sprite, SPRITE, 1 );

          /* all sprites read this way are considered "proto" until otherwise said so*/
          sprite->proto = TRUE;
          
         for ( ; ; )
         {
            strcpy( buf, strrep( buf, word, " ",buf));
            word = read_word(buf);
            
            if ( !stricmp( word, "Proto" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( !stricmp( word, "FALSE" ) )
                  sprite->proto = FALSE;
                 continue;
            }
            
            if ( !stricmp( word, "Name" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 sprite->name = (char *)strdup(word);
                 
                 continue;
            }
            
            if ( !stricmp( word, "Bitmap" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 BMP *bmp = get_bmp( word );
                 sprite->bitmap = bmp;
                 continue;
            }
            
            if ( !stricmp( word, "Position" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);
                 
                 if ( !stricmp( word, "POINT" ) )
                 {
                    int x[2];
                    int i;
                    
                    for (i = 0; i < 2; i++)
                    {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);

                       x[i] = atoi(word);
                    }
                    sprite->position.x = x[0];
                    sprite->position.y = x[1];
                    continue;
                 }
                 
                 if ( !stricmp( word, "RANDOM" ) )
                 {
                    int x[2];
                    int y[2];
                    int i;
                    
                    for (i = 0; i < 2; i++)
                    {
                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       x[i] = atoi(word);

                       strcpy( buf, strrep( buf, word, " ",buf));
                       word = read_word(buf);
                       
                       y[i] = atoi(word);
                    }

                    sprite->position.x = random( x[0], x[1] );
                    sprite->position.y = random( y[0], y[1] );
                    continue;
                 }
              continue;
            }
            
            if ( !stricmp( word, "Velocity" ) )
            {
                 int x1,x2;
                 int y1,y2;
                 char temp[40] = { '\0' };
                 char bleep = '-';

                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);
                 
                 strcpy( temp, word );
                 sscanf( temp, "%d-%d", &x1, &x2 );

                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 temp[0] = '\0';
                 strcpy( temp, word );
                 sscanf( temp, "%d-%d", &y1, &y2 );

                 if ( x1 <= x2 )
                  sprite->velocity.x = random(x1,x2);
                 else
                  sprite->velocity.x = random(x2,x1);
                 
                 if ( y1 <= y2 )
                  sprite->velocity.y = random(y1,y2);
                 else
                  sprite->velocity.y = random(y2,y1);
                  
                  continue;
            }
            
            if ( !stricmp( word, "Bounds" ) )
            {
             int loop;
             int num[4];

             for ( loop = 0; loop < 4; loop++ )
             {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( is_number(word) == FALSE )
                   {
                     if ( !stricmp(word, "PRGW") )
                      num[loop] = PRG_WIDTH;
                     else if ( !stricmp(word, "PRGH") )
                      num[loop] = PRG_HEIGHT;
                   }
                   else
                     num[loop] = atoi(word);
             }

               SetRect( &sprite->bounds, num[0], num[1], num[2], num[3] );
               continue;
            }
            
            if ( !stricmp( word, "Hidden" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);
                 
                 if ( !stricmp( word, "TRUE" ) )
                   sprite->hidden = TRUE;
                 else
                   sprite->hidden = FALSE;
                   
                 continue;
            }

            if ( !stricmp( word, "Drag" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( !stricmp( word, "TRUE" ) )
                   sprite->drag = TRUE;
                 else
                   sprite->drag = FALSE;
                   
                 continue;
            }

            if ( !stricmp( word, "Gravity" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( !stricmp( word, "TRUE" ) )
                   sprite->gravity = TRUE;
                 else
                   sprite->gravity = FALSE;
                   
                 continue;
            }
            
            if ( !stricmp( word, "Z" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 sprite->z = atoi(word);
                 
                 continue;
            }

            if ( !stricmp( word, "Type" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                if ( is_number(word) == TRUE )
                 sprite->type = atoi(word);
                else
                {
                  switch( tolower(word[0]) )
                  {
                      default:
                      case 's':
                           sprite->type = S_NONE;
                           break;
                           
                      case 'p':
                           if ( tolower(word[1]) == 'l' )
                           {
                            sprite->type = PLAYER;
                            break;
                           }
                           else if ( tolower(word[1]) == 'r' )
                           {
                            sprite->type = PROJECTILE;
                            break;
                           }
                           else if ( tolower(word[1]) == '_' )
                           {
                            sprite->type = P_PROJECTILE;
                            break;
                           }
                           else
                            break;
                           
                      case 'e':
                           sprite->type = ENEMY;
                           break;
                           
                      case 'b':
                           sprite->type = BOSS;
                           break;
                  }
                }

                 continue;
            }

            if ( !stricmp( word, "Action" ) )
            {
                 strcpy( buf, strrep( buf, word, " ",buf));
                 word = read_word(buf);

                 if ( !stricmp( word, "DIE" ) )
                   sprite->action = DIE;
                 else if ( !stricmp( word, "WRAP" ) )
                   sprite->action = WRAP;
                 else if ( !stricmp( word, "BOUNCE" ) )
                   sprite->action = BOUNCE;
                 else
                   sprite->action = STOP;
                   
                 continue;
            }
            
            if ( !stricmp( word, "Direction" ) )
            {
                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);

                if ( !stricmp( word, "LEFT" ) )
                 sprite->direction = LEFT;
                else
                 sprite->direction = RIGHT;
                 
                continue;
            }
            
            if ( !stricmp( word, "Dimensions" ) || !stricmp(word, "Dims") )
            {
              int i;
              int dims[2];
              
              for ( i = 0; i < 2; i++ )
              {
                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
                dims[i] = atoi(word);
              }
                
              sprite->width = dims[0];
              sprite->height = dims[1];
              continue;
            }
            
            if ( !stricmp( word, "Frames" ) )
            {
                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
                sprite->frames = atoi(word);
                continue;
            }
            
            if ( !stricmp( word, "Delay" ) )
            {
                strcpy( buf, strrep( buf, word, " ",buf));
                word = read_word(buf);
                
                sprite->delay = atoi(word);
                continue;
            }
            
            if ( !stricmp( word, "End" ) )
            {
             if ( sprite->proto == TRUE )
             {
              LINK( sprite, level->first_proto, level->last_proto, next, prev );
              level->num_proto++;
             }
             else
             {
              SPRITE *loop = NULL;
              
              if ( level->first_sprite != NULL )
                for (loop = level->first_sprite; loop != NULL; loop = loop->next)
                {
                  if (sprite->z <= loop->z)
                  {
                     INSERT( sprite, loop, level->first_sprite, next, prev );
                     break;
                  }
                  
                  /* have we hit the end? if so, add this sprite to the end, as its zorder is highest */
                  if ( loop == level->last_sprite )
                  {
                    LINK( sprite, level->first_sprite, level->last_sprite, next, prev );
                    break;
                  }
                }
              else
                  LINK( sprite, level->first_sprite, level->last_sprite, next, prev );

               /* generate bitmask infromation for collisions */
               sprite->bitmask = bitmask_create(sprite->width, sprite->height);
               bitmask_fill(sprite->bitmask);
               
               level->num_sprites++;
             }

              CalcCollisionRect( sprite );

#ifdef LEVEL_LOG
#ifdef XLOG
              LT( "Parse_Level", EVENT, "Sprite: done loading (%s)", sprite->name );
#else
              glog( "Parse_Level -> Sprite: done loading sprite (%s)", sprite->name );
#endif
#endif

              strcpy(buf, strrep( buf, word, " ",buf));
              break;
            } /* end if-end */
         } /* end for*/

       } /* end sprite */

#ifdef LOG
#ifdef LEVEL_LOG
        {
#ifdef XLOG
          LT( "Parse_Level", ERR, "Bad Word: %s", word );
#else
          glog( "Parse_level: Bad word: %s", word );
#endif
        }
#endif
#endif
    } /* end if-# */
#ifdef LOG
#ifdef LEVEL_LOG
    else
    {
#ifdef XLOG
      LT( "Parse_Level", ERR, "# not found", 0 );
#else
      glog( "Parse_level: # not found" );
#endif
      exit(1);
    }
#endif
#endif
  } /* end high-level for */
  

   DISPOSE( obuf );
   
   return level;
} /* end parse level */

char *read_level( int level )
{
   if ( level < 0 )
    return NULL;

  return (char *)strdup( level_buf[level] );
}

/*
 * Delete everything with level, and possibly bitmaps
 */
void clean_level( LEVEL *level, bool bmp )
{
  OBJ *obj= NULL;
  OBJ *objnext = NULL;
  SPRITE *sprite = NULL, *snext = NULL;
  SPRITE_INFO *info = NULL, *infonext = NULL;
  
  if ( level == NULL )
   return;

  bg_clean( level->bg ); /* dispose of the background information */
  CleanSprites(); /* clean up the sprites */

  for ( obj = level->first_obj; obj != NULL; obj = objnext )
  {
     objnext = obj->next;
     UNLINK( obj, level->first_obj, level->last_obj, next, prev );
     DISPOSE( obj->name );
     DISPOSE( obj );
  }

  for ( sprite = level->first_proto; sprite != NULL; sprite = snext )
  {
     snext = sprite->next;
     UNLINK( sprite, level->first_proto, level->last_proto, next, prev );
     level->num_proto--;                       /* subtract from total */
     sprite->bitmap = NULL;
     sprite->next = sprite->prev = NULL;
     DISPOSE( sprite->name );
     DISPOSE( sprite );                         /* unalloc */
  }
  
  for ( info = level->first_info; info != NULL; info = infonext )
  {
    infonext = info->next;
    UNLINK( info, level->first_info, level->last_info, next, prev );
    DISPOSE( info->name );
    DISPOSE( info );
  }
  
  DISPOSE( level );
  
  if ( bmp == TRUE )
   clean_bitmaps(game);
}