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