NetBSD/games/larn/create.c

607 lines
14 KiB
C

/* $NetBSD: create.c,v 1.12 2012/06/19 05:30:43 dholland Exp $ */
/* create.c Larn is copyrighted 1986 by Noah Morgan. */
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: create.c,v 1.12 2012/06/19 05:30:43 dholland Exp $");
#endif /* not lint */
#include "header.h"
#include "extern.h"
#include <unistd.h>
static void makemaze(int);
static int cannedlevel(int);
static void treasureroom(int);
static void troom(int, int, int, int, int, int);
static void makeobject(int);
static void fillmroom(int, int, int);
static void froom(int, int, int);
static void fillroom(int, int);
static void sethp(int);
static void checkgen(void);
/*
makeplayer()
subroutine to create the player and the players attributes
this is called at the beginning of a game and at no other time
*/
void
makeplayer(void)
{
int i;
scbr();
clear();
c[HPMAX] = c[HP] = 10; /* start player off with 15 hit points */
c[LEVEL] = 1; /* player starts at level one */
c[SPELLMAX] = c[SPELLS] = 1; /* total # spells starts off as 3 */
c[REGENCOUNTER] = 16;
c[ECOUNTER] = 96; /* start regeneration correctly */
c[SHIELD] = c[WEAR] = c[WIELD] = -1;
for (i = 0; i < 26; i++)
iven[i] = 0;
spelknow[0] = spelknow[1] = 1; /* he knows protection, magic missile */
if (c[HARDGAME] <= 0) {
iven[0] = OLEATHER;
iven[1] = ODAGGER;
ivenarg[1] = ivenarg[0] = c[WEAR] = 0;
c[WIELD] = 1;
}
playerx = rnd(MAXX - 2);
playery = rnd(MAXY - 2);
oldx = 0;
oldy = 25;
gltime = 0; /* time clock starts at zero */
cbak[SPELLS] = -50;
for (i = 0; i < 6; i++)
c[i] = 12; /* make the attributes, ie str, int, etc. */
recalc();
}
/*
newcavelevel(level)
int level;
function to enter a new level. This routine must be called anytime the
player changes levels. If that level is unknown it will be created.
A new set of monsters will be created for a new level, and existing
levels will get a few more monsters.
Note that it is here we remove genocided monsters from the present level.
*/
void
newcavelevel(int x)
{
int i, j;
if (beenhere[level])
savelevel(); /* put the level back into storage */
level = x; /* get the new level and put in working
* storage */
if (beenhere[x]) {
getlevel();
sethp(0);
checkgen();
return;
}
/* fill in new level */
for (i = 0; i < MAXY; i++)
for (j = 0; j < MAXX; j++)
know[j][i] = mitem[j][i] = 0;
makemaze(x);
makeobject(x);
beenhere[x] = 1;
sethp(1);
checkgen(); /* wipe out any genocided monsters */
#if WIZID
if (wizard || x == 0)
#else
if (x == 0)
#endif
for (j = 0; j < MAXY; j++)
for (i = 0; i < MAXX; i++)
know[i][j] = 1;
}
/*
makemaze(level)
int level;
subroutine to make the caverns for a given level. only walls are made.
*/
static int mx, mxl, mxh, my, myl, myh, tmp2;
static void
makemaze(int k)
{
int i, j, tmp;
int z;
if (k > 1 && (rnd(17) <= 4 || k == MAXLEVEL - 1 || k == MAXLEVEL + MAXVLEVEL - 1)) {
if (cannedlevel(k))
return; /* read maze from data file */
}
if (k == 0)
tmp = 0;
else
tmp = OWALL;
for (i = 0; i < MAXY; i++)
for (j = 0; j < MAXX; j++)
item[j][i] = tmp;
if (k == 0)
return;
eat(1, 1);
if (k == 1)
item[33][MAXY - 1] = 0; /* exit from dungeon */
/* now for open spaces -- not on level 10 */
if (k != MAXLEVEL - 1) {
tmp2 = rnd(3) + 3;
for (tmp = 0; tmp < tmp2; tmp++) {
my = rnd(11) + 2;
myl = my - rnd(2);
myh = my + rnd(2);
if (k < MAXLEVEL) {
mx = rnd(44) + 5;
mxl = mx - rnd(4);
mxh = mx + rnd(12) + 3;
z = 0;
} else {
mx = rnd(60) + 3;
mxl = mx - rnd(2);
mxh = mx + rnd(2);
z = makemonst(k);
}
for (i = mxl; i < mxh; i++)
for (j = myl; j < myh; j++) {
item[i][j] = 0;
if ((mitem[i][j] = z))
hitp[i][j] = monster[z].hitpoints;
}
}
}
if (k != MAXLEVEL - 1) {
my = rnd(MAXY - 2);
for (i = 1; i < MAXX - 1; i++)
item[i][my] = 0;
}
if (k > 1)
treasureroom(k);
}
/*
function to eat away a filled in maze
*/
void
eat(int xx, int yy)
{
int dir, try;
dir = rnd(4);
try = 2;
while (try) {
switch (dir) {
case 1:
if (xx <= 2)
break; /* west */
if ((item[xx - 1][yy] != OWALL) || (item[xx - 2][yy] != OWALL))
break;
item[xx - 1][yy] = item[xx - 2][yy] = 0;
eat(xx - 2, yy);
break;
case 2:
if (xx >= MAXX - 3)
break; /* east */
if ((item[xx + 1][yy] != OWALL) || (item[xx + 2][yy] != OWALL))
break;
item[xx + 1][yy] = item[xx + 2][yy] = 0;
eat(xx + 2, yy);
break;
case 3:
if (yy <= 2)
break; /* south */
if ((item[xx][yy - 1] != OWALL) || (item[xx][yy - 2] != OWALL))
break;
item[xx][yy - 1] = item[xx][yy - 2] = 0;
eat(xx, yy - 2);
break;
case 4:
if (yy >= MAXY - 3)
break; /* north */
if ((item[xx][yy + 1] != OWALL) || (item[xx][yy + 2] != OWALL))
break;
item[xx][yy + 1] = item[xx][yy + 2] = 0;
eat(xx, yy + 2);
break;
};
if (++dir > 4) {
dir = 1;
--try;
}
}
}
/*
* function to read in a maze from a data file
*
* Format of maze data file: 1st character = # of mazes in file (ascii digit)
* For each maze: 18 lines (1st 17 used) 67 characters per line
*
* Special characters in maze data file:
*
* # wall D door . random monster
* ~ eye of larn ! cure dianthroritis
* - random object
*/
static int
cannedlevel(int k)
{
char *row;
int i, j;
int it, arg, mit, marg;
if (lopen(larnlevels) < 0) {
write(1, "Can't open the maze data file\n", 30);
died(-282);
return (0);
}
i = lgetc();
if (i <= '0') {
died(-282);
return (0);
}
for (i = 18 * rund(i - '0'); i > 0; i--)
lgetl(); /* advance to desired maze */
for (i = 0; i < MAXY; i++) {
row = lgetl();
for (j = 0; j < MAXX; j++) {
it = mit = arg = marg = 0;
switch (*row++) {
case '#':
it = OWALL;
break;
case 'D':
it = OCLOSEDDOOR;
arg = rnd(30);
break;
case '~':
if (k != MAXLEVEL - 1)
break;
it = OLARNEYE;
mit = rund(8) + DEMONLORD;
marg = monster[mit].hitpoints;
break;
case '!':
if (k != MAXLEVEL + MAXVLEVEL - 1)
break;
it = OPOTION;
arg = 21;
mit = DEMONLORD + 7;
marg = monster[mit].hitpoints;
break;
case '.':
if (k < MAXLEVEL)
break;
mit = makemonst(k + 1);
marg = monster[mit].hitpoints;
break;
case '-':
it = newobject(k + 1, &arg);
break;
};
item[j][i] = it;
iarg[j][i] = arg;
mitem[j][i] = mit;
hitp[j][i] = marg;
#if WIZID
know[j][i] = (wizard) ? 1 : 0;
#else
know[j][i] = 0;
#endif
}
}
lrclose();
return (1);
}
/*
function to make a treasure room on a level
level 10's treasure room has the eye in it and demon lords
level V3 has potion of cure dianthroritis and demon prince
*/
static void
treasureroom(int lv)
{
int tx, ty, xsize, ysize;
for (tx = 1 + rnd(10); tx < MAXX - 10; tx += 10)
if ((lv == MAXLEVEL - 1) || (lv == MAXLEVEL + MAXVLEVEL - 1) || rnd(13) == 2) {
xsize = rnd(6) + 3;
ysize = rnd(3) + 3;
ty = rnd(MAXY - 9) + 1; /* upper left corner of room */
if (lv == MAXLEVEL - 1 || lv == MAXLEVEL + MAXVLEVEL - 1)
troom(lv, xsize, ysize, tx = tx + rnd(MAXX - 24), ty, rnd(3) + 6);
else
troom(lv, xsize, ysize, tx, ty, rnd(9));
}
}
/*
* subroutine to create a treasure room of any size at a given location
* room is filled with objects and monsters
* the coordinate given is that of the upper left corner of the room
*/
static void
troom(int lv, int xsize, int ysize, int tx, int ty, int glyph)
{
int i, j;
int tp1, tp2;
for (j = ty - 1; j <= ty + ysize; j++)
for (i = tx - 1; i <= tx + xsize; i++) /* clear out space for
* room */
item[i][j] = 0;
for (j = ty; j < ty + ysize; j++)
for (i = tx; i < tx + xsize; i++) { /* now put in the walls */
item[i][j] = OWALL;
mitem[i][j] = 0;
}
for (j = ty + 1; j < ty + ysize - 1; j++)
for (i = tx + 1; i < tx + xsize - 1; i++) /* now clear out
* interior */
item[i][j] = 0;
switch (rnd(2)) { /* locate the door on the treasure room */
case 1:
item[i = tx + rund(xsize)][j = ty + (ysize - 1) * rund(2)] = OCLOSEDDOOR;
iarg[i][j] = glyph; /* on horizontal walls */
break;
case 2:
item[i = tx + (xsize - 1) * rund(2)][j = ty + rund(ysize)] = OCLOSEDDOOR;
iarg[i][j] = glyph; /* on vertical walls */
break;
};
tp1 = playerx;
tp2 = playery;
playery = ty + (ysize >> 1);
if (c[HARDGAME] < 2)
for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
for (i = 0, j = rnd(6); i <= j; i++) {
something(lv + 2);
createmonster(makemonst(lv + 1));
}
else
for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
for (i = 0, j = rnd(4); i <= j; i++) {
something(lv + 2);
createmonster(makemonst(lv + 3));
}
playerx = tp1;
playery = tp2;
}
/*
***********
MAKE_OBJECT
***********
subroutine to create the objects in the maze for the given level
*/
static void
makeobject(int j)
{
int i;
if (j == 0) {
fillroom(OENTRANCE, 0); /* entrance to dungeon */
fillroom(ODNDSTORE, 0); /* the DND STORE */
fillroom(OSCHOOL, 0); /* college of Larn */
fillroom(OBANK, 0); /* 1st national bank of larn */
fillroom(OVOLDOWN, 0); /* volcano shaft to temple */
fillroom(OHOME, 0); /* the players home & family */
fillroom(OTRADEPOST, 0); /* the trading post */
fillroom(OLRS, 0); /* the larn revenue service */
return;
}
if (j == MAXLEVEL)
fillroom(OVOLUP, 0); /* volcano shaft up from the temple */
/* make the fixed objects in the maze STAIRS */
if ((j > 0) && (j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
fillroom(OSTAIRSDOWN, 0);
if ((j > 1) && (j != MAXLEVEL))
fillroom(OSTAIRSUP, 0);
/* make the random objects in the maze */
fillmroom(rund(3), OBOOK, j);
fillmroom(rund(3), OALTAR, 0);
fillmroom(rund(3), OSTATUE, 0);
fillmroom(rund(3), OPIT, 0);
fillmroom(rund(3), OFOUNTAIN, 0);
fillmroom(rnd(3) - 2, OIVTELETRAP, 0);
fillmroom(rund(2), OTHRONE, 0);
fillmroom(rund(2), OMIRROR, 0);
fillmroom(rund(2), OTRAPARROWIV, 0);
fillmroom(rnd(3) - 2, OIVDARTRAP, 0);
fillmroom(rund(3), OCOOKIE, 0);
if (j == 1)
fillmroom(1, OCHEST, j);
else
fillmroom(rund(2), OCHEST, j);
if ((j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
fillmroom(rund(2), OIVTRAPDOOR, 0);
if (j <= 10) {
fillmroom((rund(2)), ODIAMOND, rnd(10 * j + 1) + 10);
fillmroom(rund(2), ORUBY, rnd(6 * j + 1) + 6);
fillmroom(rund(2), OEMERALD, rnd(4 * j + 1) + 4);
fillmroom(rund(2), OSAPPHIRE, rnd(3 * j + 1) + 2);
}
for (i = 0; i < rnd(4) + 3; i++)
fillroom(OPOTION, newpotion()); /* make a POTION */
for (i = 0; i < rnd(5) + 3; i++)
fillroom(OSCROLL, newscroll()); /* make a SCROLL */
for (i = 0; i < rnd(12) + 11; i++)
fillroom(OGOLDPILE, 12 * rnd(j + 1) + (j << 3) + 10); /* make GOLD */
if (j == 5)
fillroom(OBANK2, 0); /* branch office of the bank */
froom(2, ORING, 0); /* a ring mail */
froom(1, OSTUDLEATHER, 0); /* a studded leather */
froom(3, OSPLINT, 0); /* a splint mail */
froom(5, OSHIELD, rund(3)); /* a shield */
froom(2, OBATTLEAXE, rund(3)); /* a battle axe */
froom(5, OLONGSWORD, rund(3)); /* a long sword */
froom(5, OFLAIL, rund(3)); /* a flail */
froom(4, OREGENRING, rund(3)); /* ring of regeneration */
froom(1, OPROTRING, rund(3)); /* ring of protection */
froom(2, OSTRRING, 4); /* ring of strength + 4 */
froom(7, OSPEAR, rnd(5)); /* a spear */
froom(3, OORBOFDRAGON, 0); /* orb of dragon slaying */
froom(4, OSPIRITSCARAB, 0); /* scarab of negate spirit */
froom(4, OCUBEofUNDEAD, 0); /* cube of undead control */
froom(2, ORINGOFEXTRA, 0); /* ring of extra regen */
froom(3, ONOTHEFT, 0); /* device of antitheft */
froom(2, OSWORDofSLASHING, 0); /* sword of slashing */
if (c[BESSMANN] == 0) {
froom(4, OHAMMER, 0); /* Bessman's flailing hammer */
c[BESSMANN] = 1;
}
if (c[HARDGAME] < 3 || (rnd(4) == 3)) {
if (j > 3) {
froom(3, OSWORD, 3); /* sunsword + 3 */
froom(5, O2SWORD, rnd(4)); /* a two handed sword */
froom(3, OBELT, 4); /* belt of striking */
froom(3, OENERGYRING, 3); /* energy ring */
froom(4, OPLATE, 5); /* platemail + 5 */
}
}
}
/*
subroutine to fill in a number of objects of the same kind
*/
static void
fillmroom(int n, int what_i, int arg)
{
int i;
char what;
/* truncate to char width (just in case it matters) */
what = (char)what_i;
for (i = 0; i < n; i++)
fillroom(what, arg);
}
static void
froom(int n, int theitem, int arg)
{
if (rnd(151) < n)
fillroom(theitem, arg);
}
/*
subroutine to put an object into an empty room
* uses a random walk
*/
static void
fillroom(int what_i, int arg)
{
int x, y;
char what;
/* truncate to char width (just in case it matters) */
what = (char)what_i;
#ifdef EXTRA
c[FILLROOM]++;
#endif
x = rnd(MAXX - 2);
y = rnd(MAXY - 2);
while (item[x][y]) {
#ifdef EXTRA
c[RANDOMWALK]++;/* count up these random walks */
#endif
x += rnd(3) - 2;
y += rnd(3) - 2;
if (x > MAXX - 2)
x = 1;
if (x < 1)
x = MAXX - 2;
if (y > MAXY - 2)
y = 1;
if (y < 1)
y = MAXY - 2;
}
item[x][y] = what;
iarg[x][y] = arg;
}
/*
subroutine to put monsters into an empty room without walls or other
monsters
*/
int
fillmonst(int what)
{
int x, y, trys;
for (trys = 5; trys > 0; --trys) { /* max # of creation attempts */
x = rnd(MAXX - 2);
y = rnd(MAXY - 2);
if ((item[x][y] == 0) && (mitem[x][y] == 0) && ((playerx != x) || (playery != y))) {
mitem[x][y] = what;
know[x][y] = 0;
hitp[x][y] = monster[what].hitpoints;
return (0);
}
}
return (-1); /* creation failure */
}
/*
creates an entire set of monsters for a level
must be done when entering a new level
if sethp(1) then wipe out old monsters else leave them there
*/
static void
sethp(int flg)
{
int i, j;
if (flg)
for (i = 0; i < MAXY; i++)
for (j = 0; j < MAXX; j++)
stealth[j][i] = 0;
if (level == 0) {
c[TELEFLAG] = 0;
return;
} /* if teleported and found level 1 then know
* level we are on */
if (flg)
j = rnd(12) + 2 + (level >> 1);
else
j = (level >> 1) + 1;
for (i = 0; i < j; i++)
fillmonst(makemonst(level));
positionplayer();
}
/*
* Function to destroy all genocided monsters on the present level
*/
static void
checkgen(void)
{
int x, y;
for (y = 0; y < MAXY; y++)
for (x = 0; x < MAXX; x++)
if (monster[mitem[x][y]].genocided)
mitem[x][y] = 0; /* no more monster */
}