Well, ok, if you are going to turn off writable strings, then the code
[dragonfly.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.4 2006/06/13 22:12:16 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[][32],scrollname[][32];
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 */