From: nhmall <nhmall@nethack.org> Date: Tue, 18 Sep 2018 22:35:13 +0000 (-0400) Subject: Gnomish Mines changes involving "Orctown" level variant X-Git-Tag: NetHack-3.6.2_Released~197^2~13 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9eb783081977d6754348a3f71196a1581d2d1d26;p=nethack Gnomish Mines changes involving "Orctown" level variant Changes to be committed: modified: include/decl.h modified: include/dungeon.h modified: include/extern.h modified: include/hack.h modified: src/decl.c modified: src/do_name.c modified: src/dog.c modified: src/dokick.c modified: src/makemon.c modified: src/mkmaze.c modified: src/mkobj.c modified: src/pager.c This commit is an attempt to address the complaints about the orc town variation taking away lots of stuff that is normally available in mine town. The statement in the level description says "A tragic accident has occurred in Frontier Town...It has been overrun by orcs." The changes in this commit attempt to uphold that premise, while making things a bit more interesting and perhaps more palatable for the player. This update does the following in keeping with the mythos: - While many of the orcs still remain to wander about the level, many of the orcs took off deeper into the mines with some of the stuff that they plundered. You may now be able to hunt some of it down. - Adds some appearance of this particular horde of marauding orcs working as part of a larger collective. - This evolves the Orc Town mine town variation into a a feature over multiple levels of The Gnomish Mines, rather than just the single-level "feature" that it was previously. - You may have to work longer and a bit harder for some things than other mine town variations, but at least with these changes, there is hope that some of it may be found elsewhere. Game mechanics notes (maybe spoily?) - Add mechanism to place objects into limbo (okay, really place them onto the migrating_objs list for transferring between levels etc.) and destine them to become part of the monster inventory of a particular species. In this particular usage case, it's using the M2_ORC flag setting to identify the recipients. - At present, there is no mechanism in the level compiler for placing objects onto the migrating objects, nor with more sophisticated landing logic, so a somewhat kludgy hard-coded fixup and supporting routines were used. Some day the need for that might change if additional capabilities move to the level compiler. This is a NetHack-3.6.2-beta01 update. Please give it a workout. Fixes #127 --- diff --git a/include/decl.h b/include/decl.h index f0d806dc8..53902a07f 100644 --- a/include/decl.h +++ b/include/decl.h @@ -160,6 +160,7 @@ E NEARDATA struct sinfo { } program_state; E boolean restoring; +E boolean ransacked; E const char quitchars[]; E const char vowels[]; diff --git a/include/dungeon.h b/include/dungeon.h index f7b16cf2a..45246f150 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -146,7 +146,8 @@ typedef struct branch { #define MIGR_WITH_HERO 9 /* mon: followers; obj: trap door */ #define MIGR_NOBREAK 1024 /* bitmask: don't break on delivery */ #define MIGR_NOSCATTER 2048 /* don't scatter on delivery */ - +#define MIGR_TO_SPECIES 4096 /* migrating to species as they are made */ +#define MIGR_LEFTOVERS 8192 /* grab remaining MIGR_TO_SPECIES objects */ /* level information (saved via ledger number) */ struct linfo { diff --git a/include/extern.h b/include/extern.h index abd4be118..ed186e667 100644 --- a/include/extern.h +++ b/include/extern.h @@ -428,6 +428,8 @@ E const char *NDECL(roguename); E struct obj *FDECL(realloc_obj, (struct obj *, int, genericptr_t, int, const char *)); E char *FDECL(coyotename, (struct monst *, char *)); +E char *FDECL(rndorcname, (char *)); +E struct monst *FDECL(christen_orc, (struct monst *, char *)); E const char *FDECL(noveltitle, (int *)); E const char *FDECL(lookup_novel, (const char *, int *)); @@ -519,6 +521,7 @@ E void FDECL(container_impact_dmg, (struct obj *, XCHAR_P, XCHAR_P)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(obj_delivery, (BOOLEAN_P)); +E void FDECL(deliver_obj_to_mon, (struct monst *mtmp, unsigned long)); E schar FDECL(down_gate, (XCHAR_P, XCHAR_P)); E void FDECL(impact_drop, (struct obj *, XCHAR_P, XCHAR_P, XCHAR_P)); @@ -1283,6 +1286,7 @@ E void FDECL(new_omailcmd, (struct obj *, const char *)); E void FDECL(free_omailcmd, (struct obj *)); E struct obj *FDECL(mkobj_at, (CHAR_P, int, int, BOOLEAN_P)); E struct obj *FDECL(mksobj_at, (int, int, int, BOOLEAN_P, BOOLEAN_P)); +E struct obj *FDECL(mksobj_migr_to_species, (int, unsigned, BOOLEAN_P, BOOLEAN_P)); E struct obj *FDECL(mkobj, (CHAR_P, BOOLEAN_P)); E int NDECL(rndmonnum); E boolean FDECL(bogon_is_pname, (CHAR_P)); @@ -1753,7 +1757,7 @@ E char *FDECL(self_lookat, (char *)); E void FDECL(mhidden_description, (struct monst *, BOOLEAN_P, char *)); E boolean FDECL(object_from_map, (int,int,int,struct obj **)); E int FDECL(do_screen_description, (coord, BOOLEAN_P, int, char *, - const char **)); + const char **, struct permonst **)); E int FDECL(do_look, (int, coord *)); E int NDECL(dowhatis); E int NDECL(doquickwhatis); diff --git a/include/hack.h b/include/hack.h index ed699a943..f65d2ddd1 100644 --- a/include/hack.h +++ b/include/hack.h @@ -270,6 +270,12 @@ typedef struct sortloot_item Loot; #define SHIFT_SEENMSG 0x01 /* put out a message if in sight */ #define SHIFT_MSG 0x02 /* always put out a message */ +/* flags for deliver_obj_to_mon */ +#define DF_NONE 0x00 +#define DF_RANDOM2 0x01 +#define DF_RANDOM3 0x02 +#define DF_ALL 0x04 + /* special mhpmax value when loading bones monster to flag as extinct or * genocided */ #define DEFUNCT_MONSTER (-100) diff --git a/src/decl.c b/src/decl.c index 2a9c28746..ffd9ef974 100644 --- a/src/decl.c +++ b/src/decl.c @@ -57,6 +57,7 @@ NEARDATA char pl_fruit[PL_FSIZ] = DUMMY; NEARDATA struct fruit *ffruit = (struct fruit *) 0; NEARDATA char tune[6] = DUMMY; +NEARDATA boolean ransacked = 0; const char *occtxt = DUMMY; const char quitchars[] = " \r\n\033"; diff --git a/src/do_name.c b/src/do_name.c index e4a874126..ef1870742 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -543,7 +543,7 @@ int cx, cy; cc.x = cx; cc.y = cy; - if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch, (struct permonst **)0)) { (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); custompline(SUPPRESS_HISTORY, "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, @@ -593,7 +593,8 @@ int gloc; any.a_int = i + 1; tmpcc.x = garr[i].x; tmpcc.y = garr[i].y; - if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, + &firstmatch, (struct permonst **)0)) { (void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords); Sprintf(fullbuf, "%s%s%s", firstmatch, @@ -2067,6 +2068,47 @@ char *buf; return buf; } +char * +rndorcname(s) +char *s; +{ + int i; + const char *v[] = {"a", "ai", "og", "u"}; + const char *snd[] = {"gor", "gris", "un", "bane", "ruk", + "oth","ul", "z", "thos","akh","hai"}; + int vstart = rn2(2); + + if (s) { + *s = '\0'; + for (i = 0; i < rn2(2) + 3; ++i) { + vstart = 1 - vstart; /* 0 -> 1, 1 -> 0 */ + if (!rn2(30) && i > 0) + (void) strcat(s, "-"); + (void) sprintf(eos(s), "%s", vstart ? v[rn2(SIZE(v))] : + snd[rn2(SIZE(snd))]); + } + } + return s; +} + +struct monst * +christen_orc(mtmp, gang) +struct monst *mtmp; +char *gang; +{ + size_t sz = 0; + char buf[BUFSZ], buf2[BUFSZ], *orcname; + + orcname = rndorcname(buf2); + sz = strlen(gang) + strlen(orcname) + strlen(" of "); + if (buf && gang && orcname && (sz < (BUFSZ - 1))) { + Sprintf(buf, "%s of %s", + upstart(orcname), upstart(gang)); + mtmp = christen_monst(mtmp, buf); + } + return mtmp; +} + /* make sure "The Colour of Magic" remains the first entry in here */ static const char *const sir_Terry_novels[] = { "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort", diff --git a/src/dog.c b/src/dog.c index 4bcdd7722..46cd832ef 100644 --- a/src/dog.c +++ b/src/dog.c @@ -407,6 +407,12 @@ boolean with_you; break; } + if ((mtmp->mspare1 & MIGR_LEFTOVERS) != 0L) { + /* Pick up the rest of the MIGR_TO_SPECIES objects */ + if (migrating_objs) + deliver_obj_to_mon(mtmp, DF_ALL); + } + if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ diff --git a/src/dokick.c b/src/dokick.c index 874db822a..b2d36de70 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1612,6 +1612,9 @@ boolean near_hero; continue; where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) != 0) + continue; + nobreak = (where & MIGR_NOBREAK) != 0; noscatter = (where & MIGR_WITH_HERO) != 0; where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER); @@ -1667,6 +1670,48 @@ boolean near_hero; } } +void +deliver_obj_to_mon(mtmp, deliverflags) +struct monst *mtmp; +unsigned long deliverflags; +{ + struct obj *otmp, *otmp2; + int where, cnt = 0, maxobj = 0; + + if (deliverflags & DF_RANDOM3) + maxobj = rn2(3) + 1; + else if (deliverflags & DF_RANDOM2) + maxobj = rn2(2) + 1; + else if (deliverflags == DF_NONE) + maxobj = 1; + + for (otmp = migrating_objs; otmp; otmp = otmp2) { + otmp2 = otmp->nobj; + where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) == 0) + continue; + + if ((mtmp->data->mflags2 & otmp->corpsenm) != 0) { + obj_extract_self(otmp); + otmp->owornmask = 0L; + otmp->ox = otmp->oy = 0; + + /* special treatment for orcs and their kind */ + if ((otmp->corpsenm & M2_ORC) != 0 && has_oname(otmp)) { + if (!has_mname(mtmp)) + mtmp = christen_orc(mtmp, ONAME(otmp)); + free_oname(otmp); + } + otmp->corpsenm = 0; + (void) add_to_minv(mtmp, otmp); + cnt++; + if (maxobj && cnt >= maxobj) + break; + /* getting here implies DF_ALL */ + } + } +} + STATIC_OVL void otransit_msg(otmp, nodrop, num) register struct obj *otmp; diff --git a/src/makemon.c b/src/makemon.c index 0d38383dc..e4cece72d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1390,6 +1390,9 @@ int mmflags; mtmp->mstrategy |= STRAT_APPEARMSG; } + if (allow_minvent && migrating_objs) + deliver_obj_to_mon(mtmp, DF_RANDOM3); /* in case there's waiting items */ + if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 22fb42d03..2e2646647 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -25,6 +25,10 @@ STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, STATIC_DCL void NDECL(baalz_fixup); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); +STATIC_DCL void FDECL(check_ransacked, (char *)); +STATIC_DCL void FDECL(migr_booty_item, (int, const char *)); +STATIC_DCL void FDECL(migrate_orc, (struct monst *, unsigned long)); +STATIC_DCL void NDECL(stolen_booty); /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ @@ -610,6 +614,8 @@ fixup_special() } else if (on_level(&u.uz, &baalzebub_level)) { /* custom wallify the "beetle" potion of the level */ baalz_fixup(); + } else if (u.uz.dnum == mines_dnum && ransacked) { + stolen_booty(); } if (lregions) @@ -617,6 +623,141 @@ fixup_special() num_lregions = 0; } +void +check_ransacked(s) +char *s; +{ + /* this kludge only works as long as orctown is minetn-1 */ + if (dungeons[u.uz.dnum].dname + && !strcmp(dungeons[u.uz.dnum].dname, "The Gnomish Mines") + && !strcmp(s, "minetn-1")) + ransacked = 1; + else + ransacked = 0; +} + +#define ORC_LEADER 1 + +void +migrate_orc(mtmp, flags) +struct monst *mtmp; +unsigned long flags; +{ + int nlev, max_depth, cur_depth; + d_level dest; + + cur_depth = (int) depth(&u.uz); + max_depth = dunlevs_in_dungeon(&u.uz) + + (dungeons[u.uz.dnum].depth_start - 1); + if (flags == ORC_LEADER) { + /* Note that the orc leader will take possession of any + * remaining stuff not already delivered to other + * orcs between here and the bottom of the mines. + */ + nlev = max_depth; + mtmp->mspare1 = MIGR_LEFTOVERS; + } else { + nlev = rn2(max_depth - cur_depth) + cur_depth + 1; + if (nlev == cur_depth) + nlev++; + if (nlev > max_depth) + nlev = max_depth; + mtmp->mspare1 = 0L; + } + get_level(&dest, nlev); + migrate_to_level(mtmp, ledger_no(&dest), MIGR_RANDOM, (coord *) 0); +} + +void +migr_booty_item(otyp, gang) +int otyp; +const char *gang; +{ + struct obj *otmp; + otmp = mksobj_migr_to_species(otyp, (unsigned long) M2_ORC, FALSE, FALSE); + if (otmp && gang) { + new_oname(otmp, strlen(gang) + 1); /* removes old name if one is present */ + Strcpy(ONAME(otmp), gang); + } +} + +void +stolen_booty(VOID_ARGS) +{ + char *gang, gang_name[BUFSZ]; + struct monst *mtmp; + int cnt, i, otyp; + + /* + * -------------------------------------------------------- + * Mythos: + * + * A tragic accident has occurred in Frontier Town... + * It has been overrun by orcs. + * + * The booty that the orcs took from the town is now + * in the possession of the orcs that did this and + * have long since fled the level. + * -------------------------------------------------------- + */ + + gang = rndorcname(gang_name); + /* create the leader of the orc gang */ + mtmp = makemon(&mons[PM_ORC_CAPTAIN], 0, 0, MM_NONAME); + if (mtmp) { + mtmp = christen_monst(mtmp, upstart(gang)); + mtmp->mpeaceful = 0; + migrate_orc(mtmp, ORC_LEADER); + } + /* create the stuff that the rest of the gang took */ + cnt = rn2(3) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, gang); + cnt = rn2(2) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(SKELETON_KEY, gang); + migr_booty_item(rn2(2) ? LONG_SWORD : SILVER_SABER, gang); + otyp = rn2((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1) + LEATHER_GLOVES; + migr_booty_item(otyp, gang); + cnt = rn2(9) + 1; + for (i = 0; i < cnt; ++i) { + /* Food items - but no lembas! (or some other weird things) */ + otyp = rn2((TIN - TRIPE_RATION) + 1) + TRIPE_RATION; + if (otyp != LEMBAS_WAFER && otyp != GLOB_OF_GRAY_OOZE && + otyp != GLOB_OF_BROWN_PUDDING && otyp != GLOB_OF_GREEN_SLIME && + otyp != GLOB_OF_BLACK_PUDDING && otyp != MEAT_STICK && + otyp != MEATBALL && otyp != MEAT_STICK && otyp != MEAT_RING && + otyp != HUGE_CHUNK_OF_MEAT && otyp != CORPSE) + migr_booty_item(otyp, gang); + } + /* Make most of the orcs on the level be part of the invading gang */ + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + + if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) + mtmp = christen_orc(mtmp, upstart(gang)); + } + /* Lastly, ensure there's a few more orcs from the gang along the way + * The mechanics are such that they aren't actually identified as + * members of the invading gang until they get their spoils assigned + * to the inventory; handled during that assignment. + */ + cnt = rn2(6) + 1; + for (i = 0; i < cnt; ++i) { + int mtyp; + + mtyp = rn2((PM_ORC_SHAMAN - PM_ORC) + 1) + PM_ORC; + mtmp = makemon(&mons[mtyp], 0, 0, MM_NONAME); + if (mtmp) + migrate_orc(mtmp, 0L); + } + + ransacked = 0; +} + +#undef ORC_LEADER + boolean maze_inbounds(x, y) int x, y; @@ -819,6 +960,7 @@ const char *s; } if (*protofile) { + check_ransacked(protofile); Strcat(protofile, LEV_EXT); if (load_special(protofile)) { /* some levels can end up with monsters diff --git a/src/mkobj.c b/src/mkobj.c index cf7a77233..558be1dc6 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -224,6 +224,23 @@ boolean init, artif; return otmp; } +struct obj * +mksobj_migr_to_species(otyp, mflags2, init, artif) +int otyp; +unsigned mflags2; +boolean init, artif; +{ + struct obj *otmp; + + otmp = mksobj(otyp, init, artif); + if (otmp) { + add_to_migration(otmp); + otmp->owornmask = (long) MIGR_TO_SPECIES; + otmp->corpsenm = mflags2; + } + return otmp; +} + /* mkobj(): select a type of item from a class, use mksobj() to create it */ struct obj * mkobj(oclass, artif) diff --git a/src/pager.c b/src/pager.c index 9c2d74946..6ef7bf6ce 100644 --- a/src/pager.c +++ b/src/pager.c @@ -16,8 +16,9 @@ STATIC_DCL void FDECL(look_at_monster, (char *, char *, struct monst *, int, int)); STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *, struct permonst *, - BOOLEAN_P, BOOLEAN_P)); + BOOLEAN_P, BOOLEAN_P, char *)); STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); +STATIC_DCL void FDECL(do_supplemental_info, (char *, struct permonst *,BOOLEAN_P)); STATIC_DCL void NDECL(whatdoes_help); STATIC_DCL void NDECL(docontact); STATIC_DCL void NDECL(dispfile_help); @@ -509,10 +510,11 @@ char *buf, *monbuf; * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void -checkfile(inp, pm, user_typed_name, without_asking) +checkfile(inp, pm, user_typed_name, without_asking, supplemental_name) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; +char *supplemental_name; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ]; @@ -619,7 +621,7 @@ boolean user_typed_name, without_asking; int chk_skip, pass = 1; boolean yes_to_moreinfo, found_in_file, pass1found_in_file, skipping_entry; - char *ap, *alt = 0; /* alternate description */ + char *sp, *ap, *alt = 0; /* alternate description */ /* adjust the input to remove "named " and "called " */ if ((ep = strstri(dbase_str, " named ")) != 0) { @@ -629,6 +631,8 @@ boolean user_typed_name, without_asking; } else if ((ep = strstri(dbase_str, " called ")) != 0) { copynchars(givenname, ep + 8, BUFSZ - 1); alt = givenname; + if (supplemental_name && (sp = strstri(inp, " called ")) != 0) + copynchars(supplemental_name, sp + 8, BUFSZ - 1); } else ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) @@ -760,12 +764,13 @@ boolean user_typed_name, without_asking; } int -do_screen_description(cc, looked, sym, out_str, firstmatch) +do_screen_description(cc, looked, sym, out_str, firstmatch, for_supplement) coord cc; boolean looked; int sym; char *out_str; const char **firstmatch; +struct permonst **for_supplement; { static const char mon_interior[] = "the interior of a monster", unreconnoitered[] = "unreconnoitered"; @@ -1008,11 +1013,15 @@ const char **firstmatch; didlook: if (looked) { + struct permonst *pm = (struct permonst *)0; + if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; - (void) lookat(cc.x, cc.y, look_buf, monbuf); + pm = lookat(cc.x, cc.y, look_buf, monbuf); + if (pm && for_supplement) + *for_supplement = pm; *firstmatch = look_buf; if (*(*firstmatch)) { Sprintf(temp_buf, " (%s)", *firstmatch); @@ -1043,7 +1052,7 @@ coord *click_cc; boolean clicklook = (mode == 2); /* right mouse-click method */ char out_str[BUFSZ] = DUMMY; const char *firstmatch = 0; - struct permonst *pm = 0; + struct permonst *pm = 0, *supplemental_pm = 0; int i = '\0', ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ @@ -1137,7 +1146,7 @@ coord *click_cc; break; } if (*out_str) - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } case '?': @@ -1151,7 +1160,7 @@ coord *click_cc; return 0; if (out_str[1]) { /* user typed in a complete string */ - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } sym = out_str[0]; @@ -1204,7 +1213,7 @@ coord *click_cc; } found = do_screen_description(cc, (from_screen || clicklook), sym, - out_str, &firstmatch); + out_str, &firstmatch, &supplemental_pm); /* Finally, print out our explanation. */ if (found) { @@ -1215,16 +1224,18 @@ coord *click_cc; if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick)) && !clicklook) { - char temp_buf[BUFSZ]; + char temp_buf[BUFSZ], supplemental_name[BUFSZ]; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, - (boolean) (ans == LOOK_VERBOSE)); + (boolean) (ans == LOOK_VERBOSE), supplemental_name); + if (supplemental_pm && supplemental_name) + do_supplemental_info(supplemental_name, supplemental_pm, + (boolean) (ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } - } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook); flags.verbose = save_verbose; @@ -1319,6 +1330,68 @@ boolean do_mons; /* True => monsters, False => objects */ destroy_nhwindow(win); } +void +do_supplemental_info(name, pm, without_asking) +char *name; +struct permonst *pm; +boolean without_asking; +{ + winid datawin = WIN_ERR; + char *entrytext = name, *bp; + char question[QBUFSZ]; + boolean yes_to_moreinfo = FALSE; + + /* + * Provide some info on some specific things + * meant to support in-game mythology, and not + * available from data.base or other sources. + */ + if (name && pm && is_orc(pm) && + (strlen(name) < (BUFSZ - 1)) && + (bp = strstri(name, " of ")) != 0) { + char fullname[BUFSZ]; + + Strcpy(fullname, name); + if (!without_asking) { + Strcpy(question, "More info about \""); + /* +2 => length of "\"?" */ + copynchars(eos(question), entrytext, + (int) (sizeof question - 1 - (strlen(question) + 2))); + Strcat(question, "\"?"); + if (yn(question) == 'y') + yes_to_moreinfo = TRUE; + } + if (yes_to_moreinfo) { + int i, subs = 0; + char *gang = bp + 4; + char *text[] = { + "%s is a member of a marauding horde of orcs", + "rumored to have brutally attacked and plundered the ordinarily", + "sheltered town that is located deep within The Gnomish Mines.", + "", + "The members of that vicious horde proudly and defiantly acclaim their", + "allegiance to their leader %s in their names.", + }; + + *bp = '\0'; + datawin = create_nhwindow(NHW_MENU); + for (i = 0; i < SIZE(text); i++) { + char buf[BUFSZ], *txt; + + if (strstri(text[i], "%s") != 0) { + Sprintf(buf, text[i], + subs++ ? gang : fullname); + txt = buf; + } else + txt = text[i]; + putstr(datawin, 0, txt); + } + display_nhwindow(datawin, FALSE); + destroy_nhwindow(datawin), datawin = WIN_ERR; + } + } +} + /* the '/' command */ int dowhatis()