1 /* NetHack 3.6 attrib.c $NHDT-Date: 1455357587 2016/02/13 09:59:47 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.55 $ */
2 /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* attribute modification routines. */
10 /* part of the output on gain or loss of attribute */
12 *const plusattr
[] = { "strong", "smart", "wise",
13 "agile", "tough", "charismatic" },
14 *const minusattr
[] = { "weak", "stupid",
16 "fragile", "repulsive" };
18 static const struct innate
{
21 const char *gainstr
, *losestr
;
22 } arc_abil
[] = { { 1, &(HStealth
), "", "" },
23 { 1, &(HFast
), "", "" },
24 { 10, &(HSearching
), "perceptive", "" },
27 bar_abil
[] = { { 1, &(HPoison_resistance
), "", "" },
28 { 7, &(HFast
), "quick", "slow" },
29 { 15, &(HStealth
), "stealthy", "" },
32 cav_abil
[] = { { 7, &(HFast
), "quick", "slow" },
33 { 15, &(HWarning
), "sensitive", "" },
36 hea_abil
[] = { { 1, &(HPoison_resistance
), "", "" },
37 { 15, &(HWarning
), "sensitive", "" },
40 kni_abil
[] = { { 7, &(HFast
), "quick", "slow" }, { 0, 0, 0, 0 } },
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" },
55 pri_abil
[] = { { 15, &(HWarning
), "sensitive", "" },
56 { 20, &(HFire_resistance
), "cool", "warmer" },
59 ran_abil
[] = { { 1, &(HSearching
), "", "" },
60 { 7, &(HStealth
), "stealthy", "" },
61 { 15, &(HSee_invisible
), "", "" },
64 rog_abil
[] = { { 1, &(HStealth
), "", "" },
65 { 10, &(HSearching
), "perceptive", "" },
68 sam_abil
[] = { { 1, &(HFast
), "", "" },
69 { 15, &(HStealth
), "stealthy", "" },
72 tou_abil
[] = { { 10, &(HSearching
), "perceptive", "" },
73 { 20, &(HPoison_resistance
), "hardy", "" },
76 val_abil
[] = { { 1, &(HCold_resistance
), "", "" },
77 { 1, &(HStealth
), "", "" },
78 { 7, &(HFast
), "quick", "slow" },
81 wiz_abil
[] = { { 15, &(HWarning
), "sensitive", "" },
82 { 17, &(HTeleport_control
), "controlled", "uncontrolled" },
85 /* Intrinsics conferred by race */
86 dwa_abil
[] = { { 1, &HInfravision
, "", "" },
89 elf_abil
[] = { { 1, &HInfravision
, "", "" },
90 { 4, &HSleep_resistance
, "awake", "tired" },
93 gno_abil
[] = { { 1, &HInfravision
, "", "" },
96 orc_abil
[] = { { 1, &HInfravision
, "", "" },
97 { 1, &HPoison_resistance
, "", "" },
100 hum_abil
[] = { { 0, 0, 0, 0 } };
102 STATIC_DCL
void NDECL(exerper
);
103 STATIC_DCL
void FDECL(postadjabil
, (long *));
104 STATIC_DCL
const struct innate
*FDECL(role_abil
, (int));
105 STATIC_DCL
const struct innate
*FDECL(check_innate_abil
, (long *, long));
106 STATIC_DCL
int FDECL(innately
, (long *));
108 /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
110 adjattrib(ndx
, incr
, msgflg
)
112 int msgflg
; /* positive => no message, zero => message, and */
113 { /* negative => conditional (msg if change made) */
118 if (Fixed_abil
|| !incr
)
121 if ((ndx
== A_INT
|| ndx
== A_WIS
) && uarmh
&& uarmh
->otyp
== DUNCE_CAP
) {
123 Your("cap constricts briefly, then relaxes again.");
127 old_acurr
= ACURR(ndx
);
130 if (ABASE(ndx
) > AMAX(ndx
)) {
131 incr
= ABASE(ndx
) - AMAX(ndx
);
133 if (AMAX(ndx
) > ATTRMAX(ndx
))
134 AMAX(ndx
) = ATTRMAX(ndx
);
135 ABASE(ndx
) = AMAX(ndx
);
137 attrstr
= plusattr
[ndx
];
138 abonflg
= (ABON(ndx
) < 0);
141 if (ABASE(ndx
) < ATTRMIN(ndx
)) {
142 incr
= ABASE(ndx
) - ATTRMIN(ndx
);
143 ABASE(ndx
) = ATTRMIN(ndx
);
145 if (AMAX(ndx
) < ATTRMIN(ndx
))
146 AMAX(ndx
) = ATTRMIN(ndx
);
148 attrstr
= minusattr
[ndx
];
149 abonflg
= (ABON(ndx
) > 0);
151 if (ACURR(ndx
) == old_acurr
) {
152 if (msgflg
== 0 && flags
.verbose
)
153 pline("You're %s as %s as you can get.",
154 abonflg
? "currently" : "already", attrstr
);
159 You_feel("%s%s!", (incr
> 1 || incr
< -1) ? "very " : "", attrstr
);
161 if (moves
> 1 && (ndx
== A_STR
|| ndx
== A_CON
))
162 (void) encumber_msg();
167 gainstr(otmp
, incr
, givemsg
)
175 if (ABASE(A_STR
) < 18)
176 num
= (rn2(4) ? 1 : rnd(6));
177 else if (ABASE(A_STR
) < STR18(85))
182 (void) adjattrib(A_STR
, (otmp
&& otmp
->cursed
) ? -num
: num
,
186 /* may kill you; cause may be poison or monster like 'a' */
191 int ustr
= ABASE(A_STR
) - num
;
204 (void) adjattrib(A_STR
, -num
, 1);
207 static const struct poison_effect_message
{
208 void VDECL((*delivery_func
), (const char *, ...));
209 const char *effect_msg
;
211 { You_feel
, "weaker" }, /* A_STR */
212 { Your
, "brain is on fire" }, /* A_INT */
213 { Your
, "judgement is impaired" }, /* A_WIS */
214 { Your
, "muscles won't obey you" }, /* A_DEX */
215 { You_feel
, "very sick" }, /* A_CON */
216 { You
, "break out in hives" } /* A_CHA */
219 /* feedback for attribute loss due to poisoning */
221 poisontell(typ
, exclaim
)
222 int typ
; /* which attribute */
223 boolean exclaim
; /* emphasis */
225 void VDECL((*func
), (const char *, ...)) = poiseff
[typ
].delivery_func
;
227 (*func
)("%s%c", poiseff
[typ
].effect_msg
, exclaim
? '!' : '.');
230 /* called when an attack or trap has poisoned the hero (used to be in mon.c)
233 poisoned(reason
, typ
, pkiller
, fatal
, thrown_weapon
)
234 const char *reason
, /* controls what messages we display */
235 *pkiller
; /* for score+log file if fatal */
236 int typ
, fatal
; /* if fatal is 0, limit damage to adjattrib */
237 boolean thrown_weapon
; /* thrown weapons are less deadly */
239 int i
, loss
, kprefix
= KILLED_BY_AN
;
241 /* inform player about being poisoned unless that's already been done;
242 "blast" has given a "blast of poison gas" message; "poison arrow",
243 "poison dart", etc have implicitly given poison messages too... */
244 if (strcmp(reason
, "blast") && !strstri(reason
, "poison")) {
245 boolean plural
= (reason
[strlen(reason
) - 1] == 's') ? 1 : 0;
247 /* avoid "The" Orcus's sting was poisoned... */
248 pline("%s%s %s poisoned!",
249 isupper((uchar
) *reason
) ? "" : "The ", reason
,
250 plural
? "were" : "was");
252 if (Poison_resistance
) {
253 if (!strcmp(reason
, "blast"))
254 shieldeff(u
.ux
, u
.uy
);
255 pline_The("poison doesn't seem to affect you.");
259 /* suppress killer prefix if it already has one */
260 i
= name_to_mon(pkiller
);
261 if (i
>= LOW_PM
&& (mons
[i
].geno
& G_UNIQ
)) {
263 if (!type_is_pname(&mons
[i
]))
264 pkiller
= the(pkiller
);
265 } else if (!strncmpi(pkiller
, "the ", 4) || !strncmpi(pkiller
, "an ", 3)
266 || !strncmpi(pkiller
, "a ", 2)) {
267 /*[ does this need a plural check too? ]*/
271 i
= !fatal
? 1 : rn2(fatal
+ (thrown_weapon
? 20 : 0));
272 if (i
== 0 && typ
!= A_CHA
) {
275 pline_The("poison was deadly...");
277 /* HP damage; more likely--but less severe--with missiles */
278 loss
= thrown_weapon
? rnd(6) : rn1(10, 6);
279 losehp(loss
, pkiller
, kprefix
); /* poison damage */
281 /* attribute loss; if typ is A_STR, reduction in current and
282 maximum HP will occur once strength has dropped down to 3 */
283 loss
= (thrown_weapon
|| !fatal
) ? 1 : d(2, 2); /* was rn1(3,3) */
284 /* check that a stat change was made */
285 if (adjattrib(typ
, -loss
, 1))
286 poisontell(typ
, TRUE
);
290 killer
.format
= kprefix
;
291 Strcpy(killer
.name
, pkiller
);
292 /* "Poisoned by a poisoned ___" is redundant */
293 done(strstri(pkiller
, "poison") ? DIED
: POISONING
);
295 (void) encumber_msg();
303 if (u
.uluck
< 0 && u
.uluck
< LUCKMIN
)
305 if (u
.uluck
> 0 && u
.uluck
> LUCKMAX
)
310 stone_luck(parameter
)
311 boolean parameter
; /* So I can't think up of a good name. So sue me. --KAA */
313 register struct obj
*otmp
;
314 register long bonchance
= 0;
316 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
317 if (confers_luck(otmp
)) {
319 bonchance
-= otmp
->quan
;
320 else if (otmp
->blessed
)
321 bonchance
+= otmp
->quan
;
323 bonchance
+= otmp
->quan
;
326 return sgn((int) bonchance
);
329 /* there has just been an inventory change affecting a luck-granting item */
333 int luckbon
= stone_luck(TRUE
);
335 if (!luckbon
&& !carrying(LUCKSTONE
))
337 else if (luckbon
>= 0)
338 u
.moreluck
= LUCKADD
;
340 u
.moreluck
= -LUCKADD
;
348 for (i
= 0; i
< A_MAX
; i
++) { /* all temporary losses/gains */
350 if (ATEMP(i
) && ATIME(i
)) {
351 if (!(--(ATIME(i
)))) { /* countdown for change */
352 ATEMP(i
) += ATEMP(i
) > 0 ? -1 : 1;
354 if (ATEMP(i
)) /* reset timer */
355 ATIME(i
) = 100 / ACURR(A_CON
);
359 (void) encumber_msg();
362 #define AVAL 50 /* tune value for exercise gains */
365 exercise(i
, inc_or_dec
)
369 debugpline0("Exercise:");
370 if (i
== A_INT
|| i
== A_CHA
)
371 return; /* can't exercise these */
373 /* no physical exercise while polymorphed; the body's temporary */
374 if (Upolyd
&& i
!= A_WIS
)
377 if (abs(AEXE(i
)) < AVAL
) {
379 * Law of diminishing returns (Part I):
381 * Gain is harder at higher attribute values.
382 * 79% at "3" --> 0% at "18"
383 * Loss is even at all levels (50%).
385 * Note: *YES* ACURR is the right one to use.
387 AEXE(i
) += (inc_or_dec
) ? (rn2(19) > ACURR(i
)) : -rn2(2);
388 debugpline3("%s, %s AEXE = %d",
389 (i
== A_STR
) ? "Str" : (i
== A_WIS
) ? "Wis" : (i
== A_DEX
)
392 (inc_or_dec
) ? "inc" : "dec", AEXE(i
));
394 if (moves
> 0 && (i
== A_STR
|| i
== A_CON
))
395 (void) encumber_msg();
404 int hs
= (u
.uhunger
> 1000) ? SATIATED
: (u
.uhunger
> 150)
412 debugpline0("exerper: Hunger checks");
415 exercise(A_DEX
, FALSE
);
416 if (Role_if(PM_MONK
))
417 exercise(A_WIS
, FALSE
);
420 exercise(A_CON
, TRUE
);
423 exercise(A_STR
, FALSE
);
424 if (Role_if(PM_MONK
)) /* fasting */
425 exercise(A_WIS
, TRUE
);
429 exercise(A_CON
, FALSE
);
433 /* Encumbrance Checks */
434 debugpline0("exerper: Encumber checks");
435 switch (near_capacity()) {
437 exercise(A_STR
, TRUE
);
440 exercise(A_STR
, TRUE
);
441 exercise(A_DEX
, FALSE
);
444 exercise(A_DEX
, FALSE
);
445 exercise(A_CON
, FALSE
);
452 debugpline0("exerper: Status checks");
453 if ((HClairvoyant
& (INTRINSIC
| TIMEOUT
)) && !BClairvoyant
)
454 exercise(A_WIS
, TRUE
);
456 exercise(A_STR
, TRUE
);
458 if (Sick
|| Vomiting
)
459 exercise(A_CON
, FALSE
);
460 if (Confusion
|| Hallucination
)
461 exercise(A_WIS
, FALSE
);
462 if ((Wounded_legs
&& !u
.usteed
) || Fumbling
|| HStun
)
463 exercise(A_DEX
, FALSE
);
467 /* exercise/abuse text (must be in attribute order, not botl order);
468 phrased as "You must have been [][0]." or "You haven't been [][1]." */
469 static NEARDATA
const char *const exertext
[A_MAX
][2] = {
470 { "exercising diligently", "exercising properly" }, /* Str */
472 { "very observant", "paying attention" }, /* Wis */
473 { "working on your reflexes", "working on reflexes lately" }, /* Dex */
474 { "leading a healthy life-style", "watching your health" }, /* Con */
481 int i
, ax
, mod_val
, lolim
, hilim
;
483 /* Check out the periodic accumulations */
486 if (moves
>= context
.next_attrib_check
) {
487 debugpline1("exerchk: ready to test. multi = %d.", multi
);
489 /* Are we ready for a test? */
490 if (moves
>= context
.next_attrib_check
&& !multi
) {
491 debugpline0("exerchk: testing.");
493 * Law of diminishing returns (Part II):
495 * The effects of "exercise" and "abuse" wear
496 * off over time. Even if you *don't* get an
497 * increase/decrease, you lose some of the
498 * accumulated effects.
500 for (i
= 0; i
< A_MAX
; ++i
) {
502 /* nothing to do here if no exercise or abuse has occurred
503 (Int and Cha always fall into this category) */
505 continue; /* ok to skip nextattrib */
507 mod_val
= sgn(ax
); /* +1 or -1; used below */
508 /* no further effect for exercise if at max or abuse if at min;
509 can't exceed 18 via exercise even if actual max is higher */
510 lolim
= ATTRMIN(i
); /* usually 3; might be higher */
511 hilim
= ATTRMAX(i
); /* usually 18; maybe lower or higher */
514 if ((ax
< 0) ? (ABASE(i
) <= lolim
) : (ABASE(i
) >= hilim
))
516 /* can't exercise non-Wisdom while polymorphed; previous
517 exercise/abuse gradually wears off without impact then */
518 if (Upolyd
&& i
!= A_WIS
)
521 debugpline2("exerchk: testing %s (%d).",
537 * Law of diminishing returns (Part III):
539 * You don't *always* gain by exercising.
540 * [MRS 92/10/28 - Treat Wisdom specially for balance.]
542 if (rn2(AVAL
) > ((i
!= A_WIS
) ? (abs(ax
) * 2 / 3) : abs(ax
)))
545 debugpline1("exerchk: changing %d.", i
);
546 if (adjattrib(i
, mod_val
, -1)) {
547 debugpline1("exerchk: changed %d.", i
);
548 /* if you actually changed an attrib - zero accumulation */
550 /* then print an explanation */
552 (mod_val
> 0) ? "must have been" : "haven't been",
553 exertext
[i
][(mod_val
> 0) ? 0 : 1]);
556 /* this used to be ``AEXE(i) /= 2'' but that would produce
557 platform-dependent rounding/truncation for negative vals */
558 AEXE(i
) = (abs(ax
) / 2) * mod_val
;
560 context
.next_attrib_check
+= rn1(200, 800);
561 debugpline1("exerchk: next check at %ld.", context
.next_attrib_check
);
569 register int i
, x
, tryct
;
571 for (i
= 0; i
< A_MAX
; i
++) {
572 ABASE(i
) = AMAX(i
) = urole
.attrbase
[i
];
573 ATEMP(i
) = ATIME(i
) = 0;
574 np
-= urole
.attrbase
[i
];
578 while (np
> 0 && tryct
< 100) {
580 for (i
= 0; (i
< A_MAX
) && ((x
-= urole
.attrdist
[i
]) > 0); i
++)
583 continue; /* impossible */
585 if (ABASE(i
) >= ATTRMAX(i
)) {
596 while (np
< 0 && tryct
< 100) { /* for redistribution */
599 for (i
= 0; (i
< A_MAX
) && ((x
-= urole
.attrdist
[i
]) > 0); i
++)
602 continue; /* impossible */
604 if (ABASE(i
) <= ATTRMIN(i
)) {
620 for (i
= 0; i
< A_MAX
; i
++) {
621 if (i
== A_INT
|| i
== A_WIS
)
623 /* Polymorphing doesn't change your mind */
625 AMAX(i
) += (rn2(5) - 2);
626 if (AMAX(i
) > ATTRMAX(i
))
627 AMAX(i
) = ATTRMAX(i
);
628 if (AMAX(i
) < ATTRMIN(i
))
629 AMAX(i
) = ATTRMIN(i
);
630 ABASE(i
) = ABASE(i
) * AMAX(i
) / tmp
;
631 /* ABASE(i) > ATTRMAX(i) is impossible */
632 if (ABASE(i
) < ATTRMIN(i
))
633 ABASE(i
) = ATTRMIN(i
);
635 (void) encumber_msg();
645 if (ability
== &(HWarning
) || ability
== &(HSee_invisible
))
649 STATIC_OVL
const struct innate
*
655 const struct innate
*abil
;
657 { PM_ARCHEOLOGIST
, arc_abil
},
658 { PM_BARBARIAN
, bar_abil
},
659 { PM_CAVEMAN
, cav_abil
},
660 { PM_HEALER
, hea_abil
},
661 { PM_KNIGHT
, kni_abil
},
662 { PM_MONK
, mon_abil
},
663 { PM_PRIEST
, pri_abil
},
664 { PM_RANGER
, ran_abil
},
665 { PM_ROGUE
, rog_abil
},
666 { PM_SAMURAI
, sam_abil
},
667 { PM_TOURIST
, tou_abil
},
668 { PM_VALKYRIE
, val_abil
},
669 { PM_WIZARD
, wiz_abil
},
673 for (i
= 0; roleabils
[i
].abil
&& roleabils
[i
].role
!= r
; i
++);
674 return roleabils
[i
].abil
;
677 STATIC_OVL
const struct innate
*
678 check_innate_abil(ability
, frommask
)
682 const struct innate
*abil
= 0;
684 if (frommask
== FROMEXPER
)
685 abil
= role_abil(Role_switch
);
686 else if (frommask
== FROMRACE
)
687 switch (Race_switch
) {
707 while (abil
&& abil
->ability
) {
708 if ((abil
->ability
== ability
) && (u
.ulevel
>= abil
->ulevel
))
712 return (struct innate
*) 0;
715 /* reasons for innate ability */
717 #define FROM_ROLE 1 /* from experience at level 1 */
719 #define FROM_INTR 3 /* intrinsically (eating some corpse or prayer reward) */
720 #define FROM_EXP 4 /* from experience for some level > 1 */
724 /* check whether particular ability has been obtained via innate attribute */
729 const struct innate
*iptr
;
731 if ((iptr
= check_innate_abil(ability
, FROMEXPER
)) != 0)
732 return (iptr
->ulevel
== 1) ? FROM_ROLE
: FROM_EXP
;
733 if ((iptr
= check_innate_abil(ability
, FROMRACE
)) != 0)
735 if ((*ability
& FROMOUTSIDE
) != 0L)
737 if ((*ability
& FROMFORM
) != 0L)
748 /* innately() would report FROM_FORM for this; caller wants specificity */
749 if (propidx
== DRAIN_RES
&& u
.ulycn
>= LOW_PM
)
751 if (propidx
== FAST
&& Very_fast
)
752 return FROM_NONE
; /* can't become very fast innately */
753 if ((innateness
= innately(&u
.uprops
[propidx
].intrinsic
)) != FROM_NONE
)
755 if (propidx
== JUMPING
&& Role_if(PM_KNIGHT
)
756 /* knight has intrinsic jumping, but extrinsic is more versatile so
757 ignore innateness if equipment is going to claim responsibility */
758 && !u
.uprops
[propidx
].extrinsic
)
760 if (propidx
== BLINDED
&& !haseyes(youmonst
.data
))
767 int propidx
; /* special cases can have negative values */
769 static char buf
[BUFSZ
];
773 * Restrict the source of the attributes just to debug mode for now
776 static NEARDATA
const char because_of
[] = " because of %s";
780 struct obj
*obj
= (struct obj
*) 0;
781 int innateness
= is_innate(propidx
);
784 * Properties can be obtained from multiple sources and we
785 * try to pick the most significant one. Classification
786 * priority is not set in stone; current precedence is:
787 * "from the start" (from role or race at level 1),
788 * "from outside" (eating corpse, divine reward, blessed potion),
789 * "from experience" (from role or race at level 2+),
790 * "from current form" (while polymorphed),
791 * "from timed effect" (potion or spell),
792 * "from worn/wielded equipment" (Firebrand, elven boots, &c),
793 * "from carried equipment" (mainly quest artifacts).
794 * There are exceptions. Versatile jumping from spell or boots
795 * takes priority over knight's innate but limited jumping.
797 if (propidx
== BLINDED
&& u
.uroleplay
.blind
)
798 Sprintf(buf
, " from birth");
799 else if (innateness
== FROM_ROLE
|| innateness
== FROM_RACE
)
800 Strcpy(buf
, " innately");
801 else if (innateness
== FROM_INTR
) /* [].intrinsic & FROMOUTSIDE */
802 Strcpy(buf
, " intrinsically");
803 else if (innateness
== FROM_EXP
)
804 Strcpy(buf
, " because of your experience");
805 else if (innateness
== FROM_LYCN
)
806 Strcpy(buf
, " due to your lycanthropy");
807 else if (innateness
== FROM_FORM
)
808 Strcpy(buf
, " from current creature form");
809 else if (propidx
== FAST
&& Very_fast
)
810 Sprintf(buf
, because_of
,
811 ((HFast
& TIMEOUT
) != 0L) ? "a potion or spell"
812 : ((EFast
& W_ARMF
) != 0L && uarmf
->dknown
813 && objects
[uarmf
->otyp
].oc_name_known
)
814 ? ysimple_name(uarmf
) /* speed boots */
815 : EFast
? "worn equipment"
818 && (obj
= what_gives(&u
.uprops
[propidx
].extrinsic
)) != 0)
819 Sprintf(buf
, because_of
, obj
->oartifact
820 ? bare_artifactname(obj
)
821 : ysimple_name(obj
));
822 else if (propidx
== BLINDED
&& Blindfolded_only
)
823 Sprintf(buf
, because_of
, ysimple_name(ublindf
));
825 /* remove some verbosity and/or redundancy */
826 if ((p
= strstri(buf
, " pair of ")) != 0)
827 copynchars(p
+ 1, p
+ 9, BUFSZ
); /* overlapping buffers ok */
828 else if (propidx
== STRANGLED
829 && (p
= strstri(buf
, " of strangulation")) != 0)
832 } else { /* negative property index */
833 /* if more blocking capabilities get implemented we'll need to
834 replace this with what_blocks() comparable to what_gives() */
838 && ublindf
->oartifact
== ART_EYES_OF_THE_OVERWORLD
)
839 Sprintf(buf
, because_of
, bare_artifactname(ublindf
));
842 if (u
.uprops
[INVIS
].blocked
& W_ARMC
)
843 Sprintf(buf
, because_of
,
844 ysimple_name(uarmc
)); /* mummy wrapping */
847 if (wizard
&& (u
.uprops
[CLAIRVOYANT
].blocked
& W_ARMH
))
848 Sprintf(buf
, because_of
,
849 ysimple_name(uarmh
)); /* cornuthaum */
859 adjabil(oldlevel
, newlevel
)
860 int oldlevel
, newlevel
;
862 register const struct innate
*abil
, *rabil
;
863 long prevabil
, mask
= FROMEXPER
;
865 abil
= role_abil(Role_switch
);
867 switch (Race_switch
) {
882 while (abil
|| rabil
) {
883 /* Have we finished with the intrinsics list? */
884 if (!abil
|| !abil
->ability
) {
885 /* Try the race intrinsics */
886 if (!rabil
|| !rabil
->ability
)
892 prevabil
= *(abil
->ability
);
893 if (oldlevel
< abil
->ulevel
&& newlevel
>= abil
->ulevel
) {
894 /* Abilities gained at level 1 can never be lost
895 * via level loss, only via means that remove _any_
896 * sort of ability. A "gain" of such an ability from
897 * an outside source is devoid of meaning, so we set
898 * FROMOUTSIDE to avoid such gains.
900 if (abil
->ulevel
== 1)
901 *(abil
->ability
) |= (mask
| FROMOUTSIDE
);
903 *(abil
->ability
) |= mask
;
904 if (!(*(abil
->ability
) & INTRINSIC
& ~mask
)) {
905 if (*(abil
->gainstr
))
906 You_feel("%s!", abil
->gainstr
);
908 } else if (oldlevel
>= abil
->ulevel
&& newlevel
< abil
->ulevel
) {
909 *(abil
->ability
) &= ~mask
;
910 if (!(*(abil
->ability
) & INTRINSIC
)) {
911 if (*(abil
->losestr
))
912 You_feel("%s!", abil
->losestr
);
913 else if (*(abil
->gainstr
))
914 You_feel("less %s!", abil
->gainstr
);
917 if (prevabil
!= *(abil
->ability
)) /* it changed */
918 postadjabil(abil
->ability
);
923 if (newlevel
> oldlevel
)
924 add_weapon_skill(newlevel
- oldlevel
);
926 lose_weapon_skill(oldlevel
- newlevel
);
936 /* Initialize hit points */
937 hp
= urole
.hpadv
.infix
+ urace
.hpadv
.infix
;
938 if (urole
.hpadv
.inrnd
> 0)
939 hp
+= rnd(urole
.hpadv
.inrnd
);
940 if (urace
.hpadv
.inrnd
> 0)
941 hp
+= rnd(urace
.hpadv
.inrnd
);
942 if (moves
<= 1L) { /* initial hero; skip for polyself to new man */
943 /* Initialize alignment stuff */
944 u
.ualign
.type
= aligns
[flags
.initalign
].value
;
945 u
.ualign
.record
= urole
.initrecord
;
947 /* no Con adjustment for initial hit points */
949 if (u
.ulevel
< urole
.xlev
) {
950 hp
= urole
.hpadv
.lofix
+ urace
.hpadv
.lofix
;
951 if (urole
.hpadv
.lornd
> 0)
952 hp
+= rnd(urole
.hpadv
.lornd
);
953 if (urace
.hpadv
.lornd
> 0)
954 hp
+= rnd(urace
.hpadv
.lornd
);
956 hp
= urole
.hpadv
.hifix
+ urace
.hpadv
.hifix
;
957 if (urole
.hpadv
.hirnd
> 0)
958 hp
+= rnd(urole
.hpadv
.hirnd
);
959 if (urace
.hpadv
.hirnd
> 0)
960 hp
+= rnd(urace
.hpadv
.hirnd
);
962 if (ACURR(A_CON
) <= 3)
964 else if (ACURR(A_CON
) <= 6)
966 else if (ACURR(A_CON
) <= 14)
968 else if (ACURR(A_CON
) <= 16)
970 else if (ACURR(A_CON
) == 17)
972 else if (ACURR(A_CON
) == 18)
980 if (u
.ulevel
< MAXULEV
)
981 u
.uhpinc
[u
.ulevel
] = (xchar
) hp
;
989 register int tmp
= (u
.abon
.a
[x
] + u
.atemp
.a
[x
] + u
.acurr
.a
[x
]);
992 if (tmp
>= 125 || (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
))
996 return (x
= ((tmp
<= 3) ? 3 : tmp
));
998 return (schar
) ((tmp
<= 3) ? 3 : tmp
);
1000 } else if (x
== A_CHA
) {
1002 && (youmonst
.data
->mlet
== S_NYMPH
|| u
.umonnum
== PM_SUCCUBUS
1003 || u
.umonnum
== PM_INCUBUS
))
1005 } else if (x
== A_INT
|| x
== A_WIS
) {
1006 /* yes, this may raise int/wis if player is sufficiently
1007 * stupid. there are lower levels of cognition than "dunce".
1009 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
)
1013 return (x
= ((tmp
>= 25) ? 25 : (tmp
<= 3) ? 3 : tmp
));
1015 return (schar
) ((tmp
>= 25) ? 25 : (tmp
<= 3) ? 3 : tmp
);
1019 /* condense clumsy ACURR(A_STR) value into value that fits into game formulas
1024 register int str
= ACURR(A_STR
);
1029 return (schar
) (19 + str
/ 50); /* map to 19..21 */
1031 return (schar
) (min(str
, 125) - 100); /* 22..25 */
1034 /* when wearing (or taking off) an unID'd item, this routine is used
1035 to distinguish between observable +0 result and no-visible-effect
1036 due to an attribute not being able to exceed maximum or minimum */
1038 extremeattr(attrindx
) /* does attrindx's value match its max or min? */
1041 /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */
1042 int lolimit
= 3, hilimit
= 25, curval
= ACURR(attrindx
);
1044 /* upper limit for Str is 25 but its value is encoded differently */
1045 if (attrindx
== A_STR
) {
1046 hilimit
= STR19(25); /* 125 */
1047 /* lower limit for Str can also be 25 */
1048 if (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
)
1051 /* this exception is hypothetical; the only other worn item affecting
1052 Int or Wis is another helmet so can't be in use at the same time */
1053 if (attrindx
== A_INT
|| attrindx
== A_WIS
) {
1054 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
)
1055 hilimit
= lolimit
= 6;
1058 /* are we currently at either limit? */
1059 return (curval
== lolimit
|| curval
== hilimit
) ? TRUE
: FALSE
;
1062 /* avoid possible problems with alignment overflow, and provide a centralized
1063 location for any future alignment limits */
1068 int newalign
= u
.ualign
.record
+ n
;
1071 if (newalign
< u
.ualign
.record
)
1072 u
.ualign
.record
= newalign
;
1073 } else if (newalign
> u
.ualign
.record
) {
1074 u
.ualign
.record
= newalign
;
1075 if (u
.ualign
.record
> ALIGNLIM
)
1076 u
.ualign
.record
= ALIGNLIM
;
1080 /* change hero's alignment type, possibly losing use of artifacts */
1082 uchangealign(newalign
, reason
)
1084 int reason
; /* 0==conversion, 1==helm-of-OA on, 2==helm-of-OA off */
1086 aligntyp oldalign
= u
.ualign
.type
;
1088 u
.ublessed
= 0; /* lose divine protection */
1089 context
.botl
= 1; /* status line needs updating */
1091 /* conversion via altar */
1092 u
.ualignbase
[A_CURRENT
] = (aligntyp
) newalign
;
1093 /* worn helm of opposite alignment might block change */
1094 if (!uarmh
|| uarmh
->otyp
!= HELM_OF_OPPOSITE_ALIGNMENT
)
1095 u
.ualign
.type
= u
.ualignbase
[A_CURRENT
];
1096 You("have a %ssense of a new direction.",
1097 (u
.ualign
.type
!= oldalign
) ? "sudden " : "");
1099 /* putting on or taking off a helm of opposite alignment */
1100 u
.ualign
.type
= (aligntyp
) newalign
;
1102 Your("mind oscillates %s.", Hallucination
? "wildly" : "briefly");
1103 else if (reason
== 2)
1104 Your("mind is %s.", Hallucination
1105 ? "much of a muchness"
1106 : "back in sync with your body");
1109 if (u
.ualign
.type
!= oldalign
) {
1110 u
.ualign
.record
= 0; /* slate is wiped clean */
1111 retouch_equipment(0);