score display.
- There were issues with input flushing, often preventing the Game
Over screen from displaying.
+- The level editor was crashing and was using 100% CPU time.
ISSUES:
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.
- There are some globals in pacman.h that should really be macro
definitions, and/or moved to the main module.
- Uses ad-hoc command line arguments processing rather than getopt(3).
- Should save/load/remember the high score.
+- Should support monochrome displays.
+- With the colors used some ghosts can be difficult to see properly under
+ common terminals+screens.
+CC=cc
PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
DATAROOTDIR=$(PREFIX)/share
+LIBS=-lcurses
+
+CFLAGS=-O2 -Wall
+
+# Very useful to correct important bugs
+#CFLAGS+=-Wall -O0 -g -Werror=missing-prototypes \
+# -Werror=implicit-function-declaration -Werror=int-to-pointer-cast \
+# -Werror=pointer-to-int-cast -Werror=format-extra-args -Werror=format= \
+# -Werror=maybe-uninitialized
+
+LDFLAGS+=$(LIBS)
+#LDFLAGS+=-g
+
+
all:
-# gcc pacman.c -o pacman -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lncurses
- gcc pacman.c -o pacman -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lcurses
-# gcc pacmanedit.c -o pacmanedit -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lncurses
+ $(CC) pacman.c -o pacman -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
+ $(CC) pacmanedit.c -o pacmanedit -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
install: all
install -D pacman $(DESTDIR)/usr/games/pacman4console
-# install -D pacmanedit $(DESTDIR)/usr/bin/pacman4consoleedit
+ install -D pacmanedit $(DESTDIR)/usr/bin/pacman4consoleedit
install -d $(DESTDIR)/usr/share/pacman4console/Levels
install -m 644 Levels/*dat $(DESTDIR)/usr/share/pacman4console/Levels/
uninstall:
rm -f $(DESTDIR)$(BINDIR)/pacman
-# rm -f $(DESTDIR)$(BINDIR)/pacmanedit
+ rm -f $(DESTDIR)$(BINDIR)/pacmanedit
rm -f $(DESTDIR)$(DATAROOTDIR)/pacman/Levels/level0[1-9].dat
rm -f $(DESTDIR)$(DATAROOTDIR)/pacman/Levels/README
rm -f $(DESTDIR)$(DATAROOTDIR)/pacman/Levels/template.dat
clean:
rm -f pacman
-# rm -f pacmanedit
+ rm -f pacmanedit
* By: Mike Billars (michael@gmail.com) *
* Date: 2014-04-26 *
* *
+* Improved by Matthew Mondor in 2023. *
+* *
* Please see file COPYING for details on licensing *
* and redistribution of this program *
* *
void IntroScreen(void); //Show introduction screen and menu
int CheckCollision(void); //See if Pacman and Ghosts collided
void CheckScreenSize(void); //Make sure resolution is at least 33x29
-void CreateWindows(int y, int x, int y0, int x0); //Make ncurses windows
+void CreateWindows(int y, int x, int y0, int x0); //Make curses windows
void Delay(void); //Slow down game for better control
void DrawWindow(void); //Refresh display
void Cleanup(void); //endwin(3) cleanup handler
void ExitProgram(const char *message); //Exit and display something
void GetInput(void); //Get user input
-void InitCurses(void); //Start up ncurses
+void InitCurses(void); //Start up curses
void LoadLevel(char *levelfile); //Load level into memory
int MainLoop(void); //Main program function
void MoveGhosts(void); //Update Ghosts' location
void MovePacman(void); //Update Pacman's location
void PauseGame(void); //Pause
void PrintHelp(char* name); //Print help and exit
+int GameOverScreen(void);
/*******************
* GLOBAL VARIABLES *
*******************/
//I know global variables are bad, but it's just sooo easy!
-//Windows used by ncurses
+//Windows used by curses
WINDOW * win;
WINDOW * status;
//For colors
enum { Wall = 1, Normal, Pellet, PowerUp, GhostWall, Ghost1, Ghost2, Ghost3, Ghost4, BlueGhost, Pacman };
-int Loc[5][2] = { 0 }; //Location of Ghosts and Pacman
-int Dir[5][2] = { 0 }; //Direction of Ghosts and Pacman
-int StartingPoints[5][2] = { 0 }; //Default location in case Pacman/Ghosts die
-int Invincible = 0; //Check for invincibility
-int Food = 0; //Number of pellets left in level
-int Level[29][28] = { 0 }; //Main level array
-int LevelNumber = 0; //What level number are we on?
-int HiPoints = 0; //Highscore
-int HiLevelNumber = 0; //Level number reached by hiscore
-int GhostsInARow = 0; //Keep track of how many points to give for eating ghosts
-int tleft = 0; //How long left for invincibility
+int Loc[5][2]; //Location of Ghosts and Pacman
+int Dir[5][2]; //Direction of Ghosts and Pacman
+int StartingPoints[5][2]; //Default location in case Pacman/Ghosts die
+int Invincible = 0; //Check for invincibility
+int Food = 0; //Number of pellets left in level
+int Level[29][28]; //Main level array
+int LevelNumber = 0; //What level number are we on?
+int HiPoints = 0; //Highscore
+int HiLevelNumber = 0; //Level number reached by hiscore
+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';
srand( (unsigned)time( NULL ) );
- InitCurses(); //Must be called to start ncurses
+ InitCurses(); //Must be called to start curses
CheckScreenSize(); //Make sure screen is big enough
CreateWindows(30, 28, 1, 1); //Create the main and status windows
curses_initialized = true;
}
-int GameOverScreen() {
+int GameOverScreen(void) {
int ch;
if (Points > HiPoints) {
//Temporary variables
int a = 0; int b = 0;
char chr = ' '; //Variable used to display certain characters
- int attr; //Variable that displays normal/bold character
+ int attr = A_NORMAL; //Variable that displays normal/bold character
//Display level array
for(a = 0; a < 29; a++) for(b = 0; b < 28; b++) {
* Description: Gracefully end program *
****************************************************************/
void ExitProgram(const char *message) {
- endwin(); //Uninitialize ncurses and destroy windows
+ endwin(); //Uninitialize curses and destroy windows
curses_initialized = false;
printf("%s\n", message); //Display message
exit(0); //End program, return 0
* Function: InitCurses() *
* Parameters: none *
* Returns: none *
-* Description: Initialize ncurses and set defined colors *
+* Description: Initialize curses and set defined colors *
****************************************************************/
void InitCurses() {
- initscr(); //Needed for ncurses windows
+ initscr(); //Needed for curses windows
start_color(); //Activate colors in console
curs_set(0); //Hide cursor
* By: Mike Billars (michaelbillars@gmail.com) *
* Date: 2014-04-26 *
* *
+* Improved by Matthew Mondor in 2023. *
+* *
* Please see file COPYING for details on licensing *
* and redistribution of this program *
* *
/***********
* INCLUDES *
***********/
+#include <stdbool.h>
#include <stdio.h>
#include <curses.h>
#include <string.h>
/*************
* PROTOTYPES *
*************/
-void CheckScreenSize(); //Make sure resolution is at least 32x29
+void CheckScreenSize(void); //Make sure resolution is at least 32x29
void CreateWindows(int y, int x, int y0, int x0); //Make ncurses windows
-void DrawWindow(); //Refresh display
+void DrawWindow(void); //Refresh display
void ExitProgram(char message[255]); //Exit gracefully
-void GetInput(); //Get user input
-void InitCurses(); //Start up ncurses
-void LoadLevel(); //Load level into memory
-void MainLoop(); //Main loop
-void SaveLevel(); //Save level to specified file
+void Cleanup(void); //Curses cleanup
+void GetInput(void); //Get user input
+void InitCurses(void); //Start up ncurses
+void LoadLevel(void); //Load level into memory
+void MainLoop(void); //Main loop
+void SaveLevel(void); //Save level to specified file
/*******************
* GLOBAL VARIABLES *
*******************/
//I know global variables are bad, but it's just sooo easy!
+//Curses cleanup
+bool curses_initialized = false;
+
//Windows used by ncurses
WINDOW * win;
WINDOW * status;
//For colors
enum { Wall = 1, Normal, Pellet, PowerUp, GhostWall, Ghost1, Ghost2, Ghost3, Ghost4, BlueGhost, Pacman, Cursor};
-int Level[29][28] = { 0 }; //Main level array
-int Loc[6][2] = { 0 }; //Ghosts, Pacman, and cursor locations
-int tleft = 0; //How long left for invincibility
-char filename[255] = ""; //Name of file to load/save
+int Level[29][28]; //Main level array
+int Loc[6][2]; //Ghosts, Pacman, and cursor locations
+int tleft = 0; //How long left for invincibility
+char filename[255] = ""; //Name of file to load/save
/****************************************************************
* Function: main() *
****************************************************************/
int main(int argc, char *argv[100]) {
+ InitCurses(); //Initialize curses
+ curses_initialized = true;
+ (void)atexit(Cleanup);
+
//Make sure they entered a filename to open/save
if((argc > 1) && (strlen(argv[1]) >= 1)) {
strcpy(filename, argv[1]); //Copy command line parameter into string
LoadLevel(); //Load the file
- InitCurses(); //Initialize ncurses
CheckScreenSize(); //Make sure the screen is big enough
CreateWindows(29, 28, 1, 1); //
else
ExitProgram("You must specify a file to use (load and save)");
+ exit(EXIT_SUCCESS);
+}
+
+void Cleanup(void)
+{
+
+ if (curses_initialized) {
+ endwin();
+ curses_initialized = false;
+ }
}
/****************************************************************
* Returns: none *
* Description: Make sure the virtual console is big enough *
****************************************************************/
-void CheckScreenSize() {
+void CheckScreenSize(void) {
//Make sure the window is big enough
int h, w; getmaxyx(stdscr, h, w);
if((h < 32) || (w < 29)) {
- endwin();
+ Cleanup();
fprintf(stderr, "\nSorry.\n");
fprintf(stderr, "To edit levels for Pacman for Console, your console window\n");
fprintf(stderr, "must be at least 32x29 Please resize your window/resolution\n");
* Returns: none *
* Description: Redraw each window to update the screen *
****************************************************************/
-void DrawWindow() {
+void DrawWindow(void) {
int a = 0; int b = 0;
char chr = ' ';
- int attr;
+ int attr = A_NORMAL;
//Display level array
for(a = 0; a < 29; a++) for(b = 0; b < 28; b++) {
****************************************************************/
void ExitProgram(char message[255]) {
- endwin();
+ Cleanup();
//Must save file
if(message[0]=='s') {
else
printf("%s\n\n", message);
- exit(0);
+ exit(EXIT_FAILURE);
}
/****************************************************************
* Returns: none *
* Description: Get input from user and take appropriate action *
****************************************************************/
-void GetInput() {
+void GetInput(void) {
int ch;
int a=0;
int b=0;
- static int chtmp;
-
ch = getch();
- //Buffer input
- do {
- DrawWindow();
- ch = getch();
- } while (ch == ERR);
-
switch (ch) {
case KEY_UP: case 'w': case 'W':
Loc[5][0]--;
* Returns: none *
* Description: Initialize ncurses and set defined colors *
****************************************************************/
-void InitCurses() {
+void InitCurses(void) {
initscr(); //Needed for ncurses windows
start_color(); //Activate colors in console
- curs_set(0); // Don't remember
+ curs_set(0); //Invisible cursor
keypad(stdscr, TRUE); //Activate arrow keys
- nodelay(stdscr, TRUE); //Allow getch to work without pausing
- nonl(); // Don't remember
- cbreak(); // Don't remember
+ nodelay(stdscr, FALSE); //getch(3) mode
+ timeout(-1); //blocking getch(3)
+ nonl(); //No Newline translation
+ cbreak(); //No line buffering
noecho(); //Don't display input key
+ leaveok(stdscr, FALSE); //Leave cursor alone
//Make custom text colors
init_pair(Normal, COLOR_WHITE, COLOR_BLACK);
* Returns: none *
* Description: Open level file and load it into memory *
****************************************************************/
-void LoadLevel() {
+void LoadLevel(void) {
int a = 0; int b = 0;
FILE *fin;
* Returns: none *
* Description: Control the main execution of the game *
****************************************************************/
-void MainLoop() {
+void MainLoop(void) {
+ (void)ungetch(' '); // For some reason we need this
do {
- GetInput();
DrawWindow();
+ GetInput();
} while (1);
}
* Returns: none *
* Description: Save current level array to a specified file *
****************************************************************/
-void SaveLevel() {
+void SaveLevel(void) {
int a=0;
int b=0;