Special effects for Vlad's throne

Part 1 of implementing wish spreading. Vlad's throne is now
guaranteed to eventually give a wish, but has a range of other
powerful (and mostly bad) effects, like removing intrinsics, that
can be much harder to deal with than typical throne effects.
This commit is contained in:
Alex Smith
2025-05-30 01:11:41 +01:00
parent 0e50adcc1e
commit 3fd30c4ec8

136
src/sit.c
View File

@@ -7,6 +7,7 @@
#include "artifact.h"
staticfn void throne_sit_effect(void);
staticfn void rndcurse_inner(boolean);
staticfn int lay_an_egg(void);
/* take away the hero's money */
@@ -32,12 +33,16 @@ take_gold(void)
}
}
staticfn void special_throne_effect(int effect);
/* maybe do something when hero sits on a throne */
staticfn void
throne_sit_effect(void)
{
coordxy tx = u.ux, ty = u.uy;
boolean special_throne = !!In_V_tower(&u.uz);
if (rnd(6) > 4) { /* [why so convoluted? it's the same as '!rn2(3)'] */
int effect = rnd(13);
@@ -56,6 +61,11 @@ throne_sit_effect(void)
effect = which;
}
if (special_throne) {
special_throne_effect(effect);
return;
}
switch (effect) {
case 1:
(void) adjattrib(rn2(A_MAX), -rn1(4, 3), FALSE);
@@ -212,7 +222,8 @@ throne_sit_effect(void)
only happened when teleporting back to the same point where hero
started from.] "Analyzing a throne" doesn't really make any sense
but if the answer is yes than it will vanish in a puff of logic. */
if (!rn2(3) && (!wizard || y_n("Analyze throne?") == 'y')) {
if (!special_throne &&
!rn2(3) && (!wizard || y_n("Analyze throne?") == 'y')) {
levl[tx][ty].typ = ROOM, levl[tx][ty].flags = 0;
map_background(tx, ty, FALSE);
newsym_force(tx, ty);
@@ -223,6 +234,110 @@ throne_sit_effect(void)
}
}
/* special throne in Vlad's tower: effect is 1 to 13 inclusive */
staticfn void
special_throne_effect(int effect) {
coordxy tx = u.ux, ty = u.uy;
switch (effect) {
case 1:
case 2:
case 3:
case 4:
/* 4 chances of a wish, but then the throne disappears.
This is the only way the throne can disappear from sitting
on it, so if you sit on it enough (enduring the negative
effects) you are guaranteed an eventual wish. */
makewish();
levl[tx][ty].typ = ROOM, levl[tx][ty].flags = 0;
map_background(tx, ty, FALSE);
newsym_force(tx, ty);
pline_The("throne disintegrates, having spent its power.");
break;
case 5:
/* permanent level drain */
pline("Sitting on the throne was a terrible experience.");
if (!Drain_resistance) {
losexp("a bad experience sitting on a throne");
if (u.ulevelmax > u.ulevel)
u.ulevelmax -= 1;
}
break;
case 6:
/* containers become cursed */
rndcurse_inner(TRUE);
break;
case 7:
/* lose an intrinsic */
attrcurse();
pline_The("throne somehow seems to be amused.");
break;
case 8:
{
/* level teleport to Vibrating Square level */
d_level vs_level;
find_hell(&vs_level);
vs_level.dlevel = svd.dungeons[vs_level.dnum].num_dunlevs - 1;
if (u.uhave.amulet)
You_feel("extremely disoriented for a moment.");
else
schedule_goto(
&vs_level, UTOTYPE_NONE, (char *) 0,
"You feel extremely out of place.");
break;
}
case 9:
{
/* summon demons; a NULL argument to msummon summons demons as
though they were summoned by the Wizard of Yendor */
pline_The("throne seeems to be calling for help!");
msummon(NULL);
msummon(NULL);
msummon(NULL);
break;
}
case 10:
{
/* confused blessed remove curse effect */
struct obj fake_spellbook;
long save_confusion = HConfusion;
fake_spellbook = cg.zeroobj;
fake_spellbook.otyp = SPE_REMOVE_CURSE;
fake_spellbook.oclass = SPBOOK_CLASS;
fake_spellbook.blessed = 1;
HConfusion = 1L;
(void) seffects(&fake_spellbook);
HConfusion = save_confusion;
break;
}
case 11:
/* polymorph effect (not blocked by magic resistance) */
pline("This throne was not meant for those such as you!");
You_feel("a change coming over you.");
polyself(POLY_NOFLAGS);
break;
case 12:
/* acid damage */
pline("The throne is covered in acid!");
losehp(Acid_resistance ? rnd(16) : rnd(80), "acidic chair",
KILLED_BY_AN);
exercise(A_CON, FALSE);
break;
case 13:
{
/* ability shuffle */
int ability;
pline("As you sit on the throne, your body and mind start to warp.");
for (ability = 0; ability < A_MAX; ++ability) {
adjattrib(ability, rn2(5) - 2, -1);
}
break;
}
}
}
/* hero lays an egg */
staticfn int
lay_an_egg(void)
@@ -436,6 +551,12 @@ dosit(void)
/* curse a few inventory items at random! */
void
rndcurse(void)
{
rndcurse_inner(FALSE);
}
staticfn void
rndcurse_inner(boolean prefer_containers)
{
int nobj = 0;
int cnt, onum;
@@ -449,23 +570,30 @@ rndcurse(void)
if (Antimagic) {
shieldeff(u.ux, u.uy);
You(mal_aura, "you");
}
You(mal_aura, "you");
for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
/* gold isn't subject to being cursed or blessed */
if (otmp->oclass == COIN_CLASS)
continue;
if (prefer_containers && !otmp->cobj)
continue;
nobj++;
}
cnt = rnd(6 / ((!!Antimagic) + (!!Half_spell_damage) + 1));
if (prefer_containers)
cnt = nobj * 2;
if (nobj) {
for (cnt = rnd(6 / ((!!Antimagic) + (!!Half_spell_damage) + 1));
cnt > 0; cnt--) {
for (; cnt > 0; cnt--) {
onum = rnd(nobj);
for (otmp = gi.invent; otmp; otmp = otmp->nobj) {
/* as above */
if (otmp->oclass == COIN_CLASS)
continue;
if (prefer_containers && !otmp->cobj)
continue;
if (--onum == 0)
break; /* found the target */
}