1 /* NetHack 3.6 attrib.c $NHDT-Date: 1575245050 2019/12/02 00:04:10 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.66 $ */
2 /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
8 /* JNetHack may be freely redistributed. See license for details. */
11 /* attribute modification routines. */
16 /* part of the output on gain or loss of attribute */
19 *const plusattr[] = { "strong", "smart", "wise",
20 "agile", "tough", "charismatic" },
22 *const plusattr[] = { "
\8b
\82¢", "
\8c«
\96¾
\82¾", "
\8c«
\82¢",
23 "
\8b@
\95q
\82¾", "
\8aæ
\8fä
\82¾", "
\96£
\97Í
\93I
\82¾" },
26 *const minusattr[] = { "weak", "stupid",
28 "fragile", "repulsive" };
30 *const minusattr[] = { "
\8eã
\82¢", "
\8bð
\82©
\82¾",
31 "
\8aÔ
\94²
\82¯
\82¾", "
\95s
\8aí
\97p
\82¾",
32 "
\82Ð
\8eã
\82¾", "
\8fX
\82¢" };
34 /* also used by enlightenment for non-abbreviated status info */
37 *const attrname[] = { "strength", "intelligence", "wisdom",
38 "dexterity", "constitution", "charisma" };
40 *const attrname[] = { "
\8b
\82³", "
\92m
\97Í", "
\8c«
\82³",
41 "
\91f
\91\81\82³", "
\91Ï
\8bv
\97Í", "
\96£
\97Í" };
44 static const struct innate {
47 const char *gainstr, *losestr;
48 } arc_abil[] = { { 1, &(HStealth), "", "" },
49 { 1, &(HFast), "", "" },
51 { 10, &(HSearching), "perceptive", "" },
53 { 10, &(HSearching), "
\92m
\8ao
\97Í
\82ð
\93¾
\82½", "
\92m
\8ao
\97Í
\82ð
\8e¸
\82Á
\82½" },
56 bar_abil[] = { { 1, &(HPoison_resistance), "", "" },
58 { 7, &(HFast), "quick", "slow" },
60 { 7, &(HFast), "
\91f
\91\81\82³
\82ð
\93¾
\82½", "
\92x
\82
\82È
\82Á
\82½" },
62 { 15, &(HStealth), "stealthy", "" },
64 { 15, &(HStealth), "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\93¾
\82½", "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\8e¸
\82Á
\82½" },
68 cav_abil[] = { { 7, &(HFast), "quick", "slow" },
70 cav_abil[] = { { 7, &(HFast), "
\91f
\91\81\82³
\82ð
\93¾
\82½", "
\92x
\82
\82È
\82Á
\82½" },
72 { 15, &(HWarning), "sensitive", "" },
74 { 15, &(HWarning), "
\95q
\8a´
\82É
\82È
\82Á
\82½", "
\93Ý
\8a´
\82É
\82È
\82Á
\82½" },
77 hea_abil[] = { { 1, &(HPoison_resistance), "", "" },
79 { 15, &(HWarning), "sensitive", "" },
81 { 15, &(HWarning), "
\95q
\8a´
\82É
\82È
\82Á
\82½", "
\93Ý
\8a´
\82É
\82È
\82Á
\82½" },
85 kni_abil[] = { { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } },
87 kni_abil[] = { { 7, &(HFast), "
\91f
\91\81\82³
\82ð
\93¾
\82½", "
\92x
\82
\82È
\82Á
\82½" }, { 0, 0, 0, 0 } },
89 mon_abil[] = { { 1, &(HFast), "", "" },
90 { 1, &(HSleep_resistance), "", "" },
91 { 1, &(HSee_invisible), "", "" },
93 { 3, &(HPoison_resistance), "healthy", "" },
95 { 3, &(HPoison_resistance), "
\8c\92\8dN
\82É
\82È
\82Á
\82½", "
\95s
\8c\92\8dN
\82É
\82È
\82Á
\82½" },
97 { 5, &(HStealth), "stealthy", "" },
99 { 5, &(HStealth), "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\93¾
\82½", "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\8e¸
\82Á
\82½" },
101 { 7, &(HWarning), "sensitive", "" },
103 { 7, &(HWarning), "
\95q
\8a´
\82É
\82È
\82Á
\82½", "
\93Ý
\8a´
\82É
\82È
\82Á
\82½" },
105 { 9, &(HSearching), "perceptive", "unaware" },
107 { 9, &(HSearching), "
\92m
\8ao
\97Í
\82ð
\93¾
\82½", "
\92m
\8ao
\97Í
\82ð
\8e¸
\82Á
\82½" },
109 { 11, &(HFire_resistance), "cool", "warmer" },
111 { 11, &(HFire_resistance), "
\97â
\82½
\82
\82È
\82Á
\82½", "
\92g
\82©
\82
\82È
\82Á
\82½" },
113 { 13, &(HCold_resistance), "warm", "cooler" },
115 { 13, &(HCold_resistance), "
\92g
\82©
\82
\82È
\82Á
\82½", "
\97â
\82½
\82
\82È
\82Á
\82½"},
117 { 15, &(HShock_resistance), "insulated", "conductive" },
119 { 15, &(HShock_resistance), "
\90â
\89\8f\82³
\82ê
\82½", "
\93±
\93d
\82³
\82ê
\82½" },
121 { 17, &(HTeleport_control), "controlled", "uncontrolled" },
123 { 17, &(HTeleport_control), "
\90§
\8cä
\97Í
\82ð
\93¾
\82½", "
\90§
\8cä
\97Í
\82ð
\8e¸
\82Á
\82½" },
127 pri_abil[] = { { 15, &(HWarning), "sensitive", "" },
129 pri_abil[] = { { 15, &(HWarning), "
\95q
\8a´
\82É
\82È
\82Á
\82½", "
\93Ý
\8a´
\82É
\82È
\82Á
\82½" },
131 { 20, &(HFire_resistance), "cool", "warmer" },
133 { 20, &(HFire_resistance), "
\97â
\82½
\82
\82È
\82Á
\82½", "
\92g
\82©
\82
\82È
\82Á
\82½" },
136 ran_abil[] = { { 1, &(HSearching), "", "" },
138 { 7, &(HStealth), "stealthy", "" },
140 { 7, &(HStealth), "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\93¾
\82½", "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\8e¸
\82Á
\82½" },
141 { 15, &(HSee_invisible), "", "" },
144 rog_abil[] = { { 1, &(HStealth), "", "" },
146 { 10, &(HSearching), "perceptive", "" },
148 { 10, &(HSearching), "
\92m
\8ao
\97Í
\82ð
\93¾
\82½", "
\92m
\8ao
\97Í
\82ð
\8e¸
\82Á
\82½" },
151 sam_abil[] = { { 1, &(HFast), "", "" },
153 { 15, &(HStealth), "stealthy", "" },
155 { 15, &(HStealth), "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\93¾
\82½", "
\90l
\96Ú
\82ð
\93\90\82Þ
\97Í
\82ð
\8e¸
\82Á
\82½" },
159 tou_abil[] = { { 10, &(HSearching), "perceptive", "" },
161 tou_abil[] = { { 10, &(HSearching), "
\92m
\8ao
\97Í
\82ð
\93¾
\82½", "
\92m
\8ao
\97Í
\82ð
\8e¸
\82Á
\82½" },
163 { 20, &(HPoison_resistance), "hardy", "" },
165 { 20, &(HPoison_resistance), "
\96Æ
\89u
\97Í
\82ð
\93¾
\82½", "
\96Æ
\89u
\97Í
\82ð
\8e¸
\82Á
\82½" },
168 val_abil[] = { { 1, &(HCold_resistance), "", "" },
169 { 1, &(HStealth), "", "" },
171 { 7, &(HFast), "quick", "slow" },
173 { 7, &(HFast), "
\91f
\91\81\82³
\82ð
\93¾
\82½", "
\92x
\82
\82È
\82Á
\82½" },
177 wiz_abil[] = { { 15, &(HWarning), "sensitive", "" },
179 wiz_abil[] = { { 15, &(HWarning), "
\95q
\8a´
\82É
\82È
\82Á
\82½", "
\93Ý
\8a´
\82É
\82È
\82Á
\82½" },
181 { 17, &(HTeleport_control), "controlled", "uncontrolled" },
183 { 17, &(HTeleport_control), "
\90§
\8cä
\97Í
\82ð
\93¾
\82½", "
\90§
\8cä
\97Í
\82ð
\8e¸
\82Á
\82½" },
186 /* Intrinsics conferred by race */
187 dwa_abil[] = { { 1, &HInfravision, "", "" },
190 elf_abil[] = { { 1, &HInfravision, "", "" },
192 { 4, &HSleep_resistance, "awake", "tired" },
194 { 4, &(HSleep_resistance), "
\96Ú
\82ª
\8ao
\82ß
\82½", "
\96°
\82
\82È
\82Á
\82½" },
197 gno_abil[] = { { 1, &HInfravision, "", "" },
200 orc_abil[] = { { 1, &HInfravision, "", "" },
201 { 1, &HPoison_resistance, "", "" },
204 hum_abil[] = { { 0, 0, 0, 0 } };
206 STATIC_DCL void NDECL(exerper);
207 STATIC_DCL void FDECL(postadjabil, (long *));
208 STATIC_DCL const struct innate *FDECL(role_abil, (int));
209 STATIC_DCL const struct innate *FDECL(check_innate_abil, (long *, long));
210 STATIC_DCL int FDECL(innately, (long *));
212 /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
214 adjattrib(ndx, incr, msgflg)
216 int msgflg; /* positive => no message, zero => message, and */
217 { /* negative => conditional (msg if change made) */
218 int old_acurr, old_abase, old_amax, decr;
222 if (Fixed_abil || !incr)
225 if ((ndx == A_INT || ndx == A_WIS) && uarmh && uarmh->otyp == DUNCE_CAP) {
228 Your("cap constricts briefly, then relaxes again.");
230 Your("
\96X
\8eq
\82ª
\82µ
\82Î
\82ç
\82
\82Ì
\8aÔ
\83L
\83\85\82Á
\82Æ
\92÷
\82ß
\82Â
\82¯
\81C
\82»
\82µ
\82Ä
\82ä
\82é
\82ñ
\82¾
\81D");
234 old_acurr = ACURR(ndx);
235 old_abase = ABASE(ndx);
236 old_amax = AMAX(ndx);
237 ABASE(ndx) += incr; /* when incr is negative, this reduces ABASE() */
239 if (ABASE(ndx) > AMAX(ndx)) {
240 AMAX(ndx) = ABASE(ndx);
241 if (AMAX(ndx) > ATTRMAX(ndx))
242 ABASE(ndx) = AMAX(ndx) = ATTRMAX(ndx);
244 attrstr = plusattr[ndx];
245 abonflg = (ABON(ndx) < 0);
246 } else { /* incr is negative */
247 if (ABASE(ndx) < ATTRMIN(ndx)) {
249 * If base value has dropped so low that it is trying to be
250 * taken below the minimum, reduce max value (peak reached)
251 * instead. That means that restore ability and repeated
252 * applications of unicorn horn will not be able to recover
253 * all the lost value. As of 3.6.2, we only take away
254 * some (average half, possibly zero) of the excess from max
255 * instead of all of it, but without intervening recovery, it
256 * can still eventually drop to the minimum allowed. After
257 * that, it can't be recovered, only improved with new gains.
259 * This used to assign a new negative value to incr and then
260 * add it, but that could affect messages below, possibly
261 * making a large decrease be described as a small one.
263 * decr = rn2(-(ABASE - ATTRMIN) + 1);
265 decr = rn2(ATTRMIN(ndx) - ABASE(ndx) + 1);
266 ABASE(ndx) = ATTRMIN(ndx);
268 if (AMAX(ndx) < ATTRMIN(ndx))
269 AMAX(ndx) = ATTRMIN(ndx);
271 attrstr = minusattr[ndx];
272 abonflg = (ABON(ndx) > 0);
274 if (ACURR(ndx) == old_acurr) {
275 if (msgflg == 0 && flags.verbose) {
276 if (ABASE(ndx) == old_abase && AMAX(ndx) == old_amax) {
278 pline("You're %s as %s as you can get.",
279 abonflg ? "currently" : "already", attrstr);
281 You("%s
\8f\
\95ª
\82É%s
\81D",
282 abonflg ? "
\8d¡
\82Ì
\82Æ
\82±
\82ë" : "
\8aù
\82É", attrstr);
285 /* current stayed the same but base value changed, or
286 base is at minimum and reduction caused max to drop */
288 Your("innate %s has %s.", attrname[ndx],
289 (incr > 0) ? "improved" : "declined");
291 Your("
\96{
\8e¿
\93I
\82È%s
\82ª%s
\82µ
\82½
\81D", attrname[ndx],
292 (incr > 0) ? "
\8cü
\8fã" : "
\92á
\89º");
301 You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr);
303 You("%s%s
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I", (incr > 1 || incr < -1) ? "
\82Æ
\82Ä
\82à" : "", jconj_adj(attrstr));
305 if (program_state.in_moveloop && (ndx == A_STR || ndx == A_CON))
306 (void) encumber_msg();
311 gainstr(otmp, incr, givemsg)
319 if (ABASE(A_STR) < 18)
320 num = (rn2(4) ? 1 : rnd(6));
321 else if (ABASE(A_STR) < STR18(85))
326 (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num,
330 /* may kill you; cause may be poison or monster like 'a' */
335 int ustr = ABASE(A_STR) - num;
348 (void) adjattrib(A_STR, -num, 1);
351 static const struct poison_effect_message {
352 void VDECL((*delivery_func), (const char *, ...));
353 const char *effect_msg;
356 { You_feel, "weaker" }, /* A_STR */
358 { You_feel, "
\8eã
\82
\82È
\82Á
\82½" }, /* A_STR */
361 { Your, "brain is on fire" }, /* A_INT */
363 { You, "
\93ª
\82É
\8c\8c\82ª
\82Ì
\82Ú
\82Á
\82½" }, /* A_INT */
366 { Your, "judgement is impaired" }, /* A_WIS */
368 { You, "
\94»
\92f
\97Í
\82ð
\8e¸
\82Á
\82½" }, /* A_WIS */
371 { Your, "muscles won't obey you" }, /* A_DEX */
373 { You, "
\8ev
\82¤
\82æ
\82¤
\82É
\93®
\82¯
\82È
\82¢" }, /* A_DEX */
376 { You_feel, "very sick" }, /* A_CON */
378 { You_feel, "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½" }, /* A_CON */
381 { You, "break out in hives" } /* A_CHA */
383 { You, "
\82¶
\82ñ
\82Ü
\82µ
\82ñ
\82ª
\82 \82ç
\82í
\82ê
\82½" } /* A_CHA */
387 /* feedback for attribute loss due to poisoning */
389 poisontell(typ, exclaim)
390 int typ; /* which attribute */
391 boolean exclaim; /* emphasis */
393 void VDECL((*func), (const char *, ...)) = poiseff[typ].delivery_func;
394 const char *msg_txt = poiseff[typ].effect_msg;
397 * "You feel weaker" or "you feel very sick" aren't appropriate when
398 * wearing or wielding something (gauntlets of power, Ogresmasher)
399 * which forces the attribute to maintain its maximum value.
400 * Phrasing for other attributes which might have fixed values
401 * (dunce cap) is such that we don't need message fixups for them.
403 if (typ == A_STR && ACURR(A_STR) == STR19(25))
405 msg_txt = "innately weaker";
407 msg_txt = "
\96{
\8e¿
\93I
\82É
\8eã
\82
\82È
\82Á
\82½";
408 else if (typ == A_CON && ACURR(A_CON) == 25)
410 msg_txt = "sick inside";
412 msg_txt = "
\93à
\95\94\82É
\95a
\82ð
\82©
\82©
\82¦
\82½";
415 (*func)("%s%c", msg_txt, exclaim ? '!' : '.');
417 (*func)("%s%s", msg_txt, exclaim ? "
\81I" : "
\81D");
420 /* called when an attack or trap has poisoned hero (used to be in mon.c) */
422 poisoned(reason, typ, pkiller, fatal, thrown_weapon)
423 const char *reason, /* controls what messages we display */
424 *pkiller; /* for score+log file if fatal */
425 int typ, fatal; /* if fatal is 0, limit damage to adjattrib */
426 boolean thrown_weapon; /* thrown weapons are less deadly */
428 int i, loss, kprefix = KILLED_BY_AN;
430 /* inform player about being poisoned unless that's already been done;
431 "blast" has given a "blast of poison gas" message; "poison arrow",
432 "poison dart", etc have implicitly given poison messages too... */
434 if (strcmp(reason, "blast") && !strstri(reason, "poison")) {
436 if (strcmp(reason, "
\95\97") && strcmp(reason, "
\91§") && !strstri(reason, "
\93Å")) {
439 boolean plural = (reason[strlen(reason) - 1] == 's') ? 1 : 0;
442 /* avoid "The" Orcus's sting was poisoned... */
444 pline("%s%s %s poisoned!",
445 isupper((uchar) *reason) ? "" : "The ", reason,
446 plural ? "were" : "was");
448 pline("%s
\82Í
\93Å
\82É
\82¨
\82©
\82³
\82ê
\82Ä
\82¢
\82é
\81I", reason);
451 if (Poison_resistance) {
453 if (!strcmp(reason, "blast"))
455 if (!strcmp(reason, "
\95\97") || !strcmp(reason, "
\91§"))
457 shieldeff(u.ux, u.uy);
459 pline_The("poison doesn't seem to affect you.");
461 pline("
\93Å
\82Í
\8cø
\82©
\82È
\82©
\82Á
\82½
\82æ
\82¤
\82¾
\81D");
465 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\95s
\97v*/
466 /* suppress killer prefix if it already has one */
467 i = name_to_mon(pkiller);
468 if (i >= LOW_PM && (mons[i].geno & G_UNIQ)) {
470 if (!type_is_pname(&mons[i]))
471 pkiller = the(pkiller);
472 } else if (!strncmpi(pkiller, "the ", 4) || !strncmpi(pkiller, "an ", 3)
473 || !strncmpi(pkiller, "a ", 2)) {
474 /*[ does this need a plural check too? ]*/
479 i = !fatal ? 1 : rn2(fatal + (thrown_weapon ? 20 : 0));
480 if (i == 0 && typ != A_CHA) {
485 pline_The("poison was deadly...");
487 pline("
\93Å
\82Í
\92v
\8e\80\97Ê
\82¾
\82Á
\82½
\81D
\81D
\81D");
489 /* HP damage; more likely--but less severe--with missiles */
490 loss = thrown_weapon ? rnd(6) : rn1(10, 6);
491 losehp(loss, pkiller, kprefix); /* poison damage */
493 /* attribute loss; if typ is A_STR, reduction in current and
494 maximum HP will occur once strength has dropped down to 3 */
495 loss = (thrown_weapon || !fatal) ? 1 : d(2, 2); /* was rn1(3,3) */
496 /* check that a stat change was made */
497 if (adjattrib(typ, -loss, 1))
498 poisontell(typ, TRUE);
502 killer.format = kprefix;
503 Strcpy(killer.name, pkiller);
505 /* "Poisoned by a poisoned ___" is redundant */
506 done(strstri(pkiller, "poison") ? DIED : POISONING);
507 #else /*JP:
\93ú
\96{
\8cê
\82Å
\82Í
\8bæ
\95Ê
\82µ
\82Ä
\82¢
\82È
\82¢*/
511 (void) encumber_msg();
519 if (u.uluck < 0 && u.uluck < LUCKMIN)
521 if (u.uluck > 0 && u.uluck > LUCKMAX)
526 stone_luck(parameter)
527 boolean parameter; /* So I can't think up of a good name. So sue me. --KAA */
529 register struct obj *otmp;
530 register long bonchance = 0;
532 for (otmp = invent; otmp; otmp = otmp->nobj)
533 if (confers_luck(otmp)) {
535 bonchance -= otmp->quan;
536 else if (otmp->blessed)
537 bonchance += otmp->quan;
539 bonchance += otmp->quan;
542 return sgn((int) bonchance);
545 /* there has just been an inventory change affecting a luck-granting item */
549 int luckbon = stone_luck(TRUE);
551 if (!luckbon && !carrying(LUCKSTONE))
553 else if (luckbon >= 0)
554 u.moreluck = LUCKADD;
556 u.moreluck = -LUCKADD;
565 * Note: this gets called on every turn but ATIME() is never set
566 * to non-zero anywhere, and ATEMP() is only used for strength loss
567 * from hunger, so it doesn't actually do anything.
570 for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
571 equilibrium = (i == A_STR && u.uhs >= WEAK) ? -1 : 0;
572 if (ATEMP(i) != equilibrium && ATIME(i) != 0) {
573 if (!(--(ATIME(i)))) { /* countdown for change */
574 ATEMP(i) += (ATEMP(i) > 0) ? -1 : 1;
576 if (ATEMP(i)) /* reset timer */
577 ATIME(i) = 100 / ACURR(A_CON);
582 (void) encumber_msg();
585 #define AVAL 50 /* tune value for exercise gains */
588 exercise(i, inc_or_dec)
592 debugpline0("Exercise:");
593 if (i == A_INT || i == A_CHA)
594 return; /* can't exercise these */
596 /* no physical exercise while polymorphed; the body's temporary */
597 if (Upolyd && i != A_WIS)
600 if (abs(AEXE(i)) < AVAL) {
602 * Law of diminishing returns (Part I):
604 * Gain is harder at higher attribute values.
605 * 79% at "3" --> 0% at "18"
606 * Loss is even at all levels (50%).
608 * Note: *YES* ACURR is the right one to use.
610 AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2);
611 debugpline3("%s, %s AEXE = %d",
612 (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" : (i == A_DEX)
615 (inc_or_dec) ? "inc" : "dec", AEXE(i));
617 if (moves > 0 && (i == A_STR || i == A_CON))
618 (void) encumber_msg();
627 int hs = (u.uhunger > 1000) ? SATIATED : (u.uhunger > 150)
635 debugpline0("exerper: Hunger checks");
638 exercise(A_DEX, FALSE);
639 if (Role_if(PM_MONK))
640 exercise(A_WIS, FALSE);
643 exercise(A_CON, TRUE);
646 exercise(A_STR, FALSE);
647 if (Role_if(PM_MONK)) /* fasting */
648 exercise(A_WIS, TRUE);
652 exercise(A_CON, FALSE);
656 /* Encumbrance Checks */
657 debugpline0("exerper: Encumber checks");
658 switch (near_capacity()) {
660 exercise(A_STR, TRUE);
663 exercise(A_STR, TRUE);
664 exercise(A_DEX, FALSE);
667 exercise(A_DEX, FALSE);
668 exercise(A_CON, FALSE);
675 debugpline0("exerper: Status checks");
676 if ((HClairvoyant & (INTRINSIC | TIMEOUT)) && !BClairvoyant)
677 exercise(A_WIS, TRUE);
679 exercise(A_STR, TRUE);
681 if (Sick || Vomiting)
682 exercise(A_CON, FALSE);
683 if (Confusion || Hallucination)
684 exercise(A_WIS, FALSE);
685 if ((Wounded_legs && !u.usteed) || Fumbling || HStun)
686 exercise(A_DEX, FALSE);
690 /* exercise/abuse text (must be in attribute order, not botl order);
691 phrased as "You must have been [][0]." or "You haven't been [][1]." */
692 static NEARDATA const char *const exertext[A_MAX][2] = {
694 { "exercising diligently", "exercising properly" }, /* Str */
696 { "very observant", "paying attention" }, /* Wis */
697 { "working on your reflexes", "working on reflexes lately" }, /* Dex */
698 { "leading a healthy life-style", "watching your health" }, /* Con */
701 { "
\94O
\93ü
\82è
\82É
\89^
\93®
\82µ
\82Ä
\82¢
\82½", "
\93K
\90Ø
\82É
\89^
\93®
\82µ
\82Ä
\82¢
\82È
\82©
\82Á
\82½" }, /* Str */
703 { "
\90T
\8fd
\82É
\8ds
\93®
\82µ
\82Ä
\82¢
\82½", "
\92\8d\88Ó
\95s
\91«
\82¾
\82Á
\82½" }, /* Wis */
704 { "
\94½
\8eË
\90_
\8co
\82ð
\8eg
\82Á
\82Ä
\82¢
\82½", "
\8dÅ
\8bß
\94½
\8eË
\90_
\8co
\82ð
\8eg
\82Á
\82Ä
\82¢
\82È
\82©
\82Á
\82½" }, /* Dex */
705 { "
\8c\92\8dN
\93I
\82È
\90¶
\8a\88\82ð
\82µ
\82Ä
\82¢
\82½", "
\8c\92\8dN
\8aÇ
\97\9d\82ð
\91Ó
\82Á
\82Ä
\82¢
\82½" }, /* Con */
713 int i, ax, mod_val, lolim, hilim;
715 /* Check out the periodic accumulations */
718 if (moves >= context.next_attrib_check) {
719 debugpline1("exerchk: ready to test. multi = %d.", multi);
721 /* Are we ready for a test? */
722 if (moves >= context.next_attrib_check && !multi) {
723 debugpline0("exerchk: testing.");
725 * Law of diminishing returns (Part II):
727 * The effects of "exercise" and "abuse" wear
728 * off over time. Even if you *don't* get an
729 * increase/decrease, you lose some of the
730 * accumulated effects.
732 for (i = 0; i < A_MAX; ++i) {
734 /* nothing to do here if no exercise or abuse has occurred
735 (Int and Cha always fall into this category) */
737 continue; /* ok to skip nextattrib */
739 mod_val = sgn(ax); /* +1 or -1; used below */
740 /* no further effect for exercise if at max or abuse if at min;
741 can't exceed 18 via exercise even if actual max is higher */
742 lolim = ATTRMIN(i); /* usually 3; might be higher */
743 hilim = ATTRMAX(i); /* usually 18; maybe lower or higher */
746 if ((ax < 0) ? (ABASE(i) <= lolim) : (ABASE(i) >= hilim))
748 /* can't exercise non-Wisdom while polymorphed; previous
749 exercise/abuse gradually wears off without impact then */
750 if (Upolyd && i != A_WIS)
753 debugpline2("exerchk: testing %s (%d).",
769 * Law of diminishing returns (Part III):
771 * You don't *always* gain by exercising.
772 * [MRS 92/10/28 - Treat Wisdom specially for balance.]
774 if (rn2(AVAL) > ((i != A_WIS) ? (abs(ax) * 2 / 3) : abs(ax)))
777 debugpline1("exerchk: changing %d.", i);
778 if (adjattrib(i, mod_val, -1)) {
779 debugpline1("exerchk: changed %d.", i);
780 /* if you actually changed an attrib - zero accumulation */
782 /* then print an explanation */
785 (mod_val > 0) ? "must have been" : "haven't been",
786 exertext[i][(mod_val > 0) ? 0 : 1]);
788 You("%s
\82É
\88á
\82¢
\82È
\82¢
\81D",
789 exertext[i][(mod_val > 0) ? 0 : 1]);
793 /* this used to be ``AEXE(i) /= 2'' but that would produce
794 platform-dependent rounding/truncation for negative vals */
795 AEXE(i) = (abs(ax) / 2) * mod_val;
797 context.next_attrib_check += rn1(200, 800);
798 debugpline1("exerchk: next check at %ld.", context.next_attrib_check);
806 register int i, x, tryct;
808 for (i = 0; i < A_MAX; i++) {
809 ABASE(i) = AMAX(i) = urole.attrbase[i];
810 ATEMP(i) = ATIME(i) = 0;
811 np -= urole.attrbase[i];
815 while (np > 0 && tryct < 100) {
817 for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++)
820 continue; /* impossible */
822 if (ABASE(i) >= ATTRMAX(i)) {
833 while (np < 0 && tryct < 100) { /* for redistribution */
836 for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++)
839 continue; /* impossible */
841 if (ABASE(i) <= ATTRMIN(i)) {
857 for (i = 0; i < A_MAX; i++) {
858 if (i == A_INT || i == A_WIS)
860 /* Polymorphing doesn't change your mind */
862 AMAX(i) += (rn2(5) - 2);
863 if (AMAX(i) > ATTRMAX(i))
864 AMAX(i) = ATTRMAX(i);
865 if (AMAX(i) < ATTRMIN(i))
866 AMAX(i) = ATTRMIN(i);
867 ABASE(i) = ABASE(i) * AMAX(i) / tmp;
868 /* ABASE(i) > ATTRMAX(i) is impossible */
869 if (ABASE(i) < ATTRMIN(i))
870 ABASE(i) = ATTRMIN(i);
872 (void) encumber_msg();
882 if (ability == &(HWarning) || ability == &(HSee_invisible))
886 STATIC_OVL const struct innate *
892 const struct innate *abil;
894 { PM_ARCHEOLOGIST, arc_abil },
895 { PM_BARBARIAN, bar_abil },
896 { PM_CAVEMAN, cav_abil },
897 { PM_HEALER, hea_abil },
898 { PM_KNIGHT, kni_abil },
899 { PM_MONK, mon_abil },
900 { PM_PRIEST, pri_abil },
901 { PM_RANGER, ran_abil },
902 { PM_ROGUE, rog_abil },
903 { PM_SAMURAI, sam_abil },
904 { PM_TOURIST, tou_abil },
905 { PM_VALKYRIE, val_abil },
906 { PM_WIZARD, wiz_abil },
911 for (i = 0; roleabils[i].abil && roleabils[i].role != r; i++)
913 return roleabils[i].abil;
916 STATIC_OVL const struct innate *
917 check_innate_abil(ability, frommask)
921 const struct innate *abil = 0;
923 if (frommask == FROMEXPER)
924 abil = role_abil(Role_switch);
925 else if (frommask == FROMRACE)
926 switch (Race_switch) {
946 while (abil && abil->ability) {
947 if ((abil->ability == ability) && (u.ulevel >= abil->ulevel))
951 return (struct innate *) 0;
954 /* reasons for innate ability */
956 #define FROM_ROLE 1 /* from experience at level 1 */
958 #define FROM_INTR 3 /* intrinsically (eating some corpse or prayer reward) */
959 #define FROM_EXP 4 /* from experience for some level > 1 */
963 /* check whether particular ability has been obtained via innate attribute */
968 const struct innate *iptr;
970 if ((iptr = check_innate_abil(ability, FROMEXPER)) != 0)
971 return (iptr->ulevel == 1) ? FROM_ROLE : FROM_EXP;
972 if ((iptr = check_innate_abil(ability, FROMRACE)) != 0)
974 if ((*ability & FROMOUTSIDE) != 0L)
976 if ((*ability & FROMFORM) != 0L)
987 /* innately() would report FROM_FORM for this; caller wants specificity */
988 if (propidx == DRAIN_RES && u.ulycn >= LOW_PM)
990 if (propidx == FAST && Very_fast)
991 return FROM_NONE; /* can't become very fast innately */
992 if ((innateness = innately(&u.uprops[propidx].intrinsic)) != FROM_NONE)
994 if (propidx == JUMPING && Role_if(PM_KNIGHT)
995 /* knight has intrinsic jumping, but extrinsic is more versatile so
996 ignore innateness if equipment is going to claim responsibility */
997 && !u.uprops[propidx].extrinsic)
999 if (propidx == BLINDED && !haseyes(youmonst.data))
1006 int propidx; /* special cases can have negative values */
1008 static char buf[BUFSZ];
1012 * Restrict the source of the attributes just to debug mode for now
1014 /*JP:
\81u
\82 \82È
\82½
\82Í
\82 \82È
\82½
\82Ì
\81c
\82É
\82æ
\82Á
\82Ä
\81v
\82Æ
\82È
\82é
\82Æ
\95s
\8e©
\91R
\82È
\82Ì
\82Åsimpleonames()
\82ð
\8eg
\82¤*/
1015 /*JP:
\96{
\97\88\82Íminimal_xname()
\82ð
\8eg
\82¤
\82×
\82«
\82¾
\82ªstatic
\82È
\82Ì
\82Å
\91ã
\97p*/
1018 static NEARDATA const char because_of[] = " because of %s";
1020 static NEARDATA const char because_of[] = "%s
\82É
\82æ
\82Á
\82Ä";
1026 struct obj *obj = (struct obj *) 0;
1027 int innateness = is_innate(propidx);
1030 * Properties can be obtained from multiple sources and we
1031 * try to pick the most significant one. Classification
1032 * priority is not set in stone; current precedence is:
1033 * "from the start" (from role or race at level 1),
1034 * "from outside" (eating corpse, divine reward, blessed potion),
1035 * "from experience" (from role or race at level 2+),
1036 * "from current form" (while polymorphed),
1037 * "from timed effect" (potion or spell),
1038 * "from worn/wielded equipment" (Firebrand, elven boots, &c),
1039 * "from carried equipment" (mainly quest artifacts).
1040 * There are exceptions. Versatile jumping from spell or boots
1041 * takes priority over knight's innate but limited jumping.
1043 if (propidx == BLINDED && u.uroleplay.blind)
1045 Sprintf(buf, " from birth");
1047 Sprintf(buf, "
\90¶
\82Ü
\82ê
\82Ä
\82©
\82ç
\82¸
\82Á
\82Æ");
1048 else if (innateness == FROM_ROLE || innateness == FROM_RACE)
1050 Strcpy(buf, " innately");
1052 Strcpy(buf, "
\90¶
\82Ü
\82ê
\82È
\82ª
\82ç
\82É");
1053 else if (innateness == FROM_INTR) /* [].intrinsic & FROMOUTSIDE */
1055 Strcpy(buf, " intrinsically");
1057 Strcpy(buf, "
\96{
\8e¿
\93I
\82É");
1058 else if (innateness == FROM_EXP)
1060 Strcpy(buf, " because of your experience");
1062 Strcpy(buf, "
\8co
\8c±
\82É
\82æ
\82Á
\82Ä");
1063 else if (innateness == FROM_LYCN)
1065 Strcpy(buf, " due to your lycanthropy");
1067 Strcpy(buf, "
\8fb
\89»
\95a
\82É
\82æ
\82Á
\82Ä");
1068 else if (innateness == FROM_FORM)
1070 Strcpy(buf, " from current creature form");
1072 Strcpy(buf, "
\8c»
\8dÝ
\82Ì
\8ep
\82É
\82æ
\82Á
\82Ä");
1073 else if (propidx == FAST && Very_fast)
1075 Sprintf(buf, because_of,
1076 ((HFast & TIMEOUT) != 0L) ? "a potion or spell"
1077 : ((EFast & W_ARMF) != 0L && uarmf->dknown
1078 && objects[uarmf->otyp].oc_name_known)
1079 ? ysimple_name(uarmf) /* speed boots */
1080 : EFast ? "worn equipment"
1083 Sprintf(buf, because_of,
1084 ((HFast & TIMEOUT) != 0L) ? "
\96ò
\82â
\8eô
\95¶"
1085 : ((EFast & W_ARMF) != 0L && uarmf->dknown
1086 && objects[uarmf->otyp].oc_name_known)
1087 ? ysimple_name(uarmf) /* speed boots */
1088 : EFast ? "
\91\95\94õ"
1092 && (obj = what_gives(&u.uprops[propidx].extrinsic)) != 0)
1093 Sprintf(buf, because_of, obj->oartifact
1094 ? bare_artifactname(obj)
1096 : ysimple_name(obj));
1098 : simpleonames(obj));
1099 else if (propidx == BLINDED && Blindfolded_only)
1101 Sprintf(buf, because_of, ysimple_name(ublindf));
1103 Sprintf(buf, because_of, simpleonames(ublindf));
1105 #if 0 /*JP*//*
\95s
\97v*/
1106 /* remove some verbosity and/or redundancy */
1107 if ((p = strstri(buf, " pair of ")) != 0)
1108 copynchars(p + 1, p + 9, BUFSZ); /* overlapping buffers ok */
1109 else if (propidx == STRANGLED
1110 && (p = strstri(buf, " of strangulation")) != 0)
1114 } else { /* negative property index */
1115 /* if more blocking capabilities get implemented we'll need to
1116 replace this with what_blocks() comparable to what_gives() */
1120 && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD)
1121 Sprintf(buf, because_of, bare_artifactname(ublindf));
1124 if (u.uprops[INVIS].blocked & W_ARMC)
1126 Sprintf(buf, because_of,
1127 ysimple_name(uarmc)); /* mummy wrapping */
1129 Sprintf(buf, because_of,
1130 simpleonames(uarmc)); /* mummy wrapping */
1134 if (wizard && (u.uprops[CLAIRVOYANT].blocked & W_ARMH))
1136 Sprintf(buf, because_of,
1137 ysimple_name(uarmh)); /* cornuthaum */
1139 Sprintf(buf, because_of,
1140 simpleonames(uarmh)); /* cornuthaum */
1151 adjabil(oldlevel, newlevel)
1152 int oldlevel, newlevel;
1154 register const struct innate *abil, *rabil;
1155 long prevabil, mask = FROMEXPER;
1157 abil = role_abil(Role_switch);
1159 switch (Race_switch) {
1174 while (abil || rabil) {
1175 /* Have we finished with the intrinsics list? */
1176 if (!abil || !abil->ability) {
1177 /* Try the race intrinsics */
1178 if (!rabil || !rabil->ability)
1184 prevabil = *(abil->ability);
1185 if (oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
1186 /* Abilities gained at level 1 can never be lost
1187 * via level loss, only via means that remove _any_
1188 * sort of ability. A "gain" of such an ability from
1189 * an outside source is devoid of meaning, so we set
1190 * FROMOUTSIDE to avoid such gains.
1192 if (abil->ulevel == 1)
1193 *(abil->ability) |= (mask | FROMOUTSIDE);
1195 *(abil->ability) |= mask;
1196 if (!(*(abil->ability) & INTRINSIC & ~mask)) {
1197 if (*(abil->gainstr))
1199 You_feel("%s!", abil->gainstr);
1201 You("%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I", abil->gainstr);
1203 } else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) {
1204 *(abil->ability) &= ~mask;
1205 if (!(*(abil->ability) & INTRINSIC)) {
1206 if (*(abil->losestr))
1208 You_feel("%s!", abil->losestr);
1210 You("%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81I", abil->losestr);
1211 /*JP:
\82±
\82Ì
\8fð
\8c\8f\82Í
\96\9e\82³
\82È
\82¢
\82Í
\82¸
\81D*/
1212 else if (*(abil->gainstr))
1213 You_feel("less %s!", abil->gainstr);
1216 if (prevabil != *(abil->ability)) /* it changed */
1217 postadjabil(abil->ability);
1222 if (newlevel > oldlevel)
1223 add_weapon_skill(newlevel - oldlevel);
1225 lose_weapon_skill(oldlevel - newlevel);
1234 if (u.ulevel == 0) {
1235 /* Initialize hit points */
1236 hp = urole.hpadv.infix + urace.hpadv.infix;
1237 if (urole.hpadv.inrnd > 0)
1238 hp += rnd(urole.hpadv.inrnd);
1239 if (urace.hpadv.inrnd > 0)
1240 hp += rnd(urace.hpadv.inrnd);
1241 if (moves <= 1L) { /* initial hero; skip for polyself to new man */
1242 /* Initialize alignment stuff */
1243 u.ualign.type = aligns[flags.initalign].value;
1244 u.ualign.record = urole.initrecord;
1246 /* no Con adjustment for initial hit points */
1248 if (u.ulevel < urole.xlev) {
1249 hp = urole.hpadv.lofix + urace.hpadv.lofix;
1250 if (urole.hpadv.lornd > 0)
1251 hp += rnd(urole.hpadv.lornd);
1252 if (urace.hpadv.lornd > 0)
1253 hp += rnd(urace.hpadv.lornd);
1255 hp = urole.hpadv.hifix + urace.hpadv.hifix;
1256 if (urole.hpadv.hirnd > 0)
1257 hp += rnd(urole.hpadv.hirnd);
1258 if (urace.hpadv.hirnd > 0)
1259 hp += rnd(urace.hpadv.hirnd);
1261 if (ACURR(A_CON) <= 3)
1263 else if (ACURR(A_CON) <= 6)
1265 else if (ACURR(A_CON) <= 14)
1267 else if (ACURR(A_CON) <= 16)
1269 else if (ACURR(A_CON) == 17)
1271 else if (ACURR(A_CON) == 18)
1279 if (u.ulevel < MAXULEV)
1280 u.uhpinc[u.ulevel] = (xchar) hp;
1288 register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]);
1291 if (tmp >= 125 || (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER))
1295 return (x = ((tmp <= 3) ? 3 : tmp));
1297 return (schar) ((tmp <= 3) ? 3 : tmp);
1299 } else if (x == A_CHA) {
1301 && (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS
1302 || u.umonnum == PM_INCUBUS))
1304 } else if (x == A_CON) {
1305 if (uwep && uwep->oartifact == ART_OGRESMASHER)
1307 } else if (x == A_INT || x == A_WIS) {
1308 /* yes, this may raise int/wis if player is sufficiently
1309 * stupid. there are lower levels of cognition than "dunce".
1311 if (uarmh && uarmh->otyp == DUNCE_CAP)
1315 return (x = ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
1317 return (schar) ((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp);
1321 /* condense clumsy ACURR(A_STR) value into value that fits into game formulas
1326 register int str = ACURR(A_STR);
1331 return (schar) (19 + str / 50); /* map to 19..21 */
1333 return (schar) (min(str, 125) - 100); /* 22..25 */
1336 /* when wearing (or taking off) an unID'd item, this routine is used
1337 to distinguish between observable +0 result and no-visible-effect
1338 due to an attribute not being able to exceed maximum or minimum */
1340 extremeattr(attrindx) /* does attrindx's value match its max or min? */
1343 /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */
1344 int lolimit = 3, hilimit = 25, curval = ACURR(attrindx);
1346 /* upper limit for Str is 25 but its value is encoded differently */
1347 if (attrindx == A_STR) {
1348 hilimit = STR19(25); /* 125 */
1349 /* lower limit for Str can also be 25 */
1350 if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER)
1352 } else if (attrindx == A_CON) {
1353 if (uwep && uwep->oartifact == ART_OGRESMASHER)
1356 /* this exception is hypothetical; the only other worn item affecting
1357 Int or Wis is another helmet so can't be in use at the same time */
1358 if (attrindx == A_INT || attrindx == A_WIS) {
1359 if (uarmh && uarmh->otyp == DUNCE_CAP)
1360 hilimit = lolimit = 6;
1363 /* are we currently at either limit? */
1364 return (curval == lolimit || curval == hilimit) ? TRUE : FALSE;
1367 /* avoid possible problems with alignment overflow, and provide a centralized
1368 location for any future alignment limits */
1373 int newalign = u.ualign.record + n;
1376 if (newalign < u.ualign.record)
1377 u.ualign.record = newalign;
1378 } else if (newalign > u.ualign.record) {
1379 u.ualign.record = newalign;
1380 if (u.ualign.record > ALIGNLIM)
1381 u.ualign.record = ALIGNLIM;
1385 /* change hero's alignment type, possibly losing use of artifacts */
1387 uchangealign(newalign, reason)
1389 int reason; /* 0==conversion, 1==helm-of-OA on, 2==helm-of-OA off */
1391 aligntyp oldalign = u.ualign.type;
1393 u.ublessed = 0; /* lose divine protection */
1394 /* You/Your/pline message with call flush_screen(), triggering bot(),
1395 so the actual data change needs to come before the message */
1396 context.botl = TRUE; /* status line needs updating */
1398 /* conversion via altar */
1399 u.ualignbase[A_CURRENT] = (aligntyp) newalign;
1400 /* worn helm of opposite alignment might block change */
1401 if (!uarmh || uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT)
1402 u.ualign.type = u.ualignbase[A_CURRENT];
1404 You("have a %ssense of a new direction.",
1405 (u.ualign.type != oldalign) ? "sudden " : "");
1407 You("%s
\95Ê
\82Ì
\95û
\8cü
\90«
\82É
\82ß
\82´
\82ß
\82½
\81D",
1408 (u.ualign.type != oldalign) ? "
\93Ë
\91R" : "");
1411 /* putting on or taking off a helm of opposite alignment */
1412 u.ualign.type = (aligntyp) newalign;
1415 Your("mind oscillates %s.", Hallucination ? "wildly" : "briefly");
1417 You("%s
\90Q
\95Ô
\82Á
\82½
\81D", Hallucination ? "
\8dr
\82Á
\82Û
\82" : "
\82 \82Á
\82³
\82è
\82Æ");
1418 else if (reason == 2)
1420 Your("mind is %s.", Hallucination
1421 ? "much of a muchness"
1422 : "back in sync with your body");
1424 Your("
\90S
\82Í%s
\81D", Hallucination
1425 ? "
\8e\97\82½
\82è
\8añ
\82Á
\82½
\82è
\82É
\82È
\82Á
\82½"
1426 : "
\8dÄ
\82Ñ
\91Ì
\82Æ
\88ê
\92v
\82·
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82½");
1429 if (u.ualign.type != oldalign) {
1430 u.ualign.record = 0; /* slate is wiped clean */
1431 retouch_equipment(0);