From 1bb8545563a4c2d6356b7f62127f48c9ae80fc86 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 5 Dec 2006 03:09:13 +0000 Subject: [PATCH] endgame: high altars, offering the Amulet to Moloch (trunk only) Several small related changes that ended up being not quite so small: Allow the Amulet of Yendor to be offered on the altar in the temple of Moloch's Sanctum level; doing so is fatal. Fake ones can be offered too, but that doesn't do anything special (they act the same as they do in the temples on the Astral level). Unlike in the endgame, the Amulet and its fakes aren't listed as likely candidate for #offer's pick-an-object prompt; like the endgame, corpses must be carried rather than being on the altar in order to be sacrificed. Prevent non-chaotics from destroying the chaotic high altar on the Astral level via same-race sacrifice. From a bug report. (Chaotics converting non-chaotic high altars via same method was already handled. I think the behavior for ordinary altars if wrong here; why should a chaotic altar be destroyed this way?) Prevent demon princes and demon lords from being summoned in the endgame. Lesser demons answer instead. Mostly prevents Yeenoghu from being summoned by a chaotic who performs same-race sacrified on the chaotic high altar, but might affect the Wizard and arch-liches too. Identify (via ':', ';', '/') altars in temples on the Astral and Sanctum levels as "high altars" rather than just as "altars". '/' and ';' commands now work on those when you're adjacent, like they do when used on adjacent high priests; from farther away, the altars' alignment is still suppressed. --- doc/fixes35.0 | 3 +++ src/invent.c | 8 +++++++- src/minion.c | 6 +++--- src/pager.c | 13 ++++++++----- src/pray.c | 45 +++++++++++++++++++++++++++++++++------------ 5 files changed, 54 insertions(+), 21 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index d7e830b38..0553fdae0 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -176,6 +176,8 @@ worn item transformed by polymorph remains worn if feasible can't dip or apply grease to a worn item that's covered by another worn item hero poly'd into stone golem and wielding cockatrice corpse casts stone-to- flesh at self to become flesh golem will revert to stone if no gloves +demon lords/princes can't be summoned to the elemental or Astral planes +same-race sacrifice can't damage high altars Platform- and/or Interface-Specific Fixes @@ -262,6 +264,7 @@ multiple squeaks for squeaky boards include time, user ID, and play mode in paniclog entries add oracle and rumor regarding priestly donations anti-magic traps have alternate effect on targets who have magic resistance +the Amulet can be offered to Moloch Platform- and/or Interface-Specific New Features diff --git a/src/invent.c b/src/invent.c index b14d436fb..a08a297db 100644 --- a/src/invent.c +++ b/src/invent.c @@ -925,6 +925,8 @@ register const char *let,*word; || (!strncmp(word, "rub on the stone", 16) && *let == GEM_CLASS && otmp->dknown && objects[otyp].oc_name_known) + || (!strcmp(word, "sacrifice") && Is_sanctum(&u.uz) && + (otyp == AMULET_OF_YENDOR || otyp == FAKE_AMULET_OF_YENDOR)) ) { foo--; allowall = TRUE; @@ -2228,7 +2230,11 @@ char *buf; cmap = S_sink; /* "sink" */ #endif else if (IS_ALTAR(ltyp)) { - Sprintf(altbuf, "altar to %s (%s)", a_gname(), + Sprintf(altbuf, "%saltar to %s (%s)", + ((lev->altarmask & AM_SHRINE) && + (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? + "high " : "", + a_gname(), align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); dfeature = altbuf; } else if ((x == xupstair && y == yupstair) || diff --git a/src/minion.c b/src/minion.c index 5d4806e65..c48c4eb48 100644 --- a/src/minion.c +++ b/src/minion.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)minion.c 3.5 2006/09/06 */ +/* SCCS Id: @(#)minion.c 3.5 2006/12/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -299,7 +299,7 @@ aligntyp atyp; { int tryct, pm; - for (tryct = 0; tryct < 20; tryct++) { + for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) @@ -314,7 +314,7 @@ aligntyp atyp; { int tryct, pm; - for (tryct = 0; tryct < 20; tryct++) { + for (tryct = !In_endgame(&u.uz) ? 20 : 0; tryct > 0; --tryct) { pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) diff --git a/src/pager.c b/src/pager.c index 430167a7f..7c935b3d1 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)pager.c 3.5 2006/07/08 */ +/* SCCS Id: @(#)pager.c 3.5 2006/12/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -266,10 +266,13 @@ lookat(x, y, buf, monbuf) Strcpy(buf,"dark part of a room"); } else switch(glyph_to_cmap(glyph)) { case S_altar: - if(!In_endgame(&u.uz)) - Sprintf(buf, "%s altar", - align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE))); - else Sprintf(buf, "aligned altar"); + Sprintf(buf, "%s %saltar", + /* like endgame high priests, endgame high altars + are only recognizable when immediately adjacent */ + (Is_astralevel(&u.uz) && distu(x, y) > 2) ? "aligned" : + align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE)), + ((levl[x][y].altarmask & AM_SHRINE) && + (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) ? "high " : ""); break; case S_ndoor: if (is_drawbridge_wall(x, y) >= 0) diff --git a/src/pray.c b/src/pray.c index 4e2dc741d..6bb4481f7 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1156,17 +1156,21 @@ register struct obj *otmp; int dosacrifice() { + static NEARDATA const char cloud_of_smoke[] = + "A cloud of %s smoke surrounds you..."; register struct obj *otmp; - int value = 0; - int pm; + int value = 0, pm; + boolean highaltar; aligntyp altaralign = a_align(u.ux,u.uy); if (!on_altar() || u.uswallow) { You("are not standing on an altar."); return 0; } + highaltar = ((Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) && + (levl[u.ux][u.uy].altarmask & AM_SHRINE)); - if (In_endgame(&u.uz)) { + if (highaltar) { if (!(otmp = getobj(sacrifice_types, "sacrifice"))) return 0; } else { if (!(otmp = floorfood("sacrifice", 1))) return 0; @@ -1210,11 +1214,13 @@ dosacrifice() exercise(A_WIS, FALSE); } - if (altaralign != A_CHAOTIC && altaralign != A_NONE) { + if (highaltar && + (altaralign != A_CHAOTIC || u.ualign.type != A_CHAOTIC)) { + goto desecrate_high_altar; + } else if (altaralign != A_CHAOTIC && altaralign != A_NONE) { /* curse the lawful/neutral altar */ pline_The("altar is stained with %s blood.", urace.adj); - if(!Is_astralevel(&u.uz)) - levl[u.ux][u.uy].altarmask = AM_CHAOTIC; + levl[u.ux][u.uy].altarmask = AM_CHAOTIC; angry_priest(); } else { struct monst *dmon; @@ -1306,7 +1312,7 @@ dosacrifice() } /* corpse */ if (otmp->otyp == AMULET_OF_YENDOR) { - if (!Is_astralevel(&u.uz)) { + if (!highaltar) { if (Hallucination) You_feel("homesick."); else @@ -1319,7 +1325,23 @@ dosacrifice() if(carried(otmp)) useup(otmp); /* well, it's gone now */ else useupf(otmp, 1L); You("offer the Amulet of Yendor to %s...", a_gname()); - if (u.ualign.type != altaralign) { + if (altaralign == A_NONE) { + /* Moloch's high altar */ + if (u.ualign.record > -99) u.ualign.record = -99; + /*[apparently shrug/snarl can be sensed without being seen]*/ + pline("%s shrugs and retains dominion over %s,", + Moloch, u_gname()); + pline("then mercilessly snuffs out your life."); + Sprintf(killer.name, "%s indifference", s_suffix(Moloch)); + killer.format = KILLED_BY; + done(DIED); + /* life-saved (or declined to die in wizard/explore mode) */ + pline("%s snarls and tries again...", Moloch); + fry_by_god(A_NONE); /* wrath of Moloch */ + /* declined to die in wizard or explore mode */ + pline(cloud_of_smoke, hcolor(NH_BLACK)); + done(ESCAPED); + } else if (u.ualign.type != altaralign) { /* And the opposing team picks you up and carries you off on their shoulders */ adjalign(-99); @@ -1327,8 +1349,7 @@ dosacrifice() a_gname(), u_gname()); pline("%s is enraged...", u_gname()); pline("Fortunately, %s permits you to live...", a_gname()); - pline("A cloud of %s smoke surrounds you...", - hcolor((const char *)"orange")); + pline(cloud_of_smoke, hcolor("orange")); done(ESCAPED); } else { /* super big win */ adjalign(10); @@ -1366,8 +1387,8 @@ verbalize("In return for thy service, I grant thee the gift of Immortality!"); return (1); } - if (altaralign != u.ualign.type && - (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { + if (altaralign != u.ualign.type && highaltar) { + desecrate_high_altar: /* * REAL BAD NEWS!!! High altars cannot be converted. Even an attempt * gets the god who owns it truely pissed off.