Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!cmcl2!philabs!aecom2!safern From: safern@aecom2.UUCP (Eric Safern) Newsgroups: net.sources.games Subject: System III/V PacMan (1 of 2) Message-ID: <172@aecom2.UUCP> Date: Fri, 14-Mar-86 01:51:07 EST Article-I.D.: aecom2.172 Posted: Fri Mar 14 01:51:07 1986 Date-Received: Fri, 21-Mar-86 04:27:14 EST Distribution: net Organization: Albert Einstein College of Medicine/Yeshiva University Lines: 1800 #!/bin/sh : "This is a shell archive, meaning: " : "1. Remove everything above the #! /bin/sh line. " : "2. Save the resulting test in a file. " : "3. Execute the file with /bin/sh (not csh) to create the files:" : " READ_ME" : " Makefile" : " Makefile.b" : " TODO" : " pm.h" : " pm.6" : " shar" : " pm.c" : " random.c" : " rip.c" : " score.c" : " screen.c" : " timing.c" : " warning.c" : "This archive created: Fri Mar 14 01:19:33 EST 1986 " echo file: READ_ME sed 's/^X//' >READ_ME << 'END-of-READ_ME' XThis distribution is a System III/V version of pacman. XAll comments, etc. concerning this game should be directed to X XEric Safern X...{ihnp4,rocky2,philabs,esquire,cucard,pegasus}!aecom!safern X XHere is the readme from earlier distributions: X X XThis is the first source distribution of the game "pm". This game should Xrun under Version 7, BSD4.2, BSD4.3, BSD2.8, BSD2.9. A BSD4.3 version has Xnot been tested, but binary distribution bug reports have indicated some Xproblems in "flsbuf.c" that I think are now corrected. X XThis version still does busy looping. An implementation of msleep() was Xtried that used setitimer() for sleeping, but this did not work satisfactorly. XIf someone else is able to make a better version of msleep(), I would Xappreciate it if they could send me the source. However, thus far I have Xfound the current msleep() to be the most portable between different Xoperating system versions (it is the original UNIX Version 7 version). XNote the define "MYTIMER" turns on the busy looping and off the setitimer(2). X X XWed Oct 30 00:23:20 PST 1985 X XThis is the first binary distribution of the game "pm", a UNIX version Xof the arcade game Pacman. A source distribution will be made within Xthe next couple of months via netnews. Please send all bug reports to Xme (...!ucbvax!ucdavis!deneb!ccohesh001) so that they can be incorporated Xinto the first source distribution. X XThis binary distribution will only run under UNIX 4.2BSD. A binary for XUNIX 2.9BSD can be provided upon request. X XSince I am the main source of distribution, please mail all suggestions Xor comments to me. X X Peter Costantinidis, Jr. X ...!ucbvax!ucdavis!deneb!ccohesh001 X X XThe following may not make much sense unless you have a source distribution: X XMon Aug 30 11:18:09 PDT 1982 X XLook an pending(), it's sole purpose is to tell if the user has Xtyped anything, and if so, then read it, if not, then go on. If Xyou don't have a similar function, then you are screwed!!! X XThe purpose of delay() is to slow the CPU down so that the terminal can Xkeep up. I load in my own copy of flsbuf (stdio) that counts the number Xof characters that are printed. I make sure that the CPU waits long Xenough to make sure that they all got printed (a simple function of the Xbaud rate will tell you how long you need to wait). X XIf you want a list of commands, type in a '?'. If you want Xthe Wizard's commands, look in the define file. If you want the XWizard's password, decrypt the one in the define file or make your own. XIf (argv[0] == "tester") then you are wizard automatically (this Xshould probably be kept secret). X XPm "remembers" the uids of everyone who has played. These are maintained Xin the pm_user file by setting the bit corresponding to the uid. If a Xplayer has not played before, they are given an opening message (printed Xout by the inappropriately named function directions()), and will then Xnever see it again. X XIf you don't have curses, then give up! X XOne problem encountered during the development of this program was curses. XThe one I was using had problems and you may notice code that might not be Xuseful any longer (assuming your version of curses doesn't have these bugs). X XThe game looks best if the `maze' ('#' characters) are in inverse video. XIf your termcap defines standout to be high intensity, the board would Xprobably look best if you tweeked the code and made the maze normal (i.e. Xnot in standout) and everything else in high intensity (standout). X XI would like to thank Rick Heli, a member of UCD's Computer Center staff Xfor his help in the documentation of this program. END-of-READ_ME echo file: Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# X# Makefile: makefile for pm X# X# Tunables: X# PM_ROLL - pathname of score file X# PM_USER - pathname of user log file X# OS_VERS - operating system version X# (BSD29, BSD41, BSD42, BSD43, SYSIII, SYSV) X# SEND - pathname of binary export directory X# X# Please note: on system 5.2 and any systems whose curses does not X# use termcap, you must comment out TERMLIB. X# X# [pm by Peter Costantinidis, Jr. @ University of California at Davis] X# X X# X# Files X# XHDRS = pm.h XOBJS = flsbuf.o init.o make_moves.o\ X misc.o monsters.o msg.o pm.o random.o\ X rip.o score.o screen.o timing.o warning.o XSRCS1 = config.c flsbuf.c init.c make_moves.c\ X misc.c monsters.c msg.c XSRCS2 = pm.c random.c rip.c score.c screen.c timing.c warning.c XSRCS = $(SRCS1) $(SRCS2) X X# X# Configuration section X# XPM_ROLL = /y1/safern/bin/lib/pm_roll XPM_USER = /y1/safern/bin/lib/pm_user XOS_VERS = SYSV XDEFS = -DPM_ROLL=\"$(PM_ROLL)\" -DPM_USER=\"$(PM_USER)\" \ X -DWIZARD_UID=283 XDEST = /y3/safern/bin/lib/xhesh X X# X# Flags section X# XCFLAGS = -O -D$(OS_VERS) XLDFLAGS = -o tester XLINTARGS = -ahxc $(DEFS) -DLINT XCRLIB = -lcurses XTERMLIB = -ltermcap # on ATT 5.2, this line must be commented out. X X# X# Misc. X# XPMLIB = pm.a XPMDOC = pm.6 XBEXPORT = READ_ME Makefile.b TODO $(PMLIB) $(PMDOC) config.c XALL = READ_ME Makefile Makefile.b TODO $(HDRS) $(SRCS) $(PMDOC) shar XREST = READ_ME Makefile Makefile.b TODO $(HDRS) $(PMDOC) shar XEX1 = $(REST) $(SRCS2) XEX2 = $(SRCS1) X Xtester: config.o $(OBJS) X -mv tester tester.old X cc $(LDFLAGS) $(OBJS) config.o $(CRLIB) $(TERMLIB) X chmod 04711 tester X Xconfig.o: $(HDRS) X cc $(CFLAGS) $(DEFS) -c config.c X Xinstall: pm pm_roll pm_user clean X Xclean: X rm $(OBJS) *.old X Xpm: tester X -mv pm pm.old; mv tester pm X# @strip pm X >tester X X$(OBJS): $(HDRS) X Xtags: $(HDRS) $(SRCS) X ctags -u $? X sort tags -o tags X Xpm_roll: X > $(PM_ROLL) X Xpm_user: X > $(PM_USER) X XPrint: $(HDRS) $(SRCS) X pr $? | print X -touch Print X XP_all: X pr $(HDRS) $(SRCS) | print X -touch Print X Xlint: X lint $(LINTARGS) $(SRCS) -lcurses X Xcount: X wc $(HDRS) $(SRCS) X Xbexport: $(PMLIB) X cp $(BEXPORT) $(DEST) X Xexport: X /bin/sh shar $(EX1) > pm1.shar X /bin/sh shar $(EX2) > pm2.shar X Xcrypt: pm.tar X crypt < pm.tar > pm.tar.c X XSave: $(HDRS) $(SRCS) X cp $? Makefile xsave X XCxref: $(SRCS) $(HDRS) X cxref $(SRCS) $(HDRS) > $@ END-of-Makefile echo file: Makefile.b sed 's/^X//' >Makefile.b << 'END-of-Makefile.b' X# X# Makefile.b - makefile for binary distribution X# X# The following macros must be redefined for your installation. X# X# [pm by Peter Costantinidis, Jr. @ University of California at Davis] X# XGROUP = sorcerer XOWNER = wizard XBINDEST = /usr/games XLIBDEST = /usr/games/lib XWIZARD_UID= 666 X# X# The following need not be changed. X# X XOBJS = config.o XSRCS = config.c XOS_VERS = BSD42 XPM_ROLL = $(LIBDEST)/pm_roll XPM_USER = $(LIBDEST)/pm_user XDEFS = -DPM_ROLL=\"$(PM_ROLL)\" -DPM_USER=\"$(PM_USER)\" \ X -D$(OS_VERS) -DWIZARD_UID=$(WIZARD_UID) XCFLAGS = -O $(DEFS) XLDFLAGS = -o pm XCRLIB = -lcurses XTERMLIB = -ltermlib XPMLIB = pm.a X Xall: pm X Xinstall: all pm_roll pm_user X cp pm $(BINDEST) X chgrp $(GROUP) $(BINDEST)/pm X chgrp $(GROUP) $(PM_ROLL) $(PM_USER) X chown $(OWNER) $(BINDEST)/pm X chown $(OWNER) $(PM_ROLL) $(PM_USER) X chmod 4711 $(BINDEST)/pm X Xpm: $(OBJS) X ranlib $(PMLIB) X cc $(LDFLAGS) $(OBJS) $(PMLIB) $(CRLIB) $(TERMLIB) X X$(OBJS): Makefile.b X XMakefile.b: X Xpm_roll: X > $(PM_ROLL) Xpm_user: X > $(PM_USER) X Xclean: X rm -f pm config.o X Xremove: clean X rm -f $(PM_ROLL) $(PM_USER) END-of-Makefile.b echo file: TODO sed 's/^X//' >TODO << 'END-of-TODO' X- Make the fruit appear and go away X- Fix the bug that sometimes causes wierd characters floating around X (something to do with the tunnel, the monster gets its mo_name mixed up) X (Note: haven't seen this one in quite a while, it might be fixed.) X- Possibly combine pm_roll and pm_user into one file X- Test on BSD4.3. END-of-TODO echo file: pm.h sed 's/^X//' >pm.h << 'END-of-pm.h' X/* X** pm.h - all pm source files include this X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X/* X** defines that control things X*/ X#define PATTERNS /* let there be patterns!!! */ X#define FASTER /* let the monsters move fast (monsters.c) */ X#define MAX_UPDATE /* more refreshes */ X X#if BSD42|BSD43|BSD29 X# define BAD_OVERLAY /* bug in curses (overlay.c) */ X#endif X X#if SYSIII|SYSV X# define ECHOBUG /* bug in curses (ttyctl.c) */ X#endif /* if you haven't got this problem, remove this */ X X#define MYTIMER /* quite reliable */ X X#define BYTE_SIZE 8 /* # of bits in a byte */ X X X#include X#include X#include X X#ifdef MYTIMER X# undef ITIMER_REAL X#endif X X/* X** bound defines X*/ X#define TOP 1 X#define LEFT 0 X#define RIGHT 52 X X/* X** function status returns X*/ X#define ERROR -1 X#define STOP -2 X#define QUIT -3 X#define FINE -4 X#define BAD -5 X X/* X** input defines X*/ X#define MUP 'k' /* move up */ X#define MDOWN 'j' /* move down */ X#define MLEFT 'h' /* move left */ X#define MRIGHT 'l' /* move right */ X#define MSTOP ' ' /* stop movement */ X#define MKP_UP '8' /* key pad move up */ X#define MKP_DOWN '2' /* key pad move down */ X#define MKP_LEFT '4' /* key pad move left */ X#define MKP_RIGHT '6' /* key pad move right */ X#define MKP_STOP '5' /* key pad stop movement */ X#define MQUIT 'q' /* quit game */ X#define MREDRAW CTRL(L) /* redraw the screen */ X#define MSHELL '!' /* shell escape */ X#define MHELP '?' /* give list of commands */ X#define MFAST 'f' /* toggle looping in make_move */ X#define MQUIET 'b' /* toggle beeping */ X#define MPAUSE 'p' /* hang on getchar() */ X#define MHUH CTRL(R) /* reprint last message */ X#define MNULL '\0' X X/* X** special input defines (cheating) X*/ X#define MWIZARD CTRL(P) /* request to become wizard */ X#define MSTATUS 's' /* print debugging info */ X#define MMONS 'm' /* print monster "" "" */ X#define MPM '@' /* request for more pm's */ X#define MUP_LVL CTRL(U) /* up a level */ X#define MDN_LVL CTRL(D) /* down a level */ X#define MEAT CTRL(E) /* make them eatable */ X#define MMEAN CTRL(M) /* make them non-eatable */ X#define MSLOW 'r' /* change null padding */ X X/* X** wizardly defines X*/ X#define W_PASSWD "LuWBlzHTlqQ0g" X#define SALT "Lu" X X/* X** various characters on the screen X** the underscores mean the "submissive" ghost associated with * X*/ X#define PM '@' X#define HARPO 'H' X#define _HARPO 'h' X#define GROUCHO 'G' X#define _GROUCHO 'g' X#define ZEPPO 'Z' X#define _ZEPPO 'z' X#define CHICO 'C' X#define _CHICO 'c' X#define BLOCK '#' X#define DOT '.' X#define TUNNEL '-' X#define ENERGY '*' X#define EMPTY ' ' X#define DOOR '=' X X/* X** monster attributes X*/ X#define FAST 001 /* three different (relative) speeds */ X#define MED 002 X#define SLOW 004 X#define SMART 010 /* three different (relative) smarts */ X#define NORMAL 020 X#define DUMB 040 X X/* X** to keep lint quiet X** used primarily for the "Hit return to continue"'s X*/ X#ifdef LINT X# define trash(x) _trash_ = x X#else X# define trash(x) x X#endif X X/* X** miscellaneous definition X*/ X#define BELL '\07' X#define SPEED 15 X#define MIN_BAUD 1200 /* must alter bauds[] if this value is X ** changed */ X#if SYSV|SYSIII X# define EAT_PAUSE 20 /* used when pm is eaten */ X#else X# define EAT_PAUSE ((unss) 20) /* used when pm is eaten */ X#endif X X#define MAX_DIRS 4 X#define MAX_LEVEL 13 X#define MAX_ENERGY 4 X#define MAX_DOTS 208 X#define MAX_MONS 4 X#define MAX_PMS 4 X#define MAX_BLINKS 30 /* number of warning blinks */ X#define MAX_CNT 50 /* kind of useless, (see get_move) */ X#define TUNN_TIME 2 X#define TUNN_ROW 11 X#define DOOR_COL 26 /* column where door to monsters is */ X#define V_DOT 10 X#define V_ENERGY 50 X#define ALARM_TIME 10 /* messages get erased every 10 sec */ X#define BONUS 10000 /* get a free pm with 10000 score*/ X#define CMASK 0177 /* used to strip garbage from what X ** inch() returns (when in stand...) X */ X/* X** useful defines to make source more terse X*/ X#define when break; case X#define otherwise break; default X X#ifdef PATTERNS X# define SEED (uid+level) /* their uid */ X#else X# define SEED get_seed() /* their uid */ X#endif X X/* X** stuff to do with the score routines X*/ X#define DEFAULT_SH "/bin/sh" /* default shell */ X#define MAX_SCORES 10 /* maximum scores on pm roll */ X#define SCR_SIZE (sizeof(score)) X#define NAME_SIZE 50 /* biggest name allowed on roll */ X#define MODE 0644 /* the mode of the PM_ROLL */ X#define MAX_BYTES 4096 /* byte size of user file */ X#define MAX_USERS (MAX_BYTES*BYTE_SIZE)/* number of uid's (bit size of X ** PM_USER) X */ X X/* X** flag stuff for the above X*/ X#define FL_DIE 0 /* indicates he died */ X#define FL_QUIT 1 /* indicates he quit */ X X/* X** misc definitions X*/ X#define unss unsigned short X X/* X** structure definitions X*/ Xtypedef struct X{ X int x, y; X} coord; X Xtypedef struct /* monster description */ X{ X coord mo_pos; /* where it is at */ X char mo_inch; /* what it is on top of */ X bool mo_run, /* TRUE if it is eatable */ X mo_tunn, /* TRUE if it is in a tunnel */ X mo_eaten, /* TRUE if eaten */ X mo_inside; /* TRUE if inside */ X char mo_ch, /* current move */ X mo_name; /* name (letter) of monster */ X int mo_cnt, /* how many times to do mo_ch */ X mo_extunn, /* how long left in tunnel */ X mo_attrib; /* monsters characteristics */ X} mons; X Xtypedef struct X{ X int sc_uid; /* player's uid */ X long sc_score; /* player's score */ X int sc_level; /* how deep the player went */ X int sc_flags; /* misc. info */ X char sc_name[NAME_SIZE], /* player's name */ X sc_mons; /* monster's name */ X} score; X X/* X** psuedo functions X*/ X/* X** need to strip out the garbage that inch() returns, i only want X** the single character, and i think that it gets messed up when X** that character is in background X*/ X#define INCH() (inch() & CMASK) X#define abs(x) ((x) < 0 ? - (x) : (x)) X#define MVADDCH(p, c) mvaddch(p.y, p.x, c) X#define TF(x) (x ? "True" : "False") X#define DIST() rnd(4, 15) X#define IS_FRUIT(c) (c == fr_ch) X#define SLOWER() slow(FALSE) X#ifndef CTRL X# define CTRL(ch) ('ch' & '\037') X#endif X#define AT(pos1, pos2) (((pos1)->x == (pos2)->x) && ((pos1)->y == (pos2)->y)) X#define OUTOFTUNN(pos) (((pos)->y != 0) && ((pos)->y != 52)) X#define beep() putchar(BELL) X#define RN (((seed = (seed * 11109) + 13849) & 0xfff) >> 1) X#define randomize(i) seed = i X#define flush() raw(), noraw() X#define m_erase(mon) mvaddch(mon.mo_pos.y, mon.mo_pos.x, mon.mo_inch) X X#ifdef SYSV X# define doclear() refresh(), wclear(cls), wrefresh(cls); X#else X# define doclear() _puts(CL); X#endif X X#ifdef ECHOBUG X# define Echo() Necho() Xextern void Necho(); X#else X# define Echo() echo() X#endif X X#if SYSV|SYSIII X# include Xextern int oldfl, baud; Xextern long _tp; Xextern struct tbuffer garbage; X# define draw() _tp = times(&garbage), refresh(), delay() X#else Xextern int bauds[]; /* this is a character array on SYS3/V */ Xextern char baud; Xextern struct timeb _tp; X# define draw() ftime(&_tp), refresh(), delay() X#endif X X#ifdef SYSV Xextern WINDOW *cls; /* to clear the screen */ X#endif Xextern coord pm_pos; Xextern int pm_tunn, pm_extunn, d_left, e_left, level, fr_val, X fruit_val[], pms_left, pm_bonus, pm_eaten, pm_run, X mons_eaten, mons_val[], eat_times[], timer, was_wiz, is_wiz, X timeit, quiet, fast, uid, seed, wizard_uid; Xextern char *argv0, fruit[], fruit_eaten[], fr_ch, ch, oldch, X newch, moves[], *mesg, **environ, *pm_user, *pm_roll; X#ifdef LINT Xextern char _trash_; X#endif Xextern long thescore, hi_score, demon, move_cntr, chcnt; Xextern mons ghosts[]; Xextern mons *h, *g, *c, *z; Xextern char _putchar(), *crypt(), *strcpy(); Xextern int getuid(); Xextern off_t lseek(); X X/* X** local functions X*/ Xextern void add_fruit(), aggressive(), chg_lvl(), check_scrs(), X commands(), delay(), die(), directions(), X doadd(), draw_screen(), eat_pm(), init(), X m_eat_pm(), X mons_init(), m_move(), msg(), msg_erase(), msleep(), X mv_mon(), new_screen(), old_screen(), p_barriers(), p_dots(), X p_energizers(), p_fruits(), p_info(), p_monsters(), X p_pm(), p_pms(), p_scores(), place_m(), pm_eat_m(), X pmers(), X print_scrs(), quit_it(), quitit(), X re_msg(), redraw(), scores(), scrcpy(), X shell(), slow(), slowness(), status(), strucpy(), X submissive(), tombstone(), trap(), usage(), warning(); Xextern int _mv_mon(), can_see(), chk_pm_user(), dir_int(), get_move(), X is_mons(), is_safe(), m_is_safe(), X make_moves(), moveit(), move_to(), pending(), rnd(); Xextern char gen_mv(), *get_pass(), int_dir(), lturn(), *mons_str(), X opposite(), *punctrl(), rturn(), to_baud(), toletter(), X tunn_look(); Xextern long get_hi_scr(); X Xextern mons *wh_mons(); X X#ifdef PATTERNS Xextern int get_seed(); X#endif END-of-pm.h echo file: pm.6 sed 's/^X//' >pm.6 << 'END-of-pm.6' X.TH PM UCD "16 October 1985" X.SH NAME Xpm \- computer version of PacMan X.SH SYNOPSIS X.B pm X[ X.B -s X] [ X.B -p X] [ X.B -Bn X] X.SH OPTIONS X.TP X.B \-s XPrint out the list of scores. X.TP X.B \-Bn XSpecify the baud rate which you are using. X.TP X.B \-p XPrint list of players. X.SH DESCRIPTION X.I Pm Xis a UNIX version of the popular arcade game PacMan. XThe player, represented by the `@' symbol, attempts to score as many Xpoints as possible. He does this by eating the small dots on the Xscreeen, the energizers, the monsters and fruit. Each item provides Xa number of points as follows: X.sp X.nf X.ta 3i XDot(.) 10 XEnergizer(*) 50 XMonster varies XFruit(%,&,0,etc.) varies X.fi X.LP XOf course it would be simple if this was all there was to do. XUnfortunately, the pacman is chased by Groucho, Zeppo, Harpo and Chico Xwhich are represented by G, Z, H and C respectively. If they ever Xrun into the pacman, he is eaten and loses a life (you begin the game Xwith three). However, pacman can retaliate by eating an energizer. XWhen this happens, the characters representing the monsters become Xlower case and pacman will be able to eat them. But beware, the Xopportunity to do this is short. X.LP XThe points gained for eating monsters vary based on the number consecutively Xconsumed. This is probably related to the fact that the monsters Xtend to move more quickly as the game continues. XIn addition, fruit is worth more as the pacman continues. X.PP X.TP X.I List of Commands X.nf X.ta 3i X! exec a shell Xb toggle beeping Xf toggle speed Xh move left Xj move down Xk move up Xl move right Xp pause Xq quit XSPACE stop X.fi X.LP XPlayers will discover several interesting features in the game. For Xone, the monsters will become faster and more aggressive as the game Xgoes on. For another, players may notice that the monsters have their Xown personalities; it has been postulated that this is related to Xthe favorite machines of the author. X.LP XNormally the game does not generate beeps, but the player can cause X.I pm Xto beep whenever the pacman eats anything with the X.B b Xcommand. In addition, the game Xpauses after each cycle. These pauses may be shortened with the X.B f Xcommand. X.SH FILES X*/pm_roll list of the top ten X.br X*/pm_user list of who plays X.SH AUTHOR XPeter Costantinidis, Jr., University of California, Davis XSystem III, V port by Eric Safern, Yeshiva University, N.Y. X.SH DIAGNOSTICS XOccasionally complains when strange things seem to occur in the tunnel. X.SH BUGS X.I Pm Xis at less than its best at terminal speeds of less than 9600 Baud. XIn addition, the algorithm X.I pm Xuses to simulate real time is very cpu intensive, and thus the game is Xexpensive to play. END-of-pm.6 echo file: shar sed 's/^X//' >shar << 'END-of-shar' X#!/bin/sh Xecho "#!/bin/sh" Xecho ": \"This is a shell archive, meaning: \"" Xecho ": \"1. Remove everything above the #! /bin/sh line. \"" Xecho ": \"2. Save the resulting test in a file. \"" Xecho ": \"3. Execute the file with /bin/sh (not csh) to create the files:\"" Xfor i Xdo X echo ": \" $i\"" Xdone Xecho ": \"This archive created: " Xecho `date` \" Xfor i Xdo X echo "echo file: $i" X echo "sed 's/^X//' >$i << 'END-of-$i'" X sed 's/^/X/' $i X echo "END-of-$i" Xdone Xecho exit END-of-shar echo file: pm.c sed 's/^X//' >pm.c << 'END-of-pm.c' X/* X** pm.c - main: argument parsing, main control loop and usage messages X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include "pm.h" X Xmain (argc, argv) Xreg int argc; Xreg char **argv; X{ X argv0 = *argv++, argc--; X if (argc == 1) X { X if (*((*argv)++) != '-') X usage(); X switch (**argv) X { X case 'p': X pmers(); X exit(0); X case 's': X check_scrs(); X exit(0); X case 'B': X baud = to_baud(++*argv); X break; X default: X usage(); X } X } X else if (argc) X usage(); X if (!strcmp("tester", argv0)) X was_wiz = is_wiz = TRUE; X#ifdef NOFULLPATH X /* X ** at one time the author was worried about the whole world finding X ** out this games existed. to keep its location a little private X ** he tried to discourage full pathnames to the game from showing X ** up on a ps(1) output by forcing argv[0] to be "pm". X ** the following code checked for this condition. X */ X else if (getuid() != wizard_uid && strcmp("pm", argv0)) X { X fprintf(stderr, "That is a Big No NO!!!"); X setuid(getuid()); X if (getuid() != 0) X kill(0, 9); /* blast them out of the water */ X } X#endif X init(); X for (;;) X { X slow(); X demon++; X if (make_moves()) X break; X if (timer > 0) X timer--; X /* X ** we know we need a new board drawn when we are X ** out of dots and energizers X */ X p_scores(); X if (!e_left && !d_left) X { /* no more dots left */ X chg_lvl(1); X continue; X } X if (!timer && !pm_run) /* energizers ran out */ X { X aggressive(); X pm_run = TRUE; X continue; X } X if ((timer < MAX_BLINKS) && !(timer % 4)) X warning(); /* warn every four moves*/ X m_move(); /* move the monsters */ X } X quitit(); X X#if SYSV|SYSIII X fcntl(0, F_SETFL, oldfl); X#endif X exit(0); X} X X/* X** usage() - print a usage message and exit X*/ Xvoid usage () X{ X fprintf(stderr, "Usage: %s [-s] [-p] [-Bn]\n", argv0); X exit(1); X} END-of-pm.c echo file: random.c sed 's/^X//' >random.c << 'END-of-random.c' X/* X** random.c - yet another random number generator and random seed maker X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X#include "pm.h" X X/* X** rnd() - return a number between a and b, inclusive X*/ Xint rnd (a, b) Xreg int a, b; X{ X return((RN % (abs(b - a) + 1)) + a); X} X X#ifndef PATTERNS X/* X** get_seed() - returns a seed for the random number generator X** dependent upon the time and date X*/ Xint get_seed () X{ X reg int seed; X reg struct tm *timestruct; X auto long clock; X extern long time(); X extern struct tm *localtime(); X X clock = time(0); X timestruct = localtime(&clock); X seed = timestruct->tm_sec + X timestruct->tm_min + X timestruct->tm_hour + X timestruct->tm_mday + X timestruct->tm_mon + X timestruct->tm_year + X timestruct->tm_yday; X return((int) ((seed + clock) % 32767)); X} X#endif END-of-random.c echo file: rip.c sed 's/^X//' >rip.c << 'END-of-rip.c' X/* X** rip.c - code dealing with the end of the game X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X#include "pm.h" X X/* X** die() - pm has died forever... X*/ Xvoid die (mon) Xreg char mon; X{ X doclear(); X tombstone(thescore, mon); X printf("[Press return to continue]"); X#if SYSV|SYSIII X fcntl(0, F_SETFL, oldfl); X#endif X endwin(); X trash(getchar()); X scores(mon, FL_DIE); X exit(0); X} X X/* X** quitit() - called when they quit X*/ Xvoid quitit () X{ X clear(); X move(LINES - 1, 0); X refresh(); X#if SYSV|SYSIII X fcntl(0, F_SETFL, oldfl); X#endif X printf("[Press return to continue]"); X endwin(); X trash(getchar()); X scores(NULL, FL_QUIT); X exit(0); X} X X/* X** tombstone() - print a pretty little pm X*/ Xstatic char *stone[] = X{ " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", X " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", X " @@@@@@ @@@@@", X " @@@@@ @@@@@@@@@@@@@ @@@@", X " @@@@@ @@@@@@@@@@@@@@@@@@@ @@@@", X " @@@@@ @@@@@ @@@@@ @@@@", X " @@@@@ @@@@ Eaten by @@@ @@@@@", X " @@@@@ @@@@ @@@ @@@@@", X " @@@@@ @@@ @@@ @@@@", X " @@@@ @@@@ @@@ @@@@", X " @@@@@ @@@ @@@ @@@@", X " @@@@@ @@@@ @@@ @@@@@", X " @@@@@ @@@@ @@@ @@@@@", X " @@@@ @@@@@ @@@@@ @@@@@@", X " @@@@@ @@@@@@@@@@@@@@@@@@@@@@@@", X " @@@@@ @@@@@@@@@@@@ @@@@", X " @@@@@", X " @@@@@", X " @@@@@", X " @@@@@", X " @@@@@@", X " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", X " @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", X 0 X}; Xvoid tombstone (scr, monster) Xlong scr; Xreg char monster; X{ X reg char **s = stone; X X clear(); X move(0, 0); X while (*s) X printw("%s\n", *s++); X move(9, 33); X printw("%9s", mons_str(monster)); X move(18, 30); X printw("After getting %ld points.", scr); X move(LINES - 1, 0); X draw(); X} END-of-rip.c echo file: score.c sed 's/^X//' >score.c << 'END-of-score.c' X/* X** score.c - code dealing with maintaining the score file and the user log X** X** Note: the score file is not encrypted X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X#include "pm.h" X#include X X#ifdef SYSIII X# include X#endif SYSIII X Xextern int fwrite(), fread(); X X/* X** check_scrs() - print out the pm roll (only for score enquiries) X*/ Xvoid check_scrs () X{ X reg int i; X auto score scrs[MAX_SCORES]; X X if (rwscore(0, scrs)) X { X printf("No scores recorded at this time\n"); X return; X } X printf("\nTop Ten Players:\n"); X printf("Rank\tScore\tName\n"); X for (i = 0; i < MAX_SCORES && scrs[i].sc_uid != -1; i++) X { X print_scrs(&scrs[i], i + 1); X printf(".\n"); X } X} X X/* X** get_hi_scr() - get the highest score from the score file X*/ Xlong get_hi_scr () X{ X auto score scrs[MAX_SCORES]; X X if (rwscore(0, scrs)) X return(0L); X if (scrs[0].sc_uid == uid) X { /* taunt the high scorer */ X printf("\nWelcome back %s,\n", scrs[0].sc_name); X printf("do you think that you can do better than\n"); X printf("last time? Just a second while I think\n"); X printf("of a better strategy!\n"); X sleep(1); X#ifdef PATTERNS X /* X ** they seem to have this pattern mastered, so X ** lets be tricky and give them a different pattern X ** (i.e. change the seed) X */ X randomize(getpid()); X#endif X } X return(scrs[0].sc_score); X} X X/* X** chk_pm_user() - check the user file X** return non-zero on error X*/ Xint chk_pm_user () X{ X reg int i; X reg int bit, byte; X auto char buf[MAX_BYTES]; X X if (!pm_user || X uid > (unsigned) MAX_USERS) /* wraps on 16 bit machines */ X return(FALSE); X byte = uid / BYTE_SIZE; X bit = 1 << (uid % BYTE_SIZE); X for (i=0; isc_uid < 0) X return; X printf("%d\t%6ld\t%s: %s after %d screen%c", X rank, scr->sc_score, scr->sc_name, X reason[scr->sc_flags], scr->sc_level+1, (scr->sc_level ? 's' : ' ')); X if (scr->sc_flags == FL_DIE) X printf(" by %s", mons_str(scr->sc_mons)); X} X X/* X** scores() - print the list of scores and conditionally add X** the new one X*/ Xvoid scores (mon, flags) Xchar mon; Xint flags; X{ X reg int i; X auto score scrs[MAX_SCORES]; X X if (rwscore(0, &(scrs[0]))) X { X fprintf(stderr, "%s: creating the score file\n", argv0); X for (i=0; isc_uid == -1) X return(TRUE); X else if (l > scrs->sc_score) X return(TRUE); X return(FALSE); X} X X/* X** pmers() - called by main() to print the list of players X*/ Xvoid pmers () X{ X auto char buf[MAX_BYTES]; X reg int j; X X if (rwuser(0, buf)) X { X perror(pm_user); X exit(1); X } X for (j = 0; j < MAX_BYTES; j++) X { X reg int i; X X if (!buf[j]) X continue; X for (i = 0; i < BYTE_SIZE; i++) X { X auto int puid; X struct passwd *pw; X extern struct passwd *getpwuid(); X X if (!((char) (1 << i) & buf[j])) X continue; X if (pw = getpwuid(puid = ((j * BYTE_SIZE) + i))) X printf("%s\n", pw->pw_name); X else X fprintf(stderr, "%s: getpwuid(%d) error\n", X argv0, puid); X } X } X} X X/* X** rwscore() - read/write the contents of the pm_roll file X** - if flag is true, write, else read X** - return non-zero on error X*/ Xstatic int rwscore (flag, scrs) Xreg int flag; Xreg score *scrs; X{ X reg FILE *fp; X reg int (*func)(); X X if (!(fp = fopen(pm_roll, flag ? "w" : "r"))) X return(TRUE); X func = flag ? fwrite : fread; X if ((*func)(scrs, sizeof(*scrs), MAX_SCORES, fp) != MAX_SCORES) X { X perror(pm_roll); X fclose(fp); X return(TRUE); X } X fclose(fp); X return(FALSE); X} X X/* X** rwuser() - read/write the contents of the pm_user file X** - if flag is true, write, else read X** - return non-zero on error X*/ Xstatic int rwuser (flag, buf) Xreg int flag; Xreg char *buf; X{ X reg FILE *fp; X reg int (*func)(); X X if (!(fp = fopen(pm_user, flag ? "w" : "r"))) X return(TRUE); X func = flag ? fwrite : fread; X if ((*func)(buf, sizeof(*buf), MAX_BYTES, fp) != MAX_BYTES) X { X perror(pm_user); X fclose(fp); X return(TRUE); X } X fclose(fp); X return(FALSE); X} END-of-score.c echo file: screen.c sed 's/^X//' >screen.c << 'END-of-screen.c' X/* X** screen.c - code dealing with display (most of what is written to the X** screen during the course of a game is done here) X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X#include "pm.h" X X/* X** p_draw_screen()- draw the board X** - this ordering is kind of important. the dots must X** be printed first and then the barriers in standout X** so that if the terminal uses "inverse video" for X** the so entry in /etc/termcap (or wherever) the X** paths through the maze are not in inverse video. X** - also, whenever the screen is cleared and dots() X** called, barriers() must be called again, or else X** dots() will overwrite the barriers. X** - the SLOWER() is so that the monsters don't move X** until the screen is totally redrawn X*/ Xvoid draw_screen () X{ X alarm(0); /* make sure the alarm is off */ X msg(""); X randomize(SEED); X clear(); X p_dots(); /* the dots must be printed first */ X/* standout(); */ X p_barriers(); X/* standend(); */ X p_scores(); X p_energizers(); X p_pm(); X p_pms(); X p_monsters(); X p_fruits(); X draw(); X sleep(1); X} X X/* X** new_screen() - called when a screen has been cleaned out X** X*/ Xvoid new_screen () X{ X reg int i; X X alarm(0); /* make sure the alarm is off */ X msg(""); X randomize(SEED); X#if !SYSV && !SYSIII X flush(); /* this totally destroys crmode on System III/V */ X#endif X mvaddch(pm_pos.y, pm_pos.x, EMPTY); X aggressive(); X for (i = 0; i < 4; i++) X m_erase(ghosts[i]); X draw(); X p_scores(); X p_dots(); X/* standout(); */ X p_barriers(); X/* standend(); */ X p_energizers(); X p_pm(); X p_monsters(); X p_fruits(); X draw(); X sleep(2); X} X X/* X** old_screen()- called when pm is eaten X*/ Xvoid old_screen () X{ X reg int i; X X alarm(0); /* make sure the alarm is off */ X msg(""); X#if !SYSV && !SYSIII X flush(); /* this totally destroys crmode on System III/V */ X#endif X mvaddch(pm_pos.y, pm_pos.x, EMPTY); X aggressive(); X for (i = 0; i < MAX_MONS; i++) X m_erase(ghosts[i]); X draw(); X p_scores(); X p_pms(); X p_pm(); X p_monsters(); X draw(); X sleep(1); X} X X/* X** redraw() - redraw the screen X*/ Xvoid redraw () X{ X alarm(0); /* make sure the alarm is off */ X clearok(stdscr, TRUE); X msg(""); X draw(); X sleep(1); X} X X/* X** p_scores() - print the score and high score if changed X** - check to see if they get another pm X** - must remember to print both scores when the X** game is first started X*/ Xvoid p_scores () X{ X static long _score = -1L; X X if (thescore == _score) X return; /* the posted score is accurate */ X if ((thescore > BONUS) && pm_bonus) X { X pm_bonus = FALSE; X pms_left++; X p_pms(); X } X move(0, 23); X printw("%06ld", thescore); X if (thescore > hi_score || _score == -1L) X { X move(0, 47); X printw("%06ld", X (thescore>hi_score) ? (hi_score=thescore) : hi_score); X } X _score = thescore; X} X X/* X** p_fruits() - place the fruit and sets its value X*/ Xvoid p_fruits () X{ X reg int lvl = (level >= MAX_LEVEL ? MAX_LEVEL-1 : level); X X fr_ch = fruit[lvl]; X fr_val = fruit_val[lvl]; X move(13, 26); X addch(fr_ch); X} X X/* X** add_fruit() - add eaten fruit to fruit list X** - have to shift things over some X*/ Xvoid add_fruit (fr) Xreg char fr; X{ X reg int i; X X for (i = 6; i > 0; i--) X fruit_eaten[i * 2] = fruit_eaten[(i - 1) * 2]; X fruit_eaten[0] = fr; X move(0, 55); X printw("%s", fruit_eaten); X} X X/* X** p_pm() - place the pm in its starting position X*/ Xvoid p_pm () X{ X pm_tunn = FALSE; X pm_pos.x = 26; X pm_pos.y = 17; X move(pm_pos.y, pm_pos.x); X addch(PM); X} X X/* X** p_pms() - place the spare pm's X*/ Xvoid p_pms () X{ X reg int i; X X for (i = 1; i < MAX_PMS; i++) X { X move(0, (2 * (i - 1))); X if (i >= pms_left) X addch(EMPTY); X else X addch(PM); X } X} X X/* X** p_energizers() - put in the energizers X*/ Xvoid p_energizers () X{ X move(4, 51); X addch(ENERGY); X move(4, 1); X addch(ENERGY); X move(17, 1); X addch(ENERGY); X move(17, 51); X addch(ENERGY); X e_left = MAX_ENERGY; X} X Xstatic char *_board[] = X{ X "#####################################################\n", X "# ##### #\n", X "# ######### ########### ##### ########### ######### #\n", X "# ######### ########### ##### ########### ######### #\n", X "# #\n", X "# ######### ##### ################# ##### ######### #\n", X "# ##### ##### ##### #\n", X "########### ########### ##### ########### ###########\n", X "# # ##### ##### # #\n", X "########### ##### ######## ######## ##### ###########\n", X " # # \n", X "########### ##### ################# ##### ###########\n", X "# # ##### ##### # #\n", X "########### ##### ################# ##### ###########\n", X "# ##### #\n", X "# ######### ########### ##### ########### ######### #\n", X "# ##### ##### #\n", X "##### ##### ##### ################# ##### ##### #####\n", X "# ##### ##### ##### #\n", X "# ##################### ##### ##################### #\n", X "# ##################### ##### ##################### #\n", X "# #\n", X "#####################################################\n", X 0 X}; X X/* X** p_barriers() - fills in the board X*/ Xvoid p_barriers () X{ X static int once = TRUE; X static WINDOW *tmp; X X if (once) X { X reg char **str = _board; X X if ((tmp = newwin(0, 0, 0, 0)) == (WINDOW *) ERR) X { X move(0, 0); X printw("barriers(): newwin() error"); X draw(); X quit_it(); X } X wmove(tmp, TOP, 0); X while (*str) X waddstr(tmp, *str++); X once = FALSE; X } X overlay(tmp, stdscr); X} X Xstatic char *_dots[] = X{ X " \n", X " . . . . . . . . . . . . . . . . . . . . . . . . \n", X " . . . . . . \n", X " . . . . . . \n", X " . . . . . . . . . . . . . . . . . . . . . . . . . . \n", X " . . . . . . \n", X " . . . . . . . . . . . . . . . . . . . . \n", X " . . \n", X " . . \n", X " . = . \n", X "- . . -\n", X " . . \n", X " . . \n", X " . . \n", X " . . . . . . . . . . . . . . . . . . . . . . . . \n", X " . . . . . . \n", X " . . . . . . . . . . . . . . . . . . . . \n", X " . . . . . . \n", X " . . . . . . . . . . . . . . . . . . . . \n", X " . . . . \n", X " . . . . \n", X " . . . . . . . . . . . . . . . . . . . . . . . . . . \n", X " \n", X 0 X}; X X/* X** p_dots() - fills in the board X*/ Xvoid p_dots () X{ X reg char **str = _dots; X X d_left = MAX_DOTS; X move(TOP, 0); X while (*str) X addstr(*str++); X} END-of-screen.c echo file: timing.c sed 's/^X//' >timing.c << 'END-of-timing.c' X/* X** timing.c - functions dealing with the "smooth" running of the game X** it is important not for the game to get ahead of the screen X** and the necessary `slowing down' of the game is done here X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X#include X#include "pm.h" X X#define BPBYTE 10 /* bits sent to termnal per character (byte) */ X#define PAWS(x) ((1000 * x * BPBYTE) / baud) X#define TIMEBS(x,y) ((x - y) * 100 / 6) X/* X** delay() - coordinate with tty speed X** / 1000 ms. \ X** | ------------------------------------ * delta(chars) | == delay in ms. X** \ (baud bits/sec)/(BPBYTE bits/char) / X*/ Xvoid delay () X{ X int u; X auto long tp; X X u = PAWS(chcnt); X for(;;) { X tp = times(&garbage); X if (TIMEBS(tp, _tp) >= u) { X chcnt = 0L; X return; X } X } X} X Xstatic int rates[] = /* these were `tuned' after much playing */ X{ X/* 0 1 2 3 4 5 6 7 8 9 */ X 320, 265, 220, 210, 200, 190, 180, 170, 160, 150, X/* 10 11 12 13 14 15 16 17 18 19 */ X 140, 130, 120, 110, 100, 100, 100, 90, 90, 80, X/* 20 21 22 23 24 25 26 27 28 29 */ X 95, 70, 45, 20, 100, 150, 50, 99, 100, 100, X/* 30 31 32 33 34 35 36 37 38 39 */ X 5, 0, 0, 0, 0, 20, 0, 0, 0, 0, X/* 40 41 42 43 44 45 46 47 48 49 */ X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X/* 50 51 52 53 54 55 56 57 58 59 */ X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X}; X X/* X** slow() - make the game go faster as they go deeper X** - assuming that they WILL NOT GET DEEPER THAN X** 60 LEVELS!!!! if they are, then they have been X** tying up the computer long enough and should stop X** playing anyway X*/ Xstatic long tp; X Xvoid initslow() X{ X tp = times(&garbage); X} X Xvoid slow() X{ X reg int ms, num; X auto long tp2; X X if (level > 59) X quitit(); X num = (fast ? rates[level]/4 : rates[level]/2); X for(;;) { X tp2 = times(&garbage); X if (TIMEBS(tp2, tp) >= num) { X tp = tp2; X return; X } X } X} X X/* X** slowness() - sets delay in rates X** X*/ Xvoid slowness () X{ X auto char buf[BUFSIZ]; X X doclear(); X nocrmode(); X printf("old delay: %d, new delay: ", rates[level]); X#if SYSV|SYSIII X fcntl(0, F_SETFL, oldfl); X#endif X Echo(); /* defined to echo() on machines without bug */ X if (!gets(buf)) X msg("EOF in slowness"); X if (buf[0]) X if (sscanf(buf, "%d", &(rates[level])) == EOF) X msg("EOF2 in slowness"); X#if SYSV|SYSIII X fcntl(0, F_SETFL, O_NDELAY); X#endif X noecho(); X crmode(); X redraw(); X} X END-of-timing.c echo file: warning.c sed 's/^X//' >warning.c << 'END-of-warning.c' X/* X** warning.c - code dealing with the energizers and them being eaten and X** wearing out and informing the player his time is ending X** X** [pm by Peter Costantinidis, Jr. @ University of California at Davis] X*/ X X#include "pm.h" X X/* X** warning() - warn pm that energizers are about to wear off X*/ Xvoid warning () X{ X reg int i; X X for (i = 0; i < MAX_MONS; i++) X { X if (!ghosts[i].mo_run) X continue; X if (!ghosts[i].mo_tunn) X mvaddch(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x, X toupper(ghosts[i].mo_name)); X } X draw(); X /* X msleep(10l); X */ X for (i = 0; i < MAX_MONS; i++) X { X if (!ghosts[i].mo_run) X continue; X if (!ghosts[i].mo_tunn) X mvaddch(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x, X ghosts[i].mo_name); X } X draw(); X} X X/* X** aggressive() - perform all the house keeping when the enegizers X** wear off the pm X*/ Xvoid aggressive () X{ X reg int i; X X mons_eaten = -1; X timer = 0; /* reset the timer */ X for (i = 0; i < MAX_MONS; i++) X { X ghosts[i].mo_run = FALSE; X if (islower(ghosts[i].mo_name)) X ghosts[i].mo_name = toupper(ghosts[i].mo_name); X else X continue; X if (!ghosts[i].mo_tunn) X mvaddch(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x, ghosts[i].mo_name); X } X} X X/* X** submissive() - make the ghosts eatable X*/ Xvoid submissive () X{ X reg int i; X X if (level >= MAX_LEVEL) X timer = eat_times[MAX_LEVEL - 1]; X else X timer = eat_times[level]; X pm_run = FALSE; X mons_eaten = -1; X for (i = 0; i < MAX_MONS; i++) X { X ghosts[i].mo_run = TRUE; X if (isupper(ghosts[i].mo_name)) X ghosts[i].mo_name = tolower(ghosts[i].mo_name); X else X continue; X if (!ghosts[i].mo_tunn) X mvaddch(ghosts[i].mo_pos.y, ghosts[i].mo_pos.x, ghosts[i].mo_name); X } X} END-of-warning.c exit -- Eric Safern ...{ihnp4,rocky2,philabs,esquire,cucard,pegasus,spike}!aecom!safern