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