From: PatR Date: Thu, 17 Jun 2021 23:03:45 +0000 (-0700) Subject: gender for figurines X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0b5a112b0cee0172e3b7ca32df7e9c4a2273f58b;p=nethack gender for figurines Use (obj->spe & CORPSTAT_GENDER) for figurines as well as for statues and corpses. Support wishing for "{female,male,neuter} {corpse,statue,figurine} [of ]". and "{female,male,neuter} {corpse,statue,figurine}". Also "{corpse,statue,figurine} of {female,male,neuter} " where the qualifier might be in the middle instead of a prefix. --- diff --git a/include/obj.h b/include/obj.h index 40e5db202..1e540e4c0 100644 --- a/include/obj.h +++ b/include/obj.h @@ -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 */ diff --git a/src/dog.c b/src/dog.c index 5657c4503..e68456e7f 100644 --- 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!"); diff --git a/src/mkobj.c b/src/mkobj.c index bd4e1d973..7c1c7b3fa 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -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: */ diff --git a/src/mondata.c b/src/mondata.c index f40febd21..07f79bc6a 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -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; } diff --git a/src/objnam.c b/src/objnam.c index 933219ba3..c1f1111d7 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -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;