add two new types of amulet: flying and guarding
We haven't added any new objects or monsters in a really long time. This adds two new useful amulets, putting more pressure on the decision over which type of amulet to wear. amulet of flying: idea from slash'em, implemented from scratch. Should be self-explanatory. Polymorphing into a form capable of eating amulets and then eating one does not confer intrinsic flight. (I've no idea how slash'em behaves is in that regard.) amulet of guarding: adds +2 AC, which is fairly negligible, also +2 MC, which is not. Initially called amulet of protection but MC of 2 is referred to as 'guarded' by enlightenment so I changed it. (By that reasoning, rings of protection ought to be called rings of warding; oh, well.) Successfully eating one confers +2 AC without any MC benefit. When wearing one of these, rings of protection only confer AC, their +1 MC gets superseded rather than combined. Monsters will wear an amulet of guarding and gain both the AC and MC benefit, but if not cursed and they acquire one of life-saving or reflection, they'll swap. They won't wear an amulet of flying. I cloned two extra copies of the tile for one of the existing amulets and ran sys/share/objects.txt through renumtiles.pl. The result appears to be ok but on X11 the tiles map ends up looking psychedelic so something beyond the tile art itself needs to be fixed here.
This commit is contained in:
@@ -784,7 +784,31 @@ Amulet_on()
|
||||
gotten set by previously eating one of these amulets */
|
||||
if (newnap < oldnap || oldnap == 0L)
|
||||
HSleepy = (HSleepy & ~TIMEOUT) | newnap;
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
case AMULET_OF_FLYING:
|
||||
/* setworn() has already set extrinisic flying */
|
||||
float_vs_flight(); /* block flying if levitating */
|
||||
if (Flying) {
|
||||
boolean already_flying;
|
||||
|
||||
/* to determine whether this flight is new we have to muck
|
||||
about in the Flying intrinsic (actually extrinsic) */
|
||||
EFlying &= ~W_AMUL;
|
||||
already_flying = !!Flying;
|
||||
EFlying |= W_AMUL;
|
||||
|
||||
if (!already_flying) {
|
||||
makeknown(AMULET_OF_FLYING);
|
||||
g.context.botl = TRUE; /* status: 'Fly' On */
|
||||
You("are now in flight.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AMULET_OF_GUARDING:
|
||||
makeknown(AMULET_OF_GUARDING);
|
||||
find_ac();
|
||||
break;
|
||||
case AMULET_OF_YENDOR:
|
||||
break;
|
||||
}
|
||||
@@ -838,6 +862,26 @@ Amulet_off()
|
||||
if (!ESleepy && !(HSleepy & ~TIMEOUT))
|
||||
HSleepy &= ~TIMEOUT; /* clear timeout bits */
|
||||
return;
|
||||
case AMULET_OF_FLYING: {
|
||||
boolean was_flying = !!Flying;
|
||||
|
||||
/* remove amulet 'early' to determine whether Flying changes */
|
||||
setworn((struct obj *) 0, W_AMUL);
|
||||
float_vs_flight(); /* probably not needed here */
|
||||
if (was_flying && !Flying) {
|
||||
makeknown(AMULET_OF_FLYING);
|
||||
g.context.botl = TRUE; /* status: 'Fly' Off */
|
||||
You("%s.", (is_pool_or_lava(u.ux, u.uy)
|
||||
|| Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
|
||||
? "stop flying"
|
||||
: "land");
|
||||
spoteffects(TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AMULET_OF_GUARDING:
|
||||
find_ac();
|
||||
break;
|
||||
case AMULET_OF_YENDOR:
|
||||
break;
|
||||
}
|
||||
@@ -2056,7 +2100,7 @@ struct obj *obj;
|
||||
g.multi_reason = "dressing up";
|
||||
g.nomovemsg = "You finish your dressing maneuver.";
|
||||
} else {
|
||||
unmul(""); /* call (*g.aftermv)(), clear it+g.nomovemsg+g.multi_reason */
|
||||
unmul(""); /* call aftermv, clear it+nomovemsg+multi_reason */
|
||||
on_msg(obj);
|
||||
}
|
||||
g.context.takeoff.mask = g.context.takeoff.what = 0L;
|
||||
@@ -2151,6 +2195,8 @@ find_ac()
|
||||
uac -= uleft->spe;
|
||||
if (uright && uright->otyp == RIN_PROTECTION)
|
||||
uac -= uright->spe;
|
||||
if (uamul && uamul->otyp == AMULET_OF_GUARDING)
|
||||
uac -= 2; /* fixed amount; main benefit is to MC */
|
||||
|
||||
/* armor class from other sources */
|
||||
if (HProtection & INTRINSIC)
|
||||
|
||||
15
src/eat.c
15
src/eat.c
@@ -1819,7 +1819,8 @@ struct obj *otmp;
|
||||
/* not cannibalism, but we use similar criteria
|
||||
for deciding whether to be sickened by this meal */
|
||||
if (rn2(2) && !CANNIBAL_ALLOWED())
|
||||
make_vomiting((long) rn1(g.context.victual.reqtime, 14), FALSE);
|
||||
make_vomiting((long) rn1(g.context.victual.reqtime, 14),
|
||||
FALSE);
|
||||
}
|
||||
break;
|
||||
case LEMBAS_WAFER:
|
||||
@@ -2031,10 +2032,13 @@ struct obj *otmp;
|
||||
RIN_INCREASE_DAMAGE);
|
||||
break;
|
||||
case RIN_PROTECTION:
|
||||
case AMULET_OF_GUARDING:
|
||||
accessory_has_effect(otmp);
|
||||
HProtection |= FROMOUTSIDE;
|
||||
u.ublessed = bounded_increase(u.ublessed, otmp->spe,
|
||||
RIN_PROTECTION);
|
||||
u.ublessed = bounded_increase(u.ublessed,
|
||||
(typ == RIN_PROTECTION) ? otmp->spe
|
||||
: 2, /* fixed amount for amulet */
|
||||
typ);
|
||||
g.context.botl = 1;
|
||||
break;
|
||||
case RIN_FREE_ACTION:
|
||||
@@ -2078,6 +2082,7 @@ struct obj *otmp;
|
||||
}
|
||||
case RIN_SUSTAIN_ABILITY:
|
||||
case AMULET_OF_LIFE_SAVING:
|
||||
case AMULET_OF_FLYING:
|
||||
case AMULET_OF_REFLECTION: /* nice try */
|
||||
/* can't eat Amulet of Yendor or fakes,
|
||||
* and no oc_prop even if you could -3.
|
||||
@@ -2839,7 +2844,9 @@ gethungry()
|
||||
need to check whether both rings are +0 protection or
|
||||
they'd both slip by the "is there another source?" test,
|
||||
but don't do that for both rings or they will both be
|
||||
treated as supplying "MC" when only one matters */
|
||||
treated as supplying "MC" when only one matters;
|
||||
note: amulet of guarding overrides both +0 rings and
|
||||
is caught by the (EProtection & ~W_RINGx) == 0L tests */
|
||||
&& (uleft->spe
|
||||
|| !objects[uleft->otyp].oc_charged
|
||||
|| (uleft->otyp == RIN_PROTECTION
|
||||
|
||||
@@ -1478,6 +1478,8 @@ int final;
|
||||
prot += uleft->spe;
|
||||
if (uright && uright->otyp == RIN_PROTECTION)
|
||||
prot += uright->spe;
|
||||
if (uamul && uamul->otyp == AMULET_OF_GUARDING)
|
||||
prot += 2;
|
||||
if (HProtection & INTRINSIC)
|
||||
prot += u.ublessed;
|
||||
prot += u.uspellprot;
|
||||
|
||||
10
src/mhitu.c
10
src/mhitu.c
@@ -911,6 +911,7 @@ struct monst *mon;
|
||||
long wearmask;
|
||||
int armpro, mc = 0;
|
||||
boolean is_you = (mon == &g.youmonst),
|
||||
via_amul = FALSE,
|
||||
gotprot = is_you ? (EProtection != 0L)
|
||||
/* high priests have innate protection */
|
||||
: (mon->data == &mons[PM_HIGH_PRIEST]);
|
||||
@@ -921,6 +922,8 @@ struct monst *mon;
|
||||
armpro = objects[o->otyp].a_can;
|
||||
if (armpro > mc)
|
||||
mc = armpro;
|
||||
} else if ((o->owornmask & W_AMUL) != 0L) {
|
||||
via_amul = TRUE;
|
||||
}
|
||||
/* if we've already confirmed Protection, skip additional checks */
|
||||
if (is_you || gotprot)
|
||||
@@ -935,9 +938,10 @@ struct monst *mon;
|
||||
}
|
||||
|
||||
if (gotprot) {
|
||||
/* extrinsic Protection increases mc by 1 */
|
||||
if (mc < 3)
|
||||
mc += 1;
|
||||
/* extrinsic Protection increases mc by 1; 2 for amulet */
|
||||
mc += via_amul ? 2 : 1;
|
||||
if (mc > 3)
|
||||
mc = 3;
|
||||
} else if (mc < 1) {
|
||||
/* intrinsic Protection is weaker (play balance; obtaining divine
|
||||
protection is too easy); it confers minimum mc 1 instead of 0 */
|
||||
|
||||
@@ -2328,7 +2328,7 @@ struct obj *obj;
|
||||
case AMULET_CLASS:
|
||||
if (typ == AMULET_OF_LIFE_SAVING)
|
||||
return (boolean) !(nonliving(mon->data) || is_vampshifter(mon));
|
||||
if (typ == AMULET_OF_REFLECTION)
|
||||
if (typ == AMULET_OF_REFLECTION || typ == AMULET_OF_GUARDING)
|
||||
return TRUE;
|
||||
break;
|
||||
case TOOL_CLASS:
|
||||
|
||||
@@ -607,15 +607,20 @@ RING("protection from shape changers", "shiny",
|
||||
OBJECT(OBJ(name, desc), \
|
||||
BITS(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, P_NONE, IRON), \
|
||||
power, AMULET_CLASS, prob, 0, 20, 150, 0, 0, 0, 0, 20, HI_METAL)
|
||||
AMULET("amulet of ESP", "circular", TELEPAT, 175),
|
||||
AMULET("amulet of ESP", "circular", TELEPAT, 120),
|
||||
AMULET("amulet of life saving", "spherical", LIFESAVED, 75),
|
||||
AMULET("amulet of strangulation", "oval", STRANGLED, 135),
|
||||
AMULET("amulet of restful sleep", "triangular", SLEEPY, 135),
|
||||
AMULET("amulet versus poison", "pyramidal", POISON_RES, 165),
|
||||
AMULET("amulet of change", "square", 0, 130),
|
||||
AMULET("amulet of unchanging", "concave", UNCHANGING, 45),
|
||||
AMULET("amulet of strangulation", "oval", STRANGLED, 115),
|
||||
AMULET("amulet of restful sleep", "triangular", SLEEPY, 115),
|
||||
AMULET("amulet versus poison", "pyramidal", POISON_RES, 115),
|
||||
AMULET("amulet of change", "square", 0, 115),
|
||||
AMULET("amulet of unchanging", "concave", UNCHANGING, 60),
|
||||
AMULET("amulet of reflection", "hexagonal", REFLECTING, 75),
|
||||
AMULET("amulet of magical breathing", "octagonal", MAGICAL_BREATHING, 65),
|
||||
AMULET("amulet of magical breathing", "octagonal", MAGICAL_BREATHING, 75),
|
||||
/* +2 AC and +2 MC; +2 takes naked hero past 'warded' to 'guarded' */
|
||||
AMULET("amulet of guarding", "pentagonal", PROTECTION, 75),
|
||||
/* cubical: some descriptions are already three dimensional and
|
||||
parallelogrammatical (real word!) would be way over the top */
|
||||
AMULET("amulet of flying", "cubical", FLYING, 60),
|
||||
/* fixed descriptions; description duplication is deliberate;
|
||||
* fake one must come before real one because selection for
|
||||
* description shuffling stops when a non-magic amulet is encountered
|
||||
|
||||
@@ -2834,6 +2834,7 @@ static const struct alt_spellings {
|
||||
{ "lantern", BRASS_LANTERN },
|
||||
{ "mattock", DWARVISH_MATTOCK },
|
||||
{ "amulet of poison resistance", AMULET_VERSUS_POISON },
|
||||
{ "amulet of protection", AMULET_OF_GUARDING },
|
||||
{ "potion of sleep", POT_SLEEPING },
|
||||
{ "stone", ROCK },
|
||||
{ "camera", EXPENSIVE_CAMERA },
|
||||
|
||||
32
src/worn.c
32
src/worn.c
@@ -441,9 +441,13 @@ register struct monst *mon;
|
||||
long mwflags = mon->misc_worn_check;
|
||||
|
||||
for (obj = mon->minvent; obj; obj = obj->nobj) {
|
||||
if (obj->owornmask & mwflags)
|
||||
base -= ARM_BONUS(obj);
|
||||
/* since ARM_BONUS is positive, subtracting it increases AC */
|
||||
if (obj->owornmask & mwflags) {
|
||||
if (obj->otyp == AMULET_OF_GUARDING)
|
||||
base -= 2; /* fixed amount, not impacted by erosion */
|
||||
else
|
||||
base -= ARM_BONUS(obj);
|
||||
/* since ARM_BONUS is positive, subtracting it increases AC */
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
@@ -527,8 +531,8 @@ boolean racialexception;
|
||||
old = which_armor(mon, flag);
|
||||
if (old && old->cursed)
|
||||
return;
|
||||
if (old && flag == W_AMUL)
|
||||
return; /* no such thing as better amulets */
|
||||
if (old && flag == W_AMUL && old->otyp != AMULET_OF_GUARDING)
|
||||
return; /* no amulet better than life-saving or reflection */
|
||||
best = old;
|
||||
|
||||
for (obj = mon->minvent; obj; obj = obj->nobj) {
|
||||
@@ -536,10 +540,18 @@ boolean racialexception;
|
||||
case W_AMUL:
|
||||
if (obj->oclass != AMULET_CLASS
|
||||
|| (obj->otyp != AMULET_OF_LIFE_SAVING
|
||||
&& obj->otyp != AMULET_OF_REFLECTION))
|
||||
&& obj->otyp != AMULET_OF_REFLECTION
|
||||
&& obj->otyp != AMULET_OF_GUARDING))
|
||||
continue;
|
||||
best = obj;
|
||||
goto outer_break; /* no such thing as better amulets */
|
||||
/* for 'best' to be non-Null, it must be an amulet of guarding;
|
||||
life-saving and reflection don't get here due to early return
|
||||
and other amulets of guarding can't be any better */
|
||||
if (!best || obj->otyp != AMULET_OF_GUARDING) {
|
||||
best = obj;
|
||||
if (best->otyp != AMULET_OF_GUARDING)
|
||||
goto outer_break; /* life-saving or reflection; use it */
|
||||
}
|
||||
continue; /* skip post-switch armor handling */
|
||||
case W_ARMU:
|
||||
if (!is_shirt(obj))
|
||||
continue;
|
||||
@@ -593,7 +605,7 @@ boolean racialexception;
|
||||
continue;
|
||||
best = obj;
|
||||
}
|
||||
outer_break:
|
||||
outer_break:
|
||||
if (!best || best == old)
|
||||
return;
|
||||
|
||||
@@ -972,7 +984,7 @@ boolean polyspot;
|
||||
if (mon == u.usteed)
|
||||
goto noride;
|
||||
} else if (mon == u.usteed && !can_ride(mon)) {
|
||||
noride:
|
||||
noride:
|
||||
You("can no longer ride %s.", mon_nam(mon));
|
||||
if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) {
|
||||
char buf[BUFSZ];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user