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