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