From: Matthew Mondor Date: Tue, 11 Apr 2023 22:59:15 +0000 (+0000) Subject: Commit custom improvements and description in MATT-README.txt X-Git-Url: http://git.pulsar-zone.net/?a=commitdiff_plain;h=231d674daa8e4d1f12f6e1900f7a34baf9935a0b;p=pacman.git Commit custom improvements and description in MATT-README.txt --- diff --git a/MATT-README.txt b/MATT-README.txt new file mode 100644 index 0000000..c3bd514 --- /dev/null +++ b/MATT-README.txt @@ -0,0 +1,37 @@ +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. diff --git a/Makefile b/Makefile index 6d0bd53..c3e9d24 100755 --- a/Makefile +++ b/Makefile @@ -3,19 +3,20 @@ BINDIR=$(PREFIX)/bin DATAROOTDIR=$(PREFIX)/share all: - gcc pacman.c -o pacman -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lncurses - gcc pacmanedit.c -o pacmanedit -DDATAROOTDIR=\"$(DATAROOTDIR)\" $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lncurses +# 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 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 @@ -24,4 +25,4 @@ uninstall: clean: rm -f pacman - rm -f pacmanedit +# rm -f pacmanedit diff --git a/pacman b/pacman deleted file mode 100755 index b9682e1..0000000 Binary files a/pacman and /dev/null differ diff --git a/pacman.c b/pacman.c index f75b993..093f20a 100755 --- a/pacman.c +++ b/pacman.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ void CheckScreenSize(); //Make sure resolution i 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 @@ -68,6 +70,13 @@ int LevelNumber = 0; //What level number are we on? 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) * @@ -113,8 +122,11 @@ int main(int argc, char *argv[100]) { 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; @@ -176,7 +188,7 @@ int CheckCollision() { 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]; @@ -192,7 +204,7 @@ int CheckCollision() { //Subtract one life and pause for 1 second Lives--; - usleep(1000000); + sleep(1); //If no more lives, game over if(Lives == -1) return 1; @@ -213,7 +225,7 @@ int CheckCollision() { 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 } } } @@ -260,9 +272,14 @@ int GameOverScreen() { //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; @@ -287,6 +304,7 @@ void CreateWindows(int y, int x, int y0, int x0) { * Returns: none * * Description: Pause the game and still get keyboard input * ****************************************************************/ +#if 0 void Delay() { //Needed to get time @@ -299,6 +317,14 @@ void Delay() { 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() * @@ -366,8 +392,7 @@ void 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 } @@ -379,10 +404,20 @@ void DrawWindow() { ****************************************************************/ 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 * @@ -437,7 +472,7 @@ void GetInput() { case 'p': case 'P': //Pause game PauseGame(); - chtmp = getch(); //Update buffered input +// chtmp = getch(); //Update buffered input break; case 'q': case 'Q': //End program @@ -456,13 +491,15 @@ void GetInput() { 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); @@ -488,7 +525,7 @@ void IntroScreen() { 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..."); @@ -505,7 +542,7 @@ void IntroScreen() { 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++) { @@ -520,7 +557,8 @@ void IntroScreen() { usleep(100000); } - usleep(150000); + sleep(1); + usleep(50000); //Pacman eats powerup and chases Ghosts for(a = 25; a > 2; a--) { @@ -618,7 +656,7 @@ int MainLoop() { 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 */ @@ -627,10 +665,11 @@ int MainLoop() { 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; } @@ -802,9 +841,13 @@ void PauseGame() { 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); } diff --git a/pacman.h b/pacman.h index 008c141..d9d0792 100755 --- a/pacman.h +++ b/pacman.h @@ -1,10 +1,13 @@ // Some variables that you may want to change -#define DATAROOTDIR "/usr/share" -#define LEVELS_FILE DATAROOTDIR "/pacman4console/Levels/level__.dat" +#ifndef DATAROOTDIR +# define DATAROOTDIR "/usr/local/share" +#endif +#define LEVELS_FILE DATAROOTDIR "/pacman/level__.dat" char LevelFile[] = LEVELS_FILE; //Locations of default levels int FreeLife = 1000; //Starting points for free life int Points = 0; //Initial points int Lives = 3; //Number of lives you start with int HowSlow = 3; //How slow vulnerable ghost move int SpeedOfGame = 175; //How much of a delay is in the game +#define FPS 5