--- /dev/null
+Fork derived from the original code found here:
+http://archive.ubuntu.com/ubuntu/ubuntu/pool/universe/p/pacman4console/
+
+
+IMPROVEMENTS:
+
+- Applied patches from the ubuntu maintainer like adding a game
+ over screen.
+- Disables the cursor, re-enabling it when requesting input in
+ blocking mode.
+- Use blocking mode outside of the main action game loop.
+- Toggle the hero between C and O characters so that it is animated
+ and "munches".
+- Use flushinp(3) instead of ad hoc getch(3) to flush input.
+- Added an atexit(3) cleanup handler for endwin(3).
+
+
+BUGFIXES:
+
+- Used to take 100% CPU time in its delay loop. It assumed that no
+ character buffering occurs and that non-blocking getch() had to
+ be called in a loop until the time expired, when it can simply be
+ called after the timer expires.
+- Used illegal usleep(1000000) with undefined behavior that waited
+ one secod on Linux+glibc but that doesn't sleep on NetBSD. These
+ were replaced with sleep(1). This affected transitions and the
+ score display.
+
+
+ISSUES:
+
+- The original makefile is buggy and includes uninstall in the
+ clean target. Can also easily use native BSD curses where
+ available rather than always depending on ncurses. Should ideally
+ detect the situation.
+- The level editor crashes, it's possible that it requires porting
+ to 64-bit or other fixes. Did not bother.
#include <stdio.h>
#include <curses.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
void CreateWindows(int y, int x, int y0, int x0); //Make ncurses windows
void Delay(); //Slow down game for better control
void DrawWindow(); //Refresh display
+void Cleanup(void); //endwin(3) cleanup handler
void ExitProgram(const char *message); //Exit and display something
void GetInput(); //Get user input
void InitCurses(); //Start up ncurses
int GhostsInARow = 0; //Keep track of how many points to give for eating ghosts
int tleft = 0; //How long left for invincibility
+//Hero
+int hero = 'C';
+
+//Curses cleanup
+bool curses_initialized = false;
+
+
/****************************************************************
* Function: main() *
* Parameters: argc, argv (passed from command line) *
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
+ curses_initialized = true;
+ (void)atexit(Cleanup);
IntroScreen(); //Show intro "movie"
+ (void)flushinp();
int start_lives = Lives;
int start_points = Points;
GhostsInARow *= 2;
wrefresh(win); //Update display
- usleep(1000000); //and pause for a second
+ sleep(1); //and pause for a second
//Reset the ghost's position to the starting location
Loc[a][0] = StartingPoints[a][0]; Loc[a][1] = StartingPoints[a][1];
//Subtract one life and pause for 1 second
Lives--;
- usleep(1000000);
+ sleep(1);
//If no more lives, game over
if(Lives == -1) return 1;
Dir[4][0] = 0; Dir[4][1] = -1;
DrawWindow(); //Redraw window
- usleep(1000000); //Pause for 1 second before continuing game
+ sleep(1); //Pause for 1 second before continuing game
}
}
}
//And wait
int chtmp;
+ (void)flushinp();
+ (void)curs_set(1);
+ (void)nodelay(stdscr, FALSE);
do {
chtmp = getch();
} while (chtmp == ERR);
+ (void)nodelay(stdscr, TRUE);
+ (void)curs_set(0);
if(chtmp == 'q' || chtmp == 'Q')
return 1;
* Returns: none *
* Description: Pause the game and still get keyboard input *
****************************************************************/
+#if 0
void Delay() {
//Needed to get time
ftime(&t_current); //Update time and check if enough time has overlapped
} while (abs(t_start.millitm - t_current.millitm) < SpeedOfGame);
}
+#endif
+void
+Delay(void)
+{
+
+ usleep(1000000 / FPS);
+ GetInput();
+}
/****************************************************************
* Function: DrawWindow() *
}
//Display Pacman
- wattron(win, COLOR_PAIR(Pacman)); mvwaddch(win, Loc[4][0], Loc[4][1], 'C');
-
+ wattron(win, COLOR_PAIR(Pacman)); mvwaddch(win, Loc[4][0], Loc[4][1], hero);
wrefresh(win); //Update main window
}
****************************************************************/
void ExitProgram(const char *message) {
endwin(); //Uninitialize ncurses and destroy windows
+ curses_initialized = false;
printf("%s\n", message); //Display message
exit(0); //End program, return 0
}
+void Cleanup(void)
+{
+
+ if (curses_initialized) {
+ endwin();
+ curses_initialized = false;
+ }
+}
+
/****************************************************************
* Function: GetInput() *
* Parameters: none *
case 'p': case 'P': //Pause game
PauseGame();
- chtmp = getch(); //Update buffered input
+// chtmp = getch(); //Update buffered input
break;
case 'q': case 'Q': //End program
void InitCurses() {
initscr(); //Needed for ncurses windows
+
start_color(); //Activate colors in console
- curs_set(0); // Don't remember
- keypad(stdscr, TRUE); //Activate arrow keys
+ curs_set(0); //Hide cursor
+ keypad(stdscr, TRUE); //Activate arrow key seq interpretation
nodelay(stdscr, TRUE); //Allow getch to work without pausing
- nonl(); // Don't remember
- cbreak(); // Don't remember
+ nonl(); //Dont convert CR to NL
+ cbreak(); //Disable line buffering input
noecho(); //Don't display input key
+ leaveok(stdscr, FALSE); //Leave cursor alone
//Make custom text colors
init_pair(Normal, COLOR_WHITE, COLOR_BLACK);
int a = 0;
int b = 23;
- a=getch(); a=getch(); a=getch();//Clear the buffer
+ (void)flushinp(); // Clear input buffer
mvwprintw(win, 20, 8, "Press any key...");
wattron(win, COLOR_PAIR(Pacman));
mvwprintw(win, 8, 12, "PACMAN");
wrefresh(win);
- usleep(1000000);
+ sleep(1);
//Ghosts chase Pacman
for(a = 0; a < 23; a++) {
usleep(100000);
}
- usleep(150000);
+ sleep(1);
+ usleep(50000);
//Pacman eats powerup and chases Ghosts
for(a = 25; a > 2; a--) {
DrawWindow(); //Draw the screen
wrefresh(win); wrefresh(status); //Refresh it just to make sure
- usleep(1000000); //Pause for a second so they know they're about to play
+ sleep(1); //Pause for a second so they know they're about to play
/* Move Pacman. Move ghosts. Check for extra life awarded
from points. Pause for a brief moment. Repeat until all pellets are eaten */
MoveGhosts(); DrawWindow(); if (CheckCollision() == 1) return 1;
if(Points > FreeLife) { Lives++; FreeLife *= 2;}
Delay();
+ hero = (hero == 'C' ? 'O' : 'C');
} while (Food > 0);
DrawWindow(); //Redraw window and...
- usleep(1000000); //Pause, level complete
+ sleep(1); //Pause, level complete
return 0;
}
wrefresh(win);
//And wait until key is pressed
+ (void)curs_set(1);
+ (void)nodelay(stdscr, FALSE);
do {
chtmp = getch(); //Get input
} while (chtmp == ERR);
+ (void)nodelay(stdscr, TRUE);
+ (void)curs_set(0);
}