OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / attrib.c
1 /* NetHack 3.6  attrib.c        $NHDT-Date: 1449269911 2015/12/04 22:58:31 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
2 /*      Copyright 1988, 1989, 1990, 1992, M. Stephenson           */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*  attribute modification routines. */
6
7 #include "hack.h"
8 #include <ctype.h>
9
10 /* part of the output on gain or loss of attribute */
11 static const char
12     *const plusattr[] = { "strong", "smart", "wise",
13                           "agile",  "tough", "charismatic" },
14     *const minusattr[] = { "weak",    "stupid",
15                            "foolish", "clumsy",
16                            "fragile", "repulsive" };
17
18 static const struct innate {
19     schar ulevel;
20     long *ability;
21     const char *gainstr, *losestr;
22 } arc_abil[] = { { 1, &(HStealth), "", "" },
23                  { 1, &(HFast), "", "" },
24                  { 10, &(HSearching), "perceptive", "" },
25                  { 0, 0, 0, 0 } },
26
27   bar_abil[] = { { 1, &(HPoison_resistance), "", "" },
28                  { 7, &(HFast), "quick", "slow" },
29                  { 15, &(HStealth), "stealthy", "" },
30                  { 0, 0, 0, 0 } },
31
32   cav_abil[] = { { 7, &(HFast), "quick", "slow" },
33                  { 15, &(HWarning), "sensitive", "" },
34                  { 0, 0, 0, 0 } },
35
36   hea_abil[] = { { 1, &(HPoison_resistance), "", "" },
37                  { 15, &(HWarning), "sensitive", "" },
38                  { 0, 0, 0, 0 } },
39
40   kni_abil[] = { { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } },
41
42   mon_abil[] = { { 1, &(HFast), "", "" },
43                  { 1, &(HSleep_resistance), "", "" },
44                  { 1, &(HSee_invisible), "", "" },
45                  { 3, &(HPoison_resistance), "healthy", "" },
46                  { 5, &(HStealth), "stealthy", "" },
47                  { 7, &(HWarning), "sensitive", "" },
48                  { 9, &(HSearching), "perceptive", "unaware" },
49                  { 11, &(HFire_resistance), "cool", "warmer" },
50                  { 13, &(HCold_resistance), "warm", "cooler" },
51                  { 15, &(HShock_resistance), "insulated", "conductive" },
52                  { 17, &(HTeleport_control), "controlled", "uncontrolled" },
53                  { 0, 0, 0, 0 } },
54
55   pri_abil[] = { { 15, &(HWarning), "sensitive", "" },
56                  { 20, &(HFire_resistance), "cool", "warmer" },
57                  { 0, 0, 0, 0 } },
58
59   ran_abil[] = { { 1, &(HSearching), "", "" },
60                  { 7, &(HStealth), "stealthy", "" },
61                  { 15, &(HSee_invisible), "", "" },
62                  { 0, 0, 0, 0 } },
63
64   rog_abil[] = { { 1, &(HStealth), "", "" },
65                  { 10, &(HSearching), "perceptive", "" },
66                  { 0, 0, 0, 0 } },
67
68   sam_abil[] = { { 1, &(HFast), "", "" },
69                  { 15, &(HStealth), "stealthy", "" },
70                  { 0, 0, 0, 0 } },
71
72   tou_abil[] = { { 10, &(HSearching), "perceptive", "" },
73                  { 20, &(HPoison_resistance), "hardy", "" },
74                  { 0, 0, 0, 0 } },
75
76   val_abil[] = { { 1, &(HCold_resistance), "", "" },
77                  { 1, &(HStealth), "", "" },
78                  { 7, &(HFast), "quick", "slow" },
79                  { 0, 0, 0, 0 } },
80
81   wiz_abil[] = { { 15, &(HWarning), "sensitive", "" },
82                  { 17, &(HTeleport_control), "controlled", "uncontrolled" },
83                  { 0, 0, 0, 0 } },
84
85   /* Intrinsics conferred by race */
86     elf_abil[] = { { 4, &(HSleep_resistance), "awake", "tired" },
87                    { 0, 0, 0, 0 } },
88
89   orc_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 0, 0, 0, 0 } };
90
91 STATIC_DCL void NDECL(exerper);
92 STATIC_DCL void FDECL(postadjabil, (long *));
93 STATIC_DCL const struct innate *FDECL(check_innate_abil, (long *, long));
94 STATIC_DCL int FDECL(innately, (long *));
95
96 /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
97 boolean
98 adjattrib(ndx, incr, msgflg)
99 int ndx, incr;
100 int msgflg; /* positive => no message, zero => message, and */
101 {           /* negative => conditional (msg if change made) */
102     int old_acurr;
103     boolean abonflg;
104     const char *attrstr;
105
106     if (Fixed_abil || !incr)
107         return FALSE;
108
109     if ((ndx == A_INT || ndx == A_WIS) && uarmh && uarmh->otyp == DUNCE_CAP) {
110         if (msgflg == 0)
111             Your("cap constricts briefly, then relaxes again.");
112         return FALSE;
113     }
114
115     old_acurr = ACURR(ndx);
116     if (incr > 0) {
117         ABASE(ndx) += incr;
118         if (ABASE(ndx) > AMAX(ndx)) {
119             incr = ABASE(ndx) - AMAX(ndx);
120             AMAX(ndx) += incr;
121             if (AMAX(ndx) > ATTRMAX(ndx))
122                 AMAX(ndx) = ATTRMAX(ndx);
123             ABASE(ndx) = AMAX(ndx);
124         }
125         attrstr = plusattr[ndx];
126         abonflg = (ABON(ndx) < 0);
127     } else {
128         ABASE(ndx) += incr;
129         if (ABASE(ndx) < ATTRMIN(ndx)) {
130             incr = ABASE(ndx) - ATTRMIN(ndx);
131             ABASE(ndx) = ATTRMIN(ndx);
132             AMAX(ndx) += incr;
133             if (AMAX(ndx) < ATTRMIN(ndx))
134                 AMAX(ndx) = ATTRMIN(ndx);
135         }
136         attrstr = minusattr[ndx];
137         abonflg = (ABON(ndx) > 0);
138     }
139     if (ACURR(ndx) == old_acurr) {
140         if (msgflg == 0 && flags.verbose)
141             pline("You're %s as %s as you can get.",
142                   abonflg ? "currently" : "already", attrstr);
143         return FALSE;
144     }
145
146     if (msgflg <= 0)
147         You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr);
148     context.botl = 1;
149     if (moves > 1 && (ndx == A_STR || ndx == A_CON))
150         (void) encumber_msg();
151     return TRUE;
152 }
153
154 void
155 gainstr(otmp, incr, givemsg)
156 struct obj *otmp;
157 int incr;
158 boolean givemsg;
159 {
160     int num = incr;
161
162     if (!num) {
163         if (ABASE(A_STR) < 18)
164             num = (rn2(4) ? 1 : rnd(6));
165         else if (ABASE(A_STR) < STR18(85))
166             num = rnd(10);
167         else
168             num = 1;
169     }
170     (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num,
171                      givemsg ? -1 : 1);
172 }
173
174 /* may kill you; cause may be poison or monster like 'a' */
175 void
176 losestr(num)
177 register int num;
178 {
179     int ustr = ABASE(A_STR) - num;
180
181     while (ustr < 3) {
182         ++ustr;
183         --num;
184         if (Upolyd) {
185             u.mh -= 6;
186             u.mhmax -= 6;
187         } else {
188             u.uhp -= 6;
189             u.uhpmax -= 6;
190         }
191     }
192     (void) adjattrib(A_STR, -num, 1);
193 }
194
195 static const struct poison_effect_message {
196     void VDECL((*delivery_func), (const char *, ...));
197     const char *effect_msg;
198 } poiseff[] = {
199     { You_feel, "weaker" },             /* A_STR */
200     { Your, "brain is on fire" },       /* A_INT */
201     { Your, "judgement is impaired" },  /* A_WIS */
202     { Your, "muscles won't obey you" }, /* A_DEX */
203     { You_feel, "very sick" },          /* A_CON */
204     { You, "break out in hives" }       /* A_CHA */
205 };
206
207 /* feedback for attribute loss due to poisoning */
208 void
209 poisontell(typ, exclaim)
210 int typ;         /* which attribute */
211 boolean exclaim; /* emphasis */
212 {
213     void VDECL((*func), (const char *, ...)) = poiseff[typ].delivery_func;
214
215     (*func)("%s%c", poiseff[typ].effect_msg, exclaim ? '!' : '.');
216 }
217
218 /* called when an attack or trap has poisoned the hero (used to be in mon.c)
219  */
220 void
221 poisoned(reason, typ, pkiller, fatal, thrown_weapon)
222 const char *reason,    /* controls what messages we display */
223     *pkiller;          /* for score+log file if fatal */
224 int typ, fatal;        /* if fatal is 0, limit damage to adjattrib */
225 boolean thrown_weapon; /* thrown weapons are less deadly */
226 {
227     int i, loss, kprefix = KILLED_BY_AN;
228
229     /* inform player about being poisoned unless that's already been done;
230        "blast" has given a "blast of poison gas" message; "poison arrow",
231        "poison dart", etc have implicitly given poison messages too... */
232     if (strcmp(reason, "blast") && !strstri(reason, "poison")) {
233         boolean plural = (reason[strlen(reason) - 1] == 's') ? 1 : 0;
234
235         /* avoid "The" Orcus's sting was poisoned... */
236         pline("%s%s %s poisoned!", isupper(*reason) ? "" : "The ", reason,
237               plural ? "were" : "was");
238     }
239     if (Poison_resistance) {
240         if (!strcmp(reason, "blast"))
241             shieldeff(u.ux, u.uy);
242         pline_The("poison doesn't seem to affect you.");
243         return;
244     }
245
246     /* suppress killer prefix if it already has one */
247     i = name_to_mon(pkiller);
248     if (i >= LOW_PM && (mons[i].geno & G_UNIQ)) {
249         kprefix = KILLED_BY;
250         if (!type_is_pname(&mons[i]))
251             pkiller = the(pkiller);
252     } else if (!strncmpi(pkiller, "the ", 4) || !strncmpi(pkiller, "an ", 3)
253                || !strncmpi(pkiller, "a ", 2)) {
254         /*[ does this need a plural check too? ]*/
255         kprefix = KILLED_BY;
256     }
257
258     i = !fatal ? 1 : rn2(fatal + (thrown_weapon ? 20 : 0));
259     if (i == 0 && typ != A_CHA) {
260         /* instant kill */
261         u.uhp = -1;
262         pline_The("poison was deadly...");
263     } else if (i > 5) {
264         /* HP damage; more likely--but less severe--with missiles */
265         loss = thrown_weapon ? rnd(6) : rn1(10, 6);
266         losehp(loss, pkiller, kprefix); /* poison damage */
267     } else {
268         /* attribute loss; if typ is A_STR, reduction in current and
269            maximum HP will occur once strength has dropped down to 3 */
270         loss = (thrown_weapon || !fatal) ? 1 : d(2, 2); /* was rn1(3,3) */
271         /* check that a stat change was made */
272         if (adjattrib(typ, -loss, 1))
273             poisontell(typ, TRUE);
274     }
275
276     if (u.uhp < 1) {
277         killer.format = kprefix;
278         Strcpy(killer.name, pkiller);
279         /* "Poisoned by a poisoned ___" is redundant */
280         done(strstri(pkiller, "poison") ? DIED : POISONING);
281     }
282     (void) encumber_msg();
283 }
284
285 void
286 change_luck(n)
287 register schar n;
288 {
289     u.uluck += n;
290     if (u.uluck < 0 && u.uluck < LUCKMIN)
291         u.uluck = LUCKMIN;
292     if (u.uluck > 0 && u.uluck > LUCKMAX)
293         u.uluck = LUCKMAX;
294 }
295
296 int
297 stone_luck(parameter)
298 boolean parameter; /* So I can't think up of a good name.  So sue me. --KAA */
299 {
300     register struct obj *otmp;
301     register long bonchance = 0;
302
303     for (otmp = invent; otmp; otmp = otmp->nobj)
304         if (confers_luck(otmp)) {
305             if (otmp->cursed)
306                 bonchance -= otmp->quan;
307             else if (otmp->blessed)
308                 bonchance += otmp->quan;
309             else if (parameter)
310                 bonchance += otmp->quan;
311         }
312
313     return sgn((int) bonchance);
314 }
315
316 /* there has just been an inventory change affecting a luck-granting item */
317 void
318 set_moreluck()
319 {
320     int luckbon = stone_luck(TRUE);
321
322     if (!luckbon && !carrying(LUCKSTONE))
323         u.moreluck = 0;
324     else if (luckbon >= 0)
325         u.moreluck = LUCKADD;
326     else
327         u.moreluck = -LUCKADD;
328 }
329
330 void
331 restore_attrib()
332 {
333     int i;
334
335     for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
336
337         if (ATEMP(i) && ATIME(i)) {
338             if (!(--(ATIME(i)))) { /* countdown for change */
339                 ATEMP(i) += ATEMP(i) > 0 ? -1 : 1;
340
341                 if (ATEMP(i)) /* reset timer */
342                     ATIME(i) = 100 / ACURR(A_CON);
343             }
344         }
345     }
346     (void) encumber_msg();
347 }
348
349 #define AVAL 50 /* tune value for exercise gains */
350
351 void
352 exercise(i, inc_or_dec)
353 int i;
354 boolean inc_or_dec;
355 {
356     debugpline0("Exercise:");
357     if (i == A_INT || i == A_CHA)
358         return; /* can't exercise these */
359
360     /* no physical exercise while polymorphed; the body's temporary */
361     if (Upolyd && i != A_WIS)
362         return;
363
364     if (abs(AEXE(i)) < AVAL) {
365         /*
366          *      Law of diminishing returns (Part I):
367          *
368          *      Gain is harder at higher attribute values.
369          *      79% at "3" --> 0% at "18"
370          *      Loss is even at all levels (50%).
371          *
372          *      Note: *YES* ACURR is the right one to use.
373          */
374         AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2);
375         debugpline3("%s, %s AEXE = %d",
376                     (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" : (i == A_DEX)
377                                                                       ? "Dex"
378                                                                       : "Con",
379                     (inc_or_dec) ? "inc" : "dec", AEXE(i));
380     }
381     if (moves > 0 && (i == A_STR || i == A_CON))
382         (void) encumber_msg();
383 }
384
385 STATIC_OVL void
386 exerper()
387 {
388     if (!(moves % 10)) {
389         /* Hunger Checks */
390
391         int hs = (u.uhunger > 1000) ? SATIATED : (u.uhunger > 150)
392                                                      ? NOT_HUNGRY
393                                                      : (u.uhunger > 50)
394                                                            ? HUNGRY
395                                                            : (u.uhunger > 0)
396                                                                  ? WEAK
397                                                                  : FAINTING;
398
399         debugpline0("exerper: Hunger checks");
400         switch (hs) {
401         case SATIATED:
402             exercise(A_DEX, FALSE);
403             if (Role_if(PM_MONK))
404                 exercise(A_WIS, FALSE);
405             break;
406         case NOT_HUNGRY:
407             exercise(A_CON, TRUE);
408             break;
409         case WEAK:
410             exercise(A_STR, FALSE);
411             if (Role_if(PM_MONK)) /* fasting */
412                 exercise(A_WIS, TRUE);
413             break;
414         case FAINTING:
415         case FAINTED:
416             exercise(A_CON, FALSE);
417             break;
418         }
419
420         /* Encumbrance Checks */
421         debugpline0("exerper: Encumber checks");
422         switch (near_capacity()) {
423         case MOD_ENCUMBER:
424             exercise(A_STR, TRUE);
425             break;
426         case HVY_ENCUMBER:
427             exercise(A_STR, TRUE);
428             exercise(A_DEX, FALSE);
429             break;
430         case EXT_ENCUMBER:
431             exercise(A_DEX, FALSE);
432             exercise(A_CON, FALSE);
433             break;
434         }
435     }
436
437     /* status checks */
438     if (!(moves % 5)) {
439         debugpline0("exerper: Status checks");
440         if ((HClairvoyant & (INTRINSIC | TIMEOUT)) && !BClairvoyant)
441             exercise(A_WIS, TRUE);
442         if (HRegeneration)
443             exercise(A_STR, TRUE);
444
445         if (Sick || Vomiting)
446             exercise(A_CON, FALSE);
447         if (Confusion || Hallucination)
448             exercise(A_WIS, FALSE);
449         if ((Wounded_legs && !u.usteed) || Fumbling || HStun)
450             exercise(A_DEX, FALSE);
451     }
452 }
453
454 /* exercise/abuse text (must be in attribute order, not botl order);
455    phrased as "You must have been [][0]." or "You haven't been [][1]." */
456 static NEARDATA const char *const exertext[A_MAX][2] = {
457     { "exercising diligently", "exercising properly" },           /* Str */
458     { 0, 0 },                                                     /* Int */
459     { "very observant", "paying attention" },                     /* Wis */
460     { "working on your reflexes", "working on reflexes lately" }, /* Dex */
461     { "leading a healthy life-style", "watching your health" },   /* Con */
462     { 0, 0 },                                                     /* Cha */
463 };
464
465 void
466 exerchk()
467 {
468     int i, ax, mod_val, lolim, hilim;
469
470     /*  Check out the periodic accumulations */
471     exerper();
472
473     if (moves >= context.next_attrib_check) {
474         debugpline1("exerchk: ready to test. multi = %d.", multi);
475     }
476     /*  Are we ready for a test? */
477     if (moves >= context.next_attrib_check && !multi) {
478         debugpline0("exerchk: testing.");
479         /*
480          *      Law of diminishing returns (Part II):
481          *
482          *      The effects of "exercise" and "abuse" wear
483          *      off over time.  Even if you *don't* get an
484          *      increase/decrease, you lose some of the
485          *      accumulated effects.
486          */
487         for (i = 0; i < A_MAX; ++i) {
488             ax = AEXE(i);
489             /* nothing to do here if no exercise or abuse has occurred
490                (Int and Cha always fall into this category) */
491             if (!ax)
492                 continue; /* ok to skip nextattrib */
493
494             mod_val = sgn(ax); /* +1 or -1; used below */
495             /* no further effect for exercise if at max or abuse if at min;
496                can't exceed 18 via exercise even if actual max is higher */
497             lolim = ATTRMIN(i); /* usually 3; might be higher */
498             hilim = ATTRMAX(i); /* usually 18; maybe lower or higher */
499             if (hilim > 18)
500                 hilim = 18;
501             if ((ax < 0) ? (ABASE(i) <= lolim) : (ABASE(i) >= hilim))
502                 goto nextattrib;
503             /* can't exercise non-Wisdom while polymorphed; previous
504                exercise/abuse gradually wears off without impact then */
505             if (Upolyd && i != A_WIS)
506                 goto nextattrib;
507
508             debugpline2("exerchk: testing %s (%d).",
509                         (i == A_STR)
510                             ? "Str"
511                             : (i == A_INT)
512                                   ? "Int?"
513                                   : (i == A_WIS)
514                                         ? "Wis"
515                                         : (i == A_DEX)
516                                               ? "Dex"
517                                               : (i == A_CON)
518                                                     ? "Con"
519                                                     : (i == A_CHA)
520                                                           ? "Cha?"
521                                                           : "???",
522                         ax);
523             /*
524              *  Law of diminishing returns (Part III):
525              *
526              *  You don't *always* gain by exercising.
527              *  [MRS 92/10/28 - Treat Wisdom specially for balance.]
528              */
529             if (rn2(AVAL) > ((i != A_WIS) ? (abs(ax) * 2 / 3) : abs(ax)))
530                 goto nextattrib;
531
532             debugpline1("exerchk: changing %d.", i);
533             if (adjattrib(i, mod_val, -1)) {
534                 debugpline1("exerchk: changed %d.", i);
535                 /* if you actually changed an attrib - zero accumulation */
536                 AEXE(i) = ax = 0;
537                 /* then print an explanation */
538                 You("%s %s.",
539                     (mod_val > 0) ? "must have been" : "haven't been",
540                     exertext[i][(mod_val > 0) ? 0 : 1]);
541             }
542         nextattrib:
543             /* this used to be ``AEXE(i) /= 2'' but that would produce
544                platform-dependent rounding/truncation for negative vals */
545             AEXE(i) = (abs(ax) / 2) * mod_val;
546         }
547         context.next_attrib_check += rn1(200, 800);
548         debugpline1("exerchk: next check at %ld.", context.next_attrib_check);
549     }
550 }
551
552 void
553 init_attr(np)
554 register int np;
555 {
556     register int i, x, tryct;
557
558     for (i = 0; i < A_MAX; i++) {
559         ABASE(i) = AMAX(i) = urole.attrbase[i];
560         ATEMP(i) = ATIME(i) = 0;
561         np -= urole.attrbase[i];
562     }
563
564     tryct = 0;
565     while (np > 0 && tryct < 100) {
566         x = rn2(100);
567         for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++)
568             ;
569         if (i >= A_MAX)
570             continue; /* impossible */
571
572         if (ABASE(i) >= ATTRMAX(i)) {
573             tryct++;
574             continue;
575         }
576         tryct = 0;
577         ABASE(i)++;
578         AMAX(i)++;
579         np--;
580     }
581
582     tryct = 0;
583     while (np < 0 && tryct < 100) { /* for redistribution */
584
585         x = rn2(100);
586         for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++)
587             ;
588         if (i >= A_MAX)
589             continue; /* impossible */
590
591         if (ABASE(i) <= ATTRMIN(i)) {
592             tryct++;
593             continue;
594         }
595         tryct = 0;
596         ABASE(i)--;
597         AMAX(i)--;
598         np++;
599     }
600 }
601
602 void
603 redist_attr()
604 {
605     register int i, tmp;
606
607     for (i = 0; i < A_MAX; i++) {
608         if (i == A_INT || i == A_WIS)
609             continue;
610         /* Polymorphing doesn't change your mind */
611         tmp = AMAX(i);
612         AMAX(i) += (rn2(5) - 2);
613         if (AMAX(i) > ATTRMAX(i))
614             AMAX(i) = ATTRMAX(i);
615         if (AMAX(i) < ATTRMIN(i))
616             AMAX(i) = ATTRMIN(i);
617         ABASE(i) = ABASE(i) * AMAX(i) / tmp;
618         /* ABASE(i) > ATTRMAX(i) is impossible */
619         if (ABASE(i) < ATTRMIN(i))
620             ABASE(i) = ATTRMIN(i);
621     }
622     (void) encumber_msg();
623 }
624
625 STATIC_OVL
626 void
627 postadjabil(ability)
628 long *ability;
629 {
630     if (!ability)
631         return;
632     if (ability == &(HWarning) || ability == &(HSee_invisible))
633         see_monsters();
634 }
635
636 STATIC_OVL const struct innate *
637 check_innate_abil(ability, frommask)
638 long *ability;
639 long frommask;
640 {
641     const struct innate *abil = 0;
642
643     if (frommask == FROMEXPER)
644         switch (Role_switch) {
645         case PM_ARCHEOLOGIST:
646             abil = arc_abil;
647             break;
648         case PM_BARBARIAN:
649             abil = bar_abil;
650             break;
651         case PM_CAVEMAN:
652             abil = cav_abil;
653             break;
654         case PM_HEALER:
655             abil = hea_abil;
656             break;
657         case PM_KNIGHT:
658             abil = kni_abil;
659             break;
660         case PM_MONK:
661             abil = mon_abil;
662             break;
663         case PM_PRIEST:
664             abil = pri_abil;
665             break;
666         case PM_RANGER:
667             abil = ran_abil;
668             break;
669         case PM_ROGUE:
670             abil = rog_abil;
671             break;
672         case PM_SAMURAI:
673             abil = sam_abil;
674             break;
675         case PM_TOURIST:
676             abil = tou_abil;
677             break;
678         case PM_VALKYRIE:
679             abil = val_abil;
680             break;
681         case PM_WIZARD:
682             abil = wiz_abil;
683             break;
684         default:
685             break;
686         }
687     else if (frommask == FROMRACE)
688         switch (Race_switch) {
689         case PM_ELF:
690             abil = elf_abil;
691             break;
692         case PM_ORC:
693             abil = orc_abil;
694             break;
695         case PM_HUMAN:
696         case PM_DWARF:
697         case PM_GNOME:
698         default:
699             break;
700         }
701
702     while (abil && abil->ability) {
703         if ((abil->ability == ability) && (u.ulevel >= abil->ulevel))
704             return abil;
705         abil++;
706     }
707     return (struct innate *) 0;
708 }
709
710 /*
711  * returns 1 if FROMRACE or FROMEXPER and exper level == 1
712  * returns 2 if FROMEXPER and exper level > 1
713  * otherwise returns 0
714  */
715 STATIC_OVL int
716 innately(ability)
717 long *ability;
718 {
719     const struct innate *iptr;
720
721     if ((iptr = check_innate_abil(ability, FROMRACE)) != 0)
722         return 1;
723     else if ((iptr = check_innate_abil(ability, FROMEXPER)) != 0)
724         return (iptr->ulevel == 1) ? 1 : 2;
725     return 0;
726 }
727
728 int
729 is_innate(propidx)
730 int propidx;
731 {
732     if (propidx == BLINDED && !haseyes(youmonst.data))
733         return 1;
734     return innately(&u.uprops[propidx].intrinsic);
735 }
736
737 char *
738 from_what(propidx)
739 int propidx; /* special cases can have negative values */
740 {
741     static char buf[BUFSZ];
742
743     buf[0] = '\0';
744     /*
745      * Restrict the source of the attributes just to debug mode for now
746      */
747     if (wizard) {
748         static NEARDATA const char because_of[] = " because of %s";
749
750         if (propidx >= 0) {
751             char *p;
752             struct obj *obj = (struct obj *) 0;
753             int innate = is_innate(propidx);
754
755             if (innate == 2)
756                 Strcpy(buf, " because of your experience");
757             else if (innate == 1)
758                 Strcpy(buf, " innately");
759             else if (wizard
760                      && (obj = what_gives(&u.uprops[propidx].extrinsic)))
761                 Sprintf(buf, because_of, obj->oartifact
762                                              ? bare_artifactname(obj)
763                                              : ysimple_name(obj));
764             else if (propidx == BLINDED && u.uroleplay.blind)
765                 Sprintf(buf, " from birth");
766             else if (propidx == BLINDED && Blindfolded_only)
767                 Sprintf(buf, because_of, ysimple_name(ublindf));
768
769             /* remove some verbosity and/or redundancy */
770             if ((p = strstri(buf, " pair of ")) != 0)
771                 copynchars(p + 1, p + 9, BUFSZ); /* overlapping buffers ok */
772             else if (propidx == STRANGLED
773                      && (p = strstri(buf, " of strangulation")) != 0)
774                 *p = '\0';
775
776         } else { /* negative property index */
777             /* if more blocking capabilities get implemented we'll need to
778                replace this with what_blocks() comparable to what_gives() */
779             switch (-propidx) {
780             case BLINDED:
781                 if (ublindf
782                     && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD)
783                     Sprintf(buf, because_of, bare_artifactname(ublindf));
784                 break;
785             case INVIS:
786                 if (u.uprops[INVIS].blocked & W_ARMC)
787                     Sprintf(buf, because_of,
788                             ysimple_name(uarmc)); /* mummy wrapping */
789                 break;
790             case CLAIRVOYANT:
791                 if (wizard && (u.uprops[CLAIRVOYANT].blocked & W_ARMH))
792                     Sprintf(buf, because_of,
793                             ysimple_name(uarmh)); /* cornuthaum */
794                 break;
795             }
796         }
797
798     } /*wizard*/
799     return buf;
800 }
801
802 void
803 adjabil(oldlevel, newlevel)
804 int oldlevel, newlevel;
805 {
806     register const struct innate *abil, *rabil;
807     long prevabil, mask = FROMEXPER;
808
809     switch (Role_switch) {
810     case PM_ARCHEOLOGIST:
811         abil = arc_abil;
812         break;
813     case PM_BARBARIAN:
814         abil = bar_abil;
815         break;
816     case PM_CAVEMAN:
817         abil = cav_abil;
818         break;
819     case PM_HEALER:
820         abil = hea_abil;
821         break;
822     case PM_KNIGHT:
823         abil = kni_abil;
824         break;
825     case PM_MONK:
826         abil = mon_abil;
827         break;
828     case PM_PRIEST:
829         abil = pri_abil;
830         break;
831     case PM_RANGER:
832         abil = ran_abil;
833         break;
834     case PM_ROGUE:
835         abil = rog_abil;
836         break;
837     case PM_SAMURAI:
838         abil = sam_abil;
839         break;
840     case PM_TOURIST:
841         abil = tou_abil;
842         break;
843     case PM_VALKYRIE:
844         abil = val_abil;
845         break;
846     case PM_WIZARD:
847         abil = wiz_abil;
848         break;
849     default:
850         abil = 0;
851         break;
852     }
853
854     switch (Race_switch) {
855     case PM_ELF:
856         rabil = elf_abil;
857         break;
858     case PM_ORC:
859         rabil = orc_abil;
860         break;
861     case PM_HUMAN:
862     case PM_DWARF:
863     case PM_GNOME:
864     default:
865         rabil = 0;
866         break;
867     }
868
869     while (abil || rabil) {
870         /* Have we finished with the intrinsics list? */
871         if (!abil || !abil->ability) {
872             /* Try the race intrinsics */
873             if (!rabil || !rabil->ability)
874                 break;
875             abil = rabil;
876             rabil = 0;
877             mask = FROMRACE;
878         }
879         prevabil = *(abil->ability);
880         if (oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
881             /* Abilities gained at level 1 can never be lost
882              * via level loss, only via means that remove _any_
883              * sort of ability.  A "gain" of such an ability from
884              * an outside source is devoid of meaning, so we set
885              * FROMOUTSIDE to avoid such gains.
886              */
887             if (abil->ulevel == 1)
888                 *(abil->ability) |= (mask | FROMOUTSIDE);
889             else
890                 *(abil->ability) |= mask;
891             if (!(*(abil->ability) & INTRINSIC & ~mask)) {
892                 if (*(abil->gainstr))
893                     You_feel("%s!", abil->gainstr);
894             }
895         } else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) {
896             *(abil->ability) &= ~mask;
897             if (!(*(abil->ability) & INTRINSIC)) {
898                 if (*(abil->losestr))
899                     You_feel("%s!", abil->losestr);
900                 else if (*(abil->gainstr))
901                     You_feel("less %s!", abil->gainstr);
902             }
903         }
904         if (prevabil != *(abil->ability)) /* it changed */
905             postadjabil(abil->ability);
906         abil++;
907     }
908
909     if (oldlevel > 0) {
910         if (newlevel > oldlevel)
911             add_weapon_skill(newlevel - oldlevel);
912         else
913             lose_weapon_skill(oldlevel - newlevel);
914     }
915 }
916
917 int
918 newhp()
919 {
920     int hp, conplus;
921
922     if (u.ulevel == 0) {
923         /* Initialize hit points */
924         hp = urole.hpadv.infix + urace.hpadv.infix;
925         if (urole.hpadv.inrnd > 0)
926             hp += rnd(urole.hpadv.inrnd);
927         if (urace.hpadv.inrnd > 0)
928             hp += rnd(urace.hpadv.inrnd);
929         if (moves <= 1L) { /* initial hero; skip for polyself to new man */
930             /* Initialize alignment stuff */
931             u.ualign.type = aligns[flags.initalign].value;
932             u.ualign.record = urole.initrecord;
933         }
934         /* no Con adjustment for initial hit points */
935     } else {
936         if (u.ulevel < urole.xlev) {
937             hp = urole.hpadv.lofix + urace.hpadv.lofix;
938             if (urole.hpadv.lornd > 0)
939                 hp += rnd(urole.hpadv.lornd);
940             if (urace.hpadv.lornd > 0)
941                 hp += rnd(urace.hpadv.lornd);
942         } else {
943             hp = urole.hpadv.hifix + urace.hpadv.hifix;
944             if (urole.hpadv.hirnd > 0)
945                 hp += rnd(urole.hpadv.hirnd);
946             if (urace.hpadv.hirnd > 0)
947                 hp += rnd(urace.hpadv.hirnd);
948         }
949         if (ACURR(A_CON) <= 3)
950             conplus = -2;
951         else if (ACURR(A_CON) <= 6)
952             conplus = -1;
953         else if (ACURR(A_CON) <= 14)
954             conplus = 0;
955         else if (ACURR(A_CON) <= 16)
956             conplus = 1;
957         else if (ACURR(A_CON) == 17)
958             conplus = 2;
959         else if (ACURR(A_CON) == 18)
960             conplus = 3;
961         else
962             conplus = 4;
963         hp += conplus;
964     }
965     if (hp <= 0)
966         hp = 1;
967     if (u.ulevel < MAXULEV)
968         u.uhpinc[u.ulevel] = (xchar) hp;
969     return hp;
970 }
971
972 schar
973 acurr(x)
974 int x;
975 {
976     register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]);
977
978     if (x == A_STR) {
979         if (tmp >= 125 || (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER))
980             return (schar) 125;
981         else
982 #ifdef WIN32_BUG
983             return (x = ((tmp <= 3) ? 3 : tmp));
984 #else
985         return (schar) ((tmp <= 3) ? 3 : tmp);
986 #endif
987     } else if (x == A_CHA) {
988         if (tmp < 18
989             && (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS
990                 || u.umonnum == PM_INCUBUS))
991             return (schar) 18;
992     } else if (x == A_INT || x == A_WIS) {
993         /* yes, this may raise int/wis if player is sufficiently
994          * stupid.  there are lower levels of cognition than "dunce".
995          */
996         if (uarmh && uarmh->otyp == DUNCE_CAP)
997             return (schar) 6;
998     }
999 #ifdef WIN32_BUG
1000     return (x = ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
1001 #else
1002     return (schar) ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp);
1003 #endif
1004 }
1005
1006 /* condense clumsy ACURR(A_STR) value into value that fits into game formulas
1007  */
1008 schar
1009 acurrstr()
1010 {
1011     register int str = ACURR(A_STR);
1012
1013     if (str <= 18)
1014         return (schar) str;
1015     if (str <= 121)
1016         return (schar) (19 + str / 50); /* map to 19..21 */
1017     else
1018         return (schar) (min(str, 125) - 100); /* 22..25 */
1019 }
1020
1021 /* when wearing (or taking off) an unID'd item, this routine is used
1022    to distinguish between observable +0 result and no-visible-effect
1023    due to an attribute not being able to exceed maximum or minimum */
1024 boolean
1025 extremeattr(attrindx) /* does attrindx's value match its max or min? */
1026 int attrindx;
1027 {
1028     /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */
1029     int lolimit = 3, hilimit = 25, curval = ACURR(attrindx);
1030
1031     /* upper limit for Str is 25 but its value is encoded differently */
1032     if (attrindx == A_STR) {
1033         hilimit = STR19(25); /* 125 */
1034         /* lower limit for Str can also be 25 */
1035         if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER)
1036             lolimit = hilimit;
1037     }
1038     /* this exception is hypothetical; the only other worn item affecting
1039        Int or Wis is another helmet so can't be in use at the same time */
1040     if (attrindx == A_INT || attrindx == A_WIS) {
1041         if (uarmh && uarmh->otyp == DUNCE_CAP)
1042             hilimit = lolimit = 6;
1043     }
1044
1045     /* are we currently at either limit? */
1046     return (curval == lolimit || curval == hilimit) ? TRUE : FALSE;
1047 }
1048
1049 /* avoid possible problems with alignment overflow, and provide a centralized
1050    location for any future alignment limits */
1051 void
1052 adjalign(n)
1053 int n;
1054 {
1055     int newalign = u.ualign.record + n;
1056
1057     if (n < 0) {
1058         if (newalign < u.ualign.record)
1059             u.ualign.record = newalign;
1060     } else if (newalign > u.ualign.record) {
1061         u.ualign.record = newalign;
1062         if (u.ualign.record > ALIGNLIM)
1063             u.ualign.record = ALIGNLIM;
1064     }
1065 }
1066
1067 /* change hero's alignment type, possibly losing use of artifacts */
1068 void
1069 uchangealign(newalign, reason)
1070 int newalign;
1071 int reason; /* 0==conversion, 1==helm-of-OA on, 2==helm-of-OA off */
1072 {
1073     aligntyp oldalign = u.ualign.type;
1074
1075     u.ublessed = 0;   /* lose divine protection */
1076     context.botl = 1; /* status line needs updating */
1077     if (reason == 0) {
1078         /* conversion via altar */
1079         u.ualignbase[A_CURRENT] = (aligntyp) newalign;
1080         /* worn helm of opposite alignment might block change */
1081         if (!uarmh || uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT)
1082             u.ualign.type = u.ualignbase[A_CURRENT];
1083         You("have a %ssense of a new direction.",
1084             (u.ualign.type != oldalign) ? "sudden " : "");
1085     } else {
1086         /* putting on or taking off a helm of opposite alignment */
1087         u.ualign.type = (aligntyp) newalign;
1088         if (reason == 1)
1089             Your("mind oscillates %s.", Hallucination ? "wildly" : "briefly");
1090         else if (reason == 2)
1091             Your("mind is %s.", Hallucination
1092                                     ? "much of a muchness"
1093                                     : "back in sync with your body");
1094     }
1095
1096     if (u.ualign.type != oldalign) {
1097         u.ualign.record = 0; /* slate is wiped clean */
1098         retouch_equipment(0);
1099     }
1100 }
1101
1102 /*attrib.c*/