Logo Search packages:      
Sourcecode: icebreaker version File versions  Download package

level.c

/*
* IceBreaker
* Copyright (c) 2000-2001 Matthew Miller <mattdm@mattdm.org>
*   http://www.mattdm.org/
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/

#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>

#include "icebreaker.h"
#include "cursor.h"
#include "penguin.h"
#include "line.h"
#include "grid.h"
#include "laundry.h"
#include "sound.h"
#include "globals.h"
#include "level.h"
#include "status.h"
#include "text.h"
#include "dialog.h"
#include "options.h"

Line line1;
Line line2;

static void setuplevel(void);

void setuplevel()
{
      int x,y;
      int c;
      SDL_Rect tmprect;

      setcursor(CURSORARROW);
      SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
      
      tmprect.x=BORDERLEFT; tmprect.y=BORDERTOP;
      tmprect.w=PLAYWIDTH; tmprect.h=PLAYHEIGHT;
      SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xC0, 0xC0, 0xC0));

      //tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
      //for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
      //    for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
      //          SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));

      tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
      for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
            for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
                  {
                        c = (random() % 32)+224;
                        SDL_FillRect(screen,&tmprect,SDL_MapRGB(screen->format, c, c, c));
                  }
      SDL_BlitSurface(screen, NULL, screensave, NULL);


      
      SDL_UpdateRect(screen,0,0,0,0);

      for (x=0;x<WIDTH;x++)
            for (y=0;y<HEIGHT;y++)
            {
                  if (x<BORDERLEFT || x>=BORDERRIGHT || y <BORDERTOP || y>=BORDERBOTTOM)  
                        grid[x][y]='X';
                  else
                        grid[x][y]=' ';
            }
      

}



LevelExitType playlevel(int level, long oldscore, ScoreSheet * levelscore)
{
      int penguincount=level+1;
      int lives=level+1;

      LevelExitType returncode=ERROR;
      int i,x,y,xdif,ydif;

      SDL_Rect menubuttonrect;
      int menubuttonglow=false;
      int menubuttonpressed=false;
      int paused=false;

      int clear=0;
      int linedoneflag=false;
      LineType linetype;
      float scoremod=1;
      float bonusmod=1;
      
      int tick=0;
      int timepenalty=0;
      int timepenaltyinterval=0;
      
      int domenuflag = false;
      
      int done = false;
      
      // FIX -- this is a good candidate for dynamic memory allocation...
      //Penguin flock[penguincount];
      Penguin flock[MAXPENGUINS];
      
      SDL_Event event;

      switch(options.difficulty)
      {
            case NORMAL:
                  scoremod=(level+1)/2.0;
                  bonusmod=(level+1)/2.0;
                  timepenaltyinterval=100;
            break;
            case EASY:
                  scoremod=(level+1)/5.0;
                  bonusmod=(level+1)/7.0;
                  timepenaltyinterval=200;
            break;
            case HARD:
                  scoremod=(level+1)/1.75;
                  bonusmod=(level+1)/1.5;
                  timepenaltyinterval=75;
            break;
            default:
                  fprintf(stderr,"Unknown difficulty -- that can't happen!\n");
            break;
      }

      levelscore->basescore=0;
      levelscore->clearbonus=0;
      levelscore->lifebonus=0;
      
      setuplevel();
      
      setcursor(CURSORVERTICAL); linetype=VERTICAL; 

/*    printf("===========================================================\n"
             "Starting level %d.\n"
             "Lives: %d\n",
             level,lives);
*/           

      menubuttonrect.x=WIDTH-(CHARWIDTH*2*4)-MARGINRIGHT-4;
      menubuttonrect.y=BOTTOMSTATUSY;
      menubuttonrect.w=CHARWIDTH*2*4+3;
      menubuttonrect.h=CHARHEIGHT*2+3;
      puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
      soil(menubuttonrect);   

      line1=createline('1',0x00, 0x00, 0x00);
      //line1=createline('1',0x00, 0x40, 0x80);
      line2=createline('2',0xC0, 0x00, 0x40);

      for (i=0;i<penguincount;i++)
      {
            flock[i] = createpenguin();
      }

      updatestatuslives(lives);
      updatestatuscleared(clear);
      updatestatusscore(oldscore);
      
      updatehiscorebox();     
      clean();
      
      do 
      {
            // FIX -- this is way too messy. time to split it up into
            // neat little functions or something. Especially the menubutton stuff.
            while (SDL_PollEvent(&event))
            {
                  if (event.type == SDL_QUIT)
                  {
                        lives=0; // is this the right way?
                        done = true;
                        return QUIT;
                  }
                  else if (event.type == SDL_MOUSEMOTION)
                  {
                        //if (grid[event.motion.x][event.motion.y] == ' ' || grid[event.motion.x][event.motion.y] == '*')
                        if (event.motion.x>BORDERLEFT && event.motion.x<BORDERRIGHT && event.motion.y>BORDERTOP && event.motion.y<BORDERBOTTOM) 
                        {
                              switch (linetype)
                              {
                                    case HORIZONTAL:
                                          setcursor(CURSORHORIZONTAL);
                                    break;
                                    case VERTICAL:
                                          setcursor(CURSORVERTICAL);
                                    break;
                              }
                              
                        }                 
                        else  // we're somewhere outside of the playing area
                        {
                              setcursor(CURSORARROW);
                        }
                        
                        if (event.motion.x>=menubuttonrect.x && event.motion.y>=menubuttonrect.y && event.motion.x<menubuttonrect.x+menubuttonrect.w && event.motion.y<menubuttonrect.y+menubuttonrect.h)
                        { // over the menu button
                              if (!menubuttonglow)
                              {
                                    menubuttonglow=true;
                                    SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0xF0, 0xF0, 0xF0));
                                    puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),"MENU");
                              }

                        }
                        else 
                        {
                              if (menubuttonglow && !menubuttonpressed)
                              {
                                    menubuttonglow=false;
                                    SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
                                    puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
                              }
                        
                        }
                        soil(menubuttonrect);   
                  }
                  else if (event.type == SDL_MOUSEBUTTONDOWN)
                  {
                        if (event.button.button==1) //left
                        {
                              // in game area?
                              if (event.button.x>BORDERLEFT && event.button.x<BORDERRIGHT && event.button.y>BORDERTOP && event.button.y<BORDERBOTTOM)
                              {
                                    x=(((event.button.x-BORDERLEFT)/BLOCKWIDTH ) * BLOCKWIDTH ) +BORDERLEFT;
                                    y=(((event.button.y-BORDERTOP)/BLOCKHEIGHT) * BLOCKHEIGHT) +BORDERTOP;
                                    xdif=event.button.x-x; ydif=event.button.y-y;

                                    if (grid[x][y] == '*' || grid[event.button.x][event.button.y] == '*') 
                                    { // a little bit of grace if the player clicks directly on the penguin
                                          playsound(SNDOUCH);
                                    }
                                    else if (grid[x][y] == ' ')
                                    {

                                          switch (linetype)
                                          {
                                                case VERTICAL:
                                                      if (!line1.on) (ydif<BLOCKHEIGHT/2) ? startline(&line1,UP,x,y) : startline(&line1,UP,x,y+BLOCKHEIGHT);
                                                      if (!line2.on) (ydif<BLOCKHEIGHT/2) ? startline(&line2,DOWN,x,y) : startline(&line2,DOWN,x,y+BLOCKHEIGHT);
                                                break;
                                                case HORIZONTAL:
                                                      if (!line1.on) (xdif<BLOCKWIDTH/2) ? startline(&line1,LEFT,x,y) : startline(&line1,LEFT,x+BLOCKWIDTH,y);
                                                      if (!line2.on) (xdif<BLOCKWIDTH/2) ? startline(&line2,RIGHT,x,y) : startline(&line2,RIGHT,x+BLOCKWIDTH,y);
                                                break;
                                          }
                                    
                                    }
                              }
                              else if (event.button.x>=menubuttonrect.x && event.button.y>=menubuttonrect.y && event.button.x<menubuttonrect.x+menubuttonrect.w && event.button.y<menubuttonrect.y+menubuttonrect.h)
                              {
                                    menubuttonpressed=true;
                              }
                                       
                        }
                        //else if (event.button.button==3) // for testing!
                        //{
                        //    printwholegrid();                         
                        //}
                        else //middle or right
                        {
                              switch (linetype)
                              {
                                    case VERTICAL:
                                          linetype=HORIZONTAL;
                                          setcursor(CURSORHORIZONTAL); 
                                    break;
                                    case HORIZONTAL:
                                          linetype=VERTICAL;
                                          setcursor(CURSORVERTICAL);
                                    break;
                              }
                        }
                  }
                  else if (event.type == SDL_MOUSEBUTTONUP)
                  {
                        if (menubuttonpressed && event.button.x>=menubuttonrect.x && event.button.y>=menubuttonrect.y && event.button.x<menubuttonrect.x+menubuttonrect.w && event.button.y<menubuttonrect.y+menubuttonrect.h)
                        {
                              menubuttonglow=true;
                              
                              SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0xF0, 0xF0, 0xF0));
                              puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80),"MENU");
                              soil(menubuttonrect);

                              domenuflag=true;
                        }
                        else if (menubuttonglow && menubuttonpressed)
                        {
                              menubuttonglow=false;
                              SDL_FillRect(screen,&menubuttonrect,SDL_MapRGB(screen->format, 0x00, 0x40, 0x80));
                              puttext(menubuttonrect.x+3,menubuttonrect.y+3,2,SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF),"MENU");
                              soil(menubuttonrect);   
                        }
                        menubuttonpressed=false;
                  }
                  else if (event.type == SDL_ACTIVEEVENT && ((options.autopause == AUTOPAUSEON) || (event.active.state & SDL_APPACTIVE)))
                  {   
                        if (event.active.gain==0)
                        { // iconified / lost focus
                              paused=true;
                        }
                        else // event.active.gain==1
                        { // restored /got focus
                              paused=false;
                        }
                  }
                  // FIX -- add keyboard support, handle other events.
            }
            if (paused) 
            {
                  SDL_WaitEvent(NULL);
                  continue;
            }
            
            
            
            // move split-lines
            if (line1.on)
            {
                  // kludgy crap to implement speed = 1 1/2
                  linedoneflag=moveline(&line1);
                  if (!linedoneflag && line1.speedslower)
                  {
                        line1.speedslower=false;
                        linedoneflag=moveline(&line1);
                  }
                  else
                  {
                        line1.speedslower=true;
                  }
                        
                  if (linedoneflag)
                  {
                        clear=(100-(countcleared()*100/(PLAYWIDTH*PLAYHEIGHT)));
                        levelscore->basescore=(int)(clear*scoremod)-timepenalty;
                        tick=0; // reset this to keep score from seeming to flicker around a lot. and to be nice. :)
                        
                        updatestatuscleared(clear);
                        updatestatusscore(oldscore+levelscore->basescore);
                        //printf("Cleared: %d%%\n",clear);                    
                  }

                  if (line1.dead) 
                  {
                        playsound(SNDBREAK);
                        killline(&line1);
                        lives--;
                        if (lives<0) lives=0;
                        updatestatuslives(lives);
                        //printf("Lives: %d\n",lives); 
                  }
            }
            if (line2.on)
            {
                  linedoneflag=moveline(&line2);
                  if (!linedoneflag && line2.speedslower)
                  {
                        line2.speedslower=false;
                        linedoneflag=moveline(&line2);
                  }
                  else
                  {
                        line2.speedslower=true;
                  }

                  if (linedoneflag)
                  {
                        clear=(100-(countcleared()*100/(PLAYWIDTH*PLAYHEIGHT)));
                        levelscore->basescore=(int)(clear*scoremod)-timepenalty;
                        tick=0; // reset this to keep score from seeming to flicker around a lot. and to be nice. :)

                        updatestatuscleared(clear);
                        updatestatusscore(oldscore+levelscore->basescore);
                        //printf("Cleared: %d%%\n",clear);
                  }

                  if (line2.dead)
                  { 
                        playsound(SNDBREAK);
                        killline(&line2);
                        lives--;
                        if (lives<0) lives=0;
                        updatestatuslives(lives);
                        //printf("Lives: %d\n",lives);
                        
                  }
            }
            
      
            // move (and get old background)
            for (i=0;i<penguincount;i++)
            {
                  
                  soil(flock[i].geom); // mark the penguin's old position as dirty
                  movepenguin(&flock[i]);
            
                  soil(flock[i].geom); // mark the penguin's new position as dirty too (it will be soon...)
                  savebehindpenguin(&flock[i]);
            }
            

            // actually draw
            for (i=0;i<penguincount;i++)
            {
                  drawpenguin(&flock[i]);
            }

            if (domenuflag)
            {
                  switch (popupmenu())
                  {
                        case POPUPMENUQUITGAME:
                              lives=0; // is this the right way?
                              done = true;
                              return QUIT;
                        break;
                        case POPUPMENUNEWGAME:
                              // hmmm... maybe this could be done better
                              done = true;
                              returncode=DEAD;
                        break;
                  }
                  
                  domenuflag=false;
            }

            
            // update clock
            tick++;
            if (tick>timepenaltyinterval)
            {
                  tick=0;
                  if (levelscore->basescore>0)
                  {
                        timepenalty++;
                        levelscore->basescore--;
                        updatestatusscore(oldscore+levelscore->basescore);
                  }
            }
            
            // update screen
            clean();

            // clear for next update
            for (i=0;i<penguincount;i++)
            {
                  erasepenguin(&flock[i]);
            }
            
            if (lives<=0) // game over
            {
                  done = true;
                  returncode=DEAD;
            } 
            else if (!line1.on && !line2.on && clear>=PERCENTREQUIRED) // success!
            { 
                  done = true;
                  levelscore->basescore=(int)(clear*scoremod)-timepenalty;
                  returncode=PASS;


                  levelscore->clearbonus=0;
                  // bonuses for clearing lots
                  if (clear>PERCENTBONUS)
                        levelscore->clearbonus+=(int)((clear-PERCENTBONUS)*bonusmod);
                  if (clear>PERCENTEXTRABONUS)
                        levelscore->clearbonus+=(int)((clear-PERCENTEXTRABONUS)*(clear-PERCENTEXTRABONUS)*bonusmod);
                        
                  // bonuses for leftover lives
                  levelscore->lifebonus=(int)((lives-1)*3*bonusmod);
            } 

            //printboard();
            
            // oh, if only we could sleep for less than 10ms on 
            // intel. too bad alpha systems suck so much in other
            // ways -- they can sleep with 1ms resolution.
            // (we could on intel with nanosleep, if we were suid root...)
            SDL_Delay(10);
            
      } while (!done);


      // make sure visible penguins are actually in the screen memory.
      for (i=0;i<penguincount;i++)
      {
            drawpenguin(&flock[i]);
      }

      clean();
      return returncode;
}


Generated by  Doxygen 1.6.0   Back to index