From 37b10da9b581fc59c93bf283440a34b8fad25fcf Mon Sep 17 00:00:00 2001 From: Nephi Allred Date: Wed, 7 Jun 2023 14:53:25 -0600 Subject: [PATCH] Add the Amulet of Storms artifact Note by copperwater: Intent of this is to continue expanding a few pools of artifacts: - non-weapon non-quest artifacts - chaotic artifacts - less powerful artifacts while still being useful enough to appreciate when given as a sacrifice gift. From the original patch, I adjusted the price down (it's not powerful enough to be worth 2000 base price) and refactored is_stormy_monster for clarity. I also gave it an additional side effect of blocking lightning paralysis (but not damage) on the Plane of Air; seems reasonable that it'd have this protective effect as well. --- doc/xnh-changelog-9.0.md | 4 ++++ include/artilist.h | 5 +++++ src/objnam.c | 4 +++- src/sounds.c | 41 ++++++++++++++++++++++++++++++++++++++++ src/timeout.c | 3 ++- 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/doc/xnh-changelog-9.0.md b/doc/xnh-changelog-9.0.md index 4687e3c41..ffb69a254 100644 --- a/doc/xnh-changelog-9.0.md +++ b/doc/xnh-changelog-9.0.md @@ -40,6 +40,10 @@ changes: monsters. - Monsters stepping on a squeaky board near you can wake you up. - Leprechauns have a one-sided grudge against gold golems and gold dragons. +- New artifact The Amulet of Storms: a chaotic amulet of flying that grants + shock resistance when worn and allows you to chat to hostile vortices, air + elementals, and storm giants to pacify them. It also prevents you from being + paralyzed by lightning on the Plane of Air. ### Interface changes diff --git a/include/artilist.h b/include/artilist.h index e943586f3..5fd4b5647 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -189,6 +189,11 @@ static NEARDATA struct artifact artilist[] = { NO_CARY, CONFLICT, A_CHAOTIC, NON_PM, NON_PM, 4000L, NO_COLOR, GOLD, APPLE_OF_DISCORD), + A("The Amulet of Storms", AMULET_OF_FLYING, + (SPFX_RESTR | SPFX_DEFN), 0, 0, + NO_ATTK, DFNS(AD_ELEC), NO_CARY, 0, A_CHAOTIC, NON_PM, + NON_PM, 600L, NO_COLOR, DEFAULT_MAT, AMULET_OF_STORMS), + /* * The artifacts for the quest dungeon, all self-willed. */ diff --git a/src/objnam.c b/src/objnam.c index 2d32c6f93..3b2e2a73b 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -4472,7 +4472,9 @@ readobjnam_postparse1(struct _readobjnam_data *d) && strncmpi(d->bp, "light armor", 11) && strncmpi(d->bp, "tooled horn", 11) && strncmpi(d->bp, "food ration", 11) - && strncmpi(d->bp, "meat ring", 9)) + && strncmpi(d->bp, "meat ring", 9) + && strncmpi(d->bp, "amulet of storms", 16) + ) for (i = 0; i < (int) (sizeof wrpsym); i++) { register int j = Strlen(wrp[i]); diff --git a/src/sounds.c b/src/sounds.c index 3612437c2..ed9526658 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -12,6 +12,8 @@ static boolean temple_priest_sound(struct monst *); static boolean mon_is_gecko(struct monst *); static int domonnoise(struct monst *); static int dochat(void); +static boolean is_stormy_monster(struct monst *); +static void pacify_with_words(struct monst *); static struct monst *responsive_mon_at(int, int); static int mon_in_room(struct monst *, int); @@ -1353,6 +1355,11 @@ dochat(void) return ECMD_OK; } if (u.uswallow) { + if (uamul && uamul->oartifact == ART_AMULET_OF_STORMS + && is_stormy_monster(u.ustuck)) { + pacify_with_words(u.ustuck); + return ECMD_OK; + } pline("They won't hear you out there."); return ECMD_OK; } @@ -1490,6 +1497,12 @@ dochat(void) return ECMD_OK; } + if (uamul && uamul->oartifact == ART_AMULET_OF_STORMS + && !mtmp->mpeaceful && is_stormy_monster(mtmp)) { + pacify_with_words(mtmp); + return ECMD_OK; + } + /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; @@ -1513,6 +1526,34 @@ dochat(void) return domonnoise(mtmp); } +/* is mtmp a storm-like monster pacifiable by the Amulet of Storms? */ +static boolean +is_stormy_monster(struct monst *mtmp) +{ + /* already peaceful */ + if (mtmp->mpeaceful) + return FALSE; + + /* not a "true" stormy monster (but shapeshifters currently turned into one + * are okay) */ + if (mtmp->iswiz || is_vampshifter(mtmp)) + return FALSE; + + return (mtmp->data->mlet == S_VORTEX + || mtmp->data == &mons[PM_AIR_ELEMENTAL] + || mtmp->data == &mons[PM_STORM_GIANT]); +} + +static void +pacify_with_words(struct monst *mtmp) +{ + pline("%s recognizes your amulet.", Monnam(mtmp)); + You("manage to calm %s.", + genders[pronoun_gender(mtmp, PRONOUN_HALLU)].him); + mtmp->mpeaceful = 1; + newsym(mtmp->mx, mtmp->my); +} + /* is there a monster at that can see the hero and react? */ static struct monst * responsive_mon_at(int x, int y) diff --git a/src/timeout.c b/src/timeout.c index d0eb0e5c2..db19165df 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1829,7 +1829,8 @@ do_storms(void) pline("Kaboom!!! Boom!! Boom!!"); incr_itimeout(&HDeaf, rn1(20, 30)); gc.context.botl = TRUE; - if (!u.uinvulnerable) { + if (!u.uinvulnerable + || !(uamul && uamul->oartifact == ART_AMULET_OF_STORMS)) { stop_occupation(); nomul(-3); gm.multi_reason = "hiding from thunderstorm";