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
) {
276 pline_The("poison was deadly...");
278 /* HP damage; more likely--but less severe--with missiles */
279 loss
= thrown_weapon
? rnd(6) : rn1(10, 6);
280 losehp(loss
, pkiller
, kprefix
); /* poison damage */
282 /* attribute loss; if typ is A_STR, reduction in current and
283 maximum HP will occur once strength has dropped down to 3 */
284 loss
= (thrown_weapon
|| !fatal
) ? 1 : d(2, 2); /* was rn1(3,3) */
285 /* check that a stat change was made */
286 if (adjattrib(typ
, -loss
, 1))
287 poisontell(typ
, TRUE
);
291 killer
.format
= kprefix
;
292 Strcpy(killer
.name
, pkiller
);
293 /* "Poisoned by a poisoned ___" is redundant */
294 done(strstri(pkiller
, "poison") ? DIED
: POISONING
);
296 (void) encumber_msg();
304 if (u
.uluck
< 0 && u
.uluck
< LUCKMIN
)
306 if (u
.uluck
> 0 && u
.uluck
> LUCKMAX
)
311 stone_luck(parameter
)
312 boolean parameter
; /* So I can't think up of a good name. So sue me. --KAA */
314 register struct obj
*otmp
;
315 register long bonchance
= 0;
317 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
318 if (confers_luck(otmp
)) {
320 bonchance
-= otmp
->quan
;
321 else if (otmp
->blessed
)
322 bonchance
+= otmp
->quan
;
324 bonchance
+= otmp
->quan
;
327 return sgn((int) bonchance
);
330 /* there has just been an inventory change affecting a luck-granting item */
334 int luckbon
= stone_luck(TRUE
);
336 if (!luckbon
&& !carrying(LUCKSTONE
))
338 else if (luckbon
>= 0)
339 u
.moreluck
= LUCKADD
;
341 u
.moreluck
= -LUCKADD
;
349 for (i
= 0; i
< A_MAX
; i
++) { /* all temporary losses/gains */
351 if (ATEMP(i
) && ATIME(i
)) {
352 if (!(--(ATIME(i
)))) { /* countdown for change */
353 ATEMP(i
) += ATEMP(i
) > 0 ? -1 : 1;
355 if (ATEMP(i
)) /* reset timer */
356 ATIME(i
) = 100 / ACURR(A_CON
);
360 (void) encumber_msg();
363 #define AVAL 50 /* tune value for exercise gains */
366 exercise(i
, inc_or_dec
)
370 debugpline0("Exercise:");
371 if (i
== A_INT
|| i
== A_CHA
)
372 return; /* can't exercise these */
374 /* no physical exercise while polymorphed; the body's temporary */
375 if (Upolyd
&& i
!= A_WIS
)
378 if (abs(AEXE(i
)) < AVAL
) {
380 * Law of diminishing returns (Part I):
382 * Gain is harder at higher attribute values.
383 * 79% at "3" --> 0% at "18"
384 * Loss is even at all levels (50%).
386 * Note: *YES* ACURR is the right one to use.
388 AEXE(i
) += (inc_or_dec
) ? (rn2(19) > ACURR(i
)) : -rn2(2);
389 debugpline3("%s, %s AEXE = %d",
390 (i
== A_STR
) ? "Str" : (i
== A_WIS
) ? "Wis" : (i
== A_DEX
)
393 (inc_or_dec
) ? "inc" : "dec", AEXE(i
));
395 if (moves
> 0 && (i
== A_STR
|| i
== A_CON
))
396 (void) encumber_msg();
405 int hs
= (u
.uhunger
> 1000) ? SATIATED
: (u
.uhunger
> 150)
413 debugpline0("exerper: Hunger checks");
416 exercise(A_DEX
, FALSE
);
417 if (Role_if(PM_MONK
))
418 exercise(A_WIS
, FALSE
);
421 exercise(A_CON
, TRUE
);
424 exercise(A_STR
, FALSE
);
425 if (Role_if(PM_MONK
)) /* fasting */
426 exercise(A_WIS
, TRUE
);
430 exercise(A_CON
, FALSE
);
434 /* Encumbrance Checks */
435 debugpline0("exerper: Encumber checks");
436 switch (near_capacity()) {
438 exercise(A_STR
, TRUE
);
441 exercise(A_STR
, TRUE
);
442 exercise(A_DEX
, FALSE
);
445 exercise(A_DEX
, FALSE
);
446 exercise(A_CON
, FALSE
);
453 debugpline0("exerper: Status checks");
454 if ((HClairvoyant
& (INTRINSIC
| TIMEOUT
)) && !BClairvoyant
)
455 exercise(A_WIS
, TRUE
);
457 exercise(A_STR
, TRUE
);
459 if (Sick
|| Vomiting
)
460 exercise(A_CON
, FALSE
);
461 if (Confusion
|| Hallucination
)
462 exercise(A_WIS
, FALSE
);
463 if ((Wounded_legs
&& !u
.usteed
) || Fumbling
|| HStun
)
464 exercise(A_DEX
, FALSE
);
468 /* exercise/abuse text (must be in attribute order, not botl order);
469 phrased as "You must have been [][0]." or "You haven't been [][1]." */
470 static NEARDATA
const char *const exertext
[A_MAX
][2] = {
471 { "exercising diligently", "exercising properly" }, /* Str */
473 { "very observant", "paying attention" }, /* Wis */
474 { "working on your reflexes", "working on reflexes lately" }, /* Dex */
475 { "leading a healthy life-style", "watching your health" }, /* Con */
482 int i
, ax
, mod_val
, lolim
, hilim
;
484 /* Check out the periodic accumulations */
487 if (moves
>= context
.next_attrib_check
) {
488 debugpline1("exerchk: ready to test. multi = %d.", multi
);
490 /* Are we ready for a test? */
491 if (moves
>= context
.next_attrib_check
&& !multi
) {
492 debugpline0("exerchk: testing.");
494 * Law of diminishing returns (Part II):
496 * The effects of "exercise" and "abuse" wear
497 * off over time. Even if you *don't* get an
498 * increase/decrease, you lose some of the
499 * accumulated effects.
501 for (i
= 0; i
< A_MAX
; ++i
) {
503 /* nothing to do here if no exercise or abuse has occurred
504 (Int and Cha always fall into this category) */
506 continue; /* ok to skip nextattrib */
508 mod_val
= sgn(ax
); /* +1 or -1; used below */
509 /* no further effect for exercise if at max or abuse if at min;
510 can't exceed 18 via exercise even if actual max is higher */
511 lolim
= ATTRMIN(i
); /* usually 3; might be higher */
512 hilim
= ATTRMAX(i
); /* usually 18; maybe lower or higher */
515 if ((ax
< 0) ? (ABASE(i
) <= lolim
) : (ABASE(i
) >= hilim
))
517 /* can't exercise non-Wisdom while polymorphed; previous
518 exercise/abuse gradually wears off without impact then */
519 if (Upolyd
&& i
!= A_WIS
)
522 debugpline2("exerchk: testing %s (%d).",
538 * Law of diminishing returns (Part III):
540 * You don't *always* gain by exercising.
541 * [MRS 92/10/28 - Treat Wisdom specially for balance.]
543 if (rn2(AVAL
) > ((i
!= A_WIS
) ? (abs(ax
) * 2 / 3) : abs(ax
)))
546 debugpline1("exerchk: changing %d.", i
);
547 if (adjattrib(i
, mod_val
, -1)) {
548 debugpline1("exerchk: changed %d.", i
);
549 /* if you actually changed an attrib - zero accumulation */
551 /* then print an explanation */
553 (mod_val
> 0) ? "must have been" : "haven't been",
554 exertext
[i
][(mod_val
> 0) ? 0 : 1]);
557 /* this used to be ``AEXE(i) /= 2'' but that would produce
558 platform-dependent rounding/truncation for negative vals */
559 AEXE(i
) = (abs(ax
) / 2) * mod_val
;
561 context
.next_attrib_check
+= rn1(200, 800);
562 debugpline1("exerchk: next check at %ld.", context
.next_attrib_check
);
570 register int i
, x
, tryct
;
572 for (i
= 0; i
< A_MAX
; i
++) {
573 ABASE(i
) = AMAX(i
) = urole
.attrbase
[i
];
574 ATEMP(i
) = ATIME(i
) = 0;
575 np
-= urole
.attrbase
[i
];
579 while (np
> 0 && tryct
< 100) {
581 for (i
= 0; (i
< A_MAX
) && ((x
-= urole
.attrdist
[i
]) > 0); i
++)
584 continue; /* impossible */
586 if (ABASE(i
) >= ATTRMAX(i
)) {
597 while (np
< 0 && tryct
< 100) { /* for redistribution */
600 for (i
= 0; (i
< A_MAX
) && ((x
-= urole
.attrdist
[i
]) > 0); i
++)
603 continue; /* impossible */
605 if (ABASE(i
) <= ATTRMIN(i
)) {
621 for (i
= 0; i
< A_MAX
; i
++) {
622 if (i
== A_INT
|| i
== A_WIS
)
624 /* Polymorphing doesn't change your mind */
626 AMAX(i
) += (rn2(5) - 2);
627 if (AMAX(i
) > ATTRMAX(i
))
628 AMAX(i
) = ATTRMAX(i
);
629 if (AMAX(i
) < ATTRMIN(i
))
630 AMAX(i
) = ATTRMIN(i
);
631 ABASE(i
) = ABASE(i
) * AMAX(i
) / tmp
;
632 /* ABASE(i) > ATTRMAX(i) is impossible */
633 if (ABASE(i
) < ATTRMIN(i
))
634 ABASE(i
) = ATTRMIN(i
);
636 (void) encumber_msg();
646 if (ability
== &(HWarning
) || ability
== &(HSee_invisible
))
650 STATIC_OVL
const struct innate
*
656 const struct innate
*abil
;
658 { PM_ARCHEOLOGIST
, arc_abil
},
659 { PM_BARBARIAN
, bar_abil
},
660 { PM_CAVEMAN
, cav_abil
},
661 { PM_HEALER
, hea_abil
},
662 { PM_KNIGHT
, kni_abil
},
663 { PM_MONK
, mon_abil
},
664 { PM_PRIEST
, pri_abil
},
665 { PM_RANGER
, ran_abil
},
666 { PM_ROGUE
, rog_abil
},
667 { PM_SAMURAI
, sam_abil
},
668 { PM_TOURIST
, tou_abil
},
669 { PM_VALKYRIE
, val_abil
},
670 { PM_WIZARD
, wiz_abil
},
674 for (i
= 0; roleabils
[i
].abil
&& roleabils
[i
].role
!= r
; i
++);
675 return roleabils
[i
].abil
;
678 STATIC_OVL
const struct innate
*
679 check_innate_abil(ability
, frommask
)
683 const struct innate
*abil
= 0;
685 if (frommask
== FROMEXPER
)
686 abil
= role_abil(Role_switch
);
687 else if (frommask
== FROMRACE
)
688 switch (Race_switch
) {
708 while (abil
&& abil
->ability
) {
709 if ((abil
->ability
== ability
) && (u
.ulevel
>= abil
->ulevel
))
713 return (struct innate
*) 0;
716 /* reasons for innate ability */
718 #define FROM_ROLE 1 /* from experience at level 1 */
720 #define FROM_INTR 3 /* intrinsically (eating some corpse or prayer reward) */
721 #define FROM_EXP 4 /* from experience for some level > 1 */
725 /* check whether particular ability has been obtained via innate attribute */
730 const struct innate
*iptr
;
732 if ((iptr
= check_innate_abil(ability
, FROMEXPER
)) != 0)
733 return (iptr
->ulevel
== 1) ? FROM_ROLE
: FROM_EXP
;
734 if ((iptr
= check_innate_abil(ability
, FROMRACE
)) != 0)
736 if ((*ability
& FROMOUTSIDE
) != 0L)
738 if ((*ability
& FROMFORM
) != 0L)
749 /* innately() would report FROM_FORM for this; caller wants specificity */
750 if (propidx
== DRAIN_RES
&& u
.ulycn
>= LOW_PM
)
752 if (propidx
== FAST
&& Very_fast
)
753 return FROM_NONE
; /* can't become very fast innately */
754 if ((innateness
= innately(&u
.uprops
[propidx
].intrinsic
)) != FROM_NONE
)
756 if (propidx
== JUMPING
&& Role_if(PM_KNIGHT
)
757 /* knight has intrinsic jumping, but extrinsic is more versatile so
758 ignore innateness if equipment is going to claim responsibility */
759 && !u
.uprops
[propidx
].extrinsic
)
761 if (propidx
== BLINDED
&& !haseyes(youmonst
.data
))
768 int propidx
; /* special cases can have negative values */
770 static char buf
[BUFSZ
];
774 * Restrict the source of the attributes just to debug mode for now
777 static NEARDATA
const char because_of
[] = " because of %s";
781 struct obj
*obj
= (struct obj
*) 0;
782 int innateness
= is_innate(propidx
);
785 * Properties can be obtained from multiple sources and we
786 * try to pick the most significant one. Classification
787 * priority is not set in stone; current precedence is:
788 * "from the start" (from role or race at level 1),
789 * "from outside" (eating corpse, divine reward, blessed potion),
790 * "from experience" (from role or race at level 2+),
791 * "from current form" (while polymorphed),
792 * "from timed effect" (potion or spell),
793 * "from worn/wielded equipment" (Firebrand, elven boots, &c),
794 * "from carried equipment" (mainly quest artifacts).
795 * There are exceptions. Versatile jumping from spell or boots
796 * takes priority over knight's innate but limited jumping.
798 if (propidx
== BLINDED
&& u
.uroleplay
.blind
)
799 Sprintf(buf
, " from birth");
800 else if (innateness
== FROM_ROLE
|| innateness
== FROM_RACE
)
801 Strcpy(buf
, " innately");
802 else if (innateness
== FROM_INTR
) /* [].intrinsic & FROMOUTSIDE */
803 Strcpy(buf
, " intrinsically");
804 else if (innateness
== FROM_EXP
)
805 Strcpy(buf
, " because of your experience");
806 else if (innateness
== FROM_LYCN
)
807 Strcpy(buf
, " due to your lycanthropy");
808 else if (innateness
== FROM_FORM
)
809 Strcpy(buf
, " from current creature form");
810 else if (propidx
== FAST
&& Very_fast
)
811 Sprintf(buf
, because_of
,
812 ((HFast
& TIMEOUT
) != 0L) ? "a potion or spell"
813 : ((EFast
& W_ARMF
) != 0L && uarmf
->dknown
814 && objects
[uarmf
->otyp
].oc_name_known
)
815 ? ysimple_name(uarmf
) /* speed boots */
816 : EFast
? "worn equipment"
819 && (obj
= what_gives(&u
.uprops
[propidx
].extrinsic
)) != 0)
820 Sprintf(buf
, because_of
, obj
->oartifact
821 ? bare_artifactname(obj
)
822 : ysimple_name(obj
));
823 else if (propidx
== BLINDED
&& Blindfolded_only
)
824 Sprintf(buf
, because_of
, ysimple_name(ublindf
));
826 /* remove some verbosity and/or redundancy */
827 if ((p
= strstri(buf
, " pair of ")) != 0)
828 copynchars(p
+ 1, p
+ 9, BUFSZ
); /* overlapping buffers ok */
829 else if (propidx
== STRANGLED
830 && (p
= strstri(buf
, " of strangulation")) != 0)
833 } else { /* negative property index */
834 /* if more blocking capabilities get implemented we'll need to
835 replace this with what_blocks() comparable to what_gives() */
839 && ublindf
->oartifact
== ART_EYES_OF_THE_OVERWORLD
)
840 Sprintf(buf
, because_of
, bare_artifactname(ublindf
));
843 if (u
.uprops
[INVIS
].blocked
& W_ARMC
)
844 Sprintf(buf
, because_of
,
845 ysimple_name(uarmc
)); /* mummy wrapping */
848 if (wizard
&& (u
.uprops
[CLAIRVOYANT
].blocked
& W_ARMH
))
849 Sprintf(buf
, because_of
,
850 ysimple_name(uarmh
)); /* cornuthaum */
860 adjabil(oldlevel
, newlevel
)
861 int oldlevel
, newlevel
;
863 register const struct innate
*abil
, *rabil
;
864 long prevabil
, mask
= FROMEXPER
;
866 abil
= role_abil(Role_switch
);
868 switch (Race_switch
) {
883 while (abil
|| rabil
) {
884 /* Have we finished with the intrinsics list? */
885 if (!abil
|| !abil
->ability
) {
886 /* Try the race intrinsics */
887 if (!rabil
|| !rabil
->ability
)
893 prevabil
= *(abil
->ability
);
894 if (oldlevel
< abil
->ulevel
&& newlevel
>= abil
->ulevel
) {
895 /* Abilities gained at level 1 can never be lost
896 * via level loss, only via means that remove _any_
897 * sort of ability. A "gain" of such an ability from
898 * an outside source is devoid of meaning, so we set
899 * FROMOUTSIDE to avoid such gains.
901 if (abil
->ulevel
== 1)
902 *(abil
->ability
) |= (mask
| FROMOUTSIDE
);
904 *(abil
->ability
) |= mask
;
905 if (!(*(abil
->ability
) & INTRINSIC
& ~mask
)) {
906 if (*(abil
->gainstr
))
907 You_feel("%s!", abil
->gainstr
);
909 } else if (oldlevel
>= abil
->ulevel
&& newlevel
< abil
->ulevel
) {
910 *(abil
->ability
) &= ~mask
;
911 if (!(*(abil
->ability
) & INTRINSIC
)) {
912 if (*(abil
->losestr
))
913 You_feel("%s!", abil
->losestr
);
914 else if (*(abil
->gainstr
))
915 You_feel("less %s!", abil
->gainstr
);
918 if (prevabil
!= *(abil
->ability
)) /* it changed */
919 postadjabil(abil
->ability
);
924 if (newlevel
> oldlevel
)
925 add_weapon_skill(newlevel
- oldlevel
);
927 lose_weapon_skill(oldlevel
- newlevel
);
937 /* Initialize hit points */
938 hp
= urole
.hpadv
.infix
+ urace
.hpadv
.infix
;
939 if (urole
.hpadv
.inrnd
> 0)
940 hp
+= rnd(urole
.hpadv
.inrnd
);
941 if (urace
.hpadv
.inrnd
> 0)
942 hp
+= rnd(urace
.hpadv
.inrnd
);
943 if (moves
<= 1L) { /* initial hero; skip for polyself to new man */
944 /* Initialize alignment stuff */
945 u
.ualign
.type
= aligns
[flags
.initalign
].value
;
946 u
.ualign
.record
= urole
.initrecord
;
948 /* no Con adjustment for initial hit points */
950 if (u
.ulevel
< urole
.xlev
) {
951 hp
= urole
.hpadv
.lofix
+ urace
.hpadv
.lofix
;
952 if (urole
.hpadv
.lornd
> 0)
953 hp
+= rnd(urole
.hpadv
.lornd
);
954 if (urace
.hpadv
.lornd
> 0)
955 hp
+= rnd(urace
.hpadv
.lornd
);
957 hp
= urole
.hpadv
.hifix
+ urace
.hpadv
.hifix
;
958 if (urole
.hpadv
.hirnd
> 0)
959 hp
+= rnd(urole
.hpadv
.hirnd
);
960 if (urace
.hpadv
.hirnd
> 0)
961 hp
+= rnd(urace
.hpadv
.hirnd
);
963 if (ACURR(A_CON
) <= 3)
965 else if (ACURR(A_CON
) <= 6)
967 else if (ACURR(A_CON
) <= 14)
969 else if (ACURR(A_CON
) <= 16)
971 else if (ACURR(A_CON
) == 17)
973 else if (ACURR(A_CON
) == 18)
981 if (u
.ulevel
< MAXULEV
)
982 u
.uhpinc
[u
.ulevel
] = (xchar
) hp
;
990 register int tmp
= (u
.abon
.a
[x
] + u
.atemp
.a
[x
] + u
.acurr
.a
[x
]);
993 if (tmp
>= 125 || (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
))
997 return (x
= ((tmp
<= 3) ? 3 : tmp
));
999 return (schar
) ((tmp
<= 3) ? 3 : tmp
);
1001 } else if (x
== A_CHA
) {
1003 && (youmonst
.data
->mlet
== S_NYMPH
|| u
.umonnum
== PM_SUCCUBUS
1004 || u
.umonnum
== PM_INCUBUS
))
1006 } else if (x
== A_CON
) {
1007 if (uwep
&& uwep
->oartifact
== ART_OGRESMASHER
)
1009 } else if (x
== A_INT
|| x
== A_WIS
) {
1010 /* yes, this may raise int/wis if player is sufficiently
1011 * stupid. there are lower levels of cognition than "dunce".
1013 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
)
1017 return (x
= ((tmp
>= 25) ? 25 : (tmp
<= 3) ? 3 : tmp
));
1019 return (schar
) ((tmp
>= 25) ? 25 : (tmp
<= 3) ? 3 : tmp
);
1023 /* condense clumsy ACURR(A_STR) value into value that fits into game formulas
1028 register int str
= ACURR(A_STR
);
1033 return (schar
) (19 + str
/ 50); /* map to 19..21 */
1035 return (schar
) (min(str
, 125) - 100); /* 22..25 */
1038 /* when wearing (or taking off) an unID'd item, this routine is used
1039 to distinguish between observable +0 result and no-visible-effect
1040 due to an attribute not being able to exceed maximum or minimum */
1042 extremeattr(attrindx
) /* does attrindx's value match its max or min? */
1045 /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */
1046 int lolimit
= 3, hilimit
= 25, curval
= ACURR(attrindx
);
1048 /* upper limit for Str is 25 but its value is encoded differently */
1049 if (attrindx
== A_STR
) {
1050 hilimit
= STR19(25); /* 125 */
1051 /* lower limit for Str can also be 25 */
1052 if (uarmg
&& uarmg
->otyp
== GAUNTLETS_OF_POWER
)
1054 } else if (attrindx
== A_CON
) {
1055 if (uwep
&& uwep
->oartifact
== ART_OGRESMASHER
)
1058 /* this exception is hypothetical; the only other worn item affecting
1059 Int or Wis is another helmet so can't be in use at the same time */
1060 if (attrindx
== A_INT
|| attrindx
== A_WIS
) {
1061 if (uarmh
&& uarmh
->otyp
== DUNCE_CAP
)
1062 hilimit
= lolimit
= 6;
1065 /* are we currently at either limit? */
1066 return (curval
== lolimit
|| curval
== hilimit
) ? TRUE
: FALSE
;
1069 /* avoid possible problems with alignment overflow, and provide a centralized
1070 location for any future alignment limits */
1075 int newalign
= u
.ualign
.record
+ n
;
1078 if (newalign
< u
.ualign
.record
)
1079 u
.ualign
.record
= newalign
;
1080 } else if (newalign
> u
.ualign
.record
) {
1081 u
.ualign
.record
= newalign
;
1082 if (u
.ualign
.record
> ALIGNLIM
)
1083 u
.ualign
.record
= ALIGNLIM
;
1087 /* change hero's alignment type, possibly losing use of artifacts */
1089 uchangealign(newalign
, reason
)
1091 int reason
; /* 0==conversion, 1==helm-of-OA on, 2==helm-of-OA off */
1093 aligntyp oldalign
= u
.ualign
.type
;
1095 u
.ublessed
= 0; /* lose divine protection */
1096 context
.botl
= 1; /* status line needs updating */
1098 /* conversion via altar */
1099 u
.ualignbase
[A_CURRENT
] = (aligntyp
) newalign
;
1100 /* worn helm of opposite alignment might block change */
1101 if (!uarmh
|| uarmh
->otyp
!= HELM_OF_OPPOSITE_ALIGNMENT
)
1102 u
.ualign
.type
= u
.ualignbase
[A_CURRENT
];
1103 You("have a %ssense of a new direction.",
1104 (u
.ualign
.type
!= oldalign
) ? "sudden " : "");
1106 /* putting on or taking off a helm of opposite alignment */
1107 u
.ualign
.type
= (aligntyp
) newalign
;
1109 Your("mind oscillates %s.", Hallucination
? "wildly" : "briefly");
1110 else if (reason
== 2)
1111 Your("mind is %s.", Hallucination
1112 ? "much of a muchness"
1113 : "back in sync with your body");
1116 if (u
.ualign
.type
!= oldalign
) {
1117 u
.ualign
.record
= 0; /* slate is wiped clean */
1118 retouch_equipment(0);