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