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 Harrisgwyn@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.