cem@intelca.UUCP (Chuck McManis) (06/13/85)
Included below is the original source to robots modified so that it will run on XENIX Release 3.0 (A System III clone) Hopefully all of the changes should be reversable by not defining XENIX, as I don't have access to a non XENIX machine I can't check it. THIS IS NOT A SHAR ARCHIVE, just the source to the robots game. Remove the text between the -Cut Here- and the signature at the end of the file and compile it with cc -O robots.c -o robots -lcurses -ltermcap then install it in the /usr/games directory. The man page is in the original posting. --Chuck -------------------------Cut Here------------------------------------------ /* Written by Allan R. Black, Strathclyde University. * This program may be freely distributed provided that * this comment is not removed and that * no profit is gained from such distribution. */ /* * @(#)robots.c 1.7 3/21/84 */ /* 1.7a modified by Stephen J. Muir at Lancaster University. */ /* 1.7b adapted to Xenix Rel 3.0 by Chuck McManis */ # define XENIX # include <curses.h> # include <signal.h> # include <pwd.h> # include <ctype.h> # ifdef XENIX # include <sys/types.h> # endif # include <sys/file.h> # ifdef XENIX /* Xenix defaults to 16 bit ints */ # define LONG long # define SFMT %ld # else # define SFMT %d # define LONG # endif # MIN_ROBOTS 10 # define MAX_ROBOTS 500 # define MIN_VALUE 10 # define MAX_FREE 3 # define VERT '|' # define HORIZ '-' # define ROBOT '=' # define SCRAP '@' # define ME 'I' # define MUNCH '*' # define DOT '.' # define LEVEL (level+1) # define MSGPOS 39 # define RVPOS 51 # define HOF_FILE "/usr/games/lib/robots_hof" # define TMP_FILE "/usr/games/lib/robots_tmp" # define NUMSCORES 20 # define NUMNAME "Twenty" # define TEMP_DAYS 7 # define TEMP_NAME "Week" # define MAXSTR 100 extern char *getlogin (); extern struct passwd *getpwnam (); struct scorefile { int s_uid; LONG int s_score; char s_name[MAXSTR]; bool s_eaten; int s_lev int s_days; }; # define FILE_SIZE (NUMSCORES*sizeof(struct scorefile)) /*# define ALLSCORES*/ # define SECSPERDAY 86400 # define BEL 007 # define CTLH 010 # define CTLJ 012 # define CTLK 013 # define CTLL 014 # define CTLY 031 # define 25 # define CTLB 002 # define CTLN 016 # define CTLR 022 char whoami[MAXSTR]; int my_x, my_y; int new_x, new_y; int level = 0; LONG int score = 0; int free_teleports = 0; int free_per_level = 1; bool dead = FALSE; bool last_stand; int count; char com, cmd_ch; bool running, adjacent, first_move, bad_move; int dots = 0; int robot_value = MIN_VALUE; int max_robots = MIN_ROBOTS; int robots_alive; struct passwd *pass; struct robot { bool alive; int x; int y; } robot_list[MAX_ROBOTS]; LONG int seed; #ifndef XENIX struct ltchars ltc; #endif char dsusp; int r(); int interrupt(); char *forbidden [] = { "root", "daemon", "uucp", "pop", "ingres", "demo", "chessel", "saturn", "sjm", "cosmos", 0 }; main(argc,argv) int argc; char *argv[]; { register char *x, **xx; if(argc > 1) { if(argv[1][0] == '-') { switch(argv[1][1]) { case 's': scoring(FALSE); exit(0); } } } if ((x = getlogin ()) == 0 || (pass = getpwnam (x)) == 0) { printf ("Who the hell are you?\n"); exit (1); } strcpy(whoami,x); for (xx = forbidden; *xx; ++xx) if (strcmp (whoami, *xx) == 0) { printf ("only individuals may play robots\n"); exit (1); } seed = time(0)+pass->pw_uid; signal(SIGQUIT,interrupt); signal(SIGINT,interrupt); initscr(); crmode(); noecho(); # ifndef XENIX /* Xenix doesn't support suspend yet */ ioctl(1,TIOCGLTC,<c); dsusp = ltc.t_dsuspc; ltc.t_dsustc.t_suspc; ioctl(1,TIOCSLTC,<c); # endif for(;;) { count = 0; running = FALSE; adjacent = FALSE; last_stand = FALSE; if(rnd(free_per_level) < free_teleports) { free_per_level++; if(free_per_level > MAX_FREE) free_per_level = MAX_FR } free_teleports += free_per_level; leaveok(stdscr,FALSE); draw_screen(); put_robots(); do { my_x = rndx(); my_y = rndy(); move(my_y,my_x); } while(winch(stdscr) != ' '); addch(ME); for(;;) { scorer(); if(robots_alive == 0) break; command(); robots(); if(dead) munch(); } if (!level) ice (2); #ifdef XENIX mvprintw(LINES-2,MSGPOS,"%d robots are now scrap heaps",max_robots); #else msg("%d robots are now scrap heaps",max_robots); #endif leaveok(stdscr,FALSE); move(my_y,my_x); refresh(); readchar(); level++; } } draw_screen() { register int x, y; clear(); for(y = 1; y < LINES-2; y++) { mvaddch(y,0,VERT); mvaddch(y,COLS-1,VERT); } for(x = 0; x < COLS; x++) { mvaddch(0,x,HORIZ); mvaddch(LINES-2,x,HORIZ); } } put_robots() { register struct robot *r, *end; register int x, y; robot_value += level*5+rnd(level*10); max_robots += level*3+rnd(level*5); if(max_robots > MAX_ROBOTS) max_robots = MAX_ROBOTS; robots_alive = max_robots; end = &robot_list[max_robots]; for(r = robot_list; r < end; r++) { for(;;) { x = rndx(); y = rndy(); move(y,x); if(winch(stdscr) == ' ') break; } r->x = x; r->y = y; r->alive = TRUE; addch(ROBOT); } } command() { register int x, y; retry: move(my_y,my_x); refresh(); if(last_stand) return; bad_move = FALSE; if(!running) { cmd_ch = read_com(); switch(cmd_ch) { case CTLH: case CTLJ: case CTLK: case CTLL: case CTLY case CTLU: case CTLB: case CTLN: cmd_ch |= 0100; adjacent = TRUE; case 'H': case 'J': case 'K': case 'L': case 'Y': case 'U': case 'B': case 'N': cmd_ch |= 040; running = TRUE; first_move = TRUE; case 't': case 'T': case 's': case 'S': case 'm': case 'M': case '? case 'd': case 'D': case CTLR: count = 0; } } switch(cmd_ch) { case '.': return; case 'h': case 'j': case 'k': case 'l': case 'y': case 'u': case 'b': case 'n': do_move(cmd_ch); break; case ' case 'T': teleport: new_x = rndx(); new_y = rndy(); move(new_y,new_x); switch(winch(stdscr)) { case ROBOT: case SCRAP: case ME: goto teleport; } if(free_teleports > 0) { for(x = new_x-1; x <= new_x+1; x++) { for(y = new_y-1; y <= new_y+1; y++) { move(y,x); if(winch(stdscr) == ROBOT) goto teleport; } } feports--; } break; case 's': case 'S': last_stand = TRUE; leaveok(stdscr,TRUE); return; case 'm': case 'M': case '?': good_moves(); goto retry; case 'd': case 'D': if(dots < 2) { dots++; put_dots(); } else { erase_dots(); dots = 0; } goto retry; case 'q': case 'Q': quit(FALSE); case CTLR: clearok(curscr,TRUE); wrefresh(curscr); goto retry; default: bad_move = TRUE; } if(bad_move) { if(running) { if(first_move) putchar(BEL); running = FALSE; adjacent = FALSE; first_mALSE; } else { putchar(BEL); } refresh(); count = 0; goto retry; } first_move = FALSE; mvaddch(my_y,my_x,' '); my_x = new_x; my_y = new_y; move(my_y,my_x); if(winch(stdscr) == ROBOT) munch(); mvaddch(my_y,my_x,ME); refresh(); } read_com() { if(count == 0) { if (dots) { put_dots (); move (my_y, my_x); refresh (); } f(isdigit(com = readchar())) { count = com-'0'; while(isdigit(com = readchar())) count = count*10+com-'0'; } if (dots) erase_dots (); } if(count > 0) count--; return(com); } readchar() { static char buf[1]; while(read(0,buf,1) <= 0); return(buf[0]); } do_move(dir) char dir; { register int x, y; new_x = my_x+xinc(dir); new_y = my_y+yinc(dir); move(new_y,new_x); switch(winch(stdscr)) { case VERT: case HORIZ: case SCRAP: bad_move = TRUE; } if(adjacent & !first_move) { for(x = new_x-1; x <= new_x+1; for(y = new_y-1; y <= new_y+1; y++) { move(y,x); switch(winch(stdscr)) { case ROBOT: case SCRAP: bad_move = TRUE; return; } } } } } put_dots() { register int x, y; for(x = my_x-dots; x <= my_x+dots; x++) { if (x < 1 || x > COLS - 2) continue; for(y = my_y-dots; y <= my_y+dots; y++) { if (y < 1 || y > LINES - 3) continue; move(y,x); if(winch(stdscr) == ' ') addch(DOT); } } } erase_dots() { register int x, y; for(x = my_x-dots; x <= my_x+dots; x++) { if (x < 1 || x > COLS - 2) continue; for(y = my_y-dots; y <= my_y+dots; y++) { if (y < 1 || y > LINES - 3) continue; move(y,x); if(winch(stdscr) == DOT) addch(' '); } } } good_moves() { register int x, y; register int test_x, test_y; register char *m, *a; static char moves[] = "hjklyubn."; static char ans[sizeof moves]; a = ans; for(m = moves; *m; m++) { test_x = my_x+xinc(*m); test_y = my_*m); move(test_y,test_x); switch(winch(stdscr)) { case ' ': case ME: for(x = test_x-1; x <= test_x+1; x++) { for(y = test_y-1; y <= test_y+1; y++) { move(y,x); if(winch(stdscr) == ROBOT) goto bad; } } *a++ = *m; } bad:; } *a = 0; if(ans[0]) { a = ans; } else { a = "Forget it!"; } mvprintw(LINES-1,MSGPOS,",RVPOS-MSGPOS,RVPOS-MSGPOS,a); } xinc(dir) char dir; { switch(dir) { case 'h': case 'y': case 'b': return(-1); case 'l': case 'u': case 'n': return(1); j': case 'k': default: return(0); } } yinc(dir) char dir; { switch(dir) { case 'k': case 'y': case 'u': return(-1); case 'j': case 'b': case 'n': return(1); case 'h': case 'l': default: return(0); } } robots() { register struct robot *r, *end, *find; end = &robot_list[max_robots]; for(r = robot_list; r < end; r++) { if(r->alive) { mvaddch(r->y,r->x,' '); } } for(r = robot_list; r < end; r++) { if(r->alive) { r->x += sign(my_x-r->x); r->y += sign(my_y-r->y); move(r->y,r->x); switch(winch(stdscr)) { case ME: addch(MUNCH); dead = TRUE; k; case SCRAP: r->alive = FALSE; score += robot_value; robots_alive--; break; case ROBOT: for(find = robot_list; find < r; find++) { if(find->alive) { if(r->x == find->x && r->y == find->y) { find->alive = FALSE; break; } } } r->alive = FALSE; addch(SCRAP); score += robot_value*2; robots_alive -= 2; break; case MUNCH: break; default: addch(ROBOT); } } } } munch() { scorer(); #ifdef XENIX mvprintw(LINES-2,MSGPCH! You're robot food"); #else msg("MUNCH! You're robot food"); #endif leaveok(stdscr,FALSE); leaveok(stdscr,FALSE); mvaddch(my_y,my_x,MUNCH); move(my_y,my_x); refresh(); readchar(); quit(TRUE); } quit(eaten) bool eaten; { move(LINES-1,0); refresh(); endwin(); putchar('\n'); #ifndef XENIX ltc.t_dsuspc = dsusp; ioctl(1,TIOCSLTC,<c); #endif scoring(eaten); exit(0); } scoring(eaten) bool eaten; { static char buf[MAXSTR]; sprintf(buf,"for this %s",TEMP_NAME); record_score(eaten,TMP_FILAYS,buf); printf("[Press return to continue]"); fflush(stdout); gets(buf); record_score(eaten,HOF_FILE,0,"of All Time"); } record_score(eaten,fname,max_days,type_str) bool eaten; char *fname; int max_days; char *type_str; { int fd; int (*action)(); action = signal(SIGINT,SIG_IGN); if((fd = open(fname,2)) < 0) { perror(fname); } else { #ifdef XENIX do_score(eaten,fd,max_days,type_str); #else if(flock(fd,LOCK_EX) < 0) { perror(fname); } else { do_score(eaten,fd,max_days,type_str); flock(fd,LOCK_UN); } #endif close(fd); } signal(SIGINT,action); } do_score(eaten,fd,max_days,type_str) bool eaten; int fd, max_days; char *type_str; { register struct scorefile *position; register int x; register struct scorefile *remove, *sfile, struct scorefile *oldest, *this; char *so, *ts; int uid, this_day, limit; static char buf[20]; ts = buf; this_day = max_days ? time(0)/SECSPERDAY : 0; limit = this_day-max_days; sfile = (struct scorefile *)(malloc(FILE_SIZE)); eof = &sfile[NUMSCORES]; this = 0; for(position = sfile; position < eof; position++) { position->s_score position->s_days = 0; } read(fd,sfile,FILE_SIZE); remove = 0; if(score > 0) { uid = pass->pw_uid; oldest = 0; x = limit; for(position = eof-1; position >= sfile; position--) { if(position->s_days < x) { x = position->s_days; oldest = position; } } position = 0; for(remove = sfile; remove < eof; remove++) { if(position == 0 && score > remove->s_score) position = remove; # ifndef ALLSCORES if (remove->s_uid == uid) { if (remove->s_days < limit) oldest = remove; else break; } # endif ALLSCORES } if(remove < eof) { if(position == 0 && remove->s_days < limit) position = remove; } else if(oldest) { remove = oldest; if(position == 0) { position = eof-1; } else if(remove < position) { position--; } } else if(position) { remove = eof-1; } if(position) { if(remove < position) { while(remove < position) { *remove = *(r; remove++; } } else { while(remove > position) { *remove = *(remove-1); remove--; } } position->s_score = score; strncpy(position->s_name,whoami,MAXSTR); position->s_eaten = eaten; position->s_level = LEVEL; position->s_uid = uid; position->s_days = this_day; this = position; #ifdef XENIX lseek(fd,0L,0); #else lseek(fd,0,0); #endif write(fd,sfile,FILE_SIZE); close(fd); } } printf( # ifdef ALLSCORES "\nTop %s Scores %s:\n", # else ALLSCORES "\nTop %s Robotists %s:\n", # endif ALLSCORES NUMNAME, type_str ); printf("Rank Score Name\n"); count = 0; for(position = sfile; position < eof; position++) { if(position->s_score == 0) break; if(position == this && SO && SE) { tputs(SO,0,_putchar); } if (position->s_days >= limit) { #ifdef XENIX printf ("%-6d %-8ld %s: %s on level %d.", #else printf ("%-6d %-8d %s: %s on level %d.", #endif ++count, position->s_score, position->s_name, position->s_eaten ? "eaten" : "chickened out", position->s_level ); # ifdef OLDSCORES } else { # ifdef XENIX printf ("**OLD** %-8ld %s: %s on level %d.", # else printf ("**OLD** %-8d %s: %s on level %d.", # endif position->s_score, position->s_name, position->s_eaten ? "eaten" : "chickened out", position->s_level ); # endif OLDSCORES } tion == this && SO && SE) { tputs(SE,0,_putchar); } # ifndef OLDSCORES if (position->s_days >= limit) # endif OLDSCORES putchar ('\n'); } } scorer() { static char infobuf [6]; register int x, y; if ((y = free_teleports-free_per_level) y = 0; x = free_teleports-y; sprintf(infobuf,"%d+%d",x,y); if (y == 0) infobuf[1] = '\0'; move(LINES-1,0); clrtoeol(); #ifdef XENIX printw("<%s> level: %d score: %ld",infobuf,LEVEL,score)e printw("<%s> level: %d score: %d",infobuf,LEVEL,score); #endif mvprintw(LINES-1,RVPOS,"robots: %d value: %d",robots_alive,robot_value); } rndx() { return(rnd(COLS-2)+1); } rndy() { return(rnd(LINES-3)+1); } rnd(mod) int mod; { if(mod <= 0) return(0); return((((seed = seed*11109+13849) >> 16) & 0xffff) % mod); } sign(x) register int x; { if(x < 0) return(-1); return(x > 0); } #ifndef XENIX /* XENIX can't resolve the reference to _doprnt */ msg(message,args) char *message; int args; { reint x; static FILE msgpr; static char msgbuf[1000]; msgpr._flag = _IOSTRG | _IOWRT; msgpr._ptr = msgbuf; msgpr._cnt = 1000; _doprnt(message,&args,&msgpr); putc(0,&msgpr); mvaddstr(LINES-1,MSGPOS,msgbuf); clrtoeol(); refresh(); } #endif interrupt() { quit(FALSE); } -- - - - D I S C L A I M E R - - - {ihnp4,fortune}!dual\ All opinions expressed herein are my {qantel,idi}-> !intelca!cem own and not those of my employer, my {ucbvax,hao}!hplabs/ friends, or my avocado plant. :-}
guy@sun.uucp (Guy Harris) (06/17/85)
A lot of the changes "ifdef"fed with XENIX reflect the way the code should have been in the first place: 1) Contrary to popular belief, "int"s are not guaranteed to be 32 bits long. All of the variables that are declared with LONG in the XENIX version should be declared as long in *all* versions (yes, even under 4.xBSD). All "printf" and "scanf" formats that print or read into these variables should use "%ld" format, not "%d". The second argument to "lseek" should always be a "long", so you should say lseek(fd,0L,0); not lseek(fd,0,0); even on 4.xBSD systems. 2) Contrary to popular belief, not all UNIX systems have "_doprnt". System III doesn't have it; PDP-11 V7 and System Vs Releases 1 and 2 have it, but don't document it; 4.2BSD has it and made the mistake of documenting it. Zilog's ZEUS doesn't have it because the Zilog calling sequence makes routines that take a variable number of arguments a pain to implement. If you take Chuck McManus' corrected version and: Change all the "ifdef"fed sections involving "int" vs. "long int" stuff or the "msg" routine to *only* contain the code compiled if XENIX is defined, Change the section that reads # ifdef XENIX # include <sys/types.h> # endif # include <sys/file.h> to read # ifdef BSD4_2 # include <sys/file.h> # endif because the inclusion of "sys/file.h" seems to be solely for the benefit of the "flock" system call which only exists on 4.2BSD, Change all other occurrences of # ifdef XENIX to # ifndef BSD4_2, because all the other # ifdef XENIXes are there to conditionally compile in code using 4.2BSD features (if you feel *really* ambitious, you can throw in #ifdefs for the file-locking stuff to use the various flavors of "lockf" derived from the original John Bass version for those versions of UNIX that support it), And run the whole thing through "lint" to catch trash like seed = time(0)+pass->pw_uid; and replace it with the *correct* version which is seed = time((time_t *)0)+pass->pw_uid; (I'd classify this as a venial sin, except that I've fixed that kind of stuff enough times on CCI's 16-bit-"int"/32-bit-pointer machines that I think it deserves to be a mortal sin). Could people take a little more care *NOT* to make assumptions about the version of UNIX or machine they're writing for when writing code? If so, there'll be a lot fewer "has anybody gotten 'Hump The Hostess' running under {V7,4.1BSD,4.2BSD,System III,System V,Xenix,Zeus,Penix}" questions, and a lot fewer repeated postings of programs until a portable version emerges. Guy Harris
gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (06/19/85)
> there'll be a lot fewer "has anybody gotten 'Hump The Hostess' running under > {V7,4.1BSD,4.2BSD,System III,System V,Xenix,Zeus,Penix}" questions, and a Hey, I want a copy.