OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / src / attrib.c
index 94bb78e..67f07a8 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 attrib.c        $NHDT-Date: 1449269911 2015/12/04 22:58:31 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
+/* NetHack 3.6 attrib.c        $NHDT-Date: 1494034337 2017/05/06 01:32:17 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.62 $ */
 /*      Copyright 1988, 1989, 1990, 1992, M. Stephenson           */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -31,6 +31,15 @@ static const char
                            "\8aÔ\94²\82¯\82¾", "\95s\8aí\97p\82¾",
                            "\82Ð\8eã\82¾","\8fX\82¢" };
 #endif
+/* also used by enlightenment for non-abbreviated status info */
+const char
+#if 0 /*JP*/
+    *const attrname[] = { "strength", "intelligence", "wisdom",
+                          "dexterity", "constitution", "charisma" };
+#else
+    *const attrname[] = { "\8b­\82³", "\92m\97Í", "\8c«\82³",
+                          "\91f\91\81\82³", "\91Ï\8bv\97Í", "\96£\97Í" };
+#endif
 
 static const struct innate {
     schar ulevel;
@@ -175,16 +184,28 @@ static const struct innate {
                  { 0, 0, 0, 0 } },
 
   /* Intrinsics conferred by race */
+  dwa_abil[] = { { 1, &HInfravision, "", "" },
+                 { 0, 0, 0, 0 } },
+
+  elf_abil[] = { { 1, &HInfravision, "", "" },
 /*JP
-    elf_abil[] = { { 4, &(HSleep_resistance), "awake", "tired" },
+                 { 4, &HSleep_resistance, "awake", "tired" },
 */
-    elf_abil[] = { { 4, &(HSleep_resistance), "\96Ú\82ª\8ao\82ß\82½", "\96°\82­\82È\82Á\82½" },
-                   { 0, 0, 0, 0 } },
+                 { 4, &(HSleep_resistance), "\96Ú\82ª\8ao\82ß\82½", "\96°\82­\82È\82Á\82½" },
+                 { 0, 0, 0, 0 } },
 
-  orc_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 0, 0, 0, 0 } };
+  gno_abil[] = { { 1, &HInfravision, "", "" },
+                 { 0, 0, 0, 0 } },
+
+  orc_abil[] = { { 1, &HInfravision, "", "" },
+                 { 1, &HPoison_resistance, "", "" },
+                 { 0, 0, 0, 0 } },
+
+  hum_abil[] = { { 0, 0, 0, 0 } };
 
 STATIC_DCL void NDECL(exerper);
 STATIC_DCL void FDECL(postadjabil, (long *));
+STATIC_DCL const struct innate *FDECL(role_abil, (int));
 STATIC_DCL const struct innate *FDECL(check_innate_abil, (long *, long));
 STATIC_DCL int FDECL(innately, (long *));
 
@@ -194,7 +215,7 @@ adjattrib(ndx, incr, msgflg)
 int ndx, incr;
 int msgflg; /* positive => no message, zero => message, and */
 {           /* negative => conditional (msg if change made) */
-    int old_acurr;
+    int old_acurr, old_abase;
     boolean abonflg;
     const char *attrstr;
 
@@ -211,6 +232,7 @@ int msgflg; /* positive => no message, zero => message, and */
     }
 
     old_acurr = ACURR(ndx);
+    old_abase = ABASE(ndx);
     if (incr > 0) {
         ABASE(ndx) += incr;
         if (ABASE(ndx) > AMAX(ndx)) {
@@ -235,14 +257,19 @@ int msgflg; /* positive => no message, zero => message, and */
         abonflg = (ABON(ndx) > 0);
     }
     if (ACURR(ndx) == old_acurr) {
-        if (msgflg == 0 && flags.verbose)
+        if (msgflg == 0 && flags.verbose) {
+            if (ABASE(ndx) == old_abase)
 #if 0 /*JP*/
-            pline("You're %s as %s as you can get.",
-                  abonflg ? "currently" : "already", attrstr);
+                pline("You're %s as %s as you can get.",
+                      abonflg ? "currently" : "already", attrstr);
 #else
-            You("%s\8f\\95ª\82É%s\81D",
-                  abonflg ? "\8d¡\82Ì\82Æ\82±\82ë" : "\8aù\82É", attrstr);
+                You("%s\8f\\95ª\82É%s\81D",
+                      abonflg ? "\8d¡\82Ì\82Æ\82±\82ë" : "\8aù\82É", attrstr);
 #endif
+            else /* current stayed the same but base value changed */
+                Your("innate %s has %s.", attrname[ndx],
+                     (incr > 0) ? "improved" : "declined");
+        }
         return FALSE;
     }
 
@@ -341,19 +368,31 @@ int typ;         /* which attribute */
 boolean exclaim; /* emphasis */
 {
     void VDECL((*func), (const char *, ...)) = poiseff[typ].delivery_func;
+    const char *msg_txt = poiseff[typ].effect_msg;
+
+    /*
+     * "You feel weaker" or "you feel very sick" aren't appropriate when
+     * wearing or wielding something (gauntlets of power, Ogresmasher)
+     * which forces the attribute to maintain its maximum value.
+     * Phrasing for other attributes which might have fixed values
+     * (dunce cap) is such that we don't need message fixups for them.
+     */
+    if (typ == A_STR && ACURR(A_STR) == STR19(25))
+        msg_txt = "innately weaker";
+    else if (typ == A_CON && ACURR(A_CON) == 25)
+        msg_txt = "sick inside";
 
 /*JP
-    (*func)("%s%c", poiseff[typ].effect_msg, exclaim ? '!' : '.');
+    (*func)("%s%c", msg_txt, exclaim ? '!' : '.');
 */
-    (*func)("%s%s", poiseff[typ].effect_msg, exclaim ? "\81I" : "\81D");
+    (*func)("%s%s", msg_txt, exclaim ? "\81I" : "\81D");
 }
 
-/* called when an attack or trap has poisoned the hero (used to be in mon.c)
- */
+/* called when an attack or trap has poisoned hero (used to be in mon.c) */
 void
 poisoned(reason, typ, pkiller, fatal, thrown_weapon)
 const char *reason,    /* controls what messages we display */
-    *pkiller;          /* for score+log file if fatal */
+           *pkiller;   /* for score+log file if fatal */
 int typ, fatal;        /* if fatal is 0, limit damage to adjattrib */
 boolean thrown_weapon; /* thrown weapons are less deadly */
 {
@@ -373,7 +412,8 @@ boolean thrown_weapon; /* thrown weapons are less deadly */
 
         /* avoid "The" Orcus's sting was poisoned... */
 #if 0 /*JP*/
-        pline("%s%s %s poisoned!", isupper(*reason) ? "" : "The ", reason,
+        pline("%s%s %s poisoned!",
+              isupper((uchar) *reason) ? "" : "The ", reason,
               plural ? "were" : "was");
 #else
         pline("%s\82Í\93Å\82É\82¨\82©\82³\82ê\82Ä\82¢\82é\81I", reason);
@@ -411,6 +451,7 @@ boolean thrown_weapon; /* thrown weapons are less deadly */
     if (i == 0 && typ != A_CHA) {
         /* instant kill */
         u.uhp = -1;
+        context.botl = TRUE;
 /*JP
         pline_The("poison was deadly...");
 */
@@ -489,20 +530,27 @@ set_moreluck()
 void
 restore_attrib()
 {
-    int i;
+    int i, equilibrium;;
 
-    for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
+    /*
+     * Note:  this gets called on every turn but ATIME() is never set
+     * to non-zero anywhere, and ATEMP() is only used for strength loss
+     * from hunger, so it doesn't actually do anything.
+     */
 
-        if (ATEMP(i) && ATIME(i)) {
+    for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
+        equilibrium = (i == A_STR && u.uhs >= WEAK) ? -1 : 0;
+        if (ATEMP(i) != equilibrium && ATIME(i) != 0) {
             if (!(--(ATIME(i)))) { /* countdown for change */
-                ATEMP(i) += ATEMP(i) > 0 ? -1 : 1;
-
+                ATEMP(i) += (ATEMP(i) > 0) ? -1 : 1;
+                context.botl = 1;
                 if (ATEMP(i)) /* reset timer */
                     ATIME(i) = 100 / ACURR(A_CON);
             }
         }
     }
-    (void) encumber_msg();
+    if (context.botl)
+        (void) encumber_msg();
 }
 
 #define AVAL 50 /* tune value for exercise gains */
@@ -807,6 +855,36 @@ long *ability;
 }
 
 STATIC_OVL const struct innate *
+role_abil(r)
+int r;
+{
+    const struct {
+        short role;
+        const struct innate *abil;
+    } roleabils[] = {
+        { PM_ARCHEOLOGIST, arc_abil },
+        { PM_BARBARIAN, bar_abil },
+        { PM_CAVEMAN, cav_abil },
+        { PM_HEALER, hea_abil },
+        { PM_KNIGHT, kni_abil },
+        { PM_MONK, mon_abil },
+        { PM_PRIEST, pri_abil },
+        { PM_RANGER, ran_abil },
+        { PM_ROGUE, rog_abil },
+        { PM_SAMURAI, sam_abil },
+        { PM_TOURIST, tou_abil },
+        { PM_VALKYRIE, val_abil },
+        { PM_WIZARD, wiz_abil },
+        { 0, 0 }
+    };
+    int i;
+
+    for (i = 0; roleabils[i].abil && roleabils[i].role != r; i++)
+        continue;
+    return roleabils[i].abil;
+}
+
+STATIC_OVL const struct innate *
 check_innate_abil(ability, frommask)
 long *ability;
 long frommask;
@@ -814,60 +892,24 @@ long frommask;
     const struct innate *abil = 0;
 
     if (frommask == FROMEXPER)
-        switch (Role_switch) {
-        case PM_ARCHEOLOGIST:
-            abil = arc_abil;
-            break;
-        case PM_BARBARIAN:
-            abil = bar_abil;
-            break;
-        case PM_CAVEMAN:
-            abil = cav_abil;
-            break;
-        case PM_HEALER:
-            abil = hea_abil;
-            break;
-        case PM_KNIGHT:
-            abil = kni_abil;
-            break;
-        case PM_MONK:
-            abil = mon_abil;
-            break;
-        case PM_PRIEST:
-            abil = pri_abil;
-            break;
-        case PM_RANGER:
-            abil = ran_abil;
-            break;
-        case PM_ROGUE:
-            abil = rog_abil;
-            break;
-        case PM_SAMURAI:
-            abil = sam_abil;
-            break;
-        case PM_TOURIST:
-            abil = tou_abil;
-            break;
-        case PM_VALKYRIE:
-            abil = val_abil;
-            break;
-        case PM_WIZARD:
-            abil = wiz_abil;
-            break;
-        default:
-            break;
-        }
+        abil = role_abil(Role_switch);
     else if (frommask == FROMRACE)
         switch (Race_switch) {
+        case PM_DWARF:
+            abil = dwa_abil;
+            break;
         case PM_ELF:
             abil = elf_abil;
             break;
+        case PM_GNOME:
+            abil = gno_abil;
+            break;
         case PM_ORC:
             abil = orc_abil;
             break;
         case PM_HUMAN:
-        case PM_DWARF:
-        case PM_GNOME:
+            abil = hum_abil;
+            break;
         default:
             break;
         }
@@ -880,31 +922,54 @@ long frommask;
     return (struct innate *) 0;
 }
 
-/*
- * returns 1 if FROMRACE or FROMEXPER and exper level == 1
- * returns 2 if FROMEXPER and exper level > 1
- * otherwise returns 0
- */
+/* reasons for innate ability */
+#define FROM_NONE 0
+#define FROM_ROLE 1 /* from experience at level 1 */
+#define FROM_RACE 2
+#define FROM_INTR 3 /* intrinsically (eating some corpse or prayer reward) */
+#define FROM_EXP  4 /* from experience for some level > 1 */
+#define FROM_FORM 5
+#define FROM_LYCN 6
+
+/* check whether particular ability has been obtained via innate attribute */
 STATIC_OVL int
 innately(ability)
 long *ability;
 {
     const struct innate *iptr;
 
+    if ((iptr = check_innate_abil(ability, FROMEXPER)) != 0)
+        return (iptr->ulevel == 1) ? FROM_ROLE : FROM_EXP;
     if ((iptr = check_innate_abil(ability, FROMRACE)) != 0)
-        return 1;
-    else if ((iptr = check_innate_abil(ability, FROMEXPER)) != 0)
-        return (iptr->ulevel == 1) ? 1 : 2;
-    return 0;
+        return FROM_RACE;
+    if ((*ability & FROMOUTSIDE) != 0L)
+        return FROM_INTR;
+    if ((*ability & FROMFORM) != 0L)
+        return FROM_FORM;
+    return FROM_NONE;
 }
 
 int
 is_innate(propidx)
 int propidx;
 {
+    int innateness;
+
+    /* innately() would report FROM_FORM for this; caller wants specificity */
+    if (propidx == DRAIN_RES && u.ulycn >= LOW_PM)
+        return FROM_LYCN;
+    if (propidx == FAST && Very_fast)
+        return FROM_NONE; /* can't become very fast innately */
+    if ((innateness = innately(&u.uprops[propidx].intrinsic)) != FROM_NONE)
+        return innateness;
+    if (propidx == JUMPING && Role_if(PM_KNIGHT)
+        /* knight has intrinsic jumping, but extrinsic is more versatile so
+           ignore innateness if equipment is going to claim responsibility */
+        && !u.uprops[propidx].extrinsic)
+        return FROM_ROLE;
     if (propidx == BLINDED && !haseyes(youmonst.data))
-        return 1;
-    return innately(&u.uprops[propidx].intrinsic);
+        return FROM_FORM;
+    return FROM_NONE;
 }
 
 char *
@@ -930,31 +995,59 @@ int propidx; /* special cases can have negative values */
             char *p;
 #endif
             struct obj *obj = (struct obj *) 0;
-            int innate = is_innate(propidx);
+            int innateness = is_innate(propidx);
 
-            if (innate == 2)
+            /*
+             * Properties can be obtained from multiple sources and we
+             * try to pick the most significant one.  Classification
+             * priority is not set in stone; current precedence is:
+             * "from the start" (from role or race at level 1),
+             * "from outside" (eating corpse, divine reward, blessed potion),
+             * "from experience" (from role or race at level 2+),
+             * "from current form" (while polymorphed),
+             * "from timed effect" (potion or spell),
+             * "from worn/wielded equipment" (Firebrand, elven boots, &c),
+             * "from carried equipment" (mainly quest artifacts).
+             * There are exceptions.  Versatile jumping from spell or boots
+             * takes priority over knight's innate but limited jumping.
+             */
+            if (propidx == BLINDED && u.uroleplay.blind)
 /*JP
-                Strcpy(buf, " because of your experience");
+                Sprintf(buf, " from birth");
 */
-                Strcpy(buf, "\8co\8c±\82É\82æ\82Á\82Ä");
-            else if (innate == 1)
+                Sprintf(buf, "\90\82Ü\82ê\82Ä\82©\82ç\82¸\82Á\82Æ");
+            else if (innateness == FROM_ROLE || innateness == FROM_RACE)
 /*JP
                 Strcpy(buf, " innately");
 */
                 Strcpy(buf, "\90\82Ü\82ê\82È\82ª\82ç\82É");
+            else if (innateness == FROM_INTR) /* [].intrinsic & FROMOUTSIDE */
+                Strcpy(buf, " intrinsically");
+            else if (innateness == FROM_EXP)
+/*JP
+                Strcpy(buf, " because of your experience");
+*/
+                Strcpy(buf, "\8co\8c±\82É\82æ\82Á\82Ä");
+            else if (innateness == FROM_LYCN)
+                Strcpy(buf, " due to your lycanthropy");
+            else if (innateness == FROM_FORM)
+                Strcpy(buf, " from current creature form");
+            else if (propidx == FAST && Very_fast)
+                Sprintf(buf, because_of,
+                        ((HFast & TIMEOUT) != 0L) ? "a potion or spell"
+                          : ((EFast & W_ARMF) != 0L && uarmf->dknown
+                             && objects[uarmf->otyp].oc_name_known)
+                              ? ysimple_name(uarmf) /* speed boots */
+                                : EFast ? "worn equipment"
+                                  : something);
             else if (wizard
-                     && (obj = what_gives(&u.uprops[propidx].extrinsic)))
+                     && (obj = what_gives(&u.uprops[propidx].extrinsic)) != 0)
                 Sprintf(buf, because_of, obj->oartifact
                                              ? bare_artifactname(obj)
 /*JP
                                              : ysimple_name(obj));
 */
                                              : simpleonames(obj));
-            else if (propidx == BLINDED && u.uroleplay.blind)
-/*JP
-                Sprintf(buf, " from birth");
-*/
-                Sprintf(buf, "\90\82Ü\82ê\82Ä\82©\82ç\82¸\82Á\82Æ");
             else if (propidx == BLINDED && Blindfolded_only)
 /*JP
                 Sprintf(buf, because_of, ysimple_name(ublindf));
@@ -1011,50 +1104,7 @@ int oldlevel, newlevel;
     register const struct innate *abil, *rabil;
     long prevabil, mask = FROMEXPER;
 
-    switch (Role_switch) {
-    case PM_ARCHEOLOGIST:
-        abil = arc_abil;
-        break;
-    case PM_BARBARIAN:
-        abil = bar_abil;
-        break;
-    case PM_CAVEMAN:
-        abil = cav_abil;
-        break;
-    case PM_HEALER:
-        abil = hea_abil;
-        break;
-    case PM_KNIGHT:
-        abil = kni_abil;
-        break;
-    case PM_MONK:
-        abil = mon_abil;
-        break;
-    case PM_PRIEST:
-        abil = pri_abil;
-        break;
-    case PM_RANGER:
-        abil = ran_abil;
-        break;
-    case PM_ROGUE:
-        abil = rog_abil;
-        break;
-    case PM_SAMURAI:
-        abil = sam_abil;
-        break;
-    case PM_TOURIST:
-        abil = tou_abil;
-        break;
-    case PM_VALKYRIE:
-        abil = val_abil;
-        break;
-    case PM_WIZARD:
-        abil = wiz_abil;
-        break;
-    default:
-        abil = 0;
-        break;
-    }
+    abil = role_abil(Role_switch);
 
     switch (Race_switch) {
     case PM_ELF:
@@ -1194,13 +1244,16 @@ int x;
 #ifdef WIN32_BUG
             return (x = ((tmp <= 3) ? 3 : tmp));
 #else
-        return (schar) ((tmp <= 3) ? 3 : tmp);
+            return (schar) ((tmp <= 3) ? 3 : tmp);
 #endif
     } else if (x == A_CHA) {
         if (tmp < 18
             && (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS
                 || u.umonnum == PM_INCUBUS))
             return (schar) 18;
+    } else if (x == A_CON) {
+        if (uwep && uwep->oartifact == ART_OGRESMASHER)
+            return (schar) 25;
     } else if (x == A_INT || x == A_WIS) {
         /* yes, this may raise int/wis if player is sufficiently
          * stupid.  there are lower levels of cognition than "dunce".
@@ -1246,6 +1299,9 @@ int attrindx;
         /* lower limit for Str can also be 25 */
         if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER)
             lolimit = hilimit;
+    } else if (attrindx == A_CON) {
+        if (uwep && uwep->oartifact == ART_OGRESMASHER)
+            lolimit = hilimit;
     }
     /* this exception is hypothetical; the only other worn item affecting
        Int or Wis is another helmet so can't be in use at the same time */