} program_state;
E boolean restoring;
+E boolean ransacked;
E const char quitchars[];
E const char vowels[];
#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 {
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 *));
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));
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));
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);
#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)
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";
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,
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,
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",
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 */
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);
}
}
+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;
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 */
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) \
} 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)
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;
}
if (*protofile) {
+ check_ransacked(protofile);
Strcat(protofile, LEV_EXT);
if (load_special(protofile)) {
/* some levels can end up with monsters
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)
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);
* 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];
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) {
} 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)
}
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";
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);
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 */
break;
}
if (*out_str)
- checkfile(out_str, pm, TRUE, TRUE);
+ checkfile(out_str, pm, TRUE, TRUE, (char *) 0);
return 0;
}
case '?':
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];
}
found = do_screen_description(cc, (from_screen || clicklook), sym,
- out_str, &firstmatch);
+ out_str, &firstmatch, &supplemental_pm);
/* Finally, print out our explanation. */
if (found) {
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;
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()