|
|
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 m
Length: 16047 (0x3eaf)
Types: TextFile
Names: »main.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Phantasia/main.c«
/*
* Phantasia 3.3 -- Interterminal fantasy game
*
* Edward A. Estes
* AT&T Teletype Corporation, July 9, 1985
*/
/* DISCLAIMER:
*
* This game is distributed for free as is. It is not guaranteed to work
* in every conceivable environment. It is not even guaranteed to work
* in ANY environment.
*
* This game is distributed without notice of copyright, therefore it
* may be used in any manner the recipient sees fit. However, the
* author assumes no responsibility for maintaining or revising this
* game, in its original form, or any derivitives thereof.
*
* The author shall not be responsible for any loss, cost, or damage,
* including consequential damage, caused by reliance on this material.
*
* The author makes no warranties, express or implied, including warranties
* of merchantability or fitness for a particular purpose or use.
*
* AT&T and AT&T Teletype Corporation are in no way connected with this
* game.
*/
/*
* This is the program which drives the whole mess. Hopefully, you will be
* able to wade throught the garbage if you have to fix something.
* several undocumented items exist. The program checks uid and sets the
* boolean flag 'su' (super user) if the person is allowed special powers.
* The 'su' may execute any of the valar/council options. Also,
* a 'vaporize' option exists to kill anybody at will. The 'su' can select
* character type 7, which starts out with the maximum possible in each
* category. (The resulting character is an experimento.) The 'su' may
* also change the stats of other characters with the -x option.
*/
/*
* The program allocates as much file space as it needs to store characters,
* so the possibility exists for the character file to grow without bound.
* The file is purged upon normal entry to try to avoid that problem.
* A similar problem exists for energy voids. To alleviate the problem here,
* the void file is cleared with every new king.
*/
/*
* The support functions are split between various files with no apparent
* order. Use of 'ctags' is recommended to find a particular function.
*/
/*
* Put one line of text into the file 'motd' for announcements, etc.
*/
/*
* If ENEMY is defined, a list of restricted login names is checked
* in the file 'enemy'. These names are listed, one per line, with
* no trailing blanks.
*/
#include "phant.h"
double strength, speed;
bool beyond, marsh, throne, valhala, changed, fghting, su, wmhl, timeout;
int fileloc, users;
jmp_buf fightenv, mainenv;
long secs;
/*
* worm hole map -- This table is carefully set up so that one can always
* return the way he/she came by inverting the initial path.
*/
#ifndef SMALL
struct worm_hole w_h[] =
{
0,0,0,0, 35,22,2,0, 2,2,0,1, 59,34,64,0,
54,47,0,60, 50,62,0,56, 19,31,25,0, 0,35,41,41,
0,46,40,23, 24,0,29,30, 44,57,56,0, 0,44,39,40,
61,41,0,42, 32,0,17,18, 57,0,63,64, 0,33,26,34,
48,0,54,55, 28,23,22,13, 63,25,13,19, 34,6,18,20,
27,26,19,21, 15,27,20,27, 1,28,34,17, 17,29,8,24,
29,9,23,25, 18,30,24,6, 20,32,27,15, 21,20,21,26,
22,17,46,29, 23,24,28,9, 25,38,9,31, 6,39,30,32,
26,13,31,33, 15,40,32,35, 3,19,15,22, 7,1,33,36,
37,37,35,37, 36,36,36,38, 30,42,37,39, 31,43,38,11,
33,45,11,8, 12,48,7,7, 38,49,12,43, 39,51,42,44,
11,10,43,45, 40,52,44,46, 8,53,45,28, 4,54,51,48,
41,16,47,49, 42,55,48,50, 62,5,49,51, 43,56,50,47,
45,58,53,53, 46,59,52,52, 47,4,55,16, 49,61,16,54,
51,63,5,10, 10,14,59,58, 52,64,57,59, 53,3,58,57,
60,60,4,61, 55,12,60,62, 5,50,61,63, 56,18,62,14,
58,33,14,3
};
#endif
main(argc,argv) /* Phantasia main routine */
int argc;
char *argv[];
{
static struct stats charac;
char aline[200], *login = NULL;
double x = 0.0, y = 0.0;
int ch, ch2, loop, temp;
FILE *fp;
bool shrt = FALSE, examine = FALSE, header = FALSE;
if ((login = getlogin()) == NULL)
login = getpwuid(getuid())->pw_name;
#ifdef ENEMY
/* check hit list of restricted accounts */
if ((fp = fopen(enemyfile, "r")) != NULL)
{
char enemy[25];
while (fscanf(fp, "%s", enemy) != EOF)
if (!strcmp(login,enemy))
{
printf ("The Phantasia privileges for the account \"%s\" have been revoked.\n", login);
printf ("Mail comments to %s.\n", WIZARD);
exit (0);
}
fclose (fp);
}
#endif
setbuf(stdin, (char *) NULL); /* this may or may not be necessary */
su = FALSE;
fghting = FALSE;
timeout = FALSE;
users = 0;
while (--argc && (*++argv)[0] == '-')
switch ((*argv)[1])
{
case 'h': /* help */
if ((fp = fopen(helpfile, "r")) != NULL)
{
while (fgets(aline, 200, fp))
fputs(aline, stdout);
fclose(fp);
}
exit(0);
/*NOTREACHED*/
case 's': /* short */
shrt = TRUE;
break;
case 'x': /* examine */
examine = TRUE;
break;
case 'H': /* Header */
header = TRUE;
break;
case 'm': /* monsters */
printmonster();
exit(0);
/*NOTREACHED*/
case 'a': /* all users */
showusers(FALSE);
exit(0);
/*NOTREACHED*/
case 'p': /* purge old players */
purge();
exit(0);
/*NOTREACHED*/
case 'S':
su = (getuid() == UID);
break;
case 'b':
show_sb();
exit(0);
/*NOTREACHED*/
}
if (!isatty(0)) /* don't let non-tty's play */
exit(0);
init1(); /* set up for screen stuff */
if (examine)
{
cstat();
exit1();
/*NOTREACHED*/
}
if (!shrt)
{
titlestuff();
purge(); /* clean up old characters */
}
if (header)
{
exit1();
/*NOTREACHED*/
}
#ifdef OK_TO_PLAY
if (!ok_to_play())
{
mvaddstr(23,27,"Sorry, you can't play now.\n");
exit1();
/*NOTREACHED*/
}
#endif
mvaddstr(21,24,"Do you have a character to run? ");
ch = getans("NY", FALSE);
if (ch == 'Y')
fileloc = findchar(&charac);
else
{
initchar(&charac);
clear();
mvaddstr(4,21,"Which type of character do you want:");
mvaddstr(8,4,"1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento ? ");
ch = getans("2134567", FALSE);
do
{
genchar(&charac,ch);
mvprintw(12,14,"Strength: %2.0f Mana : %3.0f Quickness : %2d",
charac.str,charac.man,charac.quk);
mvprintw(13,14,"Brains : %2.0f Magic Level: %2.0f Energy Level: %2.0f",
charac.brn,charac.mag,charac.nrg);
if (charac.typ != 6)
{
mvaddstr(14,14,"Type '1' to keep >");
ch2 = getans(" ", TRUE);
}
else
break;
}
while (ch2 != '1');
if (charac.typ == 6)
for (;;)
{
mvaddstr(16,0,"Enter the X Y coordinates of your experimento ? ");
getstring(aline,80);
sscanf(aline,"%F %F",&charac.x,&charac.y);
if (abs(charac.x) > 1.2e6 || abs(charac.y) > 1.2e6)
mvaddstr(17,0,"Invalid coordinates. Try again.\n");
else
break;
}
for (;;)
{
mvaddstr(18,0,"Give your character a name [up to 20 characters] ? ");
getstring(aline,80);
strncpy(charac.name,aline,20);
charac.name[20] = '\0';
trunc(charac.name);
if (charac.name[0] == '\0')
mvaddstr(19,0,"Invalid name.");
else if (findname(charac.name, (struct stats *) NULL) >= 0)
mvaddstr(19,0,"Name already in use.");
else
break;
addstr(" Pick another.\n");
}
putchar('\n');
fflush(stdout);
nocrmode();
do
{
strcpy(charac.pswd,getpass("Give your character a password [up to 8 characters] ? "));
putchar('\n');
strcpy(aline,getpass("One more time to verify ? "));
}
while (strcmp(charac.pswd,aline));
fileloc = findspace();
}
crmode();
if (charac.status)
{
clear();
addstr("Your character did not exit normally last time.\n");
addstr("If you think you have good cause to have your character saved,\n");
printw("you may quit and mail your reason to '%s'.\n",WIZARD);
addstr("Otherwise, continuing spells certain death.\n");
addstr("Do you want to quit ? ");
ch = getans("YN", FALSE);
if (ch== 'Y')
{
charac.tampered = charac.quk; /* store this away */
charac.quk = -100;
leave(&charac);
/*NOTREACHED*/
}
death(&charac);
}
charac.status = PLAYING;
if (charac.lvl > 5)
timeout = TRUE;
strcpy(charac.login,login);
time(&secs);
charac.lastused = localtime(&secs)->tm_yday;
update(&charac,fileloc);
clear();
#ifdef BSD41
sigset(SIGINT,interrupt);
#endif
#ifdef BSD42
signal(SIGINT,interrupt);
#endif
#ifdef SYS3
signal(SIGINT,interrupt);
#endif
#ifdef SYS5
signal(SIGINT,interrupt);
#endif
/* all set for now */
TOP:
switch (setjmp(mainenv))
{
case QUIT:
#ifdef BSD41
sigrelse(SIGINT);
#endif
#ifdef BSD42
signal(SIGINT,interrupt);
#endif
#ifdef SYS3
signal(SIGINT,interrupt);
#endif
#ifdef SYS5
signal(SIGINT,interrupt);
#endif
leave(&charac);
/*NOTREACHED*/
case DIE:
#ifdef BSD41
sigrelse(SIGINT);
#endif
#ifdef BSD42
signal(SIGINT,interrupt);
#endif
#ifdef SYS3
signal(SIGINT,interrupt);
#endif
#ifdef SYS5
signal(SIGINT,interrupt);
#endif
death(&charac);
break;
}
#ifdef OK_TO_PLAY
if (!ok_to_play())
{
mvaddstr(6,0,"Whoops! Can't play now.\n");
leave(&charac);
/*NOTREACHED*/
}
#endif
fghting = FALSE;
adjuststats(&charac);
if (throne && !charac.crn && (charac.typ < 10 || charac.typ > 20))
{
mvaddstr(5,0,"You're not allowed in the Lord's Chamber without a crown.\n");
changed = TRUE;
charac.x = charac.y = 10 + roll(8, 5);
}
if (charac.status != CLOAKED && abs(charac.x) == abs(charac.y)
&& floor(sqrt(fabs(charac.x/100.0))) == sqrt(fabs(charac.x/100.0)) && !throne)
{
trade(&charac);
clear();
}
checktampered(&charac);
checkinterm(&charac);
if (charac.nrg < 0 || (charac.lvl >= 10000 && charac.typ != 99))
death(&charac);
neatstuff(&charac);
if (changed)
{
update(&charac,fileloc);
changed = FALSE;
goto TOP;
}
mesg();
printstats(&charac);
move(6,0);
#ifndef SMALL
if (!wmhl)
#endif
{
if (throne)
kingstuff(&charac);
addstr("NSEW1:Move 2:Players 3:Talk 4:Stats 5:Quit ");
if (charac.lvl >= 7 && charac.mag >= 20)
addstr("6:Cloak ");
if (charac.lvl >= 12 && charac.mag >= 40)
addstr("7:Teleport ");
if (charac.typ > 20)
addstr("8:Intervene");
ch = gch(charac.rng.type);
mvaddstr(4,0,"\n\n");
if (charac.status == CLOAKED)
if (charac.man > 3.0)
charac.man -= 3;
else
{
charac.status = PLAYING;
changed = TRUE;
}
move(7,0);
clrtobot();
if (charac.typ == 99 && (ch == '1' || ch == '7'))
ch = ' ';
switch (ch2 = ch)
{
case 'N':
charac.y += maxmove;
break;
case 'S':
charac.y -= maxmove;
break;
case 'E':
charac.x += maxmove;
break;
case 'W':
charac.x -= maxmove;
break;
default: /* rest */
charac.nrg += (charac.mxn+charac.shd)/15+charac.lvl/3+2;
charac.nrg = min(charac.nrg,charac.mxn + charac.shd);
if (charac.status != CLOAKED)
{
charac.man += circ(charac.x,charac.y)/4;
charac.man += charac.lvl/6;
rndattack();
}
break;
case '1': /* move */
for (loop = 3; loop; --loop)
{
mvaddstr(4,0,"X Y Coordinates ? ");
getstring(aline,80);
if (sscanf(aline,"%F %F",&x,&y) != 2)
mvaddstr(5,0,"Try again\n");
else if (dist(charac.x, x, charac.y, y) > maxmove)
illmove();
else
{
charac.x = x;
charac.y = y;
break;
}
}
break;
case '2': /* players */
printplayers(&charac);
break;
case '3': /* message */
mvaddstr(4,0,"Message ? ");
getstring(aline, 80);
fp = fopen(messfile, "w");
if (*aline)
fprintf(fp, "%s: %s", charac.name, aline);
fclose(fp);
break;
case '4': /* stats */
showall(&charac);
break;
case '5': /* good-bye */
leave(&charac);
/*NOTREACHED*/
case '6': /* cloak */
if (charac.lvl < 7 || charac.mag < 20)
illcmd();
else if (charac.status == CLOAKED)
charac.status = PLAYING;
else if (charac.man < 35)
{
mvaddstr(5,0,"No power left.\n");
refresh();
}
else
{
changed = TRUE;
charac.man -= 35;
charac.status = CLOAKED;
}
break;
case '7': /* teleport */
if (charac.lvl < 12 || charac.mag < 40)
illcmd();
else
for (loop = 3; loop; --loop)
{
mvaddstr(4,0,"X Y Coordinates ? ");
getstring(aline,80);
if (sscanf(aline,"%F %F",&x,&y) == 2)
if ((temp = dist(charac.x,x,charac.y,y))
> (charac.lvl+charac.mag)*20+((charac.typ > 30) ? 1e+6 : 0)
&& !throne)
illmove();
else if ((temp = (temp/75+1)*20) > charac.man && !throne)
mvaddstr(6,0,"Not enough power for that distance.\n");
else
{
charac.x = x;
charac.y = y;
if (!throne)
charac.man -= temp;
break;
}
}
break;
case '9': /* monster */
if (throne)
mvaddstr(6,0,"No monsters in the chamber!\n");
else if (charac.typ != 99)
{
charac.status = PLAYING;
changed = TRUE;
charac.sin += 1e-6;
fight(&charac,-1);
}
break;
case '0': /* decree */
if (su || charac.typ > 10 && charac.typ < 20 && throne)
decree(&charac);
else
illcmd();
break;
case '8': /* intervention */
if (su || charac.typ > 20)
valarstuff(&charac);
else
illcmd();
break;
case '\014': /* redo screen */
clear();
}
if (ch2 == 'E' || ch2 == 'W' || ch2 == 'N' || ch2 == 'S'
|| ch2 == '1' || ch2 == '7')
{
checkmov(&charac);
rndattack();
changed = TRUE;
}
}
#ifndef SMALL
else
{
addstr("F:Forward B:Back R:Right L:Left Q:Quit T:Talk P:Players S:Stats ");
ch = getans(" ", TRUE);
move(6,0);
clrtobot();
if (charac.status == CLOAKED)
if (charac.man > 3.0)
charac.man -= 3;
else
{
charac.status = PLAYING;
changed = TRUE;
}
switch (ch)
{
default: /* rest */
charac.nrg += (charac.mxn+charac.shd)/15+charac.lvl/3+2;
charac.nrg = min(charac.nrg,charac.mxn + charac.shd);
if (charac.status != CLOAKED)
charac.man += charac.lvl/5;
break;
case 'F':
temp = w_h[charac.wormhole].f;
goto CHKMOVE;
case 'B':
temp = w_h[charac.wormhole].b;
goto CHKMOVE;
case 'R':
temp = w_h[charac.wormhole].r;
goto CHKMOVE;
case 'L':
temp = w_h[charac.wormhole].l;
goto CHKMOVE;
case 'Q':
leave(&charac);
/*NOTREACHED*/
case 'T':
mvaddstr(4,0,"Message ? ");
getstring(aline, 80);
fp = fopen(messfile, "w");
if (*aline)
fprintf(fp, "%s: %s", charac.name, aline);
fclose(fp);
break;
case 'P':
printplayers(&charac);
break;
case 'S':
showall(&charac);
break;
case '\014': /* redo screen */
clear();
}
goto TOP;
CHKMOVE:
if (!temp)
{
charac.y = 0.0;
charac.x = pow(-1.0,(double) charac.wormhole) * charac.wormhole * 400 - 1.0;
charac.wormhole = 0;
changed = TRUE;
}
else
charac.wormhole = temp;
}
#endif
goto TOP;
}
/*
* This function is provided to allow one to restrict access to the game.
* Tailor this routine as appropriate.
*/
#ifdef OK_TO_PLAY
#include <sys/types.h>
#include <utmp.h> /* used for counting users on system */
bool ok_to_play() /* return FALSE if playing is not allowed at this time */
{
#define MAXUSERS 30 /* max. number of people on system */
reg struct tm *tp;
reg int numusers = 0;
FILE *fp;
long now;
struct utmp ubuf;
if (su)
return (TRUE);
/* check time of day */
time(&now);
if (((tp = localtime(&now))->tm_hour > 8 && tp->tm_hour < 12) /* 8-noon */
|| (tp->tm_hour > 12 && tp->tm_hour < 16)) /* 1-4 pm */
return (FALSE);
/* check # of users */
if ((fp = fopen("/etc/utmp","r")) != NULL)
{
while (fread((char *) &ubuf,sizeof(ubuf),1,fp))
#ifdef SYS5
if (ubuf.ut_type == USER_PROCESS)
#else
if (*ubuf.ut_name)
#endif
++numusers;
fclose(fp);
if (numusers > MAXUSERS)
return (FALSE);
}
return (TRUE);
}
#endif