Subject: Fix some problems and add features. - Problems fixed: * Changed screen/window resolution error message. * Bugfix for possible buffer overflow when choosing a level. (Closes #641652) * Bugfix for possible index out of bound when going through a border while playing. (Closes #641657) - Feature to allow create a menu icon for X (Closes: #737997): * Game Over screen which allows to exit or to restart. - Another features: * Added a help option (documents before undocumented level choosing option). * Changed option syntax for level choosing. Author: Yannic Scheper Author: Alexandre Dantas Last-Update: 2014-08-13 --- pacman4console.orig/pacman.c +++ pacman4console/pacman.c @@ -31,7 +31,7 @@ * PROTOTYPES * *************/ void IntroScreen(); //Show introduction screen and menu -void CheckCollision(); //See if Pacman and Ghosts collided +int CheckCollision(); //See if Pacman and Ghosts collided void CheckScreenSize(); //Make sure resolution is at least 32x29 void CreateWindows(int y, int x, int y0, int x0); //Make ncurses windows void Delay(); //Slow down game for better control @@ -40,11 +40,11 @@ void ExitProgram(const char *message); void GetInput(); //Get user input void InitCurses(); //Start up ncurses void LoadLevel(char *levelfile); //Load level into memory -void MainLoop(); //Main program function +int MainLoop(); //Main program function void MoveGhosts(); //Update Ghosts' location void MovePacman(); //Update Pacman's location void PauseGame(); //Pause - +void PrintHelp(char* name); //Print help and exit /******************* * GLOBAL VARIABLES * @@ -76,41 +76,71 @@ int tleft = 0; ****************************************************************/ int main(int argc, char *argv[100]) { - int j = 0; + int loop = 1; //loop program? 0 = no, 1 = yes + char* level = NULL; //level to load + int j = 1; + int i; + for(i = 1; i < argc; ++i) { + if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { + PrintHelp(argv[0]); + return 0; + } + else if(strncmp(argv[i], "--level=", 8) == 0) { + level = argv[i]; + level += 8; + int len = strlen(level); + if(len == 0) { + level = NULL; + } + else if(len == 1) { + for(LevelNumber = '1'; LevelNumber <= '9'; LevelNumber++) { + if(LevelNumber == level[0]) { + j = LevelNumber - '0'; + level = NULL; + break; + } + } + } + } + else { + PrintHelp(argv[0]); + return 0; + } + } + srand( (unsigned)time( NULL ) ); InitCurses(); //Must be called to start ncurses CheckScreenSize(); //Make sure screen is big enough CreateWindows(29, 28, 1, 1); //Create the main and status windows - //If they specified a level to load - if((argc > 1) && (strlen(argv[1]) > 1)) { - argv[1][99] = '\0'; - LoadLevel(argv[1]); //Load it and... - MainLoop(); //Start the game - } - - //If they did not enter a level, display intro screen then use default levels - else { - IntroScreen(); //Show intro "movie" - j = 1; //Set initial level to 1 - - if(argc > 1) j = argv[1][0] - '0'; //They specified a level on which to start (1-9) - - //Load 9 levels, 1 by 1, if you can beat all 9 levels in a row, you're awesome - for(LevelNumber = j; LevelNumber < 10; LevelNumber++) { - - //Replace level string underscore with the actual level number (see pacman.h) - LevelFile[strlen(LevelFile) - 6] = '0'; - LevelFile[strlen(LevelFile) - 5] = LevelNumber + '0'; - - LoadLevel(LevelFile); //Load level into memory - Invincible = 0; //Reset invincibility with each new level - MainLoop(); //Start the level + IntroScreen(); //Show intro "movie" + int start_lives = Lives; + int start_points = Points; + do { + Lives = start_lives; + Points = start_points; + if(level == NULL) { + //j = 1; + //Load levels, 1 by 1, if you can beat all 9 levels in a row, you're awesome + for(LevelNumber = j; LevelNumber < 10; LevelNumber++) { + LevelFile[strlen(LevelFile) - 6] = '0'; + LevelFile[strlen(LevelFile) - 5] = LevelNumber + '0'; + LoadLevel(LevelFile); + Invincible = 0; //Reset invincibility + if(MainLoop() == 1) break; + } } + else { + //Load special non-standard level + LoadLevel(level); + Invincible = 0; //Reset invincibility + MainLoop(); + } - } + if(GameOverScreen() == 1) loop = 0; + } while(loop == 1); //Game has ended, deactivate and end program ExitProgram(EXIT_MSG); @@ -125,7 +155,7 @@ int main(int argc, char *argv[100]) { * Returns: none * * Description: Check and handle if Pacman collided with a ghost * ****************************************************************/ -void CheckCollision() { +int CheckCollision() { //Temporary variable int a = 0; @@ -165,7 +195,7 @@ void CheckCollision() { usleep(1000000); //If no more lives, game over - if(Lives == -1) ExitProgram(END_MSG); + if(Lives == -1) return 1; //If NOT game over... @@ -187,6 +217,7 @@ void CheckCollision() { } } } + return 0; } /**************************************************************** @@ -203,13 +234,41 @@ void CheckScreenSize() { if((h < 32) || (w < 29)) { endwin(); fprintf(stderr, "\nSorry.\n"); - fprintf(stderr, "To play Pacman for Console, your console window must be at least 32x29\n"); + fprintf(stderr, "To play Pacman for Console, your console window must be at least 29x32\n"); fprintf(stderr, "Please resize your window/resolution and re-run the game.\n\n"); exit(0); } } +int GameOverScreen() { + char chr = ' '; + int a, b; + for(a = 0; a < 29; a++) for(b = 0; b < 28; b++) { + mvwaddch(win, a, b, chr); + } + + wattron(win, COLOR_PAIR(Pacman)); + mvwprintw(win, 8, 11, "Game Over"); + + wattron(win, COLOR_PAIR(Normal)); + mvwprintw(win, 14, 2, "Press q to quit ..."); + mvwprintw(win, 16, 2, "... or any other key"); + mvwprintw(win, 17, 6, "to play again"); + + wrefresh(win); + + //And wait + int chtmp; + do { + chtmp = getch(); + } while (chtmp == ERR); + + if(chtmp == 'q' || chtmp == 'Q') + return 1; + return 0; +} + /**************************************************************** * Function: CreateWindows() * * Parameters: y, x, y0, x0 (coords and size of window) * @@ -494,7 +553,7 @@ void IntroScreen() { * Returns: none * * Description: Open level file and load it into memory * ****************************************************************/ -void LoadLevel(char levelfile[100]) { +void LoadLevel(char* levelfile) { int a = 0; int b = 0; size_t l; @@ -555,7 +614,7 @@ void LoadLevel(char levelfile[100]) { * Returns: none * * Description: Control the main execution of the game * ****************************************************************/ -void MainLoop() { +int MainLoop() { DrawWindow(); //Draw the screen wrefresh(win); wrefresh(status); //Refresh it just to make sure @@ -564,15 +623,15 @@ void MainLoop() { /* Move Pacman. Move ghosts. Check for extra life awarded from points. Pause for a brief moment. Repeat until all pellets are eaten */ do { - MovePacman(); DrawWindow(); CheckCollision(); - MoveGhosts(); DrawWindow(); CheckCollision(); + MovePacman(); DrawWindow(); if (CheckCollision() == 1) return 1; + MoveGhosts(); DrawWindow(); if (CheckCollision() == 1) return 1; if(Points > FreeLife) { Lives++; FreeLife *= 2;} Delay(); } while (Food > 0); DrawWindow(); //Redraw window and... usleep(1000000); //Pause, level complete - + return 0; } /**************************************************************** @@ -748,3 +807,12 @@ void PauseGame() { } while (chtmp == ERR); } + +void PrintHelp(char* name) { + printf("Usage: %s [OPTION]\n\n", name); + printf("Options:\n"); + printf(" -h, --help print help\n"); + printf(" --level=[1..9] start at specified standard level\n"); + printf(" --level=LEVEL play specified non-standard LEVEL\n"); +} +