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