/* bitmask for callers of hide_unhide_msgtypes() */
#define MSGTYP_MASK_REP_SHOW ((1 << MSGTYP_NOREP) | (1 << MSGTYP_NOSHOW))
-
enum bcargs {override_restriction = -1};
struct breadcrumbs {
const char *funcnm;
/* artifcat.c */
int spec_dbon_applies; /* coordinate effects from spec_dbon() with
messages in artifact_hit() */
- /* flags including which artifacts have already been created */
- boolean artiexist[1 + NROFARTIFACTS + 1];
- /* and a discovery list for them (no dummy first entry here) */
- xchar artidisco[NROFARTIFACTS];
int mkot_trap_warn_count;
/* botl.c */
/* do_name.c */
struct selectionvar *gloc_filter_map;
int gloc_filter_floodfill_match_glyph;
- int via_naming;
/* do_wear.c */
/* starting equipment gets auto-worn at beginning of new game,
extern struct obj *mk_artifact(struct obj *, aligntyp);
extern const char *artifact_name(const char *, short *);
extern boolean exist_artifact(int, const char *);
-extern void artifact_exists(struct obj *, const char *, boolean);
+extern void artifact_exists(struct obj *, const char *, boolean, boolean);
+extern void found_artifact(int);
+extern void find_artifact(struct obj *);
extern int nartifact_exist(void);
extern boolean arti_immune(struct obj *, int);
extern boolean spec_ability(struct obj *, unsigned long);
extern void free_oname(struct obj *);
extern const char *safe_oname(struct obj *);
extern struct monst *christen_monst(struct monst *, const char *);
-extern struct obj *oname(struct obj *, const char *);
+extern struct obj *oname(struct obj *, const char *, unsigned);
extern boolean objtyp_is_callable(int);
extern int docallcmd(void);
extern void docall(struct obj *);
#define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
#define ALL_TYPES_SELECTED -2
+/* Flags for oname() */
+#define ONAME_NO_FLAGS 0U /* none of the below */
+#define ONAME_VIA_NAMING 1U /* oname() is being called by do_oname() */
+#define ONAME_FOUND_ARTI 2U /* if an artifact, hero becomes aware of it */
+
/* Flags to control find_mid() */
#define FM_FMON 0x01 /* search the fmon chain */
#define FM_MIGRATE 0x02 /* search the migrating monster chain */
of hit points that will fit in a 15 bit integer. */
#define FATAL_DAMAGE_MODIFIER 200
+/* artifact tracking */
+struct arti_info {
+ Bitfield(exists, 1); /* True if corresponding artifact has been created */
+ Bitfield(found, 1); /* True if artifact is known by hero to exist */
+};
+/* array of flags tracking which artifacts exist, indexed by ART_xx;
+ ART_xx values are 1..N, element [0] isn't used */
+static struct arti_info artiexist[1 + NROFARTIFACTS];
+/* discovery list; for N discovered artifacts, the first N entries are ART_xx
+ values in discovery order, the remaining (NROFARTIFACTS-N) slots are 0 */
+static xchar artidisco[NROFARTIFACTS];
+/* note: artiexist[] and artidisco[] don't need to be in struct g; they
+ * get explicitly initialized at game start so don't need to be part of
+ * bulk re-init if game restart ever gets implemented. They are saved
+ * and restored but that is done through this file so they can be local.
+ */
+
static void hack_artifacts(void);
static boolean attacks(int, struct obj *);
void
init_artifacts(void)
{
- (void) memset((genericptr_t) g.artiexist, 0, sizeof g.artiexist);
- (void) memset((genericptr_t) g.artidisco, 0, sizeof g.artidisco);
+ (void) memset((genericptr_t) artiexist, 0, sizeof artiexist);
+ (void) memset((genericptr_t) artidisco, 0, sizeof artidisco);
hack_artifacts();
}
save_artifacts(NHFILE *nhfp)
{
if (nhfp->structlevel) {
- bwrite(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
- bwrite(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
+ bwrite(nhfp->fd, (genericptr_t) artiexist, sizeof artiexist);
+ bwrite(nhfp->fd, (genericptr_t) artidisco, sizeof artidisco);
}
}
restore_artifacts(NHFILE *nhfp)
{
if (nhfp->structlevel) {
- mread(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
- mread(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
+ mread(nhfp->fd, (genericptr_t) artiexist, sizeof artiexist);
+ mread(nhfp->fd, (genericptr_t) artidisco, sizeof artidisco);
}
hack_artifacts(); /* redo non-saved special cases */
}
for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''.
*/
struct obj *
-mk_artifact(struct obj *otmp, /* existing object; ignored if alignment specified */
- aligntyp alignment) /* target alignment, or A_NONE */
+mk_artifact(
+ struct obj *otmp, /* existing object; ignored if alignment specified */
+ aligntyp alignment) /* target alignment, or A_NONE */
{
const struct artifact *a;
int m, n, altn;
eligible[0] = 0; /* lint suppression */
/* gather eligible artifacts */
for (m = 1, a = &artilist[m]; a->otyp; a++, m++) {
- if (g.artiexist[m])
+ if (artiexist[m].exists)
continue;
if ((a->spfx & SPFX_NOGEN) || unique)
continue;
otmp = mksobj((int) a->otyp, TRUE, FALSE);
if (otmp) {
- otmp = oname(otmp, a->name);
+ otmp = oname(otmp, a->name, ONAME_NO_FLAGS);
otmp->oartifact = m;
- g.artiexist[m] = TRUE;
+ artiexist[m].exists = 1;
+ artiexist[m].found = 0;
}
} else {
/* nothing appropriate could be found; return original object */
exist_artifact(int otyp, const char *name)
{
register const struct artifact *a;
- boolean *arex;
+ struct arti_info *arex;
if (otyp && *name)
- for (a = artilist + 1, arex = g.artiexist + 1; a->otyp; a++, arex++)
+ for (a = artilist + 1, arex = artiexist + 1; a->otyp; a++, arex++)
if ((int) a->otyp == otyp && !strcmp(a->name, name))
- return *arex;
+ return arex->exists ? TRUE : FALSE;
return FALSE;
}
void
-artifact_exists(struct obj *otmp, const char *name, boolean mod)
+artifact_exists(
+ struct obj *otmp,
+ const char *name,
+ boolean mod, /* True: exists, False: being uncreated */
+ boolean knwn) /* True: hero knows it exists */
{
register const struct artifact *a;
if (otmp && *name)
for (a = artilist + 1; a->otyp; a++)
if (a->otyp == otmp->otyp && !strcmp(a->name, name)) {
- register int m = (int) (a - artilist);
+ int m = (int) (a - artilist);
+
otmp->oartifact = (char) (mod ? m : 0);
otmp->age = 0;
if (otmp->otyp == RIN_INCREASE_DAMAGE)
otmp->spe = 0;
- g.artiexist[m] = mod;
+ artiexist[m].exists = mod ? 1 : 0;
+ artiexist[m].found = (mod && knwn) ? 1 : 0;
break;
}
return;
}
+/* make an artifact as 'found' */
+void
+found_artifact(int a)
+{
+ artiexist[a].found = 1;
+}
+
+/* if an artifact hasn't already been designated 'found', do that now */
+void
+find_artifact(struct obj *otmp)
+{
+ int a = otmp->oartifact;
+
+ if (a && !artiexist[a].found) {
+ found_artifact(a); /* artiexist[a].found = 1 */
+ }
+}
+
int
nartifact_exist(void)
{
- int a = 0;
- int n = SIZE(g.artiexist);
+ int i, a = 0;
- while (n > 1)
- if (g.artiexist[--n])
- a++;
+ for (i = 1; i <= NROFARTIFACTS; ++i)
+ if (artiexist[i].exists)
+ ++a;
return a;
}
/* look for this artifact in the discoveries list;
if we hit an empty slot then it's not present, so add it */
for (i = 0; i < NROFARTIFACTS; i++)
- if (g.artidisco[i] == 0 || g.artidisco[i] == m) {
- g.artidisco[i] = m;
+ if (artidisco[i] == 0 || artidisco[i] == m) {
+ artidisco[i] = m;
+ artiexist[i].found = 1; /* (we expect this to already be set) */
return;
}
/* there is one slot per artifact, so we should never reach the
/* look for this artifact in the discoveries list;
if we hit an empty slot then it's undiscovered */
for (i = 0; i < NROFARTIFACTS; i++)
- if (g.artidisco[i] == m)
+ if (artidisco[i] == m)
return FALSE;
- else if (g.artidisco[i] == 0)
+ else if (artidisco[i] == 0)
break;
return TRUE;
}
char buf[BUFSZ];
for (i = 0; i < NROFARTIFACTS; i++) {
- if (g.artidisco[i] == 0)
+ if (artidisco[i] == 0)
break; /* empty slot implies end of list */
if (tmpwin == WIN_ERR)
continue; /* for WIN_ERR, we just count */
if (i == 0)
putstr(tmpwin, iflags.menu_headings, "Artifacts");
- m = g.artidisco[i];
+ m = artidisco[i];
otyp = artilist[m].otyp;
Sprintf(buf, " %s [%s %s]", artiname(m),
align_str(artilist[m].alignment), simple_typename(otyp));
if (has_oname(otmp))
free_oname(otmp);
} else {
- artifact_exists(otmp, safe_oname(otmp), TRUE);
+ artifact_exists(otmp, safe_oname(otmp), TRUE, FALSE);
}
} else if (has_oname(otmp)) {
sanitize_name(ONAME(otmp));
/* artifact.c */
0, /* spec_dbon_applies */
- UNDEFINED_VALUES, /* artiexist */
- UNDEFINED_VALUES, /* artdisco */
0, /* mkot_trap_warn_count */
/* botl.c */
/* do_name.c */
NULL, /* gloc_filter_map */
UNDEFINED_VALUE, /* gloc_filter_floodfill_match_glyph */
- 0, /* via_naming */
/* do_wear.c */
FALSE, /* initial_don */
a valid artifact name */
u.uconduct.literate++;
}
- ++g.via_naming; /* This ought to be an argument rather than a static... */
- obj = oname(obj, buf);
- --g.via_naming; /* ...but oname() is used in a lot of places, so defer. */
+ obj = oname(obj, buf, ONAME_VIA_NAMING);
}
struct obj *
-oname(struct obj *obj, const char *name)
+oname(struct obj *obj, const char *name, unsigned oflgs)
{
int lth;
char buf[PL_PSIZ];
+ boolean via_naming = (oflgs & ONAME_VIA_NAMING) != 0,
+ found_arti = (oflgs & ONAME_FOUND_ARTI) != 0;
lth = *name ? (int) (strlen(name) + 1) : 0;
if (lth > PL_PSIZ) {
buf[PL_PSIZ - 1] = '\0';
}
/* If named artifact exists in the game, do not create another.
- * Also trying to create an artifact shouldn't de-artifact
- * it (e.g. Excalibur from prayer). In this case the object
- * will retain its current name. */
+ Also trying to create an artifact shouldn't de-artifact
+ it (e.g. Excalibur from prayer). In this case the object
+ will retain its current name. */
if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
return obj;
Strcpy(ONAME(obj), name);
if (lth)
- artifact_exists(obj, name, TRUE);
+ artifact_exists(obj, name, TRUE, via_naming || found_arti);
if (obj->oartifact) {
/* can't dual-wield with artifact as secondary weapon */
if (obj == uswapwep)
/* if obj is owned by a shop, increase your bill */
if (obj->unpaid)
alter_cost(obj, 0L);
- if (g.via_naming) {
+ if (via_naming) {
/* violate illiteracy conduct since successfully wrote arti-name */
if (!u.uconduct.literate++)
livelog_printf(LL_CONDUCT | LL_ARTIFACT,
return;
}
- /* Don't grant Excalibur when there's more than one object. */
- /* (quantity could be > 1 if merged daggers got polymorphed) */
- if (obj->otyp == LONG_SWORD && obj->quan == 1L && u.ulevel >= 5 && !rn2(6)
- && !obj->oartifact
+ if (obj->otyp == LONG_SWORD && u.ulevel >= 5 && !rn2(6)
+ /* once upon a time it was possible to poly N daggers into N swords */
+ && obj->quan == 1L && !obj->oartifact
&& !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
+ static const char lady[] = "Lady of the Lake";
+
if (u.ualign.type != A_LAWFUL) {
/* Ha! Trying to cheat her. */
pline("A freezing mist rises from the %s and envelopes the sword.",
obj->spe--;
obj->oerodeproof = FALSE;
exercise(A_WIS, FALSE);
- livelog_printf(LL_ARTIFACT, "was denied Excalibur! The Lady of the Lake has deemed %s unworthy", uhim());
+ livelog_printf(LL_ARTIFACT,
+ "was denied %s! The %s has deemed %s unworthy",
+ artiname(ART_EXCALIBUR), lady, uhim());
} else {
/* The lady of the lake acts! - Eric Backus */
/* Be *REAL* nice */
pline(
"From the murky depths, a hand reaches up to bless the sword.");
pline("As the hand retreats, the fountain disappears!");
- obj = oname(obj, artiname(ART_EXCALIBUR));
+ obj = oname(obj, artiname(ART_EXCALIBUR), ONAME_FOUND_ARTI);
discover_artifact(ART_EXCALIBUR);
bless(obj);
obj->oeroded = obj->oeroded2 = 0;
obj->oerodeproof = TRUE;
exercise(A_WIS, TRUE);
- livelog_printf(LL_ARTIFACT, "was given Excalibur");
+ livelog_printf(LL_ARTIFACT, "was given %s by the %s",
+ artiname(ART_EXCALIBUR), lady);
}
update_inventory();
levl[u.ux][u.uy].typ = ROOM, levl[u.ux][u.uy].flags = 0;
? g.context.achieveo.soko_prize_otyp
: g.context.achieveo.mines_prize_otyp);
+ /* note: OBJ_NAME() works here because both "bag of holding" and
+ "amulet of reflection" are fully named in their objects[] entry
+ but that's not true in the general case */
livelog_printf(achieve_msg[achidx].llflag, "%s %s",
achieve_msg[achidx].msg, OBJ_NAME(objects[otyp]));
} else {
else if (!Is_pudding(otmp))
otmp->owt += obj->owt;
if (!has_oname(otmp) && has_oname(obj))
- otmp = *potmp = oname(otmp, ONAME(obj));
+ otmp = *potmp = oname(otmp, ONAME(obj), ONAME_NO_FLAGS);
obj_extract_self(obj);
if (obj->pickup_prev && otmp->where == OBJ_INVENT)
struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE);
if (info->object_nam)
- obj = oname(obj, info->object_nam);
+ obj = oname(obj, info->object_nam, ONAME_NO_FLAGS);
if (info->response_cmd)
new_omailcmd(obj, info->response_cmd);
/* maybe make it special */
if (!rn2(20) || is_lord(ptr))
otmp = oname(otmp,
- artiname(rn2(2) ? ART_DEMONBANE : ART_SUNSWORD));
+ artiname(rn2(2) ? ART_DEMONBANE : ART_SUNSWORD),
+ ONAME_NO_FLAGS);
bless(otmp);
otmp->oerodeproof = TRUE;
otmp->spe = rn2(4);
if (!obj2->oextra)
obj2->oextra = newoextra();
if (has_oname(obj1))
- oname(obj2, ONAME(obj1));
+ oname(obj2, ONAME(obj1), ONAME_NO_FLAGS);
if (has_omonst(obj1)) {
if (!OMONST(obj2))
newomonst(obj2);
break;
case SPE_NOVEL:
otmp->novelidx = -1; /* "none of the above"; will be changed */
- otmp = oname(otmp, noveltitle(&otmp->novelidx));
+ otmp = oname(otmp, noveltitle(&otmp->novelidx), ONAME_NO_FLAGS);
break;
}
otmp = mkcorpstat(objtype, (struct monst *) 0, ptr, x, y, corpstatflags);
if (nm)
- otmp = oname(otmp, nm);
+ otmp = oname(otmp, nm, ONAME_NO_FLAGS);
return otmp;
}
/* this has now become very similar to m_useupall()... */
extract_from_minvent(mtmp, otmp, TRUE, TRUE);
if (uncreate_artifacts && otmp->oartifact)
- artifact_exists(otmp, safe_oname(otmp), FALSE);
+ artifact_exists(otmp, safe_oname(otmp), FALSE, FALSE);
obfree(otmp, (struct obj *) 0); /* dealloc_obj() isn't sufficient */
}
}
bypass_obj(obj);
if (has_mgivenname(mtmp))
- obj = oname(obj, MGIVENNAME(mtmp));
+ obj = oname(obj, MGIVENNAME(mtmp), ONAME_NO_FLAGS);
/* Avoid "It was hidden under a green mold corpse!"
* during Blind combat. An unseen monster referred to as "it"
}
boolean
-mpickstuff(register struct monst* mtmp, register const char* str)
+mpickstuff(struct monst *mtmp, const char *str)
{
register struct obj *otmp, *otmp2, *otmp3;
int carryamt = 0;
if (carryamt != otmp->quan) {
otmp3 = splitobj(otmp, carryamt);
}
- if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
- pline("%s picks up %s.", Monnam(mtmp),
- (distu(mtmp->mx, mtmp->my) <= 5)
- ? doname(otmp3)
- : distant_name(otmp3, doname));
+ if (cansee(mtmp->mx, mtmp->my)) {
+ if (flags.verbose)
+ /* see 'otmp3' "up close" if within a knight's jump */
+ pline("%s picks up %s.", Monnam(mtmp),
+ ((distu(mtmp->mx, mtmp->my) <= 5)
+ ? doname(otmp3)
+ : distant_name(otmp3, doname)));
+ }
obj_extract_self(otmp3); /* remove from floor */
(void) mpickobj(mtmp, otmp3); /* may merge and free otmp3 */
m_dowear(mtmp, FALSE);
corpstatflags |= CORPSTAT_HISTORIC;
otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, corpstatflags);
if (has_mgivenname(mdef))
- otmp = oname(otmp, MGIVENNAME(mdef));
+ otmp = oname(otmp, MGIVENNAME(mdef), ONAME_NO_FLAGS);
while ((obj = oldminvent) != 0) {
oldminvent = obj->nobj;
obj->nobj = 0; /* avoid merged-> obfree-> dealloc_obj-> panic */
/* oc_big is also oc_bimanual and oc_bulky */
&& (otmp->owt > 30 || objects[otyp].oc_big)) {
if (otmp->oartifact)
- artifact_exists(otmp, safe_oname(otmp), FALSE);
+ artifact_exists(otmp, safe_oname(otmp), FALSE, FALSE);
delobj(otmp);
} else if (!flooreffects(otmp, x, y, nomsg ? "" : "fall")) {
place_object(otmp, x, y);
d.name = novelname;
}
- d.otmp = oname(d.otmp, d.name);
+ d.otmp = oname(d.otmp, d.name, ONAME_NO_FLAGS);
/* name==aname => wished for artifact (otmp->oartifact => got it) */
if (d.otmp->oartifact || d.name == aname) {
d.otmp->quan = 1L;
/* and make them pay; charge them for the wish anyway! */
if ((is_quest_artifact(d.otmp)
|| (d.otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) {
- artifact_exists(d.otmp, safe_oname(d.otmp), FALSE);
+ artifact_exists(d.otmp, safe_oname(d.otmp), FALSE, FALSE);
obfree(d.otmp, (struct obj *) 0);
d.otmp = (struct obj *) &cg.zeroobj;
pline("For a moment, you feel %s in your %s, but it disappears!",
now rather than from when this special corpse got created */
deadcat->age = g.moves;
set_corpsenm(deadcat, PM_HOUSECAT);
- deadcat = oname(deadcat, sc);
+ deadcat = oname(deadcat, sc, ONAME_NO_FLAGS);
}
if (givemsg)
pline_The("%s inside the box is dead!",
Strcpy(lbuf, simpleonames(obj)); /* before transformation */
if (!Blind)
Your("sword shines brightly for a moment.");
- obj = oname(obj, artiname(ART_EXCALIBUR));
+ obj = oname(obj, artiname(ART_EXCALIBUR), ONAME_FOUND_ARTI);
if (obj && obj->oartifact == ART_EXCALIBUR) {
u.ugifts++;
livelog_printf(LL_DIVINEGIFT | LL_ARTIFACT,
; /* already got bonus above */
} else if (obj && in_hand) {
Your("%s goes snicker-snack!", xname(obj));
- obj->dknown = TRUE;
+ obj->dknown = 1;
} else if (!already_exists) {
obj = mksobj(LONG_SWORD, FALSE, FALSE);
- obj = oname(obj, artiname(ART_VORPAL_BLADE));
+ obj = oname(obj, artiname(ART_VORPAL_BLADE), ONAME_FOUND_ARTI);
obj->spe = 1;
at_your_feet("A sword");
dropy(obj);
; /* already got bonus above */
} else if (obj && in_hand) {
Your("%s hums ominously!", swordbuf);
- obj->dknown = TRUE;
+ obj->dknown = 1;
} else if (!already_exists) {
obj = mksobj(RUNESWORD, FALSE, FALSE);
- obj = oname(obj, artiname(ART_STORMBRINGER));
+ obj = oname(obj, artiname(ART_STORMBRINGER), ONAME_FOUND_ARTI);
obj->spe = 1;
at_your_feet(An(swordbuf));
dropy(obj);
/* set_corpsenm() took care of egg hatch and corpse timers */
if (named) {
- otmp = oname(otmp, o->name.str);
+ otmp = oname(otmp, o->name.str, ONAME_NO_FLAGS);
if (otmp->otyp == SPE_NOVEL) {
/* needs to be an existing title */
(void) lookup_novel(o->name.str, &otmp->novelidx);
} else {
obj_extract_self(otmp);
if (otmp->oartifact)
- artifact_exists(otmp, safe_oname(otmp), FALSE);
+ artifact_exists(otmp, safe_oname(otmp), FALSE, FALSE);
obfree(otmp, NULL);
return;
}
/* Returns 1 if otmp is free'd, 0 otherwise. */
int
-mpickobj(register struct monst* mtmp, register struct obj* otmp)
+mpickobj(struct monst *mtmp, struct obj *otmp)
{
int freed_otmp;
boolean snuff_otmp = FALSE;
even leaving the game entirely; when that happens, prevent them from
taking the Amulet, invocation items, or quest artifact with them */
void
-mdrop_special_objs(struct monst* mon)
+mdrop_special_objs(struct monst *mon)
{
struct obj *obj, *otmp;
otmp->spe = CORPSTAT_FEMALE;
else if (tt->plgend[0] == 'M')
otmp->spe = CORPSTAT_MALE;
- otmp = oname(otmp, tt->name);
+ otmp = oname(otmp, tt->name, ONAME_NO_FLAGS);
return otmp;
}