Sync audio data with other output.
[games.git] / games / larn / global.c
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 */