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 * makemonst(lev) function to return monster number for a randomly
16 * selected monster
17 * positionplayer() function to be sure player is not in a wall
18 * recalc() function to recalculate the armor class of the player
19 * quit() subroutine to ask if the player really wants to quit
20 *
21 */
22
23 #include "header.h"
24 extern int score[], dropflag;
25 extern char *what[], *who[];
26 extern char password[], winner[];
27 extern char sciv[SCORESIZE + 1][26][2];
28
29 /*
30 raiselevel()
31
32 subroutine to raise the player one level
33 uses the skill[] array to find level boundarys
34 uses c[EXPERIENCE] c[LEVEL]
35 */
36 void
raiselevel(void)37 raiselevel(void)
38 {
39 if (c[LEVEL] < MAXPLEVEL)
40 raiseexperience((long)(skill[c[LEVEL]] - c[EXPERIENCE]));
41 }
42
43 /*
44 loselevel()
45
46 subroutine to lower the players character level by one
47 */
48 void
loselevel(void)49 loselevel(void)
50 {
51 if (c[LEVEL] > 1)
52 loseexperience((long)(c[EXPERIENCE] - skill[c[LEVEL] - 1] + 1));
53 }
54
55 /*
56 raiseexperience(x)
57
58 subroutine to increase experience points
59 */
60 void
raiseexperience(long x)61 raiseexperience(long x)
62 {
63 int i, tmp;
64 i = c[LEVEL];
65 c[EXPERIENCE] += x;
66 while (c[EXPERIENCE] >= skill[c[LEVEL]] && (c[LEVEL] < MAXPLEVEL)) {
67 tmp = (c[CONSTITUTION] - c[HARDGAME]) >> 1;
68 c[LEVEL]++;
69 raisemhp((int)(rnd(3) + rnd((tmp > 0) ? tmp : 1)));
70 raisemspells((int)rund(3));
71 if (c[LEVEL] < 7 - c[HARDGAME])
72 raisemhp((int)(c[CONSTITUTION] >> 2));
73 }
74 if (c[LEVEL] != i) {
75 cursors();
76 beep();
77 lprintf("\nWelcome to level %d", (long)c[LEVEL]); /* if we changed levels */
78 }
79 bottomline();
80 }
81
82 /*
83 loseexperience(x)
84
85 subroutine to lose experience points
86 */
87 void
loseexperience(long x)88 loseexperience(long x)
89 {
90 int i, tmp;
91 i = c[LEVEL];
92 c[EXPERIENCE] -= x;
93 if (c[EXPERIENCE] < 0)
94 c[EXPERIENCE] = 0;
95 while (c[EXPERIENCE] < skill[c[LEVEL] - 1]) {
96 if (--c[LEVEL] <= 1) /* down one level */
97 c[LEVEL] = 1;
98 tmp = (c[CONSTITUTION] - c[HARDGAME]) >> 1; /* lose hpoints */
99 losemhp((int)rnd((tmp > 0) ? tmp : 1)); /* lose hpoints */
100 if (c[LEVEL] < 7 - c[HARDGAME])
101 losemhp((int)(c[CONSTITUTION] >> 2));
102 losemspells((int)rund(3)); /* lose spells */
103 }
104 if (i != c[LEVEL]) {
105 cursors();
106 beep();
107 lprintf("\nYou went down to level %d!", (long)c[LEVEL]);
108 }
109 bottomline();
110 }
111
112 /*
113 losehp(x)
114 losemhp(x)
115
116 subroutine to remove hit points from the player
117 warning -- will kill player if hp goes to zero
118 */
119 void
losehp(int x)120 losehp(int x)
121 {
122 if ((c[HP] -= x) <= 0) {
123 beep();
124 lprcat("\n");
125 nap(3000);
126 died(lastnum);
127 }
128 }
129
130 void
losemhp(int x)131 losemhp(int x)
132 {
133 c[HP] -= x;
134 if (c[HP] < 1)
135 c[HP] = 1;
136 c[HPMAX] -= x;
137 if (c[HPMAX] < 1)
138 c[HPMAX] = 1;
139 }
140
141 /*
142 raisehp(x)
143 raisemhp(x)
144
145 subroutine to gain maximum hit points
146 */
147 void
raisehp(int x)148 raisehp(int x)
149 {
150 if ((c[HP] += x) > c[HPMAX])
151 c[HP] = c[HPMAX];
152 }
153
154 void
raisemhp(int x)155 raisemhp(int x)
156 {
157 c[HPMAX] += x;
158 c[HP] += x;
159 }
160
161 /*
162 raisemspells(x)
163
164 subroutine to gain maximum spells
165 */
166 void
raisemspells(int x)167 raisemspells(int x)
168 {
169 c[SPELLMAX] += x;
170 c[SPELLS] += x;
171 }
172
173 /*
174 losemspells(x)
175
176 subroutine to lose maximum spells
177 */
178 void
losemspells(int x)179 losemspells(int x)
180 {
181 if ((c[SPELLMAX] -= x) < 0)
182 c[SPELLMAX] = 0;
183 if ((c[SPELLS] -= x) < 0)
184 c[SPELLS] = 0;
185 }
186
187 /*
188 makemonst(lev)
189 int lev;
190
191 function to return monster number for a randomly selected monster
192 for the given cave level
193 */
194 int
makemonst(int lev)195 makemonst(int lev)
196 {
197 int tmp, x;
198 if (lev < 1)
199 lev = 1;
200 if (lev > 12)
201 lev = 12;
202 tmp = WATERLORD;
203 if (lev < 5)
204 while (tmp == WATERLORD)
205 tmp = rnd((x = monstlevel[lev - 1]) ? x : 1);
206 else
207 while (tmp == WATERLORD)
208 tmp = rnd((x = monstlevel[lev - 1] - monstlevel[lev - 4])
209 ? x : 1) + monstlevel[lev - 4];
210
211 while (tmp < MAXMONST && monster[tmp].genocided) /* genocided? */
212 tmp++;
213 return (tmp);
214 }
215
216 /*
217 positionplayer()
218
219 function to be sure player is not in a wall
220 */
221 void
positionplayer(void)222 positionplayer(void)
223 {
224 int try;
225 try = 2;
226 while ((item[playerx][playery] || mitem[playerx][playery]) && (try))
227 if (++playerx >= MAXX - 1) {
228 playerx = 1;
229 if (++playery >= MAXY - 1) {
230 playery = 1;
231 --try;
232 }
233 }
234 if (try == 0)
235 lprcat("Failure in positionplayer\n");
236 }
237
238 /*
239 recalc() function to recalculate the armor class of the player
240 */
241 void
recalc(void)242 recalc(void)
243 {
244 int i, j, k;
245 c[AC] = c[MOREDEFENSES];
246 if (c[WEAR] >= 0)
247 switch (iven[c[WEAR]]) {
248 case OSHIELD:
249 c[AC] += 2 + ivenarg[c[WEAR]];
250 break;
251 case OLEATHER:
252 c[AC] += 2 + ivenarg[c[WEAR]];
253 break;
254 case OSTUDLEATHER:
255 c[AC] += 3 + ivenarg[c[WEAR]];
256 break;
257 case ORING:
258 c[AC] += 5 + ivenarg[c[WEAR]];
259 break;
260 case OCHAIN:
261 c[AC] += 6 + ivenarg[c[WEAR]];
262 break;
263 case OSPLINT:
264 c[AC] += 7 + ivenarg[c[WEAR]];
265 break;
266 case OPLATE:
267 c[AC] += 9 + ivenarg[c[WEAR]];
268 break;
269 case OPLATEARMOR:
270 c[AC] += 10 + ivenarg[c[WEAR]];
271 break;
272 case OSSPLATE:
273 c[AC] += 12 + ivenarg[c[WEAR]];
274 break;
275 }
276
277 if (c[SHIELD] >= 0)
278 if (iven[c[SHIELD]] == OSHIELD)
279 c[AC] += 2 + ivenarg[c[SHIELD]];
280 if (c[WIELD] < 0)
281 c[WCLASS] = 0;
282 else {
283 i = ivenarg[c[WIELD]];
284 switch (iven[c[WIELD]]) {
285 case ODAGGER:
286 c[WCLASS] = 3 + i;
287 break;
288 case OBELT:
289 c[WCLASS] = 7 + i;
290 break;
291 case OSHIELD:
292 c[WCLASS] = 8 + i;
293 break;
294 case OSPEAR:
295 c[WCLASS] = 10 + i;
296 break;
297 case OFLAIL:
298 c[WCLASS] = 14 + i;
299 break;
300 case OBATTLEAXE:
301 c[WCLASS] = 17 + i;
302 break;
303 case OLANCE:
304 c[WCLASS] = 19 + i;
305 break;
306 case OLONGSWORD:
307 c[WCLASS] = 22 + i;
308 break;
309 case O2SWORD:
310 c[WCLASS] = 26 + i;
311 break;
312 case OSWORD:
313 c[WCLASS] = 32 + i;
314 break;
315 case OSWORDofSLASHING:
316 c[WCLASS] = 30 + i;
317 break;
318 case OHAMMER:
319 c[WCLASS] = 35 + i;
320 break;
321 default:
322 c[WCLASS] = 0;
323 }
324 }
325 c[WCLASS] += c[MOREDAM];
326
327 /* now for regeneration abilities based on rings */
328 c[REGEN] = 1;
329 c[ENERGY] = 0;
330 j = 0;
331 for (k = 25; k > 0; k--)
332 if (iven[k]) {
333 j = k;
334 k = 0;
335 }
336 for (i = 0; i <= j; i++) {
337 switch (iven[i]) {
338 case OPROTRING:
339 c[AC] += ivenarg[i] + 1;
340 break;
341 case ODAMRING:
342 c[WCLASS] += ivenarg[i] + 1;
343 break;
344 case OBELT:
345 c[WCLASS] += ((ivenarg[i] << 1)) + 2;
346 break;
347
348 case OREGENRING:
349 c[REGEN] += ivenarg[i] + 1;
350 break;
351 case ORINGOFEXTRA:
352 c[REGEN] += 5 * (ivenarg[i] + 1);
353 break;
354 case OENERGYRING:
355 c[ENERGY] += ivenarg[i] + 1;
356 break;
357 }
358 }
359 }
360
361
362 /*
363 quit()
364
365 subroutine to ask if the player really wants to quit
366 */
367 void
quit(void)368 quit(void)
369 {
370 int i;
371 cursors();
372 strcpy(lastmonst, "");
373 lprcat("\n\nDo you really want to quit?");
374 while (1) {
375 i = getchr();
376 if (i == 'y') {
377 died(300);
378 return;
379 }
380 if ((i == 'n') || (i == '\33')) {
381 lprcat(" no");
382 lflush();
383 return;
384 }
385 lprcat("\n");
386 setbold();
387 lprcat("Yes");
388 resetbold();
389 lprcat(" or ");
390 setbold();
391 lprcat("No");
392 resetbold();
393 lprcat(" please? Do you want to quit? ");
394 }
395 }
396
397 /*
398 function to ask --more-- then the user must enter a space
399 */
400 void
more(void)401 more(void)
402 {
403 lprcat("\n --- press ");
404 standout("space");
405 lprcat(" to continue --- ");
406 while (getchr() != ' ')
407 ; /* nothing */
408 }
409
410 /*
411 function to put something in the players inventory
412 returns 0 if success, 1 if a failure
413 */
414 int
take(int itm,int arg)415 take(int itm, int arg)
416 {
417 int i, limit;
418 if ((limit = 15 + (c[LEVEL] >> 1)) > 26)
419 limit = 26;
420 for (i = 0; i < limit; i++)
421 if (iven[i] == 0) {
422 iven[i] = itm;
423 ivenarg[i] = arg;
424 limit = 0;
425 switch (itm) {
426 case OPROTRING:
427 case ODAMRING:
428 case OBELT:
429 limit = 1;
430 break;
431 case ODEXRING:
432 c[DEXTERITY] += ivenarg[i] + 1;
433 limit = 1;
434 break;
435 case OSTRRING:
436 c[STREXTRA] += ivenarg[i] + 1;
437 limit = 1;
438 break;
439 case OCLEVERRING:
440 c[INTELLIGENCE] += ivenarg[i] + 1;
441 limit = 1;
442 break;
443 case OHAMMER:
444 c[DEXTERITY] += 10;
445 c[STREXTRA] += 10;
446 c[INTELLIGENCE] -= 10;
447 limit = 1;
448 break;
449
450 case OORBOFDRAGON:
451 c[SLAYING]++;
452 break;
453 case OSPIRITSCARAB:
454 c[NEGATESPIRIT]++;
455 break;
456 case OCUBEofUNDEAD:
457 c[CUBEofUNDEAD]++;
458 break;
459 case ONOTHEFT:
460 c[NOTHEFT]++;
461 break;
462 case OSWORDofSLASHING:
463 c[DEXTERITY] += 5;
464 limit = 1;
465 break;
466 }
467 lprcat("\nYou pick up:");
468 srcount = 0;
469 show3(i);
470 if (limit)
471 bottomline();
472 return (0);
473 }
474 lprcat("\nYou can't carry anything else");
475 return (1);
476 }
477
478 /*
479 subroutine to drop an object
480 returns 1 if something there already else 0
481 */
482 int
drop_object(int k)483 drop_object(int k)
484 {
485 int itm;
486 if ((k < 0) || (k > 25))
487 return (0);
488 itm = iven[k];
489 cursors();
490 if (itm == 0) {
491 lprintf("\nYou don't have item %c! ", k + 'a');
492 return (1);
493 }
494 if (item[playerx][playery]) {
495 beep();
496 lprcat("\nThere's something here already");
497 return (1);
498 }
499 if (playery == MAXY - 1 && playerx == 33) /* not in entrance */
500 return (1);
501 item[playerx][playery] = itm;
502 iarg[playerx][playery] = ivenarg[k];
503 srcount = 0;
504 lprcat("\n You drop:");
505 show3(k); /* show what item you dropped*/
506 know[playerx][playery] = 0;
507 iven[k] = 0;
508 if (c[WIELD] == k)
509 c[WIELD] = -1;
510 if (c[WEAR] == k)
511 c[WEAR] = -1;
512 if (c[SHIELD] == k)
513 c[SHIELD] = -1;
514 adjustcvalues(itm, ivenarg[k]);
515 /* say dropped an item so wont ask to pick it up right away */
516 dropflag = 1;
517 return (0);
518 }
519
520 /*
521 function to enchant armor player is currently wearing
522 */
523 void
enchantarmor(void)524 enchantarmor(void)
525 {
526 int tmp;
527 if (c[WEAR] < 0) {
528 if (c[SHIELD] < 0) {
529 cursors();
530 beep();
531 lprcat("\nYou feel a sense of loss");
532 return;
533 } else {
534 tmp = iven[c[SHIELD]];
535 if (tmp != OSCROLL)
536 if (tmp != OPOTION) {
537 ivenarg[c[SHIELD]]++;
538 bottomline();
539 }
540 }
541 }
542 tmp = iven[c[WEAR]];
543 if (tmp != OSCROLL)
544 if (tmp != OPOTION) {
545 ivenarg[c[WEAR]]++;
546 bottomline();
547 }
548 }
549
550 /*
551 function to enchant a weapon presently being wielded
552 */
553 void
enchweapon(void)554 enchweapon(void)
555 {
556 int tmp;
557 if (c[WIELD] < 0) {
558 cursors();
559 beep();
560 lprcat("\nYou feel a sense of loss");
561 return;
562 }
563 tmp = iven[c[WIELD]];
564 if (tmp != OSCROLL)
565 if (tmp != OPOTION) {
566 ivenarg[c[WIELD]]++;
567 if (tmp == OCLEVERRING)
568 c[INTELLIGENCE]++;
569 else if (tmp == OSTRRING)
570 c[STREXTRA]++;
571 else if (tmp == ODEXRING)
572 c[DEXTERITY]++;
573 bottomline();
574 }
575 }
576
577 /*
578 routine to tell if player can carry one more thing
579 returns 1 if pockets are full, else 0
580 */
581 int
pocketfull(void)582 pocketfull(void)
583 {
584 int i, limit;
585 if ((limit = 15 + (c[LEVEL] >> 1)) > 26)
586 limit = 26;
587 for (i = 0; i < limit; i++)
588 if (iven[i] == 0)
589 return (0);
590 return (1);
591 }
592
593 /*
594 function to return 1 if a monster is next to the player else returns 0
595 */
596 int
nearbymonst(void)597 nearbymonst(void)
598 {
599 int tmp, tmp2;
600 for (tmp = playerx - 1; tmp < playerx + 2; tmp++)
601 for (tmp2 = playery - 1; tmp2 < playery + 2; tmp2++)
602 if (mitem[tmp][tmp2]) /* if monster nearby */
603 return (1);
604 return (0);
605 }
606
607 /*
608 function to steal an item from the players pockets
609 returns 1 if steals something else returns 0
610 */
611 int
stealsomething(void)612 stealsomething(void)
613 {
614 int i, j;
615 j = 100;
616 while (1) {
617 i = rund(26);
618 if (iven[i])
619 if (c[WEAR] != i)
620 if (c[WIELD] != i)
621 if (c[SHIELD] != i) {
622 srcount = 0;
623 show3(i);
624 adjustcvalues(iven[i], ivenarg[i]);
625 iven[i] = 0;
626 return (1);
627 }
628 if (--j <= 0)
629 return (0);
630 }
631 }
632
633 /*
634 function to return 1 is player carrys nothing else return 0
635 */
636 int
emptyhanded(void)637 emptyhanded(void)
638 {
639 int i;
640 for (i = 0; i < 26; i++)
641 if (iven[i])
642 if (i != c[WIELD])
643 if (i != c[WEAR])
644 if (i != c[SHIELD])
645 return (0);
646 return (1);
647 }
648
649 /*
650 function to create a gem on a square near the player
651 */
652 void
creategem(void)653 creategem(void)
654 {
655 int i, j;
656 switch (rnd(4)) {
657 case 1:
658 i = ODIAMOND;
659 j = 50;
660 break;
661 case 2:
662 i = ORUBY;
663 j = 40;
664 break;
665 case 3:
666 i = OEMERALD;
667 j = 30;
668 break;
669 default:
670 i = OSAPPHIRE;
671 j = 20;
672 break;
673 }
674 createitem(i, rnd(j) + j / 10);
675 }
676
677 /*
678 function to change character levels as needed when dropping an object
679 that affects these characteristics
680 */
681 void
adjustcvalues(int itm,int arg)682 adjustcvalues(int itm, int arg)
683 {
684 int flag;
685 flag = 0;
686 switch (itm) {
687 case ODEXRING:
688 c[DEXTERITY] -= arg + 1;
689 flag = 1;
690 break;
691 case OSTRRING:
692 c[STREXTRA] -= arg + 1;
693 flag = 1;
694 break;
695 case OCLEVERRING:
696 c[INTELLIGENCE] -= arg + 1;
697 flag = 1;
698 break;
699 case OHAMMER:
700 c[DEXTERITY] -= 10;
701 c[STREXTRA] -= 10;
702 c[INTELLIGENCE] += 10;
703 flag = 1;
704 break;
705 case OSWORDofSLASHING:
706 c[DEXTERITY] -= 5;
707 flag = 1;
708 break;
709 case OORBOFDRAGON:
710 --c[SLAYING];
711 return;
712 case OSPIRITSCARAB:
713 --c[NEGATESPIRIT];
714 return;
715 case OCUBEofUNDEAD:
716 --c[CUBEofUNDEAD];
717 return;
718 case ONOTHEFT:
719 --c[NOTHEFT];
720 return;
721 case OLANCE:
722 c[LANCEDEATH] = 0;
723 return;
724 case OPOTION:
725 case OSCROLL:
726 return;
727
728 default:
729 flag = 1;
730 }
731 if (flag)
732 bottomline();
733 }
734
735 /*
736 function to ask user for a password (no echo)
737 returns 1 if entered correctly, 0 if not
738 */
739 static char gpwbuf[33];
740
741 int
getpassword(void)742 getpassword(void)
743 {
744 int i, j;
745 char *gpwp;
746 scbr();
747 gpwp = gpwbuf;
748 lprcat("\nEnter Password: ");
749 lflush();
750 i = strlen(password);
751 for (j = 0; j < i; j++)
752 read(0, gpwp++, 1);
753 gpwbuf[i] = 0;
754 sncbr();
755 if (strcmp(gpwbuf, password) != 0) {
756 lprcat("\nSorry\n");
757 lflush();
758 return (0);
759 } else
760 return (1);
761 }
762
763 /*
764 subroutine to get a yes or no response from the user
765 returns y or n
766 */
767 int
getyn(void)768 getyn(void)
769 {
770 int i;
771 i = 0;
772 while (i != 'y' && i != 'n' && i != '\33')
773 i = getchr();
774 return (i);
775 }
776
777 /*
778 function to calculate the pack weight of the player
779 returns the number of pounds the player is carrying
780 */
781 int
packweight(void)782 packweight(void)
783 {
784 int i, j, k;
785 k = c[GOLD] / 1000;
786 j = 25;
787 while ((iven[j] == 0) && (j > 0))
788 --j;
789 for (i = 0; i <= j; i++)
790 switch (iven[i]) {
791 case 0:
792 break;
793 case OSSPLATE:
794 case OPLATEARMOR:
795 k += 40;
796 break;
797 case OPLATE:
798 k += 35;
799 break;
800 case OHAMMER:
801 k += 30;
802 break;
803 case OSPLINT:
804 k += 26;
805 break;
806 case OSWORDofSLASHING:
807 case OCHAIN:
808 case OBATTLEAXE:
809 case O2SWORD:
810 k += 23;
811 break;
812 case OLONGSWORD:
813 case OSWORD:
814 case ORING:
815 case OFLAIL:
816 k += 20;
817 break;
818 case OLANCE:
819 case OSTUDLEATHER:
820 k += 15;
821 break;
822 case OLEATHER:
823 case OSPEAR:
824 k += 8;
825 break;
826 case OORBOFDRAGON:
827 case OBELT:
828 k += 4;
829 break;
830 case OSHIELD:
831 k += 7;
832 break;
833 case OCHEST:
834 k += 30 + ivenarg[i];
835 break;
836 default:
837 k++;
838 }
839 return (k);
840 }
841
842 #ifndef MACRORND
843 /* macros to generate random numbers 1<=rnd(N)<=N 0<=rund(N)<=N-1 */
844 int
rnd(int x)845 rnd(int x)
846 {
847 return ((random() % x) + 1);
848 }
849
850 int
rund(int x)851 rund(int x)
852 {
853 return (random() % x);
854 }
855 #endif /* MACRORND */
856