]> granicus.if.org Git - nethack/commitdiff
gender for figurines
authorPatR <rankin@nethack.org>
Thu, 17 Jun 2021 23:03:45 +0000 (16:03 -0700)
committerPatR <rankin@nethack.org>
Thu, 17 Jun 2021 23:03:45 +0000 (16:03 -0700)
Use (obj->spe & CORPSTAT_GENDER) for figurines as well as for
statues and corpses.

Support wishing for
 "{female,male,neuter} {corpse,statue,figurine} [of <monster>]".
and
 "{female,male,neuter} <monster> {corpse,statue,figurine}".
Also
 "{corpse,statue,figurine} of {female,male,neuter} <monster>"
where the qualifier might be in the middle instead of a prefix.

include/obj.h
src/dog.c
src/mkobj.c
src/mondata.c
src/objnam.c

index 40e5db202c4b988269c604f445740d7f34ceb3a4..1e540e4c0a3d10f125c5a8498bb909d60f552171 100644 (file)
@@ -55,8 +55,9 @@ struct obj {
                 * candy bar wrapper index;
                 * scroll of mail (normal==0, bones or wishing==1, written==2);
                 * splash of venom (normal==0, wishing==1);
-                * gender for corpses and statues (0..3, CORPSTAT_GENDER),
-                * historic flag (4, CORPSTAT_HISTORIC) for statues */
+                * gender for corpses, statues, and figurines (0..3,
+                *   CORPSTAT_GENDER),
+                * historic flag for statues (4, CORPSTAT_HISTORIC) */
     char oclass;    /* object class */
     char invlet;    /* designation in inventory */
     char oartifact; /* artifact array index */
index 5657c4503997e9a4bf312e52725971dece6e507a..e68456e7fa5887b81b5591370c8b8a1690b6913f 100644 (file)
--- a/src/dog.c
+++ b/src/dog.c
@@ -71,9 +71,11 @@ make_familiar(struct obj *otmp, xchar x, xchar y, boolean quietly)
     int chance, trycnt = 100;
 
     do {
-        if (otmp) { /* figurine; otherwise spell */
-            int mndx = otmp->corpsenm;
+        long mmflags;
+        int cgend, mndx;
 
+        if (otmp) { /* figurine; otherwise spell */
+            mndx = otmp->corpsenm;
             pm = &mons[mndx];
             /* activating a figurine provides one way to exceed the
                maximum number of the target critter created--unless
@@ -97,7 +99,12 @@ make_familiar(struct obj *otmp, xchar x, xchar y, boolean quietly)
             }
         }
 
-        mtmp = makemon(pm, x, y, MM_EDOG | MM_IGNOREWATER | NO_MINVENT);
+        mmflags = MM_EDOG | MM_IGNOREWATER | NO_MINVENT;
+        cgend = otmp ? (otmp->spe & CORPSTAT_GENDER) : 0;
+        mmflags |= ((cgend == CORPSTAT_FEMALE) ? MM_FEMALE
+                    : (cgend == CORPSTAT_MALE) ? MM_MALE : 0L);
+
+        mtmp = makemon(pm, x, y, mmflags);
         if (otmp && !mtmp) { /* monster was genocided or square occupied */
             if (!quietly)
                 pline_The("figurine writhes and then shatters into pieces!");
index bd4e1d97314352a890e88482677c3d276afe677e..7c1c7b3faf420d9a2187cf897f1af08ec1e29748 100644 (file)
@@ -1055,6 +1055,14 @@ mksobj(int otyp, boolean init, boolean artif)
     case FIGURINE:
         if (otmp->corpsenm == NON_PM)
             otmp->corpsenm = rndmonnum();
+        if (otmp->corpsenm != NON_PM) {
+            struct permonst *ptr = &mons[otmp->corpsenm];
+
+            otmp->spe = (is_neuter(ptr) ? CORPSTAT_NEUTER
+                         : is_female(ptr) ? CORPSTAT_FEMALE
+                           : is_male(ptr) ? CORPSTAT_MALE
+                             : rn2(2) ? CORPSTAT_FEMALE : CORPSTAT_MALE);
+        }
         /*FALLTHRU*/
     case EGG:
     /* case TIN: */
index f40febd2174b15545af34dd3573b357e0ee4e3dc..07f79bc6a535503dd526f83ec279e83bdf573dfd 100644 (file)
@@ -686,13 +686,11 @@ name_to_monplus(
     register int mntmp = NON_PM;
     register char *s, *str, *term;
     char buf[BUFSZ];
-    int len, slen, mgend, matchgend = NEUTRAL;
+    int len, slen, mgend, matchgend = -1;
     boolean exact_match = FALSE;
 
     if (remainder_p)
         *remainder_p = (const char *) 0;
-    if (gender_name_var)
-        *gender_name_var = matchgend; /* NEUTRAL */
 
     str = strcpy(buf, in_str);
 
@@ -848,8 +846,12 @@ name_to_monplus(
         mntmp = title_to_mon(str, (int *) 0, &len);
     if (len && remainder_p)
         *remainder_p = in_str + (&str[len] - buf);
-    if (gender_name_var)
-        *gender_name_var = matchgend;
+    if (gender_name_var && matchgend != -1) {
+        /* don't override with neuter if caller has already specified male
+           or female and we've matched the neuter name */
+        if (*gender_name_var == -1 || matchgend != NEUTRAL)
+            *gender_name_var = matchgend;
+    }
     return mntmp;
 }
 
index 933219ba384651c104d4239282b19755148a84bd..c1f1111d70cf3f57d3b4ede600916e6d0785b564 100644 (file)
@@ -515,7 +515,7 @@ xname_flags(
 
         if (typ == FIGURINE && omndx != NON_PM) {
             char anbuf[10]; /* [4] would be enough: 'a','n',' ','\0' */
-            const char *pm_name = mons[omndx].pmnames[NEUTRAL];
+            const char *pm_name = obj_pmname(obj);
 
             Sprintf(eos(buf), " of %s%s", just_an(anbuf, pm_name), pm_name);
         } else if (is_wet_towel(obj)) {
@@ -3261,7 +3261,7 @@ readobjnam_init(char *bp, struct _readobjnam_data *d)
         = d->looted /* wizard mode fountain/sink/throne/tree and grave */
         = d->real = d->fake = 0; /* Amulet */
     d->tvariety = RANDOM_TIN;
-    d->mgend = NEUTRAL;
+    d->mgend = -1; /* not specified, aka random */
     d->mntmp = NON_PM;
     d->contents = UNDEFINED;
     d->oclass = 0;
@@ -3276,14 +3276,20 @@ readobjnam_init(char *bp, struct _readobjnam_data *d)
     (void) memset(d->fruitbuf, '\0', sizeof d->globbuf);
 }
 
+/* return 1 if d->bp is empty or contains only various qualifiers like
+   "blessed", "rustproof", and so on, or 0 if anything else is present */
 static int
 readobjnam_preparse(struct _readobjnam_data *d)
 {
+    char *save_bp = 0;
+    int more_l = 0, res = 1;
+
     for (;;) {
         register int l;
 
         if (!d->bp || !*d->bp)
-            return 1;
+            break;
+
         if (!strncmpi(d->bp, "an ", l = 3) || !strncmpi(d->bp, "a ", l = 2)) {
             d->cnt = 1;
         } else if (!strncmpi(d->bp, "the ", l = 4)) {
@@ -3430,11 +3436,47 @@ readobjnam_preparse(struct _readobjnam_data *d)
             d->fake = 1, d->real = 0;
             /* ['real' isn't actually needed (unless we someday add
                "real gem" for random non-glass, non-stone)] */
-        } else
+        } else if (!strncmpi(d->bp, "female ", l = 7)) {
+            d->mgend = FEMALE;
+            /* if after "corpse/statue/figurine of", remove from string */
+            if (save_bp)
+                strsubst(d->bp, "female ", ""), l = 0;
+        } else if (!strncmpi(d->bp, "male ", l = 5)) {
+            d->mgend = MALE;
+            if (save_bp)
+                strsubst(d->bp, "male ", ""), l = 0;
+        } else if (!strncmpi(d->bp, "neuter ", l = 7)) {
+            d->mgend = NEUTRAL;
+            if (save_bp)
+                strsubst(d->bp, "neuter ", ""), l = 0;
+
+        /*
+         * Corpse/statue/figurine gender hack:  in order to accept
+         * "statue of a female gnome ruler" for gnome queen we need
+         * to recognize and skip over "statue of [a ]".  Otherwise
+         * we would only accept "female gnome ruler statue" and the
+         * viable but silly "female statue of a gnome ruler".
+         */
+        } else if ((!strncmpi(d->bp, "corpse ", l = 7)
+                    || !strncmpi(d->bp, "statue ", l = 7)
+                    || !strncmpi(d->bp, "figurine ", l = 9))
+                   && !strncmpi(d->bp + l, "of ", more_l = 3)) {
+            save_bp = d->bp; /* we'll backtrack to here later */
+            l += more_l, more_l = 0;
+            if (!strncmpi(d->bp + l, "a ", more_l = 2)
+                || !strncmpi(d->bp + l, "an ", more_l = 3)
+                || !strncmpi(d->bp + l, "the ", more_l = 4))
+                l += more_l;
+            res = 0;
+        } else {
+            res = 0;
             break;
+        }
         d->bp += l;
     }
-    return 0;
+    if (save_bp)
+        d->bp = save_bp;
+    return res;
 }
 
 static void
@@ -4301,6 +4343,7 @@ readobjnam(char *bp, struct obj *no_wish)
     case IRON_CHAIN:
         break;
     case STATUE: /* otmp->cobj already done in mksobj() */
+    case FIGURINE:
     case CORPSE: {
         struct permonst *P = (d.mntmp >= LOW_PM) ? &mons[d.mntmp] : 0;