[dev-cpp]un tetris, encore...

Contenu du snippet

Bon alrs c'est un tétris tout simple. C'est mon premier programme en C/C++, je me suis basé sur les sources du PinkTetris de Hylvenir (http://www.cppfrance.com/codes/PINKTRIS-SIMPLE-TETRIS-SDL_25010.aspx)

J'ai totalement refais le jeu. Refais la gestion d'une partie, des scores, des blocs. J'ai mis des variables un peu partout dans le codes pour pouvoir plus simplement modifié le code.

Une version 2 est en préparation dans laquelle vous pourrez changer plusieurs options du jeu ; par exemple, les blocs, le nombre de lignes pour changer de niveau, la taille du plateau de jeu.
Dans cette version, je distribuerais également les sources qui cette fois seront intégralement commentées.

-------------------------------------------------------
19/08/2007 16h00
Tetris V2.0 Par Thierry POINOT
Sources initiales du PinkTetris de Hylvenir sur http://www.cppfrance.com : http://www.cppfrance.com/codes/PINKTRIS-SIMPLE-TETRIS-SDL_25010.aspx

Ce programme à été développé en C++ avec Dev-cpp. Il utilise les librairie SDL (pour l'affichage) et SDL_TTF pour l'affichage de texte (genre les scores), ainsi que la librairie FMOD pour la gestion du son.

Et voilà la version 2 de mon Tétris ! Une interface remanié, les bloc sont, à mon goût, d'une plus jolie couleur (dégradé blanc) que dans la version 1.
Les sons ont été changés : il n'y a plus de son pour les déplacements latéraux de blocs.
Un bug de fin de partie à été corrigé; lorsqu'une partie était perdu, et que le jeu était figé, à chaque fois que l'utilisateur faisait une action sur la fenêtre, le son de fin de partie se répétait.

Désormais, il est possible de jouer avec ses propres blocs !
Le fichier 'blocs.txt' contient les blocs du jeu, et le fichier 'special_blocs.txt' contient les blocs pour généré les bordures et le fond coloré ^^
Il y a également un fichier de configuration 'options.txt' qui contient les principales variable du jeu pour personnalisé votre tétris (taille de la zone de jeu, nombre de ligne pour monter d'un niveau...)
Si les fichiers de configuration n'existe pas, ce n'est pas un problème, les options par défaut du programme seront utilisé.

Il y a aussi l'affichage du meilleur score sur le plateau de jeu pour vous situer par rapport au meilleur !

Bref cette version est plus personnalisable, plus intéractive, vous pouvez jouez avec les blocs que vous voulez, ce qui donne une nouvelle dimension au jeu !

A VENIR, une version 3 j'espère bien ! avec des blocs plus que spécial qui auront une action spéciale sur le jeu ! Par exemple le bloc point '.' pourra bouché les trous dans votre jeu et compléter les lignes que vous avez raté !
J'espère bien faire aussi un tableau de score, et crypter les score pour éviter la triche, qui donnera un esprit de compétition au jeu.

Je prévois dans une version supérieur de faire un éditeur de blocs et de niveau ! comme au snake, après chaque niveau possèdera des murs impossible à enlever, qu'il faudra contourner !
Je prévois également de faire en sorte d'envoyer les score sur le net pour un classement général du jeu, ce qui me permettra avec cette fonctionnalité d'ouvrir un site web.

Bref tout ça ne sont que des prévisions et des idées, je ne garantit rien mais bon....

Je remercie encore une fois Hylvenir pour sa source initiale, et Funto qui m'a fait découvrir la lib <vector> tableau multidimensionnel redimensionnable.

http://thierry.poinot.fr/
http://dev.thierry.poinot.fr/

P.S. : regarder les touches du pavé numérique ya un ptit truc nul certes mais marrant, c'était juste pour déconner :P

Source / Exemple :


########TETRIS.CPP########

#include "tetris.h"

// Fonction principale ----------------------------------------------------------------------------------------------------
int main( int, char** ) try
{
    srand( time(NULL) ); // Randomize

    // Initialise l'affichage (librairie SDL)
    if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER )== -1 )
        throw runtime_error( SDL_GetError() );
    
    // initialise la librairie qui gère le son (Fmod)
    if ( FSOUND_Init(44100, 32, 0) == -1 )
        throw runtime_error( "FMOD n'a pas pu s'initialiser" );
    
	// initialise la librairie qui gère l'affichage de texte
    if ( TTF_Init() == -1 ) // si la lib ne s'initialise pas...
       throw runtime_error( TTF_GetError() ); // on arrête le programme en renvoyant l'erreur
       
       
 	init_options(); // appel de la fonction qui initialise toutes les variables du jeu
       

       police = TTF_OpenFont("fonts/courbd.ttf", tetris.case_unit - 4); // on charge la police (le fichier doit obligatoirement exister !!)
       if (!police) // si il y a une erreur dans le chargement de la police...
       	  throw runtime_error( TTF_GetError() ); // on arrête le programme en renvoyant l'erreur

       police_m = TTF_OpenFont("fonts/courbd.ttf", 15); // on charge la police (ici la taille est plus petite) (le fichier doit obligatoirement exister !!)
       	  
       	  
	/* jouer un son court avec FMOD
		FSOUND_SAMPLE *grudge = NULL;
	    grudge = FSOUND_Sample_Load(FSOUND_FREE, "sounds/the grudge.mp3", 0, 0, 0);
	    FSOUND_PlaySound(FSOUND_FREE, grudge);    
    //*/
    
    /* jouer un son long (musique) avec FMOD
	    FSOUND_STREAM *musique = NULL;
	    FSOUND_Stream_SetLoopCount(musique, -1); // répétition à l'infini
	    //musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 110000, 219500); // on charge la musique
	    musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 5 * 109500, 20 * 219500); // on charge la musique
	    //FSOUND_Stream_Play(FSOUND_FREE, musique); // on lit la musique
	    
	    //FSOUND_Stream_Stop(musique); // Arrêt de la musique
	    //FSOUND_Stream_Close(musique); // On libère la mémoire (décharge la musique de la mémoire)
    //*/
    /* Faire une pause avec FMOD
        // remplacer FSOUND_ALL par le numéro du canal à mettre en pause
		if (FSOUND_GetPaused(0)) // Si le canal 0 est en pause
            FSOUND_SetPaused(FSOUND_ALL, 0); // On enlève la pause de tous les canaux
        else // Sinon, elle est en cours de lecture
            FSOUND_SetPaused(FSOUND_ALL, 1); // On met en pause tous les canaux
    //*/
    
    /* jouer un midi
       FMUSIC_MODULE *musique = NULL;
       musique = FMUSIC_LoadSong("musics/tetris.mid");
       FMUSIC_SetLooping(musique, 1); // répétition à l'infini
       FMUSIC_PlaySong(musique);
       FMUSIC_SetMasterVolume(musique, 120); // volume
       //FMUSIC_StopSong(musique); // stopper la lecture du midi
       //FMUSIC_FreeSong(musique); // on libère la mémoire (décharge le midi de la mémoire)
    //*/
    /* mettre en pause un midi
       if (FMUSIC_GetPaused(musique)) // Si la chanson est en pause
           FMUSIC_SetPaused(musique, 0); // On enlève la pause
       else // Sinon, elle est en cours de lecture
           FMUSIC_SetPaused(musique, 1); // On active la pause
    //*/
    

 	
    FSOUND_SetVolume(FSOUND_ALL, 255); // change le volume de tous les canaux ( de 0 à 255)
 	
    screen = SDL_SetVideoMode( tetris.board_width + tetris.right_panel_width + tetris.grid_width, tetris.board_height + (tetris.case_unit + tetris.grid_width) + tetris.grid_width, 32, /*SDL_FULLSCREEN | */SDL_HWSURFACE | SDL_DOUBLEBUF ); // création de la fenêtre
    if ( !screen ) // Si il y a une erreur sur la création de la fenêtre... on envoie un runtime error (erreur d'éxécution)
        throw runtime_error( SDL_GetError() );
        
    SDL_EnableKeyRepeat(500,30); // active la répétition des touches du clavier (rester appuyer pour faire plusieurs fois la même action)
    
    init_colors(screen); // on initialise les couleurs
    init_blocs(); // on initialise les blocs

    SDL_WM_SetCaption( tetris.window_title, 0 ); // Attribut le titre de la fenêtre (voir 'init_options()')
    SDL_WM_SetIcon( SDL_LoadBMP( "icon.bmp" ), 0 ); // Chargement de l'icône de la fenêtre
    
    init_window_style();
	new_game();
	
    SDL_Event event;
    //while( SDL_PollEvent( &event ) )
    while( SDL_WaitEvent( &event ) )
    {
        switch( event.type )
        {
            case SDL_KEYDOWN:
                switch( event.key.keysym.sym )
                {
                    // -- MOUVEMENT --
                    case SDLK_RIGHT:    
						 		        userMode = goRight; // déplacement du bloc à droite
								        break;
                    case SDLK_LEFT:
						     	        userMode = goLeft; // déplacement du bloc à gauche
								        break;
                    case SDLK_DOWN:
						 		        userMode = goDown; // déplacement du bloc en bas
								        break;
                    
                    case SDLK_UP:		
						 				//userMode = goUp; break;
								        //FSOUND_PlaySound(FSOUND_FREE, tetris.bloc_is_fixed); break; // on joue le son qui correspond au fait que le joueur souhaite faire descendre le bloc
                    case SDLK_KP0:
					    		        userMode = turnRight; // rotation du bloc
								        break;
								        
								        
				    //* SONS BONUS !!!! 
					    case SDLK_KP1:
									        FSOUND_PlaySound(FSOUND_FREE, tetris.sound_one);
											break;
					    case SDLK_KP2:
									        FSOUND_PlaySound(FSOUND_FREE, tetris.sound_two);
											break;
			            case SDLK_KP3:
									        FSOUND_PlaySound(FSOUND_FREE, tetris.sound_three);
											break;
			   		    case SDLK_KP4:
									        FSOUND_PlaySound(FSOUND_FREE, tetris.sound_go);
											break;
											
				        case SDLK_RCTRL: 
									        // remplacer FSOUND_ALL par le numéro du canal à mettre en pause
											if (FSOUND_GetPaused(0)) // Si le canal 0 est en pause
									            FSOUND_SetPaused(FSOUND_ALL, 0); // On enlève la pause de tous les canaux
									        else // Sinon, elle est en cours de lecture
									            FSOUND_SetPaused(FSOUND_ALL, 1); // On met en pause tous les canaux
							 			 	FSOUND_Stream_Play(FSOUND_FREE, tetris.musique); 
										  	break;
					  	case SDLK_RSHIFT:
							 			 	FSOUND_Stream_Stop(tetris.musique); // Arrêt de la musique
            								FSOUND_SetPaused(FSOUND_ALL, 1); // On met la pause
							 			 	break;
				    //*/

				    case SDLK_F2:       new_game(); break;
				                       
                    // -- PAUSE --
                    case SDLK_SPACE:    
                    case SDLK_p:        pause = !pause;     break;
                    
                    // -- EXIT --
                    case SDLK_ESCAPE:   userMode = quit;    break;
                }
                break;
            case SDL_KEYUP:     userMode = none; break;
            case SDL_QUIT:      userMode = quit; continue;
        }
        if ( pause )
        {           
            update_surface(screen); // Mise à jour de l'écran
            continue;
        }

        MoveBloc( userMode );
		update_game();
    }
    
	quit_game();

    return 0;
}
catch( exception& e )
{
   	ofstream cerr( "program_error.txt" );
    cerr << e.what();
    return 1;
}

// Fonction d'initialisation des variables principales du jeu ----------------------------------------------------------------------------------------------------
void init_options()
{
 	 
	tetris.case_unit = 25;	      // la longueur en pixel du côté du carré qui forme une tuile (la tuile est ce qui compose un bloc ce sont les cases unitaires...)
	tetris.board_size_x = 10 + 2; // la largeur de la matrice (zone de jeu) en 'case_unit' + les 2 côtés qui forment les bords (droit et gauche)
	tetris.board_size_y = 22 + 1; // la hauteur de la matrice en 'case_unit' + le bas de la zone de jeu (le sol)
	tetris.grid_width = 1;        // la largeur en pixel de la grille, du cadrillage	

	tetris.line_number_to_level_up = 10; // nombre de lignes à compléter pour monter d'un niveau (mettez la valeur que vous souhaitez, la valeur officielle est 10 lignes pour monter d'un niveau, mais si vous souhaitez que vos parties durent plus longtemps mettez 20)

//* chargement des options dans le fichier de configuration
    ifstream fichier;
    fichier.open("options.txt", ios::in);

    if(fichier)
    {
        fichier >> tetris.case_unit >> tetris.board_size_x >> tetris.board_size_y >> tetris.grid_width >> tetris.line_number_to_level_up;
        /*
	        vector <string> file_content; // variable qui contiendra le fichier (tableau avec une ligne par entrée du tableau)
	        string ligne;
	        while(getline(fichier, ligne)) {
	            file_content.push_back( ligne );
	        }
        //*/
    }
    else
    {
        throw runtime_error( "Impossible d'ouvrir le fichier de configuration !" );
        cout << "Impossible d'ouvrir le fichier de configuration !" << endl;
    }
    fichier.close();

//*/
 	 
	
	tetris.init_posY = 0;                             // position initiale d'un nouveau bloc (ordonnée)
	tetris.init_posX = (tetris.board_size_x - 2) / 2; // position initiale d'un nouveau bloc (abscisse) : ici un bloc nouveau apparaîtra toujours centré dans la zone de jeu (-2 pour les bordures de droite et gauche)
	
	tetris.bloc_number = 0;         // initialise le nombre de blocs (laissé à 0 car cette variable est automatiquement incrémenté lors de l'ajout de bloc avec la fonction 'add_bloc()')
	tetris.special_bloc_number = 0; // initialise le nombre de blocs spéciaux (laissé à 0 car cette variable est automatiquement incrémenté lors de l'ajout de bloc avec la fonction 'add_special_bloc()')
	
	tetris.board_width = tetris.board_size_x * (tetris.case_unit + tetris.grid_width);  // calcul de la largeur de la matrice en pixel
	tetris.board_height = tetris.board_size_y * (tetris.case_unit + tetris.grid_width); // calcul de la hauteur de la matrice en pixel
	tetris.right_panel_width = (tetris.case_unit + tetris.grid_width) * 10;             // taille de la zone à droite de la matrice en pixel (ici la zone fait 10 tuiles de largeur)
	
	tetris.next_bloc_preview_x = tetris.board_width;                                                            // abscisse du coin supérieur gauche de la zone d'aperçu du bloc suivant (ici, c'est juste à côté de la matrice)
	tetris.next_bloc_preview_y = 0;                                                                             // ordonée du coin supérieur gauche de la zone d'aperçu du bloc suivant (ici, c'est tout en haut)
	tetris.next_bloc_preview_size_x = 5;                                                                        // largeur en 'case_unit' de la zone d'aperçu du bloc suivant
	tetris.next_bloc_preview_size_y = 5;                                                                        // hauteur en 'case_unit' de la zone d'aperçu du bloc suivant
	tetris.next_bloc_preview_width = tetris.next_bloc_preview_size_x * (tetris.case_unit + tetris.grid_width);  // largeur en pixel de la zone d'aperçu du bloc suivant
	tetris.next_bloc_preview_height = tetris.next_bloc_preview_size_y * (tetris.case_unit + tetris.grid_width); // hauteur en pixel de la zone d'aperçu du bloc suivant
	
	tetris.window_title = "* Tetris V2 *       ...du 18/08/2007 15h45..."; // titre de la fenêtre

    tetris.musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 5 * 109500, 20 * 219500); // on charge la musique
	FSOUND_Stream_SetLoopCount(tetris.musique, 0); // répétition à l'infini
    FSOUND_SetPaused(FSOUND_ALL, 1); // On met la pause

    tetris.sound_bloc_rotate_right = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_rotate_bloc_at_right.sound", 0, 0, 0);
    tetris.sound_bloc_rotate_left = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_rotate_bloc_at_left.sound", 0, 0, 0);

    tetris.sound_bloc_go_right_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_move_bloc_at_right.sound", 0, 0, 0);
    tetris.sound_bloc_go_left_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_move_bloc_at_left.sound", 0, 0, 0);
    tetris.sound_bloc_go_down_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_down_by_user.sound", 0, 0, 0);
    tetris.sound_bloc_go_up_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_up_by_user.sound", 0, 0, 0);

    tetris.sound_bloc_go_down = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_down_auto.sound", 0, 0, 0);
    tetris.sound_bloc_go_up = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_up_auto.sound", 0, 0, 0);

	tetris.sound_bloc_is_fixed = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_is_fixed_on_the_floor.sound", 0, 0, 0);
	tetris.sound_line_completed = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_line_is_completed.sound", 0, 0, 0);
	tetris.sound_level_up = FSOUND_Sample_Load(FSOUND_FREE, "sounds/level_up.sound", 0, 0, 0);
	tetris.sound_loose_game = FSOUND_Sample_Load(FSOUND_FREE, "sounds/loose_game.sound", 0, 0, 0);
	tetris.sound_new_game = FSOUND_Sample_Load(FSOUND_FREE, "sounds/new_game.sound", 0, 0, 0);
	
	//* Sons bonus (3...2...1...GO)
		tetris.sound_three = FSOUND_Sample_Load(FSOUND_FREE, "sounds/three.ogg", 0, 0, 0);
		tetris.sound_two = FSOUND_Sample_Load(FSOUND_FREE, "sounds/two.ogg", 0, 0, 0);
		tetris.sound_one = FSOUND_Sample_Load(FSOUND_FREE, "sounds/one.ogg", 0, 0, 0);
		tetris.sound_go = FSOUND_Sample_Load(FSOUND_FREE, "sounds/go.ogg", 0, 0, 0);
	//*/
}

// Fonction d'initialisation des couleurs du jeu ----------------------------------------------------------------------------------------------------
void init_colors (SDL_Surface* screen)
{
	tetris.bloc_border_color = SDL_MapRGB(screen->format, 0, 0, 0);      // couleur de bordure d'un bloc (a utilisé uniquement sans la génération automatique du dégradé sur les bloc : voir code commenté dans la fonction addBloc)
    tetris.background_color = SDL_MapRGB(screen->format, 212, 208, 200); // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
    tetris.matrice_color = SDL_MapRGB(screen->format, 255, 255, 255);    // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
    tetris.grid_color = SDL_MapRGB(screen->format, 150, 150, 150);       // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
}
// Fonction d'initialisation des blocs utilisant la fonction addBloc ----------------------------------------------------------------------------------------------------
void init_blocs ()
{
    if (!get_blocs_by_file(true)) { // Si l'initialisation par fichier de configuration a échouée, on créé les blocs
		//*
			add_special_bloc( 1, "1", 50, 50, 50 ); // bloc unitaire pour les bordures (tétrion)
		//* blocs unitaires pour le fond aléatoire
		    add_special_bloc( 1, "1", 255, 0, 0 );
		    add_special_bloc( 1, "1", 51, 102, 255 );
		    add_special_bloc( 1, "1", 255, 220, 0 );
		    add_special_bloc( 1, "1", 255, 0, 255 );
		    add_special_bloc( 1, "1", 210, 210, 200 );
		    add_special_bloc( 1, "1", 0, 255, 0 );
		    add_special_bloc( 1, "1", 0, 0, 255 );
			/*
				for (int x = 0; x < 50; x++) // ajout de 50 blocs spéciaux unitaires dont la couleur est aléatoire
				    add_special_bloc( 1, "1" );
			//*/
		//*/
    }
    if (!get_blocs_by_file()) { // Si l'initialisation par fichier de configuration a échouée, on créé les blocs
		//*
		    //* Blocs originaux
			    add_bloc( 4, "0010001000100010", 255, 0, 0 ); // barre I
			    add_bloc( 2, "1111", 51, 102, 255 ); // carré O
			    add_bloc( 3, "010111000", 153, 51, 0 ); // T
			    add_bloc( 3, "001111000", 255, 0, 255 ); // L
			    add_bloc( 3, "100111000", 200, 200, 200 ); // J couleur originale : le blanc
			    add_bloc( 3, "100110010", 0, 255, 0 ); // S
			    add_bloc( 3, "001011010", 0, 204, 255 ); // Z
		    //*/
		    /* blocs du tétris B
			    add_bloc( 1, "1"); // le point .
			    add_bloc( 2, "1011", 255, 220, 0 ); // mini L
			    //add_bloc( 3, "111010010" ); // T (grand)
			    //add_bloc( 3, "010111010" ); // +
			    add_bloc( 3, "010010010" ); // la barre de 3
			    add_bloc( 2, "0101" ); // la barre de 2
			    add_bloc( 3, "101111000" ); // la cuvette de 3
		    //*/
		
		//*/
    }
}

// Fonction appelée lors d'une nouvelle partie ----------------------------------------------------------------------------------------------------
void new_game()
{
    if (game == true) // Si il y a une partie en cours...
        end_game(); // on termine la partie
    
	pause = false; // On enlève la pause au cas où elle serait activée
	    
    init_window_style(); // on réinitialise l'affichage de la fenêtre pour afficher un nouveau fond aléatoire
    
    FSOUND_PlaySound(FSOUND_FREE, tetris.sound_new_game); // on joue le son qui correspond à une nouvelle partie

    //* chargement du score maximal
		ifstream scoreFile( "score.txt" ); // on ouvre le fichier qui contient le record
		if ( scoreFile ) // si le fichier existe...
		    scoreFile >> scoreMax >> lineMax; // on met la première ligne du fichier comme score max et la deuxième ligne du fichier comme nombre de lignes max
	//*/
	
	board.init_board(); // Initialise le tableau de jeu (objet voir 'board.h')

    currentBloc = blocs[ rand() % tetris.bloc_number ]; // On sélectionne un bloc au hasard pour le bloc courant
    nextBloc = blocs[ rand() % tetris.bloc_number ]; // On sélectionne un bloc au hasard pour le prochain bloc

	tetris.posX = tetris.init_posX; // On initialise la position du bloc à sa position initiale (abscisse)
	tetris.posY = tetris.init_posY; // On initialise la position du bloc à sa position initiale (ordonnée)
	
	tetris.score = 0; // initialise le score à 0 (laisser à 0 sinon vous triché :P)
	tetris.lines = 0; // initialise le nombre de lignes complétées (laisser à 0, changer la valeur n'a aucune influence sur le score, c'est juste indicatif)
	tetris.level = 1; // initialise le niveau on commence au niveau 1 et pas 0 sinon les blocs ne descendent pas ^^ (augmenter le niveau de départ d'une partie influe sur la vitesse de descente du bloc)

	game = true; // On met true à la variable qui dit qu'une partie est en cours

    SDL_Delay( 500 ); // On met en pause le programme pour une demie seconde pour donner le temps au joueur de se mettre en place (utile pour ceux qui ne connaissent pas par coeur le clavier :P)
	
	//* On créé le timer pour la descente automatique du bloc
	    GAMES_MODE tmp = goDown;
		timer_MoveBloc_auto = SDL_AddTimer(1000 / tetris.level, MoveBloc_auto, &tmp); // Démarrage du Timer
	//*/
}

// Fonction appelée à la fin d'une partie ----------------------------------------------------------------------------------------------------
void end_game(bool loose_game)
{
	//* Sauvegarde les informations de la dernière partie (un genre de log)
	    ofstream cout( "last_game.txt");
	    
	    time_t ltime;
	    struct tm *today;
	    time( &ltime );
	    today = localtime( &ltime );
	    char tmpbuf[128];
	    strftime(tmpbuf, 128, "%A %d %B %Y à %H:%M:%S", today);
	
		cout << "----------------------------------------------------------------------------------------------------" << endl;
	    cout << "Partie terminée le " << tmpbuf << endl;
	    cout << "Score : " << tetris.score << endl;
	    cout << "Lignes : " << tetris.lines << endl;
	    cout << "Niveau : " << tetris.level << endl;
    //*/
    
    //* Sauvegarde du score maximal (meilleur score)
	    if (tetris.score > scoreMax) { // Si le score de la partie est supérieur au score maximum atteint...
		    ofstream scoreFile( "score.txt" );
	        scoreFile << tetris.score << endl << tetris.lines; // on sauvegarde le score actuel et son nombre de lignes
		}
	//*/
	
	if (loose_game == true) // si la partie est terminé parce que le joueur vient de perdre...
	    FSOUND_PlaySound(FSOUND_FREE, tetris.sound_loose_game); // on joue le son qui correspond à la perte de la partie
    

    SDL_RemoveTimer(timer_MoveBloc_auto); // Arrêt du Timer qui fait la descente automatique du bloc
        
	game = false;
}

int update_game()
{
	
	draw_surface( matrice, 0, 0, matrice->w, matrice->h, background, tetris.case_unit + tetris.grid_width, tetris.case_unit + tetris.grid_width ); // Effacement de l'écran
	//SDL_BlitSurface( background, 0, screen, 0 ); // Effacement de l'écran
	//update_surface(background);
	//update_surface(matrice);
	draw_surface(background, 0, 0, background->w, background->h, screen, 0, 0);
	
	board.display( screen ); // Affichage du fond d'écran
	currentBloc.display( screen, tetris.posX, tetris.posY ); // Affichage de la pièce courante
	nextBloc.display( screen, tetris.next_bloc_preview_x / (tetris.case_unit + tetris.grid_width), tetris.next_bloc_preview_y / (tetris.case_unit + tetris.grid_width)); // Affichage de la prochaine pièce
	
	// Affichage du niveau
	char level_str[100];
	sprintf(level_str, "Niveau = %d", tetris.level);
	show_text(level_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 1) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);

	// Affichage du score
	char score_str[100];
	sprintf(score_str, "Score  = %d", tetris.score);
	show_text(score_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 2) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);

	// Affichage des lignes
	char lines_str[100];
	sprintf(lines_str, "Lignes = %d", tetris.lines);
	show_text(lines_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 3) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);

	show_text("F2     = Nouvelle partie", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 1) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
	show_text("Espace = Pause", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 2) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
	show_text("Echap  = Quitter", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 3) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);

	char highScore[100];
	sprintf(highScore, "Meilleur score = %d", scoreMax);
	show_text(highScore, police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 5) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
	
	update_surface(screen); // Mise à jour de l'écran
	
	if ( !board.isMouvementValid( tetris.posX, tetris.posY, currentBloc ) && game == true ) // partie terminée
		end_game(true);    
	
	if (userMode == quit) {
	    quit_game();
	    return 0;
	}
	
}

// Fonction d'ajout de bloc : Si les taux des trois couleurs Rouge Vert Bleu ne sont pas spécifié, il y a génération aléatoire du taux de chaque couleur : voir le prototype de la fonction addBloc dans 'tetris.h' ----------------------------------------------------------------------------------------------------
void add_bloc(int blocMaxWidth, string blocShape, int redRate, int greenRate, int blueRate)
{
 	redRate = (redRate > 255) ? (rand() % 256) : redRate;
 	greenRate = (greenRate > 255) ? (rand() % 256) : greenRate;
 	blueRate = (blueRate > 255) ? (rand() % 256) : blueRate;
 	
    blocs.push_back( Bloc( tetris.bloc_number, blocMaxWidth, blocShape.c_str(), redRate, greenRate, blueRate ) ); // ajout du bloc avec dégradé vers le noir
    tetris.bloc_number++;
}

void add_special_bloc(int blocMaxWidth, string blocShape, int redRate, int greenRate, int blueRate)
{   
 	redRate = (redRate > 255) ? (rand() % 256) : redRate;
 	greenRate = (greenRate > 255) ? (rand() % 256) : greenRate;
 	blueRate = (blueRate > 255) ? (rand() % 256) : blueRate;
 	
    special_blocs.push_back( Bloc( tetris.special_bloc_number, blocMaxWidth, blocShape.c_str(), redRate, greenRate, blueRate ) ); // ajout du bloc avec dégradé vers le noir
	tetris.special_bloc_number++;
}

bool get_blocs_by_file (bool get_special_blocs)
{
//* chargement des blocs à partir du fichier
    ifstream blocs_file;
    if (!get_special_blocs)
	    blocs_file.open("blocs.txt", ios::in);
    else
	    blocs_file.open("special_blocs.txt", ios::in);
    	
	int len, redRate, greenRate, blueRate;
	string shape;
    vector <string> file_content; // variable qui contiendra le fichier (tableau avec une ligne par entrée du tableau)
    string ligne, tmp;
    int i = 0, j = 0, last_pos = 0, num = 0;
    bool no_error = false;
    if(blocs_file)
    {
        while(getline(blocs_file, ligne)) {
	        no_error = false;
            file_content.push_back( ligne );
            num = 0;
            last_pos = 0;
   			if (file_content[i].substr( 0, 2) != "//") {
	            for (j = 0; j < file_content[i].size(); j++) {
					if (file_content[i].substr( j, 1 ) == ";") {
					    tmp = file_content[i].substr( last_pos, j - last_pos );
					    last_pos = j + 1;
					    num++;
					    switch (num) {
			   		        case 1:
								len = atoi(tmp.c_str());
								break;
							case 2:
								shape = tmp.c_str();
								break;
							case 3:
								redRate = atoi(tmp.c_str());
								break;
							case 4:
								greenRate = atoi(tmp.c_str());
								break;
							case 5:
								blueRate = atoi(tmp.c_str());
								no_error = true;
								break;
						}
		   			}
				}
				if (no_error)
				    if (!get_special_blocs)
				        add_bloc( len, shape, redRate, greenRate, blueRate );
				    else
				        add_special_bloc( len, shape, redRate, greenRate, blueRate );
			}
			i++;
        }
    }
    else
    {
        return false;
    }
    blocs_file.close();
    return true;

//*/
}

void update_surface (SDL_Surface* surface)
{
    SDL_UpdateRect( surface, 0, 0, surface->w, surface->h );
	SDL_Flip(surface);
}

// Fonction d'affichage de surface sur une surface de destination ----------------------------------------------------------------------------------------------------
void draw_surface (SDL_Surface* src, int X_ori, int Y_ori, int srcWidth, int srcHeight, SDL_Surface* dest, int posX_onDest, int posY_onDest, Uint32 color)
{
 	// Les coordonnées de la surface sur la surface de destination
	    SDL_Rect srcPositionOnDestination; // définition de la variable
	    srcPositionOnDestination.x = posX_onDest; // abscisse
	    srcPositionOnDestination.y = posY_onDest; // ordonnée
	    SDL_Rect srcPosition;
	    srcPosition.x = X_ori;
	    srcPosition.y = Y_ori;
	    srcPosition.w = srcWidth;
	    srcPosition.h = srcHeight;
    if (color != 0) {
	   SDL_FillRect(src, NULL, color); // Remplissage de la surface avec la couleur (color) passée en paramètre
    }
    SDL_BlitSurface(src, &srcPosition, dest, &srcPositionOnDestination); // Collage de la surface (src) sur la destination (dest)
    // SDL_Flip(dest);
}

void init_window_style ()
{
    int i = 0; // variables pour les boucles
    // Chargement du fond d'écran
        SDL_Surface* random_background = generate_random_bmp_tuiles(); // génération aléatoire d'une image remplie de tuiles (special_blocs)
	    background = SDL_CreateRGBSurface(SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0); // On créé une surface nommée background
	    SDL_FillRect(background, NULL, tetris.background_color); // Remplissage de la surface avec la couleur (color) passée en paramètre
		draw_surface(random_background, 0, 0, random_background->w, random_background->h, background, 0, 0); // On dessine le background sur la fenêtre (screen)
	    //background = SDL_LoadBMP( "alea.bmp" ); // On charge une image de fond d'écran
	    draw_surface(background, 0, 0, background->w, background->h, screen, 0, 0); // On dessine le background sur la fenêtre (screen)
	    if ( !background ) // Si il y a une erreur sur la création du background... on envoie un runtime error (erreur d'éxécution)
	        throw runtime_error( SDL_GetError() );
			
    // Chargement de la matrice (zone de jeu)
	    matrice = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.board_width - (2 * tetris.case_unit) - tetris.grid_width, tetris.board_height - tetris.case_unit, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
	    draw_surface(matrice, 0, 0, matrice->w, matrice->h, background, tetris.case_unit + tetris.grid_width, tetris.case_unit + tetris.grid_width, tetris.matrice_color); // On dessine la matrice sur le fond d'écran
	    if ( !matrice )
		    throw runtime_error( SDL_GetError() );
    //*/
    
    //* Chargement du cadrillage
	    int numberLineY = tetris.board_size_y, numberLineX = tetris.board_size_y;
	    grid = SDL_CreateRGBSurface(SDL_HWSURFACE, matrice->w, matrice->h, 32, 0, 0, 0, 0); // On créé une surface pour la grille (grid)
		SDL_FillRect(grid, NULL, tetris.matrice_color); // on remet la couleur de la matrice comme couleur de fond
		    SDL_Surface* gridX[numberLineX];
		    for (i = 0; i < numberLineX; i++) {
		    	gridX[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, numberLineX * (tetris.case_unit + tetris.grid_width), tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la ligne
		        draw_surface(gridX[i], 0, 0, gridX[i]->w, gridX[i]->h, grid, 0, i*(tetris.case_unit + tetris.grid_width), tetris.grid_color); // On dessine la ligne (gridX[i]) sur la grille (grid)
				if ( !gridX[i] )
			        throw runtime_error( SDL_GetError() );
		    }
		    
		    SDL_Surface* gridY[numberLineY];
		    for (i = 0; i < numberLineY; i++) {
		    	gridY[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.grid_width, numberLineY * (tetris.case_unit + tetris.grid_width), 32, 0, 0, 0, 0); // On créé une surface pour la ligne
		        draw_surface(gridY[i], 0, 0, gridY[i]->w, gridY[i]->h, grid, i*(tetris.case_unit + tetris.grid_width), 0, tetris.grid_color); // On dessine la ligne (gridY[i]) sur la grille (grid)
				if ( !gridY[i] )
			        throw runtime_error( SDL_GetError() );
		    }
	    draw_surface(grid, 0, 0, grid->w, grid->h, matrice, 0, 0);
    //*/
    
    //* Chargement du fond de la zone d'aperçu du bloc suivant
	    previewBloc = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.next_bloc_preview_width + tetris.grid_width, tetris.next_bloc_preview_height + tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la grille (grid)
	    draw_surface(grid, 0, 0, grid->w, grid->h, previewBloc, 0, 0);
	    draw_surface(previewBloc, 0, 0, tetris.next_bloc_preview_width + tetris.grid_width, tetris.next_bloc_preview_height + tetris.grid_width, background, tetris.next_bloc_preview_x, tetris.next_bloc_preview_y + (tetris.case_unit + tetris.grid_width));
    //*/
    
    //* Chargement du tétrion (contour de la matrice)
        for (i = 0; i < tetris.board_size_x; i++) {
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.board_height + tetris.grid_width);
		}
        for (i = 0; i < tetris.board_size_y; i++) {
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.grid_width, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.board_width - tetris.case_unit, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		}
    //*/
    //* Chargement du tétrion de la zone d'aperçu du bloc suivant
        for (i = 0; i < tetris.next_bloc_preview_size_x; i++) {
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.next_bloc_preview_y + tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1) * (tetris.case_unit + tetris.grid_width) + tetris.next_bloc_preview_y + tetris.grid_width);
		}
        for (i = 0; i < tetris.next_bloc_preview_size_y + 2; i++) { // + 2 pour le haut et le bas
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x - tetris.case_unit, tetris.next_bloc_preview_y + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + tetris.next_bloc_preview_width  + tetris.grid_width, tetris.next_bloc_preview_y + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		}    
    //*/
    //* Chargement du tétrion de la zone d'affichage du score, des lignes et du niveau
        for (i = 0; i < tetris.right_panel_width; i++) {
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		}
	    SDL_Surface* score_background = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.right_panel_width - tetris.grid_width, 3 * (tetris.case_unit + tetris.grid_width) - tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
	    draw_surface( score_background, 0, 0, score_background->w, score_background->h, background, tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.matrice_color);
    //*/
    //* Chargement du tétrion de la zone d'affichage des aides
        for (i = 0; i < tetris.right_panel_width; i++) {
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		    draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 6)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
		}
	    SDL_Surface* help_background = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.right_panel_width - tetris.grid_width, 5 * (tetris.case_unit + tetris.grid_width) - tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
	    draw_surface( help_background, 0, 0, help_background->w, help_background->h, background, tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.matrice_color);
    //*/
}

void show_text (char* text, TTF_Font* font, SDL_Surface* dest, int posX, int posY, int redRate, int greenRate, int blueRate, int alpha)
{
	SDL_Color color = {redRate, greenRate, blueRate};
	SDL_Surface* text_surface = TTF_RenderText_Blended(font, text, color);
	SDL_SetAlpha(text_surface, SDL_SRCALPHA, alpha); // Transparence Alpha

	draw_surface(text_surface, 0, 0, text_surface->w, text_surface->h, dest, posX, posY);
}

SDL_Surface* generate_random_bmp_tuiles (bool saveBMP)
{
    //* Génération d'un fond aléatoire pleins de tuiles avec les blocs spéciaux excepté le premier bloc spécial qui sert pour le tétrion
	    SDL_Surface* random_background = SDL_CreateRGBSurface(SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0); // On créé une surface nommée background
	    int num_width = (screen->w / (tetris.case_unit + tetris.grid_width));
	    int num_height = (screen->h / (tetris.case_unit + tetris.grid_width));
		Bloc bloc2;
	    for (int x = 0; x < num_width; x++) {
	    	for (int y = 0; y < num_height; y++) {
				bloc2 = special_blocs[ (rand() % (special_blocs.size() - 1)) + 1 ];
				draw_surface( bloc2.get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, random_background, (x*(tetris.case_unit + tetris.grid_width)) + tetris.grid_width, (y*(tetris.case_unit + tetris.grid_width)) + tetris.grid_width);
			}
		}
		if (saveBMP)
		    SDL_SaveBMP(random_background, "alea.bmp"); // on sauvegarde l'image créé pour le fun ;)

    return random_background;
    //*/
}

// Fonction d'arrêt du programme ----------------------------------------------------------------------------------------------------
void quit_game()
{
    if (game == true) // Si il y a une partie en cours...
        end_game(); // on termine la partie

    // Libération des surfaces
    SDL_FreeSurface( grid );
    SDL_FreeSurface( matrice );
    SDL_FreeSurface( background );
    SDL_FreeSurface( screen );

	FSOUND_Close(); // on arrête FMOD (librairie qui gère le son)

/*
	TTF_CloseFont(police); // ferme la police chargée
	TTF_CloseFont(police_m); // ferme la police chargée
    TTF_Quit(); // arrêt de SDL_TTF
//*/
	SDL_Quit(); // On arrête SDL (lib qui gère l'affichage)
}

Uint32 MoveBloc_auto( Uint32 intervalle, void *param )
{
        if ( pause )
        {
            //SDL_BlitSurface( background, 0, screen, 0 ); // Effacement du plateau de jeu
            //SDL_BlitSurface(grid, 0, 
            update_surface(screen); // Mise à jour de l'écran
            return intervalle;
        }
        
        
	    GAMES_MODE tmp = goDown;
	    MoveBloc(tmp);
		update_game();

   
    return intervalle;
}
void MoveBloc( GAMES_MODE& mode )
{
    if (game == true) {
        switch( mode )
        {
            case quit :     break;
            case goLeft:    
	 						    FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_left_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à gauche
				 				GoLeft();
								break;
            case goRight:       
					 		    FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_right_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à droite
				                GoRight();
				 				break;
            case turnRight: 
							 	FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
				 				currentBloc.rotationRight();
							    break;
            case turnLeft:  
							 	FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
				 				currentBloc.rotationLeft();
								break;
            case goDown:    
								FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_down_user); // on joue le son qui correspond au fait que le joueur souhaite faire descendre le bloc
				 				GoDown();
								break;
            case goUp:      
				 				GoUp();
								break;
        }
        
        if ( !board.isMouvementValid( tetris.posX, tetris.posY, currentBloc ) )
        {
            switch( mode )
            {
                case goLeft:    
					   			FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_left_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à gauche
					 			GoRight();
								break;
                case goRight:
					 		    FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_right_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à droite
					            GoLeft();
								break;
                case turnRight: 
							 	FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
					 			currentBloc.rotationLeft();
                                userMode = none;
                                break;
                case goDown:    
					 			GoUp();
								board.addPiece( tetris.posX, tetris.posY, currentBloc );
                                currentBloc = nextBloc;
                                nextBloc = blocs[ rand() % blocs.size() ];
                                tetris.posY = tetris.init_posY;
                                tetris.posX = tetris.init_posX;
                                int result = board.reduce();
                                if (result == 2) {
    							    SDL_RemoveTimer(timer_MoveBloc_auto); // Arrêt du Timer
        						    GAMES_MODE tmp = goDown;
									timer_MoveBloc_auto = SDL_AddTimer(1000 / tetris.level, MoveBloc_auto, &tmp); // Démarrage du Timer
	                                FSOUND_PlaySound(FSOUND_FREE, tetris.sound_level_up); // on joue le son pour dire que le bloc à été posé
								} else if (result == 1) {
	                                FSOUND_PlaySound(FSOUND_FREE, tetris.sound_line_completed); // on joue le son pour dire que le bloc à été posé
								} else if (result == 0 ) {
	                                FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_is_fixed); // on joue le son pour dire que le bloc à été posé								  	   
		  	   					}
                                userMode = none;    // On arrête de descendre
                                                // pour une nouvelle pièce
                                break;
            }
        }
    }
       
        if ( mode == turnRight ) userMode = none; // On évite de tourner en rond en continue
        if ( mode == goLeft ) userMode = none;
        if ( mode == goRight ) userMode = none;
        if ( mode == goDown ) userMode = none;
}

########TETRIS.H########
#include <SDL/SDL.h> // librairie SDL qui gère l'affichage
#include <SDL/SDL_ttf.h> // librairie SDL_TTF qui gère l'affichage de texte
#include <FMOD/fmod.h> // librairie FMOD qui gère le son

#include <iostream>
#include <fstream>

#include <vector>
#include <stdexcept> // pour la gestion des erreurs
#include <stdlib.h>

#include <string>

using namespace std;

// ------------------- Déclarations des constantes (options du jeu)
struct options
{
	int board_size_x;
    int board_size_y;
    
    int case_unit;
    int board_width;
    int board_height;
    int grid_width;
    
    int next_bloc_preview_x;
    int next_bloc_preview_y;
    int next_bloc_preview_size_x;
    int next_bloc_preview_size_y;
    int next_bloc_preview_width;
    int next_bloc_preview_height;
    
    int right_panel_width;
    
    int bloc_border_width;
    Uint32 bloc_border_color;
   
    int bloc_number;
    int special_bloc_number;
	    
    int window_width;
    int window_height;
	char* window_title;
	
    int score;
    int lines;
    int line_number_to_level_up;
    int level;
    
    int init_posX;
    int init_posY;
    int posX;
    int posY;
    
    Uint32 background_color;
    Uint32 matrice_color;
    Uint32 tetrion_color;
    Uint32 grid_color;

	FSOUND_SAMPLE *sound_bloc_rotate_right;
	FSOUND_SAMPLE *sound_bloc_rotate_left;
	FSOUND_SAMPLE *sound_bloc_go_down;
	FSOUND_SAMPLE *sound_bloc_go_down_user;
	FSOUND_SAMPLE *sound_bloc_go_up_user;
	FSOUND_SAMPLE *sound_bloc_go_up;
	FSOUND_SAMPLE *sound_bloc_go_right_user;
	FSOUND_SAMPLE *sound_bloc_go_left_user;
	
	FSOUND_SAMPLE *sound_line_completed;
	FSOUND_SAMPLE *sound_level_up;
	FSOUND_SAMPLE *sound_loose_game;
	FSOUND_SAMPLE *sound_new_game;
	
	FSOUND_SAMPLE *sound_bloc_is_fixed;
	
	FSOUND_SAMPLE *sound_three;
	FSOUND_SAMPLE *sound_two;
	FSOUND_SAMPLE *sound_one;
	FSOUND_SAMPLE *sound_go;
	
	FSOUND_STREAM *musique;
	
};
options tetris;

// -------------------
enum GAMES_MODE { none, quit, turnRight, turnLeft, goDown, goUp, goRight, goLeft };
GAMES_MODE userMode = none;

bool pause = false;

#include "bloc.h"
vector<Bloc> blocs;
vector<Bloc> special_blocs;

Bloc currentBloc; // défini la variable qui contient le bloc qui descend
Bloc nextBloc; // défini la variable qui contient le bloc suivant (afficher en aperçu)

#include "board.h"
Board board; // Initialise le tableau de jeu (objet voir 'board.h')

SDL_Surface* screen; // la fenêtre
SDL_Surface* background; // le fond de la fenêtre
SDL_Surface* matrice; // la matrice (zone de jeu)
SDL_Surface* grid; // la grille de la matrice
SDL_Surface* previewBloc; // la zone d'aperçu du bloc suivant

int scoreMax = 0, lineMax = 0;

SDL_TimerID timer_MoveBloc_auto; // Variable pour stocker le numéro du Timer pout bouger le bloc automatiquement

int game = false; // variable boolean qui détermine si une partie est en cours ou non

TTF_Font* police = NULL;
TTF_Font* police_m = NULL;

void GoDown()   { ++tetris.posY; }
void GoUp()     { --tetris.posY; }
void GoLeft()   { --tetris.posX; }
void GoRight()  { ++tetris.posX; }

//* Prototypes des fonction de tetris.cpp
	void DisplayNumber( SDL_Surface* screen, SDL_Surface* tuiles, int x, int y, int s, int taille );
	void MoveBloc( GAMES_MODE& mode );
	Uint32 MoveBloc_auto( Uint32 intervalle, void *param ); // Timer pour le mouvement automatique du bloc
	void draw_surface (SDL_Surface* src, int X_ori, int Y_ori, int srcWidth, int srcHeight, SDL_Surface* dest, int posX_onDest, int posY_onDest, Uint32 color = 0);
	void update_surface (SDL_Surface* surface);
	void init_blocs();
	void init_colors(SDL_Surface* screen);
	void init_options();
	void add_bloc(int blocMaxWidth, string blocShape, int redRate = 256, int greenRate = 256, int blueRate = 256);
	void add_special_bloc(int blocMaxWidth, string blocShape, int redRate = 256, int greenRate = 256, int blueRate = 256);
	bool save_options(string filename);
	int update_game();
	void quit_game();
	void new_game();
	void end_game(bool loose_game = false);
	void show_grid();
	void show_text (char* text,TTF_Font* font, SDL_Surface* dest, int posX = 0, int posY = 0, int redRate = 0, int greenRate = 0, int blueRate = 0, int alpha = 255);
	SDL_Surface* generate_random_bmp_tuiles (bool saveBMP = false);
	void init_window_style();
	bool get_blocs_by_file(bool get_special_blocs = false);
//*/

########BLOC.H########

// ----------------------------------------------------
class Bloc
{
  public:
	Bloc ();
    Bloc( int, int, const char*, int redRate = (rand() % 256), int greenRate = (rand() % 256), int blueRate = (rand() % 256), const char* tuile_image = NULL );

    void display( SDL_Surface*, int, int ) const;
    
    void rotationRight();
    void rotationLeft();
    
    int index() const { return index_; }
    int size() const { return size_; }
    SDL_Surface* get_tuile() const { return tuile; }
    int get( int x, int y ) const { return data_[ x * size() + y ]; }
    

  private:
    int index_;
    int redRate_;
    int greenRate_;
    int blueRate_;
    SDL_Surface* tuile;
    int size_;  // nb de lignes/colonne de la matrice du bloc
    std::vector<int> data_;
};

Bloc::Bloc() {
}
// ----------------------------------------------------
Bloc::Bloc( int c, int s, const char* tab, int redRate, int greenRate, int blueRate, const char* tuile_image ) : index_( c ), size_( s ), redRate_( redRate ), greenRate_( greenRate ), blueRate_( blueRate )
{
    for ( ; *tab; ++tab )
	    data_.push_back( (*tab=='1')?1:0 );
    
    if (tuile_image == NULL) {
	    SDL_Surface* blocDegrade;
		tuile = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.case_unit + 2*tetris.grid_width, tetris.case_unit + 2*tetris.grid_width, 32, 0, 0, 0, 0); // La bordure du bloc
	    // Fait un dégradé de la couleur vers le noir
	    for (int i = 0; i < (tetris.case_unit / 2); i++) { // On parcourt la tuile de l'extérieur vers l'intérieur, pixel par pixel et plus on va vers l'intérieur, plus on va ver le noir
			blocDegrade = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.case_unit - (2 * i), tetris.case_unit - (2 * i), 32, 0, 0, 0, 0); // La bordure du bloc
		 	// Les coordonnées de la surface sur la surface de destination
			    SDL_Rect srcPosition; // définition de la variable
			    srcPosition.x = i + tetris.grid_width; // abscisse
			    srcPosition.y = i + tetris.grid_width; // ordonnée
		    //Uint32 color = SDL_MapRGB(tuile->format, redRate_ - (i * (redRate_ / ((tetris.case_unit / 2) - 1))), greenRate_ - (i * (greenRate_ / ((tetris.case_unit / 2) - 1))), blueRate_ - (i * (blueRate_ / ((tetris.case_unit / 2) - 1)))); // dégradé vers le noir
			Uint32 color = SDL_MapRGB(tuile->format, redRate_ + (i * ((255 - redRate_) / ((tetris.case_unit / 2) - 1))), greenRate_ + (i * ((255 - greenRate_) / ((tetris.case_unit / 2) - 1))), blueRate_ + (i * ((255 - blueRate_) / ((tetris.case_unit / 2) - 1)))); // dégradé vers le blanc
			SDL_FillRect(blocDegrade, NULL, color); // Remplissage de la surface avec la couleur (color) passée en paramètre
	    	SDL_BlitSurface(blocDegrade, NULL, tuile, &srcPosition); // Collage de la surface sur la destination (dest)

	    }
    } else {
        tuile = SDL_LoadBMP( tuile_image ); // chargement d'une image pour la tuiles
    }
}

// ----------------------------------------------------
void Bloc::rotationRight()
{
    for ( int i = 0; i < size() / 2 ; ++i )
        for ( int j = 0; j < ( size() + 1 )/ 2; ++j )
        {
          int iAux = size() - 1 - i;
          int jAux = size() - 1 - j;
          swap( data_[i * size() + j], data_[jAux * size() + i] );
          swap( data_[i * size() + j], data_[iAux * size() + jAux] );
          swap( data_[i * size() + j], data_[j * size() + iAux] );
        }
}

// ----------------------------------------------------
void Bloc::rotationLeft()
{
    for ( int i = 0; i < size() / 2 ; ++i )
        for ( int j = 0; j < ( size() + 1 )/ 2; ++j )
        {
          int iAux = size() - 1 - i;
          int jAux = size() - 1 - j;
          swap( data_[i * size() + j], data_[j * size() + iAux] );
          swap( data_[i * size() + j], data_[iAux * size() + jAux] );
          swap( data_[i * size() + j], data_[jAux * size() + i] );
        }
}

// ----------------------------------------------------
void Bloc::display( SDL_Surface* screen, int x, int y ) const
{
  for ( int i = 0; i < size(); ++i )
    for ( int j = 0; j < size(); ++j )
      if ( get( i, j ) )
      {

        SDL_Rect rectDest;
        rectDest.x = i * (tetris.case_unit + tetris.grid_width) + x * (tetris.case_unit + tetris.grid_width) + tetris.grid_width;
        rectDest.y = j * (tetris.case_unit + tetris.grid_width) + (y+1) * (tetris.case_unit + tetris.grid_width) + tetris.grid_width;
        rectDest.w = rectDest.h = 0;
				
        SDL_Rect rectSrc;
        rectSrc.x = tetris.grid_width;
        rectSrc.y = tetris.grid_width;
        rectSrc.w = rectSrc.h = tetris.case_unit;
		
        SDL_BlitSurface( tuile, &rectSrc, screen, &rectDest );
      }
}

########BOARD.H########

//--------------------------------------------
//*
class Board
{
  public:
    Board()
    {   // Initialisation des bordures
    }
    void display( SDL_Surface* ) const;
    
    bool isMouvementValid( int, int, const Bloc& ) const;
    void addPiece( int, int, const Bloc& );
	
	void init_board()
	{
		_board.resize(tetris.board_size_x); // redimensionne le tableau à sa taille réelle calculée dans l'initialisation des options
        for ( int x = 0; x < tetris.board_size_x; ++x ) {
			_board[x].resize(tetris.board_size_y);
            for ( int y = 0; y < tetris.board_size_y; ++y ) {
               _board[x][y] = ( x == 0 || x == tetris.board_size_x - 1 || y == tetris.board_size_y - 1 );
			}
		}
 	}
	
    void reduceLine( int );
    int reduce();

    private:
        vector < vector<int> > _board; // utilisation d'un tableau multidimensionnel redimensionnable vector
};

// ----------------------------------------------------
void Board::display( SDL_Surface* screen ) const
{
  for ( int x = 1; x < tetris.board_size_x-1; ++x )
    for ( int y = 0; y < tetris.board_size_y-1; ++y )
      if ( _board[x][y] )
      {
        SDL_Rect rectDest;
        rectDest.x = x * (tetris.case_unit + tetris.grid_width);
        rectDest.y = (y+1)* (tetris.case_unit + tetris.grid_width);
        rectDest.w = rectDest.h = 0;
        
        SDL_Rect rectSrc;
        rectSrc.x = 0;
        rectSrc.y = 0;
        rectSrc.w = rectSrc.h = tetris.case_unit + (2*tetris.grid_width);
        
        SDL_BlitSurface( blocs[_board[x][y] - 1].get_tuile(), &rectSrc, screen, &rectDest );
      }
}

// ----------------------------------------------------
bool Board::isMouvementValid( int posX, int posY, const Bloc& bloc ) const
{
    for ( int x = posX; x < posX + bloc.size(); ++x )
        for ( int y = posY; y < posY + bloc.size(); ++y )
            if ( bloc.get( x - posX, y - posY ) && _board[x][y] )
                return false;
    return true;
}

// ----------------------------------------------------
void Board::addPiece( int posX, int posY, const Bloc& bloc )
{
    for ( int x = posX; x < posX + bloc.size(); ++x )
        for ( int y = posY; y < posY + bloc.size(); ++y )
            if ( bloc.get( x - posX, y - posY ) )
                _board[x][y] = bloc.index() + 1;
}

// ----------------------------------------------------
int Board::reduce()
{
    int addedLine = 0;
    for ( int y = 1; y < tetris.board_size_y - 1 ; ++y )
    {
        bool lineFull = true;
        for ( int x = 1; ( x < tetris.board_size_x - 1 ) && lineFull; ++x )
            if ( !_board[x][y] ) lineFull = false;

        if ( lineFull )
        {
            ++addedLine;               // Une ligne suplémentaire
            for ( int z = y; z > 1 ; --z )
                for ( int x = 1; x < tetris.board_size_x - 1; ++x )
                    _board[x][z] = _board[x][z-1];

            for ( int x = 1; x < tetris.board_size_x - 1; ++x )
                _board[x][0] = 0;
         }
    }

    tetris.lines += addedLine;
    if (tetris.level < ( tetris.lines / tetris.line_number_to_level_up ) + 1) {
        tetris.level++; // Un niveau supplémentaire
        tetris.score += (tetris.level * 100) + (tetris.level * min( 4, addedLine ) + addedLine) * 150;        // Un point pour le niveau
        return 2;
    }
    if (addedLine > 0) {
	    tetris.score += (tetris.level * min( 4, addedLine ) + addedLine) * 150;        // Un point pour le niveau
	    return 1;
	}
    return 0;
}

Conclusion :


Tout est dans le zip A CETTE ADRESSE parce que le package est trop lourd (2MO)

Version 1 (2MO) : http://dev.thierry.poinot.fr/TetrisV1.0 10-08-2007 16h35.zip

Version 2 (5MO) : http://dev.thierry.poinot.fr/TetrisV2.0 19-08-2007 15h45.zip

Il contient les DLL, les sources, le projet Dev-cpp et l'éxécutable.

Pour les dernières mise à jour : http://blog.thierry.poinot.fr/dc/?post/2007/08/14/Tetris-V10

Bugs connus :
le jeu ne se ferme qu'en appuyant sur ECHAP
- l'action de fermer la fenêtre avec la croix de la fenêtre ne marche pas je ne sais pas pourquoi...
- lorsque le jeu est en pause, il est impossible de fermer

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.