xref: /original-bsd/games/larn/global.c (revision 89c54e86)
1 /*	global.c 		Larn is copyrighted 1986 by Noah Morgan.
2  *
3  *	raiselevel()		subroutine to raise the player one level
4  *	loselevel()		subroutine to lower the player by one level
5  *	raiseexperience(x)	subroutine to increase experience points
6  *	loseexperience(x)	subroutine to lose experience points
7  *	losehp(x)			subroutine to remove hit points from the player
8  *	losemhp(x)			subroutine to remove max # hit points from the player
9  *	raisehp(x)			subroutine to gain hit points
10  *	raisemhp(x)			subroutine to gain maximum hit points
11  *	losespells(x)		subroutine to lose spells
12  *	losemspells(x)		subroutine to lose maximum spells
13  *	raisespells(x)		subroutine to gain spells
14  *	raisemspells(x)		subroutine to gain maximum spells
15  *	recalc()			function to recalculate the armor class of the player
16  *	makemonst(lev)		function to return monster number for a randomly selected monster
17  *	positionplayer()	function to be sure player is not in a wall
18  *	quit()				subroutine to ask if the player really wants to quit
19  */
20 
21 #include "header.h"
22 extern int score[],srcount,dropflag;
23 extern int random;/*	the random number seed			*/
24 extern short playerx,playery,lastnum;
25 extern char cheat,level,monstnamelist[];
26 extern char lastmonst[],*what[],*who[];
27 extern char winner[];
28 extern char logname[],monstlevel[];
29 extern char sciv[SCORESIZE+1][26][2],*potionname[],*scrollname[];
30 /*
31 	***********
32 	RAISE LEVEL
33 	***********
34 	raiselevel()
35 
36 	subroutine to raise the player one level
37 	uses the skill[] array to find level boundarys
38 	uses c[EXPERIENCE]  c[LEVEL]
39  */
raiselevel()40 raiselevel()
41 	{
42 	if (c[LEVEL] < MAXPLEVEL) raiseexperience((long)(skill[c[LEVEL]]-c[EXPERIENCE]));
43 	}
44 
45 /*
46 	***********
47 	LOOSE LEVEL
48 	***********
49     loselevel()
50 
51 	subroutine to lower the players character level by one
52  */
loselevel()53 loselevel()
54 	{
55 	if (c[LEVEL] > 1) loseexperience((long)(c[EXPERIENCE] - skill[c[LEVEL]-1] + 1));
56 	}
57 
58 /*
59 	****************
60 	RAISE EXPERIENCE
61 	****************
62 	raiseexperience(x)
63 
64 	subroutine to increase experience points
65  */
raiseexperience(x)66 raiseexperience(x)
67 	register long x;
68 	{
69 	register int i,tmp;
70 	i=c[LEVEL];	c[EXPERIENCE]+=x;
71 	while (c[EXPERIENCE] >= skill[c[LEVEL]] && (c[LEVEL] < MAXPLEVEL))
72 		{
73 		tmp = (c[CONSTITUTION]-c[HARDGAME])>>1;
74 		c[LEVEL]++;	raisemhp((int)(rnd(3)+rnd((tmp>0)?tmp:1)));
75 		raisemspells((int)rund(3));
76 		if (c[LEVEL] < 7-c[HARDGAME]) raisemhp((int)(c[CONSTITUTION]>>2));
77 		}
78 	if (c[LEVEL] != i)
79 		{
80 		cursors();
81 		beep(); lprintf("\nWelcome to level %d",(long)c[LEVEL]);	/* if we changed levels	*/
82 		}
83 	bottomline();
84 	}
85 
86 /*
87 	****************
88 	LOOSE EXPERIENCE
89 	****************
90 	loseexperience(x)
91 
92 	subroutine to lose experience points
93  */
loseexperience(x)94 loseexperience(x)
95 	register long x;
96 	{
97 	register int i,tmp;
98 	i=c[LEVEL];		c[EXPERIENCE]-=x;
99 	if (c[EXPERIENCE] < 0) c[EXPERIENCE]=0;
100 	while (c[EXPERIENCE] < skill[c[LEVEL]-1])
101 		{
102 		if (--c[LEVEL] <= 1) c[LEVEL]=1;	/*	down one level		*/
103 		tmp = (c[CONSTITUTION]-c[HARDGAME])>>1;	/* lose hpoints */
104 		losemhp((int)rnd((tmp>0)?tmp:1));	/* lose hpoints */
105 		if (c[LEVEL] < 7-c[HARDGAME]) losemhp((int)(c[CONSTITUTION]>>2));
106 		losemspells((int)rund(3));				/*	lose spells		*/
107 		}
108 	if (i!=c[LEVEL])
109 		{
110 		cursors();
111 		beep(); lprintf("\nYou went down to level %d!",(long)c[LEVEL]);
112 		}
113 	bottomline();
114 	}
115 
116 /*
117 	********
118 	LOOSE HP
119 	********
120 	losehp(x)
121 	losemhp(x)
122 
123 	subroutine to remove hit points from the player
124 	warning -- will kill player if hp goes to zero
125  */
losehp(x)126 losehp(x)
127 	register int x;
128 	{
129 	if ((c[HP] -= x) <= 0)
130 		{
131 		beep(); lprcat("\n");  nap(3000);  died(lastnum);
132 		}
133 	}
134 
losemhp(x)135 losemhp(x)
136 	register int x;
137 	{
138 	c[HP] -= x;		if (c[HP] < 1)		c[HP]=1;
139 	c[HPMAX] -= x;	if (c[HPMAX] < 1)	c[HPMAX]=1;
140 	}
141 
142 /*
143 	********
144 	RAISE HP
145 	********
146 	raisehp(x)
147 	raisemhp(x)
148 
149 	subroutine to gain maximum hit points
150  */
raisehp(x)151 raisehp(x)
152 	register int x;
153 	{
154 	if ((c[HP] += x) > c[HPMAX]) c[HP] = c[HPMAX];
155 	}
156 
raisemhp(x)157 raisemhp(x)
158 	register int x;
159 	{
160 	c[HPMAX] += x;	c[HP] += x;
161 	}
162 
163 /*
164 	************
165 	RAISE SPELLS
166 	************
167 	raisespells(x)
168 	raisemspells(x)
169 
170 	subroutine to gain maximum spells
171  */
raisespells(x)172 raisespells(x)
173 	register int x;
174 	{
175 	if ((c[SPELLS] += x) > c[SPELLMAX])	c[SPELLS] = c[SPELLMAX];
176 	}
177 
raisemspells(x)178 raisemspells(x)
179 	register int x;
180 	{
181 	c[SPELLMAX]+=x; c[SPELLS]+=x;
182 	}
183 
184 /*
185 	************
186 	LOOSE SPELLS
187 	************
188 	losespells(x)
189 	losemspells(x)
190 
191 	subroutine to lose maximum spells
192  */
losespells(x)193 losespells(x)
194 	register int x;
195 	{
196 	if ((c[SPELLS] -= x) < 0) c[SPELLS]=0;
197 	}
198 
losemspells(x)199 losemspells(x)
200 	register int x;
201 	{
202 	if ((c[SPELLMAX] -= x) < 0) c[SPELLMAX]=0;
203 	if ((c[SPELLS] -= x) < 0) c[SPELLS]=0;
204 	}
205 
206 /*
207 	makemonst(lev)
208 		int lev;
209 
210 	function to return monster number for a randomly selected monster
211 		for the given cave level
212  */
makemonst(lev)213 makemonst(lev)
214 	register int lev;
215 	{
216 	register int tmp,x;
217 	if (lev < 1)	lev = 1;			if (lev > 12)	lev = 12;
218 	tmp=WATERLORD;
219 	if (lev < 5)
220 		while (tmp==WATERLORD) tmp=rnd((x=monstlevel[lev-1])?x:1);
221 	else while (tmp==WATERLORD)
222 		tmp=rnd((x=monstlevel[lev-1]-monstlevel[lev-4])?x:1)+monstlevel[lev-4];
223 
224 	while (monster[tmp].genocided && tmp<MAXMONST) tmp++; /* genocided? */
225 	return(tmp);
226 	}
227 
228 /*
229 	positionplayer()
230 
231 	function to be sure player is not in a wall
232  */
positionplayer()233 positionplayer()
234 	{
235 	int try;
236 	try = 2;
237 	while ((item[playerx][playery] || mitem[playerx][playery]) && (try))
238 		if (++playerx >= MAXX-1)
239 			{
240 			playerx = 1;
241 			if (++playery >= MAXY-1)
242 				{	playery = 1;	--try;	}
243 			}
244 	if (try==0)	 lprcat("Failure in positionplayer\n");
245 	}
246 
247 /*
248 	recalc()	function to recalculate the armor class of the player
249  */
recalc()250 recalc()
251 	{
252 	register int i,j,k;
253 	c[AC] = c[MOREDEFENSES];
254 	if (c[WEAR] >= 0)
255 		switch(iven[c[WEAR]])
256 			{
257 			case OSHIELD:		c[AC] += 2 + ivenarg[c[WEAR]]; break;
258 			case OLEATHER:		c[AC] += 2 + ivenarg[c[WEAR]]; break;
259 			case OSTUDLEATHER:	c[AC] += 3 + ivenarg[c[WEAR]]; break;
260 			case ORING:			c[AC] += 5 + ivenarg[c[WEAR]]; break;
261 			case OCHAIN:		c[AC] += 6 + ivenarg[c[WEAR]]; break;
262 			case OSPLINT:		c[AC] += 7 + ivenarg[c[WEAR]]; break;
263 			case OPLATE:		c[AC] += 9 + ivenarg[c[WEAR]]; break;
264 			case OPLATEARMOR:	c[AC] += 10 + ivenarg[c[WEAR]]; break;
265 			case OSSPLATE:		c[AC] += 12 + ivenarg[c[WEAR]]; break;
266 			}
267 
268 	if (c[SHIELD] >= 0) if (iven[c[SHIELD]] == OSHIELD) c[AC] += 2 + ivenarg[c[SHIELD]];
269 	if (c[WIELD] < 0)  c[WCLASS] = 0;  else
270 		{
271 		i = ivenarg[c[WIELD]];
272 		switch(iven[c[WIELD]])
273 			{
274 			case ODAGGER:    c[WCLASS] =  3 + i;  break;
275 			case OBELT:	     c[WCLASS] =  7 + i;  break;
276 			case OSHIELD:	 c[WCLASS] =  8 + i;  break;
277 			case OSPEAR:     c[WCLASS] = 10 + i;  break;
278 			case OFLAIL:     c[WCLASS] = 14 + i;  break;
279 			case OBATTLEAXE: c[WCLASS] = 17 + i;  break;
280 			case OLANCE:	 c[WCLASS] = 19 + i;  break;
281 			case OLONGSWORD: c[WCLASS] = 22 + i;  break;
282 			case O2SWORD:    c[WCLASS] = 26 + i;  break;
283 			case OSWORD:     c[WCLASS] = 32 + i;  break;
284 			case OSWORDofSLASHING: c[WCLASS] = 30 + i; break;
285 			case OHAMMER:    c[WCLASS] = 35 + i;  break;
286 			default:	     c[WCLASS] = 0;
287 			}
288 		}
289 	c[WCLASS] += c[MOREDAM];
290 
291 /*	now for regeneration abilities based on rings	*/
292 	c[REGEN]=1;		c[ENERGY]=0;
293 	j=0;  for (k=25; k>0; k--)  if (iven[k]) {j=k; k=0; }
294 	for (i=0; i<=j; i++)
295 		{
296 		switch(iven[i])
297 			{
298 			case OPROTRING: c[AC]     += ivenarg[i] + 1;	break;
299 			case ODAMRING:  c[WCLASS] += ivenarg[i] + 1;	break;
300 			case OBELT:     c[WCLASS] += ((ivenarg[i]<<1)) + 2;	break;
301 
302 			case OREGENRING:	c[REGEN]  += ivenarg[i] + 1;	break;
303 			case ORINGOFEXTRA:	c[REGEN]  += 5 * (ivenarg[i]+1); break;
304 			case OENERGYRING:	c[ENERGY] += ivenarg[i] + 1;	break;
305 			}
306 		}
307 	}
308 
309 
310 /*
311 	quit()
312 
313 	subroutine to ask if the player really wants to quit
314  */
quit()315 quit()
316 	{
317 	register int i;
318 	cursors();	strcpy(lastmonst,"");
319 	lprcat("\n\nDo you really want to quit?");
320 	while (1)
321 		{
322 		i=getchar();
323 		if (i == 'y')	{ died(300); return; }
324 		if ((i == 'n') || (i == '\33'))	{ lprcat(" no"); lflush(); return; }
325 		lprcat("\n");  setbold();  lprcat("Yes");  resetbold();  lprcat(" or ");
326 		setbold();  lprcat("No");  resetbold();  lprcat(" please?   Do you want to quit? ");
327 		}
328 	}
329 
330 /*
331 	function to ask --more-- then the user must enter a space
332  */
more()333 more()
334 	{
335 	lprcat("\n  --- press ");  standout("space");  lprcat(" to continue --- ");
336 	while (getchar() != ' ');
337 	}
338 
339 /*
340 	function to put something in the players inventory
341 	returns 0 if success, 1 if a failure
342  */
take(itm,arg)343 take(itm,arg)
344 	int itm,arg;
345 	{
346 	register int i,limit;
347 /*	cursors(); */
348 	if ((limit = 15+(c[LEVEL]>>1)) > 26)  limit=26;
349 	for (i=0; i<limit; i++)
350 		if (iven[i]==0)
351 			{
352 			iven[i] = itm;  ivenarg[i] = arg;  limit=0;
353 			switch(itm)
354 				{
355 				case OPROTRING:	case ODAMRING: case OBELT: limit=1;  break;
356 				case ODEXRING:		c[DEXTERITY] += ivenarg[i]+1; limit=1;	break;
357 				case OSTRRING:		c[STREXTRA]  += ivenarg[i]+1;	limit=1; break;
358 				case OCLEVERRING:	c[INTELLIGENCE] += ivenarg[i]+1;  limit=1; break;
359 				case OHAMMER:		c[DEXTERITY] += 10;	c[STREXTRA]+=10;
360 									c[INTELLIGENCE]-=10;	limit=1;	 break;
361 
362 				case OORBOFDRAGON:	c[SLAYING]++;		break;
363 				case OSPIRITSCARAB: c[NEGATESPIRIT]++;	break;
364 				case OCUBEofUNDEAD: c[CUBEofUNDEAD]++;	break;
365 				case ONOTHEFT:		c[NOTHEFT]++;		break;
366 				case OSWORDofSLASHING:	c[DEXTERITY] +=5;	limit=1; break;
367 				};
368 			lprcat("\nYou pick up:"); srcount=0;  show3(i);
369 			if (limit) bottomline();  return(0);
370 			}
371 	lprcat("\nYou can't carry anything else");  return(1);
372 	}
373 
374 /*
375 	subroutine to drop an object  returns 1 if something there already else 0
376  */
drop_object(k)377 drop_object(k)
378 	int k;
379 	{
380 	int itm;
381 	if ((k<0) || (k>25)) return(0);
382 	itm = iven[k];	cursors();
383 	if (itm==0) { lprintf("\nYou don't have item %c! ",k+'a'); return(1); }
384 	if (item[playerx][playery])
385 		{ beep(); lprcat("\nThere's something here already"); return(1); }
386 	if (playery==MAXY-1 && playerx==33) return(1); /* not in entrance */
387 	item[playerx][playery] = itm;
388 	iarg[playerx][playery] = ivenarg[k];
389 	srcount=0; lprcat("\n  You drop:"); show3(k); /* show what item you dropped*/
390 	know[playerx][playery] = 0;  iven[k]=0;
391 	if (c[WIELD]==k) c[WIELD]= -1;		if (c[WEAR]==k)  c[WEAR] = -1;
392 	if (c[SHIELD]==k) c[SHIELD]= -1;
393 	adjustcvalues(itm,ivenarg[k]);
394 	dropflag=1; /* say dropped an item so wont ask to pick it up right away */
395 	return(0);
396 	}
397 
398 /*
399 	function to enchant armor player is currently wearing
400  */
enchantarmor()401 enchantarmor()
402 	{
403 	register int tmp;
404 	if (c[WEAR]<0) { if (c[SHIELD] < 0)
405 		{ cursors(); beep(); lprcat("\nYou feel a sense of loss"); return; }
406 					else { tmp=iven[c[SHIELD]]; if (tmp != OSCROLL) if (tmp != OPOTION) { ivenarg[c[SHIELD]]++; bottomline(); } } }
407 	tmp = iven[c[WEAR]];
408 	if (tmp!=OSCROLL) if (tmp!=OPOTION)  { ivenarg[c[WEAR]]++;  bottomline(); }
409 	}
410 
411 /*
412 	function to enchant a weapon presently being wielded
413  */
enchweapon()414 enchweapon()
415 	{
416 	register int tmp;
417 	if (c[WIELD]<0)
418 		{ cursors(); beep(); lprcat("\nYou feel a sense of loss"); return; }
419 	tmp = iven[c[WIELD]];
420 	if (tmp!=OSCROLL) if (tmp!=OPOTION)
421 		{ ivenarg[c[WIELD]]++;
422 		  if (tmp==OCLEVERRING) c[INTELLIGENCE]++;  else
423 		  if (tmp==OSTRRING)	c[STREXTRA]++;  else
424 		  if (tmp==ODEXRING)    c[DEXTERITY]++;		  bottomline(); }
425 	}
426 
427 /*
428 	routine to tell if player can carry one more thing
429 	returns 1 if pockets are full, else 0
430  */
pocketfull()431 pocketfull()
432 	{
433 	register int i,limit;
434 	if ((limit = 15+(c[LEVEL]>>1)) > 26)  limit=26;
435 	for (i=0; i<limit; i++) if (iven[i]==0) return(0);
436 	return(1);
437 	}
438 
439 /*
440 	function to return 1 if a monster is next to the player else returns 0
441  */
nearbymonst()442 nearbymonst()
443 	{
444 	register int tmp,tmp2;
445 	for (tmp=playerx-1; tmp<playerx+2; tmp++)
446 		for (tmp2=playery-1; tmp2<playery+2; tmp2++)
447 			if (mitem[tmp][tmp2]) return(1); /* if monster nearby */
448 	return(0);
449 	}
450 
451 /*
452 	function to steal an item from the players pockets
453 	returns 1 if steals something else returns 0
454  */
stealsomething()455 stealsomething()
456 	{
457 	register int i,j;
458 	j=100;
459 	while (1)
460 		{
461 		i=rund(26);
462 		if (iven[i]) if (c[WEAR]!=i) if (c[WIELD]!=i) if (c[SHIELD]!=i)
463 			{
464 			srcount=0; show3(i);
465 			adjustcvalues(iven[i],ivenarg[i]);  iven[i]=0; return(1);
466 			}
467 		if (--j <= 0) return(0);
468 		}
469 	}
470 
471 /*
472 	function to return 1 is player carrys nothing else return 0
473  */
emptyhanded()474 emptyhanded()
475 	{
476 	register int i;
477 	for (i=0; i<26; i++)
478 		if (iven[i]) if (i!=c[WIELD]) if (i!=c[WEAR]) if (i!=c[SHIELD]) return(0);
479 	return(1);
480 	}
481 
482 /*
483 	function to create a gem on a square near the player
484  */
creategem()485 creategem()
486 	{
487 	register int i,j;
488 	switch(rnd(4))
489 		{
490 		case 1:	 i=ODIAMOND;	j=50;	break;
491 		case 2:	 i=ORUBY;		j=40;	break;
492 		case 3:	 i=OEMERALD;	j=30;	break;
493 		default: i=OSAPPHIRE;	j=20;	break;
494 		};
495 	createitem(i,rnd(j)+j/10);
496 	}
497 
498 /*
499 	function to change character levels as needed when dropping an object
500 	that affects these characteristics
501  */
adjustcvalues(itm,arg)502 adjustcvalues(itm,arg)
503 	int itm,arg;
504 	{
505 	register int flag;
506 	flag=0;
507 	switch(itm)
508 		{
509 		case ODEXRING:	c[DEXTERITY] -= arg+1;  flag=1; break;
510 		case OSTRRING:	c[STREXTRA]  -= arg+1;  flag=1; break;
511 		case OCLEVERRING: c[INTELLIGENCE] -= arg+1;  flag=1; break;
512 		case OHAMMER:	c[DEXTERITY] -= 10;	c[STREXTRA] -= 10;
513 						c[INTELLIGENCE] += 10; flag=1; break;
514 		case OSWORDofSLASHING:	c[DEXTERITY] -= 5;	flag=1; break;
515 		case OORBOFDRAGON:		--c[SLAYING];		return;
516 		case OSPIRITSCARAB:		--c[NEGATESPIRIT];	return;
517 		case OCUBEofUNDEAD:		--c[CUBEofUNDEAD];	return;
518 		case ONOTHEFT:			--c[NOTHEFT]; 		return;
519 		case OLANCE:		c[LANCEDEATH]=0;	return;
520 		case OPOTION:	case OSCROLL:	return;
521 
522 		default:	flag=1;
523 		};
524 	if (flag) bottomline();
525 	}
526 
527 /*
528 	function to read a string from token input "string"
529 	returns a pointer to the string
530  */
gettokstr(str)531 gettokstr(str)
532 	register char *str;
533 	{
534 	register int i,j;
535 	i=50;
536 	while ((getchar() != '"') && (--i > 0));
537 	i=36;
538 	while (--i > 0)
539 		{
540 		if ((j=getchar()) != '"') *str++ = j;  else i=0;
541 		}
542 	*str = 0;
543 	i=50;
544 	if (j != '"') while ((getchar() != '"') && (--i > 0)); /* if end due to too long, then find closing quote */
545 	}
546 
547 /*
548 	function to ask user for a password (no echo)
549 	returns 1 if entered correctly, 0 if not
550  */
551 static char gpwbuf[33];
getpassword()552 getpassword()
553 	{
554 	register int i,j;
555 	register char *gpwp;
556 	extern char *password;
557 	scbr();	/*	system("stty -echo cbreak"); */
558 	gpwp = gpwbuf;	lprcat("\nEnter Password: "); lflush();
559 	i = strlen(password);
560 	for (j=0; j<i; j++) read(0,gpwp++,1);	  gpwbuf[i]=0;
561 	sncbr(); /* system("stty echo -cbreak"); */
562 	if (strcmp(gpwbuf,password) != 0)
563 		{	lprcat("\nSorry\n");  lflush(); return(0);	}
564 	else  return(1);
565 	}
566 
567 /*
568 	subroutine to get a yes or no response from the user
569 	returns y or n
570  */
getyn()571 getyn()
572 	{
573 	register int i;
574 	i=0; while (i!='y' && i!='n' && i!='\33') i=getchar();
575 	return(i);
576 	}
577 
578 /*
579 	function to calculate the pack weight of the player
580 	returns the number of pounds the player is carrying
581  */
packweight()582 packweight()
583 	{
584 	register int i,j,k;
585 	k=c[GOLD]/1000; j=25;  while ((iven[j]==0) && (j>0)) --j;
586 	for (i=0; i<=j; i++)
587 		switch(iven[i])
588 			{
589 			case 0:												break;
590 			case OSSPLATE:   case OPLATEARMOR:		k += 40;	break;
591 			case OPLATE:							k += 35;	break;
592 			case OHAMMER:							k += 30;	break;
593 			case OSPLINT:							k += 26;	break;
594 			case OSWORDofSLASHING:	case OCHAIN:
595 			case OBATTLEAXE:   		case O2SWORD:	k += 23;	break;
596 			case OLONGSWORD:   		case OSWORD:
597 			case ORING:				case OFLAIL:	k += 20;	break;
598 			case OLANCE: 		case OSTUDLEATHER:	k += 15;	break;
599 			case OLEATHER:   		case OSPEAR:	k += 8;		break;
600 			case OORBOFDRAGON:   	case OBELT:		k += 4;		break;
601 			case OSHIELD:							k += 7;		break;
602 			case OCHEST:		k += 30 + ivenarg[i];			break;
603 			default:								k++;
604 			};
605 	return(k);
606 	}
607 
608 #ifndef MACRORND
609 	/* macros to generate random numbers   1<=rnd(N)<=N   0<=rund(N)<=N-1 */
rnd(x)610 rnd(x)
611 	int x;
612 	{
613 	return((((randx=randx*1103515245+12345)>>7)%(x))+1);
614 	}
615 
rund(x)616 rund(x)
617 	int x;
618 	{
619 	return((((randx=randx*1103515245+12345)>>7)%(x))  );
620 	}
621 #endif MACRORND
622