diff --git a/dat/quest.txt b/dat/quest.txt index dc0c26c36..f66fc8698 100644 --- a/dat/quest.txt +++ b/dat/quest.txt @@ -144,7 +144,7 @@ to me. close this college. "May the wisdom of %d be your guide." -%E [%nC has stolen %o. Locate %i, defeat %n within, and return %o.] +%E [%nC has stolen %o. Locate %i, defeat %ni, and return %O.] %Cp Arc 00025 "Beware, for %n is powerful and cunning." %E @@ -3338,7 +3338,7 @@ from birth as the instrument of %d. You are destined to recover the Amulet for your deity, or die in the attempt. Your hour of destiny has come. For the sake of us all: Go bravely with %d! -%E [%dC has chosen you to recover the Amulet of Yendor.] +%E [%dC has chosen you to recover the Amulet of Yendor for %dI.] %Cp - 00002 You receive a faint telepathic message from %l: Your help is urgently needed at %H! @@ -3482,6 +3482,7 @@ Go now! You are banished from this place. %l: return((char *)ldrname()); %i: return(intermed()); %o: return(artiname()); + %O: return(shortened(artiname())); %n: return((char *)neminame()); %g: return((char *)guardname()); %G: return((char *)align_gtitle(u.ualignbase[1])); @@ -3499,6 +3500,12 @@ Go now! You are banished from this place. a suffix: return an(root); A suffix: return An(root); C suffix: return capitalized(root); + h suffix: return pronoun(he_or_she, mon_of(root)); /* for %l,%n,%d,%o */ + H suffix: return capitalized(pronoun(he_or_she, mon_of(root))); + i suffix: return pronoun(him_or_her, mon_of(root)); + I suffix: return capitalized(pronoun(him_or_her, mon_of(root))); + j suffix: return pronoun(his_or_her, mon_of(root)); + J suffix: return capitalized(pronoun(his_or_her, mon_of(root))); p suffix: return makeplural(root); P suffix: return makeplural(capitalized(root)); s suffix: return s_suffix(root); diff --git a/include/quest.h b/include/quest.h index 1efe3029c..6d1171f07 100644 --- a/include/quest.h +++ b/include/quest.h @@ -26,6 +26,13 @@ struct q_score { /* Quest "scorecard" */ Bitfield(offered_artifact,1); /* offered to leader */ Bitfield(got_thanks,1); /* final message from leader */ + /* used by questpgr code when messages want to use pronouns + (set up at game start instead of waiting until monster creation; + 1 bit each would suffice--nobody involved is actually neuter) */ + Bitfield(ldrgend,2); /* leader's gender: 0=male, 1=female, 2=neuter */ + Bitfield(nemgend,2); /* nemesis's gender */ + Bitfield(godgend,2); /* deity's gender */ + /* keep track of leader presence/absence even if leader is polymorphed, raised from dead, etc */ Bitfield(leader_is_dead,1); diff --git a/src/makemon.c b/src/makemon.c index ab9729a94..959de286f 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -984,6 +984,13 @@ register int mmflags; if (is_female(ptr)) mtmp->female = TRUE; else if (is_male(ptr)) mtmp->female = FALSE; + /* leader and nemesis gender is usually hardcoded in mons[], + but for ones which can be random, it has already been chosen + (in role_init(), for possible use by the quest pager code) */ + else if (ptr->msound == MS_LEADER && quest_info(MS_LEADER) == mndx) + mtmp->female = quest_status.ldrgend; + else if (ptr->msound == MS_NEMESIS && quest_info(MS_NEMESIS) == mndx) + mtmp->female = quest_status.nemgend; else mtmp->female = rn2(2); /* ignored for neuters */ if (In_sokoban(&u.uz) && !mindless(ptr)) /* know about traps here */ diff --git a/src/questpgr.c b/src/questpgr.c index 340ab5c99..adb786d54 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -22,6 +22,7 @@ STATIC_DCL const char * NDECL(intermed); STATIC_DCL const char * NDECL(neminame); STATIC_DCL const char * NDECL(guardname); STATIC_DCL const char * NDECL(homebase); +STATIC_DCL void FDECL(qtext_pronoun, (CHAR_P,CHAR_P)); STATIC_DCL struct qtmsg * FDECL(msg_in, (struct qtmsg *,int)); STATIC_DCL void FDECL(convert_arg, (CHAR_P)); STATIC_DCL void NDECL(convert_line); @@ -213,6 +214,42 @@ homebase() /* return your role leader's location */ return(urole.homebase); } +/* replace deity, leader, nemesis, or artifact name with pronoun; + overwrites cvt_buf[] */ +STATIC_OVL void +qtext_pronoun(who, which) +char who, /* 'd' => deity, 'l' => leader, 'n' => nemesis, 'o' => artifact */ + which; /* 'h'|'H'|'i'|'I'|'j'|'J' */ +{ + const char *pnoun; + int g; + char lwhich = lowc(which); /* H,I,J -> h,i,j */ + + /* + * Invalid subject (not d,l,n,o) yields neuter, singular result. + * + * For %o, treat all artifacts as neuter; some have plural names, + * which genders[] doesn't handle; cvt_buf[] already contains name + * and makesingular() understands how to handle "the foos of bar". + */ + if (who == 'o' && strcmpi(cvt_buf, makesingular(cvt_buf))) { + pnoun = (lwhich == 'h') ? "they" : + (lwhich == 'i') ? "them" : + (lwhich == 'j') ? "their" : "?"; + } else { + g = (who == 'd') ? quest_status.godgend : + (who == 'l') ? quest_status.ldrgend : + (who == 'n') ? quest_status.nemgend : 2; /* default to neuter */ + pnoun = (lwhich == 'h') ? genders[g].he : + (lwhich == 'i') ? genders[g].him : + (lwhich == 'j') ? genders[g].his : "?"; + } + Strcpy(cvt_buf, pnoun); + /* capitalize for H,I,J */ + if (lwhich != which) cvt_buf[0] = highc(cvt_buf[0]); + return; +} + STATIC_OVL struct qtmsg * msg_in(qtm_list, msgnum) struct qtmsg *qtm_list; @@ -252,7 +289,15 @@ char c; break; case 'i': str = intermed(); break; + case 'O': case 'o': str = the(artiname(urole.questarti)); + if (c == 'O') { + /* shorten "the Foo of Bar" to "the Foo" + (buffer returned by the() is modifiable) */ + char *p = strstri(str, " of "); + + if (p) *p = '\0'; + } break; case 'n': str = neminame(); break; @@ -320,6 +365,16 @@ convert_line() /* capitalize */ case 'C': cvt_buf[0] = highc(cvt_buf[0]); + break; + + /* replace name with pronoun; + valid for %d, %l, %n, and %o */ + case 'h': /* he/she */ + case 'H': /* He/She */ + case 'i': /* him/her */ + case 'I': + case 'j': /* his/her */ + case 'J': qtext_pronoun(*(c - 1), *c); break; /* pluralize */ diff --git a/src/role.c b/src/role.c index 2e2ea948c..060fe4809 100644 --- a/src/role.c +++ b/src/role.c @@ -1578,6 +1578,7 @@ void role_init() { int alignmnt; + struct permonst *pm; /* Strip the role letter out of the player name. * This is included for backwards compatibility. @@ -1623,25 +1624,36 @@ role_init() /* Fix up the quest leader */ if (urole.ldrnum != NON_PM) { - mons[urole.ldrnum].msound = MS_LEADER; - mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL); - mons[urole.ldrnum].mflags3 |= M3_CLOSE; - mons[urole.ldrnum].maligntyp = alignmnt * 3; + pm = &mons[urole.ldrnum]; + pm->msound = MS_LEADER; + pm->mflags2 |= (M2_PEACEFUL); + pm->mflags3 |= M3_CLOSE; + pm->maligntyp = alignmnt * 3; + /* if gender is random, we choose it now instead of waiting + until the leader monster is created */ + quest_status.ldrgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : + is_male(pm) ? 0 : (rn2(100) < 50); } /* Fix up the quest guardians */ if (urole.guardnum != NON_PM) { - mons[urole.guardnum].mflags2 |= (M2_PEACEFUL); - mons[urole.guardnum].maligntyp = alignmnt * 3; + pm = &mons[urole.guardnum]; + pm->mflags2 |= (M2_PEACEFUL); + pm->maligntyp = alignmnt * 3; } /* Fix up the quest nemesis */ if (urole.neminum != NON_PM) { - mons[urole.neminum].msound = MS_NEMESIS; - mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL); - mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE); - mons[urole.neminum].mflags3 &= ~(M3_CLOSE); - mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU; + pm = &mons[urole.neminum]; + pm->msound = MS_NEMESIS; + pm->mflags2 &= ~(M2_PEACEFUL); + pm->mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE); + pm->mflags3 &= ~(M3_CLOSE); + pm->mflags3 |= M3_WANTSARTI | M3_WAITFORU; + /* if gender is random, we choose it now instead of waiting + until the nemesis monster is created */ + quest_status.nemgend = is_neuter(pm) ? 2 : is_female(pm) ? 1 : + is_male(pm) ? 0 : (rn2(100) < 50); } /* Fix up the god names */ @@ -1655,6 +1667,8 @@ role_init() urole.ngod = roles[flags.pantheon].ngod; urole.cgod = roles[flags.pantheon].cgod; } + /* 0 or 1; no gods are neuter, nor is gender randomized */ + quest_status.godgend = !strcmpi(align_gtitle(alignmnt), "goddess"); /* Fix up infravision */ if (mons[urace.malenum].mflags3 & M3_INFRAVISION) {