Home | History | Annotate | Line # | Download | only in larn
create.c revision 1.10
      1 /* $NetBSD: create.c,v 1.10 2008/02/03 19:20:40 dholland Exp $	 */
      2 
      3 /* create.c		Larn is copyrighted 1986 by Noah Morgan. */
      4 
      5 #include <sys/cdefs.h>
      6 #ifndef lint
      7 __RCSID("$NetBSD: create.c,v 1.10 2008/02/03 19:20:40 dholland Exp $");
      8 #endif				/* not lint */
      9 
     10 #include "header.h"
     11 #include "extern.h"
     12 #include <unistd.h>
     13 
     14 static void makemaze(int);
     15 static int cannedlevel(int);
     16 static void treasureroom(int);
     17 static void troom(int, int, int, int, int, int);
     18 static void makeobject(int);
     19 static void fillmroom(int, int, int);
     20 static void froom(int, int, int);
     21 static void fillroom(int, int);
     22 static void sethp(int);
     23 static void checkgen(void);
     24 
     25 /*
     26 	makeplayer()
     27 
     28 	subroutine to create the player and the players attributes
     29 	this is called at the beginning of a game and at no other time
     30  */
     31 void
     32 makeplayer()
     33 {
     34 	int i;
     35 	scbr();
     36 	clear();
     37 	c[HPMAX] = c[HP] = 10;	/* start player off with 15 hit points	 */
     38 	c[LEVEL] = 1;		/* player starts at level one		 */
     39 	c[SPELLMAX] = c[SPELLS] = 1;	/* total # spells starts off as 3 */
     40 	c[REGENCOUNTER] = 16;
     41 	c[ECOUNTER] = 96;	/* start regeneration correctly */
     42 	c[SHIELD] = c[WEAR] = c[WIELD] = -1;
     43 	for (i = 0; i < 26; i++)
     44 		iven[i] = 0;
     45 	spelknow[0] = spelknow[1] = 1;	/* he knows protection, magic missile */
     46 	if (c[HARDGAME] <= 0) {
     47 		iven[0] = OLEATHER;
     48 		iven[1] = ODAGGER;
     49 		ivenarg[1] = ivenarg[0] = c[WEAR] = 0;
     50 		c[WIELD] = 1;
     51 	}
     52 	playerx = rnd(MAXX - 2);
     53 	playery = rnd(MAXY - 2);
     54 	oldx = 0;
     55 	oldy = 25;
     56 	gltime = 0;		/* time clock starts at zero	 */
     57 	cbak[SPELLS] = -50;
     58 	for (i = 0; i < 6; i++)
     59 		c[i] = 12;	/* make the attributes, ie str, int, etc. */
     60 	recalc();
     61 }
     62 
     63 
     64 /*
     65 	newcavelevel(level)
     66 	int level;
     67 
     68 	function to enter a new level.  This routine must be called anytime the
     69 	player changes levels.  If that level is unknown it will be created.
     70 	A new set of monsters will be created for a new level, and existing
     71 	levels will get a few more monsters.
     72 	Note that it is here we remove genocided monsters from the present level.
     73  */
     74 void
     75 newcavelevel(x)
     76 	int             x;
     77 {
     78 	int             i, j;
     79 	if (beenhere[level])
     80 		savelevel();	/* put the level back into storage	 */
     81 	level = x;		/* get the new level and put in working
     82 				 * storage */
     83 	if (beenhere[x] == 0)
     84 		for (i = 0; i < MAXY; i++)
     85 			for (j = 0; j < MAXX; j++)
     86 				know[j][i] = mitem[j][i] = 0;
     87 	else {
     88 		getlevel();
     89 		sethp(0);
     90 		goto chgn;
     91 	}
     92 	makemaze(x);
     93 	makeobject(x);
     94 	beenhere[x] = 1;
     95 	sethp(1);
     96 
     97 #if WIZID
     98 	if (wizard || x == 0)
     99 #else
    100 	if (x == 0)
    101 #endif
    102 
    103 		for (j = 0; j < MAXY; j++)
    104 			for (i = 0; i < MAXX; i++)
    105 				know[i][j] = 1;
    106 chgn:	checkgen();		/* wipe out any genocided monsters */
    107 }
    108 
    109 /*
    110 	makemaze(level)
    111 	int level;
    112 
    113 	subroutine to make the caverns for a given level.  only walls are made.
    114  */
    115 static int      mx, mxl, mxh, my, myl, myh, tmp2;
    116 
    117 static void
    118 makemaze(k)
    119 	int             k;
    120 {
    121 	int             i, j, tmp;
    122 	int             z;
    123 	if (k > 1 && (rnd(17) <= 4 || k == MAXLEVEL - 1 || k == MAXLEVEL + MAXVLEVEL - 1)) {
    124 		if (cannedlevel(k))
    125 			return;		/* read maze from data file */
    126 	}
    127 	if (k == 0)
    128 		tmp = 0;
    129 	else
    130 		tmp = OWALL;
    131 	for (i = 0; i < MAXY; i++)
    132 		for (j = 0; j < MAXX; j++)
    133 			item[j][i] = tmp;
    134 	if (k == 0)
    135 		return;
    136 	eat(1, 1);
    137 	if (k == 1)
    138 		item[33][MAXY - 1] = 0;	/* exit from dungeon */
    139 
    140 	/* now for open spaces -- not on level 10	 */
    141 	if (k != MAXLEVEL - 1) {
    142 		tmp2 = rnd(3) + 3;
    143 		for (tmp = 0; tmp < tmp2; tmp++) {
    144 			my = rnd(11) + 2;
    145 			myl = my - rnd(2);
    146 			myh = my + rnd(2);
    147 			if (k < MAXLEVEL) {
    148 				mx = rnd(44) + 5;
    149 				mxl = mx - rnd(4);
    150 				mxh = mx + rnd(12) + 3;
    151 				z = 0;
    152 			} else {
    153 				mx = rnd(60) + 3;
    154 				mxl = mx - rnd(2);
    155 				mxh = mx + rnd(2);
    156 				z = makemonst(k);
    157 			}
    158 			for (i = mxl; i < mxh; i++)
    159 				for (j = myl; j < myh; j++) {
    160 					item[i][j] = 0;
    161 					if ((mitem[i][j] = z))
    162 						hitp[i][j] = monster[z].hitpoints;
    163 				}
    164 		}
    165 	}
    166 	if (k != MAXLEVEL - 1) {
    167 		my = rnd(MAXY - 2);
    168 		for (i = 1; i < MAXX - 1; i++)
    169 			item[i][my] = 0;
    170 	}
    171 	if (k > 1)
    172 		treasureroom(k);
    173 }
    174 
    175 /*
    176 	function to eat away a filled in maze
    177  */
    178 void
    179 eat(xx, yy)
    180 	int             xx, yy;
    181 {
    182 	int             dir, try;
    183 	dir = rnd(4);
    184 	try = 2;
    185 	while (try) {
    186 		switch (dir) {
    187 		case 1:
    188 			if (xx <= 2)
    189 				break;	/* west	 */
    190 			if ((item[xx - 1][yy] != OWALL) || (item[xx - 2][yy] != OWALL))
    191 				break;
    192 			item[xx - 1][yy] = item[xx - 2][yy] = 0;
    193 			eat(xx - 2, yy);
    194 			break;
    195 
    196 		case 2:
    197 			if (xx >= MAXX - 3)
    198 				break;	/* east	 */
    199 			if ((item[xx + 1][yy] != OWALL) || (item[xx + 2][yy] != OWALL))
    200 				break;
    201 			item[xx + 1][yy] = item[xx + 2][yy] = 0;
    202 			eat(xx + 2, yy);
    203 			break;
    204 
    205 		case 3:
    206 			if (yy <= 2)
    207 				break;	/* south	 */
    208 			if ((item[xx][yy - 1] != OWALL) || (item[xx][yy - 2] != OWALL))
    209 				break;
    210 			item[xx][yy - 1] = item[xx][yy - 2] = 0;
    211 			eat(xx, yy - 2);
    212 			break;
    213 
    214 		case 4:
    215 			if (yy >= MAXY - 3)
    216 				break;	/* north	 */
    217 			if ((item[xx][yy + 1] != OWALL) || (item[xx][yy + 2] != OWALL))
    218 				break;
    219 			item[xx][yy + 1] = item[xx][yy + 2] = 0;
    220 			eat(xx, yy + 2);
    221 			break;
    222 		};
    223 		if (++dir > 4) {
    224 			dir = 1;
    225 			--try;
    226 		}
    227 	}
    228 }
    229 
    230 /*
    231  *	function to read in a maze from a data file
    232  *
    233  *	Format of maze data file:  1st character = # of mazes in file (ascii digit)
    234  *				For each maze: 18 lines (1st 17 used) 67 characters per line
    235  *
    236  *	Special characters in maze data file:
    237  *
    238  *		#	wall			D	door			.	random monster
    239  *		~	eye of larn		!	cure dianthroritis
    240  *		-	random object
    241  */
    242 static int
    243 cannedlevel(k)
    244 	int             k;
    245 {
    246 	char           *row;
    247 	int             i, j;
    248 	int             it, arg, mit, marg;
    249 	if (lopen(larnlevels) < 0) {
    250 		write(1, "Can't open the maze data file\n", 30);
    251 		died(-282);
    252 		return (0);
    253 	}
    254 	i = lgetc();
    255 	if (i <= '0') {
    256 		died(-282);
    257 		return (0);
    258 	}
    259 	for (i = 18 * rund(i - '0'); i > 0; i--)
    260 		lgetl();	/* advance to desired maze */
    261 	for (i = 0; i < MAXY; i++) {
    262 		row = lgetl();
    263 		for (j = 0; j < MAXX; j++) {
    264 			it = mit = arg = marg = 0;
    265 			switch (*row++) {
    266 			case '#':
    267 				it = OWALL;
    268 				break;
    269 			case 'D':
    270 				it = OCLOSEDDOOR;
    271 				arg = rnd(30);
    272 				break;
    273 			case '~':
    274 				if (k != MAXLEVEL - 1)
    275 					break;
    276 				it = OLARNEYE;
    277 				mit = rund(8) + DEMONLORD;
    278 				marg = monster[mit].hitpoints;
    279 				break;
    280 			case '!':
    281 				if (k != MAXLEVEL + MAXVLEVEL - 1)
    282 					break;
    283 				it = OPOTION;
    284 				arg = 21;
    285 				mit = DEMONLORD + 7;
    286 				marg = monster[mit].hitpoints;
    287 				break;
    288 			case '.':
    289 				if (k < MAXLEVEL)
    290 					break;
    291 				mit = makemonst(k + 1);
    292 				marg = monster[mit].hitpoints;
    293 				break;
    294 			case '-':
    295 				it = newobject(k + 1, &arg);
    296 				break;
    297 			};
    298 			item[j][i] = it;
    299 			iarg[j][i] = arg;
    300 			mitem[j][i] = mit;
    301 			hitp[j][i] = marg;
    302 
    303 #if WIZID
    304 			know[j][i] = (wizard) ? 1 : 0;
    305 #else
    306 			know[j][i] = 0;
    307 #endif
    308 		}
    309 	}
    310 	lrclose();
    311 	return (1);
    312 }
    313 
    314 /*
    315 	function to make a treasure room on a level
    316 	level 10's treasure room has the eye in it and demon lords
    317 	level V3 has potion of cure dianthroritis and demon prince
    318  */
    319 static void
    320 treasureroom(lv)
    321 	int             lv;
    322 {
    323 	int             tx, ty, xsize, ysize;
    324 
    325 	for (tx = 1 + rnd(10); tx < MAXX - 10; tx += 10)
    326 		if ((lv == MAXLEVEL - 1) || (lv == MAXLEVEL + MAXVLEVEL - 1) || rnd(13) == 2) {
    327 			xsize = rnd(6) + 3;
    328 			ysize = rnd(3) + 3;
    329 			ty = rnd(MAXY - 9) + 1;	/* upper left corner of room */
    330 			if (lv == MAXLEVEL - 1 || lv == MAXLEVEL + MAXVLEVEL - 1)
    331 				troom(lv, xsize, ysize, tx = tx + rnd(MAXX - 24), ty, rnd(3) + 6);
    332 			else
    333 				troom(lv, xsize, ysize, tx, ty, rnd(9));
    334 		}
    335 }
    336 
    337 /*
    338  *	subroutine to create a treasure room of any size at a given location
    339  *	room is filled with objects and monsters
    340  *	the coordinate given is that of the upper left corner of the room
    341  */
    342 static void
    343 troom(lv, xsize, ysize, tx, ty, glyph)
    344 	int             lv, xsize, ysize, tx, ty, glyph;
    345 {
    346 	int             i, j;
    347 	int             tp1, tp2;
    348 	for (j = ty - 1; j <= ty + ysize; j++)
    349 		for (i = tx - 1; i <= tx + xsize; i++)	/* clear out space for
    350 							 * room */
    351 			item[i][j] = 0;
    352 	for (j = ty; j < ty + ysize; j++)
    353 		for (i = tx; i < tx + xsize; i++) {	/* now put in the walls */
    354 			item[i][j] = OWALL;
    355 			mitem[i][j] = 0;
    356 		}
    357 	for (j = ty + 1; j < ty + ysize - 1; j++)
    358 		for (i = tx + 1; i < tx + xsize - 1; i++)	/* now clear out
    359 								 * interior */
    360 			item[i][j] = 0;
    361 
    362 	switch (rnd(2)) {	/* locate the door on the treasure room */
    363 	case 1:
    364 		item[i = tx + rund(xsize)][j = ty + (ysize - 1) * rund(2)] = OCLOSEDDOOR;
    365 		iarg[i][j] = glyph;	/* on horizontal walls */
    366 		break;
    367 	case 2:
    368 		item[i = tx + (xsize - 1) * rund(2)][j = ty + rund(ysize)] = OCLOSEDDOOR;
    369 		iarg[i][j] = glyph;	/* on vertical walls */
    370 		break;
    371 	};
    372 
    373 	tp1 = playerx;
    374 	tp2 = playery;
    375 	playery = ty + (ysize >> 1);
    376 	if (c[HARDGAME] < 2)
    377 		for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
    378 			for (i = 0, j = rnd(6); i <= j; i++) {
    379 				something(lv + 2);
    380 				createmonster(makemonst(lv + 1));
    381 			}
    382 	else
    383 		for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
    384 			for (i = 0, j = rnd(4); i <= j; i++) {
    385 				something(lv + 2);
    386 				createmonster(makemonst(lv + 3));
    387 			}
    388 
    389 	playerx = tp1;
    390 	playery = tp2;
    391 }
    392 
    393 
    394 /*
    395 	***********
    396 	MAKE_OBJECT
    397 	***********
    398 	subroutine to create the objects in the maze for the given level
    399  */
    400 static void
    401 makeobject(j)
    402 	int             j;
    403 {
    404 	int             i;
    405 	if (j == 0) {
    406 		fillroom(OENTRANCE, 0);	/* entrance to dungeon			 */
    407 		fillroom(ODNDSTORE, 0);	/* the DND STORE				 */
    408 		fillroom(OSCHOOL, 0);	/* college of Larn				 */
    409 		fillroom(OBANK, 0);	/* 1st national bank of larn 	 */
    410 		fillroom(OVOLDOWN, 0);	/* volcano shaft to temple 	 */
    411 		fillroom(OHOME, 0);	/* the players home & family 	 */
    412 		fillroom(OTRADEPOST, 0);	/* the trading post			 */
    413 		fillroom(OLRS, 0);	/* the larn revenue service 	 */
    414 		return;
    415 	}
    416 	if (j == MAXLEVEL)
    417 		fillroom(OVOLUP, 0);	/* volcano shaft up from the temple */
    418 
    419 	/* make the fixed objects in the maze STAIRS	 */
    420 	if ((j > 0) && (j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
    421 		fillroom(OSTAIRSDOWN, 0);
    422 	if ((j > 1) && (j != MAXLEVEL))
    423 		fillroom(OSTAIRSUP, 0);
    424 
    425 	/* make the random objects in the maze		 */
    426 
    427 	fillmroom(rund(3), OBOOK, j);
    428 	fillmroom(rund(3), OALTAR, 0);
    429 	fillmroom(rund(3), OSTATUE, 0);
    430 	fillmroom(rund(3), OPIT, 0);
    431 	fillmroom(rund(3), OFOUNTAIN, 0);
    432 	fillmroom(rnd(3) - 2, OIVTELETRAP, 0);
    433 	fillmroom(rund(2), OTHRONE, 0);
    434 	fillmroom(rund(2), OMIRROR, 0);
    435 	fillmroom(rund(2), OTRAPARROWIV, 0);
    436 	fillmroom(rnd(3) - 2, OIVDARTRAP, 0);
    437 	fillmroom(rund(3), OCOOKIE, 0);
    438 	if (j == 1)
    439 		fillmroom(1, OCHEST, j);
    440 	else
    441 		fillmroom(rund(2), OCHEST, j);
    442 	if ((j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
    443 		fillmroom(rund(2), OIVTRAPDOOR, 0);
    444 	if (j <= 10) {
    445 		fillmroom((rund(2)), ODIAMOND, rnd(10 * j + 1) + 10);
    446 		fillmroom(rund(2), ORUBY, rnd(6 * j + 1) + 6);
    447 		fillmroom(rund(2), OEMERALD, rnd(4 * j + 1) + 4);
    448 		fillmroom(rund(2), OSAPPHIRE, rnd(3 * j + 1) + 2);
    449 	}
    450 	for (i = 0; i < rnd(4) + 3; i++)
    451 		fillroom(OPOTION, newpotion());	/* make a POTION	 */
    452 	for (i = 0; i < rnd(5) + 3; i++)
    453 		fillroom(OSCROLL, newscroll());	/* make a SCROLL	 */
    454 	for (i = 0; i < rnd(12) + 11; i++)
    455 		fillroom(OGOLDPILE, 12 * rnd(j + 1) + (j << 3) + 10);	/* make GOLD	 */
    456 	if (j == 5)
    457 		fillroom(OBANK2, 0);	/* branch office of the bank */
    458 	froom(2, ORING, 0);	/* a ring mail 			 */
    459 	froom(1, OSTUDLEATHER, 0);	/* a studded leather	 */
    460 	froom(3, OSPLINT, 0);	/* a splint mail		 */
    461 	froom(5, OSHIELD, rund(3));	/* a shield				 */
    462 	froom(2, OBATTLEAXE, rund(3));	/* a battle axe			 */
    463 	froom(5, OLONGSWORD, rund(3));	/* a long sword			 */
    464 	froom(5, OFLAIL, rund(3));	/* a flail				 */
    465 	froom(4, OREGENRING, rund(3));	/* ring of regeneration */
    466 	froom(1, OPROTRING, rund(3));	/* ring of protection	 */
    467 	froom(2, OSTRRING, 4);	/* ring of strength + 4 */
    468 	froom(7, OSPEAR, rnd(5));	/* a spear				 */
    469 	froom(3, OORBOFDRAGON, 0);	/* orb of dragon slaying */
    470 	froom(4, OSPIRITSCARAB, 0);	/* scarab of negate spirit */
    471 	froom(4, OCUBEofUNDEAD, 0);	/* cube of undead control	 */
    472 	froom(2, ORINGOFEXTRA, 0);	/* ring of extra regen		 */
    473 	froom(3, ONOTHEFT, 0);	/* device of antitheft 		 */
    474 	froom(2, OSWORDofSLASHING, 0);	/* sword of slashing */
    475 	if (c[BESSMANN] == 0) {
    476 		froom(4, OHAMMER, 0);	/* Bessman's flailing hammer */
    477 		c[BESSMANN] = 1;
    478 	}
    479 	if (c[HARDGAME] < 3 || (rnd(4) == 3)) {
    480 		if (j > 3) {
    481 			froom(3, OSWORD, 3);	/* sunsword + 3  		 */
    482 			froom(5, O2SWORD, rnd(4));	/* a two handed sword	 */
    483 			froom(3, OBELT, 4);	/* belt of striking		 */
    484 			froom(3, OENERGYRING, 3);	/* energy ring			 */
    485 			froom(4, OPLATE, 5);	/* platemail + 5 		 */
    486 		}
    487 	}
    488 }
    489 
    490 /*
    491 	subroutine to fill in a number of objects of the same kind
    492  */
    493 
    494 static void
    495 fillmroom(n, what, arg)
    496 	int             n, arg;
    497 	char            what;
    498 {
    499 	int             i;
    500 	for (i = 0; i < n; i++)
    501 		fillroom(what, arg);
    502 }
    503 
    504 static void
    505 froom(int n, int theitem, int arg)
    506 {
    507 	if (rnd(151) < n)
    508 		fillroom(theitem, arg);
    509 }
    510 
    511 /*
    512 	subroutine to put an object into an empty room
    513  *	uses a random walk
    514  */
    515 static void
    516 fillroom(what, arg)
    517 	int             arg;
    518 	char            what;
    519 {
    520 	int             x, y;
    521 
    522 #ifdef EXTRA
    523 	c[FILLROOM]++;
    524 #endif
    525 
    526 	x = rnd(MAXX - 2);
    527 	y = rnd(MAXY - 2);
    528 	while (item[x][y]) {
    529 
    530 #ifdef EXTRA
    531 		c[RANDOMWALK]++;/* count up these random walks */
    532 #endif
    533 
    534 		x += rnd(3) - 2;
    535 		y += rnd(3) - 2;
    536 		if (x > MAXX - 2)
    537 			x = 1;
    538 		if (x < 1)
    539 			x = MAXX - 2;
    540 		if (y > MAXY - 2)
    541 			y = 1;
    542 		if (y < 1)
    543 			y = MAXY - 2;
    544 	}
    545 	item[x][y] = what;
    546 	iarg[x][y] = arg;
    547 }
    548 
    549 /*
    550 	subroutine to put monsters into an empty room without walls or other
    551 	monsters
    552  */
    553 int
    554 fillmonst(what)
    555 	int            what;
    556 {
    557 	int             x, y, trys;
    558 	for (trys = 5; trys > 0; --trys) {	/* max # of creation attempts */
    559 		x = rnd(MAXX - 2);
    560 		y = rnd(MAXY - 2);
    561 		if ((item[x][y] == 0) && (mitem[x][y] == 0) && ((playerx != x) || (playery != y))) {
    562 			mitem[x][y] = what;
    563 			know[x][y] = 0;
    564 			hitp[x][y] = monster[what].hitpoints;
    565 			return (0);
    566 		}
    567 	}
    568 	return (-1);		/* creation failure */
    569 }
    570 
    571 /*
    572 	creates an entire set of monsters for a level
    573 	must be done when entering a new level
    574 	if sethp(1) then wipe out old monsters else leave them there
    575  */
    576 static void
    577 sethp(flg)
    578 	int             flg;
    579 {
    580 	int             i, j;
    581 	if (flg)
    582 		for (i = 0; i < MAXY; i++)
    583 			for (j = 0; j < MAXX; j++)
    584 				stealth[j][i] = 0;
    585 	if (level == 0) {
    586 		c[TELEFLAG] = 0;
    587 		return;
    588 	}			/* if teleported and found level 1 then know
    589 				 * level we are on */
    590 	if (flg)
    591 		j = rnd(12) + 2 + (level >> 1);
    592 	else
    593 		j = (level >> 1) + 1;
    594 	for (i = 0; i < j; i++)
    595 		fillmonst(makemonst(level));
    596 	positionplayer();
    597 }
    598 
    599 /*
    600  *	Function to destroy all genocided monsters on the present level
    601  */
    602 static void
    603 checkgen(void)
    604 {
    605 	int             x, y;
    606 	for (y = 0; y < MAXY; y++)
    607 		for (x = 0; x < MAXX; x++)
    608 			if (monster[mitem[x][y]].genocided)
    609 				mitem[x][y] = 0;	/* no more monster */
    610 }
    611