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