|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T i
Length: 18991 (0x4a2f)
Types: TextFile
Names: »init.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/War/init.c«
#ifdef SCCS
static char *sccsid = "@(#)init.c 1.2 4/5/85";
static char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
#endif
#include "war.h"
static int checkcount; /* counter for board checking */
static int didescape; /* did escape */
char *ask(); /* routine to ask a question */
int getaskchar(); /* routine to get chars */
FILE *opensetupfile(); /* open setup files */
/*
* Get commands from the user to initialize the board.
*/
userinit()
{
register struct object *obj; /* object being placed */
register int ch; /* current character */
register char *str; /* answer for user's question */
register int countone; /* command count defaulted to one */
register int countinf; /* count defaulted to infinity */
int gotcount; /* true if read a count */
int row; /* row to place it on */
int col; /* column to place it on */
row = 0;
col = 0;
obj = NULL;
newstat = 1;
setjmp(ttyjmp); /* come back here for every command */
if (newstat) viewstats();
dpymove(row, col);
dpyupdate();
countone = 0;
gotcount = 0;
while (1) { /* read numeric argument if any */
ch = scanchar();
if ((ch < '0') || (ch > '9')) break;
countone = (countone * 10) + ch - '0';
gotcount = 1;
}
if (countone < 0) countone = 0;
if (countone > 100) countone = 100;
countinf = countone;
if (gotcount == 0) { /* default values if necessary */
countone = 1;
countinf = 100;
}
switch (ch) {
case '\033': /* ESCAPE - ignore command */
break;
case '\014': /* ^L - redraw screen */
dpyredraw();
break;
case '\n': /* move to next line */
row += countone;
if (row > HOMEROW) row = HOMEROW;
col = 0;
break;
case '-': /* move to previous line */
row -= countone;
if (row < 0) row = 0;
col = 0;
break;
case '\t': /* move to next tab stop */
while ((col < (COLS-1)) && (++col % 8)) ;
break;
case '^': /* move to beginning of row */
col = 0;
break;
case '$': /* move to end of row */
col = (COLS - 1);
break;
case 'h': /* move left */
col -= countone;
if (col < 0) col = 0;
break;
case 'j': /* move down */
row += countone;
if (row > HOMEROW) row = HOMEROW;
break;
case 'k': /* move up */
row -= countone;
if (row < 0) row = 0;
break;
case 'l': /* move right */
case ' ':
col += countone;
if (col >= COLS) col = COLS - 1;
break;
case 'y': /* move to upper left */
while (countone-- && (row > 0) && (col > 0)) {
row--;
col--;
}
break;
case 'u': /* move to upper right */
while (countone-- && (row > 0) && (col < COLS-1)) {
row--;
col++;
}
break;
case 'b': /* move to lower left */
while (countone-- && (row < HOMEROW) && (col > 0)) {
row++;
col--;
}
break;
case 'n': /* move to lower right */
while (countone-- && (row<HOMEROW) && (col<COLS-1)) {
row++;
col++;
}
break;
case 'f': /* flip board left-right */
flipboard();
break;
case 'p': /* place an object */
obj = findobject(scanchar());
/* proceed into next case */
case '.': /* place same object */
placeobject(obj, row, col);
break;
case 'x': /* delete an object */
while (countone--) {
removeobject(row, col);
if (col >= (COLS-1)) break;
col++;
}
break;
case 'H': /* place lots left */
placeline(obj, &row, &col, 0, -1, countinf);
break;
case 'J': /* place lots down */
placeline(obj, &row, &col, 1, 0, countinf);
break;
case 'K': /* place lots up */
placeline(obj, &row, &col, -1, 0, countinf);
break;
case 'L': /* place lots right */
placeline(obj, &row, &col, 0, 1, countinf);
break;
case 'Y': /* place lots to upper left */
placeline(obj, &row, &col, -1, -1, countinf);
break;
case 'U': /* place lots to upper right */
placeline(obj, &row, &col, -1, 1, countinf);
break;
case 'B': /* place lots to lower left */
placeline(obj, &row, &col, 1, -1, countinf);
break;
case 'N': /* place lots to lower right */
placeline(obj, &row, &col, 1, 1, countinf);
break;
case 's': /* start to play */
if (editflag || checksetup()) {
beep();
break;
}
if (yesno("Ready to start playing? ")) return;
break;
case 'q': /* want to quit */
if (yesno("Want to quit? ")) quit(0);
break;
case 'w': /* write the setup */
str = ask("Write setup named: ");
if (str == NULL) break;
if (writesetup(setupfile, str)) beep();
break;
case 'r': /* read a setup */
str = ask("Read setup named: ");
if (str == NULL) break;
if (readsetup(setupfile, str)) beep();
break;
case 'c': /* clear board */
if (yesno("Want to clear the board? ")) clearboard();
break;
default:
beep();
break;
}
scanabort(); /* go back up for next command */
}
/*
* Ask a question and see if the answer is yes.
* Returns nonzero if so.
*/
yesno(str)
register char *str; /* string to ask, and answer */
{
str = ask(str);
if (str == NULL) return(0);
return((strcmp(str, "y") == 0) || (strcmp(str, "yes") == 0)
|| (strcmp(str, "Y") == 0) || (strcmp(str, "YES") == 0));
}
/*
* Ask the player a question and get an answer.
* Leading and trailing spaces are removed from the answer.
* If an escape or a null answer is given, a null pointer is returned.
*/
char *
ask(str)
{
register char *cp; /* current character */
static char buf[100]; /* buffer */
didescape = 0;
scanreset();
dpywindow(-1, -1, 2, COLS);
cp = buf;
cp += dpyread(str, getaskchar, cp, sizeof(buf));
if (cp < buf) cp = buf;
*cp-- = '\0';
while ((cp >= buf) && ((*cp == ' ') || (*cp == '\t'))) *cp-- = '\0';
for (cp = buf; ((*cp == ' ') || (*cp == '\t')); cp++) ;
dpyhome();
dpyclrwindow();
dpywindow(0, -1, 1, COLS);
if (didescape || (*cp == '\0')) cp = NULL;
return(cp);
}
/* Routine called by dpyread to get characters */
getaskchar()
{
char ch;
if ((read(STDIN, &ch, 1) != 1) || (ch == '\033')) {
didescape = 1;
return(-1);
}
if (ch == '\n') return(-1);
return((int)(ch & 0x7f));
}
/*
* Place a run of an object in a certain direction until it is illegal
* or until the count runs out. The new row and column are returned
* through pointers.
*/
placeline(obj, rowptr, colptr, rowsign, colsign, count)
register struct object *obj; /* object to place */
unsigned int *rowptr; /* current row */
unsigned int *colptr; /* current column */
register int rowsign; /* changes to make in rows */
register int colsign; /* changes to make in columns */
{
register unsigned int row; /* current row */
register unsigned int col; /* current column */
row = *rowptr;
col = *colptr;
while (count-- > 0) {
if (placeobject(obj, row, col)) break;
row += rowsign;
col += colsign;
if ((row > HOMEROW) || (col >= COLS)) {
row -= rowsign;
col -= colsign;
break;
}
if (board[row][col].c_obj) break;
}
*rowptr = row;
*colptr = col;
}
/*
* Clear everything from the home area of the board.
*/
clearboard()
{
register struct cell *cc; /* current cell */
for (cc = homecell; cc; cc = cc->c_next) {
if (cc->c_obj) removeobject(cc->c_row, cc->c_col);
}
}
/*
* Flip the board left to right during the initialization phase
*/
flipboard()
{
register int row; /* current row */
register struct cell *lc; /* left cell */
register struct cell *rc; /* right cell */
register struct object *lobj; /* left object */
register struct object *robj; /* right object */
for (row = 0; row <= HOMEROW; row++) {
lc = &board[row][0];
rc = &board[row][COLS-1];
for (; lc < rc; lc = lc->c_right, rc = rc->c_left) {
lobj = lc->c_obj;
robj = rc->c_obj;
if (lobj == robj) continue;
lc->c_obj = robj;
rc->c_obj = lobj;
if (lobj && (lobj->o_max <= 1)) lobj->o_cell = rc;
if (robj && (robj->o_max <= 1)) robj->o_cell = lc;
if (lobj) dpyplace(lc->c_row, lc->c_col, ' ');
if (robj) dpyplace(rc->c_row, rc->c_col, ' ');
if (lobj) dpyplace(rc->c_row, rc->c_col, lobj->o_ownch);
if (robj) dpyplace(lc->c_row, lc->c_col, robj->o_ownch);
}
}
}
/*
* Check the setup to make sure we are using all the men we are supposed to.
* Returns nonzero if some men are missing.
*/
checksetup()
{
register struct object *obj; /* current object */
for (obj = objects; obj < endobjects; obj++) {
if (obj->o_side != myside) continue;
if (obj->o_count < obj->o_min) return(1);
}
return(0);
}
/*
* Determine if an object just placed on the board leaves a legal layout.
* This means that each board location is reachable by some path which does
* not need to cross objects which can be multiply-placed (such as walls).
* Returns nonzero if the layout is illegal.
*/
checkboard(nc)
register struct cell *nc; /* new cell just placed */
{
register struct cell *cc; /* current cell */
register struct cell *rc; /* beginning of row cell */
register struct cell **ptr; /* pointer to adjacent cells */
if ((nc == NULL) || (nc->c_obj == NULL)) panic("checkboard");
if (((nc->c_obj->o_flags&F_WALL) == 0) || (nc->c_obj->o_side != myside))
return(0);
/*
* See if the placing of the object is trivially known to be legal.
* This is true if nothing surrounds the object, or if a single
* object lies next to it which isn't surrounded. We must search
* in all eight directions for this check.
*/
cc = NULL;
for (ptr = nc->c_dirs; ptr < &nc->c_dirs[8]; ptr++) {
rc = *ptr;
if ((rc->c_obj == NULL) || ((rc->c_obj->o_flags & F_WALL) == 0))
continue;
if (cc) goto hard;
cc = rc;
}
if (cc == NULL) return(0);
for (ptr = cc->c_dirs; ptr < &cc->c_dirs[8]; ptr++) {
rc = *ptr;
if ((rc->c_obj == NULL) || ((rc->c_obj->o_flags & F_WALL) == 0))
return(0);
}
/*
* At least two other objects lie next to the new one.
* We must do the brute force check now.
*/
hard: rc = &board[HOMEROW+1][0];
rc->c_checkcount = ++checkcount;
checkboardloop(rc);
for (rc = homecell; rc; rc = rc->c_next)
if (rc->c_checkcount != checkcount) return(1);
return(0);
}
/*
* Recursive subroutine used for marking accessible locations on the board.
* Call ourself for each new cell in the four orthagonal directions from
* the given cell.
*/
checkboardloop(cc)
register struct cell *cc; /* current cell to check */
{
register struct cell *tc; /* temporary cell */
register struct cell **ptr; /* cell pointer */
register int count; /* count of cells to check */
struct cell *celltab[4]; /* table of cells to check */
while (1) {
count = 0;
for (ptr = cc->c_dirs; ptr < &cc->c_dirs[4]; ptr++) {
tc = *ptr;
if (tc->c_obj == &edgeobj) continue;
if (tc->c_row > (HOMEROW + 1)) continue;
if (tc->c_checkcount == checkcount) continue;
tc->c_checkcount = checkcount;
if (tc->c_obj && (tc->c_obj->o_flags & F_WALL))
continue;
celltab[count++] = tc;
}
if (count != 1) break;
cc = celltab[0]; /* only one, no recursion needed */
}
while (count > 0) checkboardloop(celltab[--count]);
}
/*
* Initialize the cells of the board
*/
boardinit()
{
register struct cell *cc; /* current cell */
register int row; /* current row */
register int col; /* current column */
register int ch; /* character */
cc = &edge;
cc->c_row = -1;
cc->c_col = -1;
cc->c_up = cc;
cc->c_down = cc;
cc->c_left = cc;
cc->c_right = cc;
cc->c_ul = cc;
cc->c_ur = cc;
cc->c_ll = cc;
cc->c_lr = cc;
cc->c_obj = &edgeobj;
edgeobj.o_ownch = '*';
edgeobj.o_altch = '*';
edgeobj.o_side = -1;
edgeobj.o_flags = (F_WALL|F_EDGE);
for (row = 0; row < ROWS; row++) {
for (col = 0; col < COLS; col++) {
cc = &board[row][col];
cc->c_row = row;
cc->c_col = col;
cc->c_up = &board[row-1][col];
cc->c_down = &board[row+1][col];
cc->c_left = &board[row][col-1];
cc->c_right = &board[row][col+1];
cc->c_ul = &board[row-1][col-1];
cc->c_ur = &board[row-1][col+1];
cc->c_ll = &board[row+1][col-1];
cc->c_lr = &board[row+1][col+1];
cc->c_next = cc->c_left;
cc->c_obj = NULL;
}
cc = &board[row][0];
cc->c_left = &edge;
cc->c_ul = &edge;
cc->c_ll = &edge;
cc->c_next = &board[row-1][COLS-1];
cc = &board[row][COLS-1];
cc->c_right = &edge;
cc->c_ur = &edge;
cc->c_lr = &edge;
}
for (col = 0; col < COLS; col++) {
cc = &board[0][col];
cc->c_up = &edge;
cc->c_ul = &edge;
cc->c_ur = &edge;
cc = &board[ROWS-1][col];
cc->c_down = &edge;
cc->c_ll = &edge;
cc->c_lr = &edge;
}
board[0][0].c_next = NULL;
firstcell = &board[ROWS-1][COLS-1];
homecell = &board[HOMEROW][COLS-1];
/*
* Initialize the looks of the board
*/
for (row = 0; row < ROWS; row++) {
ch = '|';
if ((row == HOMEROW) || (row == (ROWS - HOMEROW - 1))) ch = '+';
dpychar(ch);
for (col = 0; col < COLS; col++) dpychar(' ');
dpychar(ch);
dpychar('\n');
}
dpywindow(0, -1, 1, COLS);
}
/*
* Clear the board and read in a setup from a board file.
* If a null board name is specified, a default one in the user's home
* directory is used. Returns nonzero if the file cannot be found.
*/
readsetup(setupfile, setupname)
char *setupfile; /* filename for board setups */
register char *setupname; /* name of setup */
{
register char *cp; /* current character */
register int row; /* current row */
register int col; /* current column */
register FILE *fd; /* file handle */
char buf[200]; /* line of the file */
if (setupname == NULL) return(0);
/*
* Open file and search for setup name
*/
fd = opensetupfile(setupfile, "r");
if (fd == NULL) return(1);
do {
cp = buf;
if (fgets(cp, sizeof(buf), fd) == NULL) {
fclose(fd);
return(1);
}
if (*cp++ != '"') continue;
while (*cp && (*cp != '"') && (*cp != '\n')) cp++;
*cp = '\0';
} while (strcmp(setupname, &buf[1]));
/*
* Found the setup, clear the board and read it in
*/
clearboard();
for (row = 0; row <= HOMEROW; row++) {
cp = buf;
if (fgets(cp, sizeof(buf), fd) == NULL) break;
if (*cp == '"') break;
for (col = 0; (col < COLS) && *cp; col++, cp++) {
if (*cp == '\n') break;
if (*cp == '\t') col |= 7;
if ((*cp <= ' ') || (*cp == 0177)) continue;
placeobject(findobject(*cp), row, col);
}
}
fclose(fd);
return(0);
}
/*
* Append the current setup to the specified file.
* Existing setups by the same name are not removed (which is a bug).
* This is to make the algorithm easy.
*/
writesetup(setupfile, setupname)
char *setupfile; /* filename for board setups */
char *setupname; /* name of setup */
{
register struct cell *rc; /* cell at front of row */
register struct cell *cc; /* current cell in row */
register char *cp; /* current character */
register FILE *fd; /* file handle */
int error; /* error flag */
char buf[COLS+2]; /* data to write */
if (setupname == NULL) return(1);
fd = opensetupfile(setupfile, "a");
if (fd == NULL) return(1);
fprintf(fd, "\"%s\"\n", setupname);
for (rc = &board[0][0]; rc->c_row <= HOMEROW; rc = rc->c_down) {
for (cc = rc, cp = buf; cc != &edge; cc = cc->c_right) {
*cp++ = cc->c_obj ? cc->c_obj->o_ownch : ' ';
}
cp = &buf[COLS-1];
while ((cp >= buf) && (*cp == ' ')) cp--;
*++cp = '\n';
*++cp = '\0';
fputs(buf, fd);
}
error = ferror(fd);
fclose(fd);
return(error);
}
/*
* Open the given setup file name, defaulting it if necessary.
* Returns a stdio FILE pointer if successfull, or NULL on an error.
*/
FILE *
opensetupfile(name, mode)
register char *name; /* file name, or NULL for default */
char *mode; /* mode to open file in */
{
char buf[200]; /* buffer for default name */
if ((name == NULL) || (*name == '\0')) {
name = (char *) getenv("HOME");
if (name == NULL) return(NULL);
sprintf(buf, "%s/%s", name, SETUPFILE);
name = buf;
}
return(fopen(name, mode));
}
/*
* Read in the parameters for the objects from the specified file.
* If a null name is given, the default file is used.
* Doesn't return if an error is encountered.
*/
readobjects(name)
register char *name; /* filename for objects */
{
register FILE *fd; /* file variable */
register struct object *obj; /* current object */
register int line; /* line number */
register int err; /* error occurred */
register int count; /* token count */
char flags[21]; /* flag characters */
char seen[3]; /* characters seen as */
char eol[2]; /* end of line character */
int life; /* life of the object */
int view; /* viewing range of the object */
int min; /* minimum number of objects */
int max; /* maximum number of objects */
char buf[200]; /* data buffer */
char altname[200]; /* alternate name */
if ((name == NULL) || (*name == '\0')) name = OBJECTFILE;
fd = fopen(name, "r");
if (fd == NULL) {
if (index(name, '/') == 0) {
sprintf(altname, "%s/%s", LIBDIR, name);
name = altname;
fd = fopen(name, "r");
}
if (fd == NULL) {
perror(name);
quit(1);
}
}
for (endobjects = objects, err = 0, line = 1; ; line++) {
fgets(buf, sizeof(buf), fd);
if (feof(fd) || ferror(fd)) break;
if (buf[0] == '#') continue; /* comment line */
eol[0] = '#';
count = sscanf(buf, "%20s%2s%d%d%d%d%1s\n",
flags, seen, &life, &view, &min, &max, eol);
if ((count < 6) || (seen[0] < ' ') || (seen[0] == 0177)
|| (view < 0) || (min < 0) || (max < min)
|| (eol[0] != '#')) {
fprintf(stderr, "%s, line %d: bad object\n",
name, line);
err = 1;
continue;
}
if (endobjects >= &objects[OBJS-1]) {
fprintf(stderr, "%s: Too many objects\n", name);
quit(1);
}
obj = endobjects++; /* allocate object */
obj->o_side = 0;
obj->o_id = (line * 2);
obj->o_ownch = seen[0];
obj->o_altch = seen[1];
if ((obj->o_altch < ' ') || (obj->o_altch == 0177))
obj->o_altch = ' ';
obj->o_view = view;
obj->o_life = life;
obj->o_min = min;
obj->o_max = max;
obj->o_count = 0;
obj->o_cell = NULL;
if (setflags(obj, flags)) {
fprintf(stderr, "%s, line %d: bad flag bits\n",
name, line);
err = 1;
}
setcmds(obj, ""); /* set to fight */
if ((obj->o_life == 0) && (obj->o_flags & F_GOAL))
obj->o_life = 1;
if (obj->o_max > 1) {
obj->o_flags |= F_IMMOB;
obj->o_flags &= ~(F_FIGHT|F_BLAST);
}
*endobjects = *obj; /* duplicate for other side */
endobjects->o_side = 1;
endobjects->o_id++;
endobjects++;
}
if (err) quit(1);
if (ferror(fd)) {
perror(name);
quit(1);
}
fclose(fd);
myside = 1;
}
/*
* Parse the flag string for an object and set the appropriate flags.
* Returns nonzero if they were illegal.
*/
setflags(obj, str)
register struct object *obj; /* object to set flags for */
register char *str; /* string */
{
register int flags; /* flag bits */
flags = 0;
while (*str) switch (*str++) {
case 'b': flags |= F_BLAST; break;
case 'f': flags |= F_FIGHT; break;
case 'g': flags |= F_GOAL; break;
case 'i': flags |= F_IMMOB; break;
case 't': flags |= F_TRANS; break;
case 'v': flags |= F_VIS; break;
case 'w': flags |= (F_WALL|F_IMMOB); break;
case 'x': flags |= F_XRAY; break;
case '-': break;
default: return(1);
}
obj->o_flags = flags;
return(0);
}