Skip to content

Instantly share code, notes, and snippets.

@Chris-plus-alphanumericgibberish
Created December 15, 2023 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Chris-plus-alphanumericgibberish/95f295934d5650e277ec85c345a9a166 to your computer and use it in GitHub Desktop.
Save Chris-plus-alphanumericgibberish/95f295934d5650e277ec85c345a9a166 to your computer and use it in GitHub Desktop.
Spellcasting patch that was incorporated into dnh
This is a copy of L's Monster Spellcasting patch, retreved from the WayBack Machine
TODO:
Tiamat gets Deluge
*** DESCRIPTIONS OF THE SPELLS ***
Open Wounds - unchanged.
Psi Bolt - unchanged.
Magic Missile - same as the player's magic missile spell.
Drain Life - same as the player's drain life spell. Drains one level and abuses CON unless you have drain resistance.
Arrow Rain - you are hit with a large quantity (increasing with the caster's level) of (in decreasing likelihood) arrows, daggers, spears, knives, javelins, axes, or random projectiles.
Cone of Cold - same as the player's basic cone of cold spell.
Lightning - if the caster is a cleric, it is unchanged. Otherwise, same effect as a wand of lightning.
Fire Pillar - unchanged.
Geyser - unchanged.
Acid Rain - does 8d6 acid damage to you, and corrodes your wielded weapons and armor.
Summon Nasties - unchanged.
Touch of Death - it is REMOVED, because it is dumb.
Aggravation - it is REMOVED, because it is useless.
Cure Self - unchanged, except that if a ruler monster casts, he heals all HP.
Make Visible - removes your intrinsic invisibility. Won't be cast by monsters that see invisible.
Haste Self - unchanged.
Stun You - unchanged.
Confuse You - unchanged.
Paralyze - unchanged.
Blind You - unchanged.
Sleep - same as player's sleep spell.
Drain Energy - drains player's mana unless you have magic resistance.
Weaken You - if you are wearing a ring of sustain ability, no effect. If the caster is a ruler monster, all of your stats are lowered by a significant amount. Otherwise, one of your stats is lowered by a significant amount based on the caster's level.
If the stat reduction fails, you lose up to 20 maximum hit points instead.
The amount of stat reduction is lessened if you have half spell damage.
Destroy Armor - unchanged.
Destroy Weapon - if you don't have magic resistance and you are wielding a non-artifact weapon, it is disintegrated, or polymorphed into a banana. Otherwise, there is a chance (inversely proportional to your strength) that you will drop your weapon. Currently has no effect on alternate (i.e secondary dual-wielded) weapons.
Curse Items - unchanged.
Summon Insects - unchanged, except that sticks to snakes has a chance of being cast even if insects still exist.
Raise Dead - same as reading the cursed Book of the Dead.
Summon Angel - only cast by clerics. An Angel of the alignment of the caster is summoned.
Punish - same as uncursed scroll of punishment.
Plague - makes you deathly sick unless you have sickness resistance.
Disappear - unchanged.
Darkness - same as cursed scroll of light.
Summon Sphere - if the caster's level is greater than 5, summons d10 spheres. Otherwise, summons a sphere.
Make Web - creates a web on your space and ensnares you in it.
Drop Boulder - a boulder (if in the dungeon) or a heavy iron ball drops on you, doing damage based on their weight.
Earthquake - same as a drum of earthquake, but the strength (number of pits opened) increases with the caster's level, and a pit will always be created on your space. Also, the following monsters have a chance of being 'unearthed' by the earthquake: zombies, xorns, earth elementals, rock moles, umber hulks and demons.
Turn to Stone - begins the petrification process.
Nightmare - you become confused, stunned and hallucinating for a long time.
Filth - does d10 damage, creams your face, greases your hands, and makes you vomit.
Strangle - if you have magic resistance and are wearing an amulet, or you are wearing an artifact amulet, no effect. Otherwise, a cursed amulet of strangulation appears around your neck (or your current amulet is polymorphed into a cursed amulet of strangulation.)
*** NORMAL SPELL SELECTION ***
As usual, spell selection methods are divided into wizard and cleric categories.
When the spellcasting monster selects a wizard spell, a random number from 0 to their level is divided by 20 and the remainder is used to choose a result thus:
0, 5, 10, 15 - Damage
1 - Cure Self
2 - Confuse You
3 - Stun You
4 - Haste Self
6 - Drain Energy
7 - Magic Missile
8 - Disappear
9 - Weaken You
11 - Drop Boulder
12 - Cone of Cold
13 - Arrow Rain
14 - Make Visible
16 - Lightning
17 - Acid Rain
18 - Summon Nasties
19 - Turn To Stone
When the spellcasting monster selects a cleric spell, a random number from 0 to their level is divided by 18 and the remainder is used to choose a result thus:
0, 5, 10, 15 - Damage
1 - Cure Self
2 - Confuse You
3 - Paralyze
4 - Blind You
6 - Summon Insects
7 - Curse Items
8 - Drain Life
9 - Lightning
11 - Fire Pillar
12 - Geyser
13 - Acid Rain
14 - Plague
16 - Summon Angel
17 - Punish
*** SPECIAL SPELL SELECTION ***
Certain "special" monsters have a 50% chance of casting a signature spell instead of choosing a spell from the list.
The special spells for each monster are:
Wizard of Yendor -
75% ????
8.3% Strangle
8.3% Clone Wizard
8.3% Haste Self
Nalzok -
see Orcus
Orcus -
50% Raise Dead
50% see Dispater
Dispater -
25% Turn to Stone
25% Curse Items
50% see Demogorgon
Demogorgon -
33.3% Haste Self
33.3% Filth
33.3% Weaken You
Apprentice -
66.7% Summon Sphere
33.3% see Neferet the Green
Neferet the Green -
Arrow Rain
Dark One -
25% Turn To Stone
25% Raise Dead
25% Darkness
25% Make Web
Thoth Amon -
33.3% Nightmare
66.7% see Chromatic Dragon
Chromatic Dragon -
50% Destroy Weapon
50% Earthquake
Ixoth -
Nightmare
Grand Master -
see Master Kaen
Master Kaen -
50% Weaken You
50% Earthquake
Minion of Huhetotl -
50% Curse Items
25% Destroy Weapon
25% Drop Boulder
Titan -
see Archon
Archon -
50% Earthquake
50% Lightning
Ki-rin -
Fire Pillar
Arch Lich -
16.7% Turn to Stone
83.3% see Master Lich
Master Lich -
20% Raise Dead
80% see Demilich
Demilich -
25% Drain Life
75% see Lich
Lich -
33.3% Curse Items
66.7% see Nalfeshnee
Nalfeshnee -
25% Destroy Armor
25% Destroy Weapon
50% see Barrow-Wight
Barrow-Wight -
33.3% Darkness
33.3% Make Web
33.3% Sleep
Gnomish Wizard -
50% Summon Sphere
diff -Nurb nethack-3.4.3-original/src/do_wear.c nethack-3.4.3/src/do_wear.c
--- nethack-3.4.3-original/src/do_wear.c Mon Dec 8 09:39:13 2003
+++ nethack-3.4.3/src/do_wear.c Tue Jan 10 12:14:07 2006
@@ -51,7 +51,6 @@
#ifdef TOURIST
STATIC_PTR int NDECL(Shirt_on);
#endif
-STATIC_DCL void NDECL(Amulet_on);
STATIC_DCL void FDECL(Ring_off_or_gone, (struct obj *, BOOLEAN_P));
STATIC_PTR int FDECL(select_off, (struct obj *));
STATIC_DCL struct obj *NDECL(do_takeoff);
@@ -574,7 +573,6 @@
return 0;
}
-STATIC_OVL void
Amulet_on()
{
switch(uamul->otyp) {
diff -Nurb nethack-3.4.3-original/src/mcastu.c nethack-3.4.3/src/mcastu.c
--- nethack-3.4.3-original/src/mcastu.c Mon Dec 8 09:39:13 2003
+++ nethack-3.4.3/src/mcastu.c Tue Jan 10 14:07:26 2006
@@ -4,39 +4,62 @@
#include "hack.h"
-/* monster mage spells */
-#define MGC_PSI_BOLT 0
-#define MGC_CURE_SELF 1
-#define MGC_HASTE_SELF 2
-#define MGC_STUN_YOU 3
-#define MGC_DISAPPEAR 4
-#define MGC_WEAKEN_YOU 5
-#define MGC_DESTRY_ARMR 6
-#define MGC_CURSE_ITEMS 7
-#define MGC_AGGRAVATION 8
-#define MGC_SUMMON_MONS 9
-#define MGC_CLONE_WIZ 10
-#define MGC_DEATH_TOUCH 11
-
-/* monster cleric spells */
-#define CLC_OPEN_WOUNDS 0
-#define CLC_CURE_SELF 1
-#define CLC_CONFUSE_YOU 2
-#define CLC_PARALYZE 3
-#define CLC_BLIND_YOU 4
-#define CLC_INSECTS 5
-#define CLC_CURSE_ITEMS 6
-#define CLC_LIGHTNING 7
-#define CLC_FIRE_PILLAR 8
-#define CLC_GEYSER 9
+/* tactics() may call for a specific spell */
+/* 0 = no spell */
+ /* attack spells */
+#define DAMAGE 1
+#define MAGIC_MISSILE 2 /* magic missile */
+#define DRAIN_LIFE 3 /* drain life */
+#define ARROW_RAIN 4
+#define CONE_OF_COLD 5 /* cone of cold */
+#define LIGHTNING 6
+#define FIRE_PILLAR 7
+#define GEYSER 8
+#define ACID_RAIN 9
+#define SUMMON_MONS 10
+ /* healing spells */
+#define CURE_SELF 11 /* healing */
+ /* divination spells */
+#define MAKE_VISIBLE 12
+ /* (dis)enchantment spells */
+#define HASTE_SELF 13 /* haste self */
+#define STUN_YOU 14
+#define CONFUSE_YOU 15
+#define PARALYZE 16
+#define BLIND_YOU 17
+#define SLEEP 18 /* sleep */
+#define DRAIN_ENERGY 19
+#define WEAKEN_YOU 20
+#define DESTRY_ARMR 21
+#define DESTRY_WEPN 22
+ /* clerical spells */
+#define CURSE_ITEMS 23
+#define INSECTS 24
+#define RAISE_DEAD 25
+#define SUMMON_ANGEL 26
+#define PLAGUE 27
+#define PUNISH 28
+ /* escape spells */
+#define DISAPPEAR 29 /* invisibility */
+ /* matter spells */
+#define DARKNESS 30
+#define SUMMON_SPHERE 31 /* flame sphere */
+#define MAKE_WEB 32
+#define DROP_BOULDER 33
+#define EARTHQUAKE 34
+#define TURN_TO_STONE 35
+ /* unique monster spells */
+#define NIGHTMARE 36
+#define FILTH 37
+#define CLONE_WIZ 38
+#define STRANGLE 39
STATIC_DCL void FDECL(cursetxt,(struct monst *,BOOLEAN_P));
STATIC_DCL int FDECL(choose_magic_spell, (int));
STATIC_DCL int FDECL(choose_clerical_spell, (int));
-STATIC_DCL void FDECL(cast_wizard_spell,(struct monst *, int,int));
-STATIC_DCL void FDECL(cast_cleric_spell,(struct monst *, int,int));
+STATIC_DCL void FDECL(cast_spell,(struct monst *, int,int));
STATIC_DCL boolean FDECL(is_undirected_spell,(unsigned int,int));
-STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,unsigned int,int));
+STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,int));
#ifdef OVL0
@@ -74,86 +97,172 @@
#endif /* OVL0 */
#ifdef OVLB
-/* convert a level based random selection into a specific mage spell;
- inappropriate choices will be screened out by spell_would_be_useless() */
+/* default spell selection for mages */
STATIC_OVL int
choose_magic_spell(spellval)
int spellval;
{
- switch (spellval) {
- case 22:
- case 21:
- case 20:
- return MGC_DEATH_TOUCH;
+ switch (spellval %20) {
case 19:
+ return TURN_TO_STONE;
case 18:
- return MGC_CLONE_WIZ;
+ return SUMMON_MONS;
case 17:
+ return ACID_RAIN;
case 16:
- case 15:
- return MGC_SUMMON_MONS;
+ return LIGHTNING;
case 14:
+ return MAKE_VISIBLE;
case 13:
- return MGC_AGGRAVATION;
+ return ARROW_RAIN;
case 12:
+ return CONE_OF_COLD;
case 11:
- case 10:
- return MGC_CURSE_ITEMS;
+ return DROP_BOULDER;
case 9:
+ return WEAKEN_YOU;
case 8:
- return MGC_DESTRY_ARMR;
+ return DISAPPEAR;
case 7:
+ return MAGIC_MISSILE;
case 6:
- return MGC_WEAKEN_YOU;
- case 5:
+ return DRAIN_ENERGY;
case 4:
- return MGC_DISAPPEAR;
+ return HASTE_SELF;
case 3:
- return MGC_STUN_YOU;
+ return STUN_YOU;
case 2:
- return MGC_HASTE_SELF;
+ return CONFUSE_YOU;
case 1:
- return MGC_CURE_SELF;
- case 0:
- default:
- return MGC_PSI_BOLT;
+ return CURE_SELF;
+ default: /* case 0, case 5, case 10, case 15 */
+ return DAMAGE;
}
}
-/* convert a level based random selection into a specific cleric spell */
+/* default spell selection for priests/monks */
STATIC_OVL int
choose_clerical_spell(spellnum)
int spellnum;
{
- switch (spellnum) {
+ switch (spellnum %18) {
+ case 17:
+ return PUNISH;
+ case 16:
+ return SUMMON_ANGEL;
+ case 14:
+ return PLAGUE;
case 13:
- return CLC_GEYSER;
+ return ACID_RAIN;
case 12:
- return CLC_FIRE_PILLAR;
+ return GEYSER;
case 11:
- return CLC_LIGHTNING;
- case 10:
+ return FIRE_PILLAR;
case 9:
- return CLC_CURSE_ITEMS;
+ return LIGHTNING;
case 8:
- return CLC_INSECTS;
+ return DRAIN_LIFE;
case 7:
+ return CURSE_ITEMS;
case 6:
- return CLC_BLIND_YOU;
- case 5:
+ return INSECTS;
case 4:
- return CLC_PARALYZE;
+ return BLIND_YOU;
case 3:
+ return PARALYZE;
case 2:
- return CLC_CONFUSE_YOU;
+ return CONFUSE_YOU;
case 1:
- return CLC_CURE_SELF;
- case 0:
- default:
- return CLC_OPEN_WOUNDS;
+ return CURE_SELF;
+ default: /* case 0, case 5, case 10, case 15 */
+ return DAMAGE;
}
}
+/* ...but first, check for monster-specific spells */
+STATIC_OVL int
+choose_magic_special(mtmp, type)
+struct monst *mtmp;
+unsigned int type;
+{
+ if (rn2(2) || mtmp->iswiz) {
+ switch(monsndx(mtmp->data)) {
+ case PM_WIZARD_OF_YENDOR:
+ return (rn2(4) ? rnd(STRANGLE) :
+ (!rn2(3) ? STRANGLE : !rn2(2) ? CLONE_WIZ : HASTE_SELF));
+
+ case PM_ORCUS:
+ case PM_NALZOK:
+ if (rn2(2)) return RAISE_DEAD;
+ /* fallthrough */
+ case PM_DISPATER:
+ if (rn2(2)) return (rn2(2) ? TURN_TO_STONE : CURSE_ITEMS);
+ /* fallthrough */
+ case PM_DEMOGORGON:
+ return (!rn2(3) ? HASTE_SELF : rn2(2) ? FILTH : WEAKEN_YOU);
+
+ case PM_APPRENTICE:
+ if (rn2(3)) return SUMMON_SPHERE;
+ /* fallthrough */
+ case PM_NEFERET_THE_GREEN:
+ return ARROW_RAIN;
+
+ case PM_DARK_ONE:
+ return (!rn2(4) ? TURN_TO_STONE : !rn2(3) ? RAISE_DEAD :
+ rn2(2) ? DARKNESS : MAKE_WEB);
+
+ case PM_THOTH_AMON:
+ if (!rn2(3)) return NIGHTMARE;
+ /* fallthrough */
+ case PM_CHROMATIC_DRAGON:
+ return (rn2(2) ? DESTRY_WEPN : EARTHQUAKE);
+
+ case PM_IXOTH:
+ return NIGHTMARE;
+
+ case PM_GRAND_MASTER:
+ case PM_MASTER_KAEN:
+ return (rn2(2) ? WEAKEN_YOU : EARTHQUAKE);
+
+ case PM_MINION_OF_HUHETOTL:
+ return (rn2(2) ? CURSE_ITEMS : (rn2(2) ? DESTRY_WEPN : DROP_BOULDER));
+
+ case PM_TITAN:
+ case PM_ARCHON:
+ return (rn2(2) ? EARTHQUAKE : LIGHTNING);
+ case PM_KI_RIN:
+ return FIRE_PILLAR;
+
+ case PM_ARCH_LICH:
+ if (!rn2(6)) return TURN_TO_STONE;
+ /* fallthrough */
+#if 0
+ case PM_VAMPIRE_MAGE:
+#endif
+ case PM_MASTER_LICH:
+ if (!rn2(5)) return RAISE_DEAD;
+ /* fallthrough */
+ case PM_DEMILICH:
+ if (!rn2(4)) return DRAIN_LIFE;
+ /* fallthrough */
+ case PM_LICH:
+ if (!rn2(3)) return CURSE_ITEMS;
+ /* fallthrough */
+ case PM_NALFESHNEE:
+ if (rn2(2)) return (rn2(2) ? DESTRY_ARMR : DESTRY_WEPN);
+ /* fallthrough */
+ case PM_BARROW_WIGHT:
+ return (!rn2(3) ? DARKNESS : (rn2(2) ? MAKE_WEB : SLEEP));
+
+ case PM_GNOMISH_WIZARD:
+ if (rn2(2)) return SUMMON_SPHERE;
+ }
+ }
+ if (type == AD_CLRC)
+ return choose_clerical_spell(rn2(mtmp->m_lev));
+ return choose_magic_spell(rn2(mtmp->m_lev));
+}
+
/* return values:
* 1: successful spell
* 0: unsuccessful spell
@@ -184,16 +293,12 @@
if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) {
int cnt = 40;
- do {
- spellnum = rn2(ml);
- if (mattk->adtyp == AD_SPEL)
- spellnum = choose_magic_spell(spellnum);
- else
- spellnum = choose_clerical_spell(spellnum);
+ if (!spellnum) do {
+ spellnum = choose_magic_special(mtmp, mattk->adtyp);
/* not trying to attack? don't allow directed spells */
if (!thinks_it_foundyou) {
if (!is_undirected_spell(mattk->adtyp, spellnum) ||
- spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) {
+ spell_would_be_useless(mtmp, spellnum)) {
if (foundyou)
impossible("spellcasting monster found you and doesn't know it?");
return 0;
@@ -201,7 +306,7 @@
break;
}
} while(--cnt > 0 &&
- spell_would_be_useless(mtmp, mattk->adtyp, spellnum));
+ spell_would_be_useless(mtmp, spellnum));
if (cnt == 0) return 0;
}
@@ -212,8 +317,8 @@
}
if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) {
- mtmp->mspec_used = 10 - mtmp->m_lev;
- if (mtmp->mspec_used < 2) mtmp->mspec_used = 2;
+ /* reduced to 2 to make kobold/orc shamans more fearsome */
+ mtmp->mspec_used = 2;
}
/* monster can cast spells, but is casting a directed spell at the
@@ -229,7 +334,8 @@
}
nomul(0);
- if(rn2(ml*10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */
+ /* increased to rn2(ml*20) to make kobold/orc shamans less helpless */
+ if(rn2(ml*20) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */
if (canseemon(mtmp) && flags.soundok)
pline_The("air crackles around %s.", mon_nam(mtmp));
return(0);
@@ -292,13 +398,9 @@
dmg = 0;
} else dmg = d((int)mtmp->m_lev/2 + 1,6);
break;
- case AD_SPEL: /* wizard spell */
- case AD_CLRC: /* clerical spell */
+ default:
{
- if (mattk->adtyp == AD_SPEL)
- cast_wizard_spell(mtmp, dmg, spellnum);
- else
- cast_cleric_spell(mtmp, dmg, spellnum);
+ cast_spell(mtmp, dmg, spellnum);
dmg = 0; /* done by the spell casting functions */
break;
}
@@ -318,36 +420,21 @@
*/
STATIC_OVL
void
-cast_wizard_spell(mtmp, dmg, spellnum)
+cast_spell(mtmp, dmg, spellnum)
struct monst *mtmp;
int dmg;
int spellnum;
{
+ boolean malediction = (mtmp->iswiz || (mtmp->data->msound == MS_NEMESIS && rn2(2)));
+ int zap; /* used for ray spells */
+
if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) {
impossible("cast directed wizard spell (%d) with dmg=0?", spellnum);
return;
}
switch (spellnum) {
- case MGC_DEATH_TOUCH:
- pline("Oh no, %s's using the touch of death!", mhe(mtmp));
- if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
- You("seem no deader than before.");
- } else if (!Antimagic && rn2(mtmp->m_lev) > 12) {
- if (Hallucination) {
- You("have an out of body experience.");
- } else {
- killer_format = KILLED_BY_AN;
- killer = "touch of death";
- done(DIED);
- }
- } else {
- if (Antimagic) shieldeff(u.ux, u.uy);
- pline("Lucky for you, it didn't work!");
- }
- dmg = 0;
- break;
- case MGC_CLONE_WIZ:
+ case CLONE_WIZ:
if (mtmp->iswiz && flags.no_of_wizards == 1) {
pline("Double Trouble...");
clonewiz();
@@ -355,146 +442,136 @@
} else
impossible("bad wizard cloning?");
break;
- case MGC_SUMMON_MONS:
+ case FILTH:
{
- int count;
-
- count = nasty(mtmp); /* summon something nasty */
- if (mtmp->iswiz)
- verbalize("Destroy the thief, my pet%s!", plur(count));
- else {
- const char *mappear =
- (count == 1) ? "A monster appears" : "Monsters appear";
-
- /* messages not quite right if plural monsters created but
- only a single monster is seen */
- if (Invisible && !perceives(mtmp->data) &&
- (mtmp->mux != u.ux || mtmp->muy != u.uy))
- pline("%s around a spot near you!", mappear);
- else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
- pline("%s around your displaced image!", mappear);
- else
- pline("%s from nowhere!", mappear);
+ struct monst *mtmp2;
+ long old;
+ pline("A cascade of filth pours onto you!");
+ if (freehand() && rn2(3)) {
+ old = Glib;
+ Glib += rn1(20, 9);
+ Your("%s %s!", makeplural(body_part(HAND)),
+ (old ? "are filthier than ever" : "get slimy"));
+ }
+ if(haseyes(youmonst.data) && !Blindfolded && rn2(3)) {
+ old = u.ucreamed;
+ u.ucreamed += rn1(20, 9);
+ Your("%s is coated in %sgunk!", body_part(FACE),
+ (old ? "even more " : ""));
+ make_blinded(Blinded + (long)u.ucreamed - old, FALSE);
+ }
+ You("smell putrid! You gag and vomit.");
+ /* same effect as "This water gives you bad breath!" */
+ for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) {
+ if(!DEADMONSTER(mtmp2) && (mtmp2 != mtmp))
+ monflee(mtmp2, 0, FALSE, FALSE);
}
- dmg = 0;
- break;
- }
- case MGC_AGGRAVATION:
- You_feel("that monsters are aware of your presence.");
- aggravate();
- dmg = 0;
- break;
- case MGC_CURSE_ITEMS:
- You_feel("as if you need some help.");
- rndcurse();
- dmg = 0;
+ vomit();
+ dmg = rnd(Half_physical_damage ? 5 : 10);
break;
- case MGC_DESTRY_ARMR:
- if (Antimagic) {
- shieldeff(u.ux, u.uy);
- pline("A field of force surrounds you!");
- } else if (!destroy_arm(some_armor(&youmonst))) {
- Your("skin itches.");
}
- dmg = 0;
- break;
- case MGC_WEAKEN_YOU: /* drain strength */
- if (Antimagic) {
+ case STRANGLE:
+ {
+ struct obj *otmp;
+ if (uamul && (Antimagic || uamul->oartifact || uamul->otyp == AMULET_OF_YENDOR)) {
shieldeff(u.ux, u.uy);
- You_feel("momentarily weakened.");
+ if (!Blind) Your("%s looks vaguely %s for a moment.", xname(uamul),
+ OBJ_DESCR(objects[AMULET_OF_STRANGULATION]));
+ else You_feel("a momentary pressure around your %s.",body_part(NECK));
} else {
- You("suddenly feel weaker!");
- dmg = mtmp->m_lev - 6;
- if (Half_spell_damage) dmg = (dmg + 1) / 2;
- losestr(rnd(dmg));
- if (u.uhp < 1)
- done_in_by(mtmp);
+ if (uamul) {
+ Your("%s warps strangely, then turns %s.", xname(uamul),
+ OBJ_DESCR(objects[AMULET_OF_STRANGULATION]));
+ poly_obj(uamul, AMULET_OF_STRANGULATION);
+ curse(uamul);
+ Amulet_on();
+ }
+ else {
+ if (malediction)
+ verbalize(rn2(2) ? "Thou desirest the amulet? I'll give thee the amulet!" :
+ "Here is the only amulet you'll need!");
+ otmp = mksobj(AMULET_OF_STRANGULATION, FALSE, FALSE);
+ curse(otmp);
+ (void) addinv(otmp);
+ pline("%s appears around your %s!",An(xname(otmp)),body_part(NECK));
+ setworn(otmp,W_AMUL);
+ Amulet_on();
+ }
}
dmg = 0;
break;
- case MGC_DISAPPEAR: /* makes self invisible */
- if (!mtmp->minvis && !mtmp->invis_blkd) {
- if (canseemon(mtmp))
- pline("%s suddenly %s!", Monnam(mtmp),
- !See_invisible ? "disappears" : "becomes transparent");
- mon_set_minvis(mtmp);
- dmg = 0;
- } else
- impossible("no reason for monster to cast disappear spell?");
- break;
- case MGC_STUN_YOU:
- if (Antimagic || Free_action) {
- shieldeff(u.ux, u.uy);
- if (!Stunned)
- You_feel("momentarily disoriented.");
- make_stunned(1L, FALSE);
+ }
+ case TURN_TO_STONE:
+ if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
+ if (malediction) /* give a warning to the player */
+ verbalize(rn2(2) ? "I shall make a statue of thee!" :
+ "I condemn thee to eternity unmoving!");
+ You_feel("less limber.");
+ Stoned = 5;
+ } dmg = 0;
+ break;
+ case MAKE_VISIBLE:
+ HInvis &= ~INTRINSIC;
+ You_feel("paranoid.");
+ dmg = 0;
+ break;
+ case PLAGUE:
+ if (!Sick_resistance) {
+ You("are afflicted with disease!");
+ make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20),
+ (char *)0, TRUE, SICK_NONVOMITABLE);
+ } else You_feel("slightly infectious.");
+ dmg = 0;
+ break;
+ case PUNISH:
+ if (!Punished) {
+ punish((struct obj *)0);
+ if (is_prince(mtmp->data)) uball->owt += 160;
} else {
- You(Stunned ? "struggle to keep your balance." : "reel...");
- dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
- if (Half_spell_damage) dmg = (dmg + 1) / 2;
- make_stunned(HStun + dmg, FALSE);
+ Your("iron ball gets heavier!");
+ uball->owt += 160;
}
dmg = 0;
break;
- case MGC_HASTE_SELF:
- mon_adjust_speed(mtmp, 1, (struct obj *)0);
- dmg = 0;
- break;
- case MGC_CURE_SELF:
- if (mtmp->mhp < mtmp->mhpmax) {
- if (canseemon(mtmp))
- pline("%s looks better.", Monnam(mtmp));
- /* note: player healing does 6d4; this used to do 1d8 */
- if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax)
- mtmp->mhp = mtmp->mhpmax;
- dmg = 0;
+ case EARTHQUAKE:
+ pline_The("entire %s is shaking around you!",
+ In_endgame(&u.uz) ? "plane" : "dungeon");
+ /* Quest nemesis maledictions */
+ if (malediction && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
+ if (rn2(2)) verbalize("The earth trembles before my %s!",
+ rn2(2) ? "power" : "might");
+ else verbalize("Open thy maw, mighty earth!");
}
+ do_earthquake(((int)mtmp->m_lev - 1) / 6, TRUE, mtmp);
+ aggravate(); /* wake up without scaring */
+ dmg = 0;
break;
- case MGC_PSI_BOLT:
- /* prior to 3.4.0 Antimagic was setting the damage to 1--this
- made the spell virtually harmless to players with magic res. */
- if (Antimagic) {
+ case ACID_RAIN: /* as seen in the Lethe patch */
+ pline("A torrent of burning acid rains down on you!");
+ dmg = d(8, 6);
+ if (Acid_resistance) {
shieldeff(u.ux, u.uy);
- dmg = (dmg + 1) / 2;
- }
- if (dmg <= 5)
- You("get a slight %sache.", body_part(HEAD));
- else if (dmg <= 10)
- Your("brain is on fire!");
- else if (dmg <= 20)
- Your("%s suddenly aches painfully!", body_part(HEAD));
- else
- Your("%s suddenly aches very painfully!", body_part(HEAD));
- break;
- default:
- impossible("mcastu: invalid magic spell (%d)", spellnum);
+ pline("It feels mildly uncomfortable.");
dmg = 0;
- break;
}
-
- if (dmg) mdamageu(mtmp, dmg);
-}
-
-STATIC_OVL
-void
-cast_cleric_spell(mtmp, dmg, spellnum)
-struct monst *mtmp;
-int dmg;
-int spellnum;
-{
- if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) {
- impossible("cast directed cleric spell (%d) with dmg=0?", spellnum);
- return;
+ erode_obj(uwep, TRUE, FALSE);
+ erode_obj(uswapwep, TRUE, FALSE);
+ erode_armor(&youmonst, TRUE);
+ if (!resists_blnd(&youmonst) && rn2(2)) {
+ pline_The("acid gets into your %s!", eyecount(youmonst.data) == 1 ?
+ body_part(EYE) : makeplural(body_part(EYE)));
+ make_blinded((long)rnd(Acid_resistance ? 10 : 50),FALSE);
+ if (!Blind) Your(vision_clears);
}
-
- switch (spellnum) {
- case CLC_GEYSER:
+ /* TODO: corrode floor objects */
+ break;
+ case GEYSER:
/* this is physical damage, not magical damage */
pline("A sudden geyser slams into you from nowhere!");
dmg = d(8, 6);
if (Half_physical_damage) dmg = (dmg + 1) / 2;
break;
- case CLC_FIRE_PILLAR:
+ case FIRE_PILLAR:
pline("A pillar of fire strikes all around you!");
if (Fire_resistance) {
shieldeff(u.ux, u.uy);
@@ -509,8 +586,11 @@
destroy_item(SPBOOK_CLASS, AD_FIRE);
(void) burn_floor_paper(u.ux, u.uy, TRUE, FALSE);
break;
- case CLC_LIGHTNING:
- {
+ case LIGHTNING:
+ if (!dmgtype(mtmp->data, AD_CLRC)) {
+ zap = AD_ELEC;
+ goto ray;
+ } else {
boolean reflects;
pline("A bolt of lightning strikes down at you from above!");
@@ -525,20 +605,60 @@
if (Half_spell_damage) dmg = (dmg + 1) / 2;
destroy_item(WAND_CLASS, AD_ELEC);
destroy_item(RING_CLASS, AD_ELEC);
+ if (!resists_blnd(&youmonst)) {
+ You("are blinded by the flash!");
+ make_blinded((long)rnd(100),FALSE);
+ if (!Blind) Your(vision_clears);
+ }
break;
}
- case CLC_CURSE_ITEMS:
- You_feel("as if you need some help.");
- rndcurse();
+ case SUMMON_ANGEL: /* cleric only */
+ {
+ struct monst *mtmp2 = mk_roamer(&mons[PM_ANGEL],
+ mtmp->data->maligntyp, mtmp->mux, mtmp->muy, FALSE);
+ if (mtmp2) {
+ if (canspotmon(mtmp2))
+ pline("%s %s!",
+ An(Hallucination ? rndmonnam() : "angel"),
+ Is_astralevel(&u.uz) ? "appears near you" :
+ "descends from above");
+ else
+ You("sense the arrival of %s.",
+ an(Hallucination ? rndmonnam() : "hostile angel"));
+ }
+ dmg = 0;
+ break;
+ }
+ case SUMMON_MONS:
+ {
+ int count;
+
+ count = nasty(mtmp); /* summon something nasty */
+ if (mtmp->iswiz)
+ verbalize("Destroy the thief, my pet%s!", plur(count));
+ else {
+ const char *mappear =
+ (count == 1) ? "A monster appears" : "Monsters appear";
+
+ /* messages not quite right if plural monsters created but
+ only a single monster is seen */
+ if (Invisible && !perceives(mtmp->data) &&
+ (mtmp->mux != u.ux || mtmp->muy != u.uy))
+ pline("%s around a spot near you!", mappear);
+ else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
+ pline("%s around your displaced image!", mappear);
+ else
+ pline("%s from nowhere!", mappear);
+ }
dmg = 0;
break;
- case CLC_INSECTS:
+ }
+ case INSECTS:
{
- /* Try for insects, and if there are none
- left, go for (sticks to) snakes. -3. */
struct permonst *pm = mkclass(S_ANT,0);
struct monst *mtmp2 = (struct monst *)0;
- char let = (pm ? S_ANT : S_SNAKE);
+ char let = ((pm && mkclass(S_SNAKE,0)) ?
+ (rn2(2) ? S_ANT : S_SNAKE) : (pm ? S_ANT : S_SNAKE));
boolean success;
int i;
coord bypos;
@@ -546,7 +666,7 @@
quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2);
if (quan < 3) quan = 3;
- success = pm ? TRUE : FALSE;
+ success = mkclass(let,0) ? TRUE : FALSE;
for (i = 0; i <= quan; i++) {
if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
break;
@@ -554,6 +674,11 @@
(mtmp2 = makemon(pm, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
success = TRUE;
mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
+ /* arbitrarily strengthen enemies in astral and sanctum */
+ if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) {
+ mtmp2->m_lev += rn1(3,3);
+ mtmp2->mhp = (mtmp2->mhpmax += rn1((int)mtmp->m_lev,20));
+ }
set_malign(mtmp2);
}
}
@@ -568,34 +693,268 @@
pline("%s casts at a clump of sticks, but nothing happens.",
Monnam(mtmp));
else if (let == S_SNAKE)
- pline("%s transforms a clump of sticks into snakes!",
- Monnam(mtmp));
+ pline("%s transforms a clump of sticks into %s!",
+ Monnam(mtmp), Hallucination ? makeplural(rndmonnam()) : "snakes");
else if (Invisible && !perceives(mtmp->data) &&
(mtmp->mux != u.ux || mtmp->muy != u.uy))
- pline("%s summons insects around a spot near you!",
- Monnam(mtmp));
+ pline("%s summons %s around a spot near you!",
+ Monnam(mtmp), Hallucination ? makeplural(rndmonnam()) : "insects");
else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
- pline("%s summons insects around your displaced image!",
- Monnam(mtmp));
+ pline("%s summons %s around your displaced image!",
+ Monnam(mtmp), Hallucination ? makeplural(rndmonnam()) : "insects");
else
pline("%s summons insects!", Monnam(mtmp));
dmg = 0;
break;
}
- case CLC_BLIND_YOU:
+ case RAISE_DEAD:
+ {
+ coord mm;
+ register int x, y;
+ pline("%s raised the dead!", Monnam(mtmp));
+ mm.x = mtmp->mx;
+ mm.y = mtmp->my;
+ mkundead(&mm, TRUE, NO_MINVENT);
+ dmg = 0;
+ break;
+ }
+ case CONE_OF_COLD: /* simulates basic cone of cold */
+ zap = AD_COLD;
+ goto ray;
+ case CURSE_ITEMS:
+ You_feel("as if you need some help.");
+ rndcurse();
+ dmg = 0;
+ break;
+ case ARROW_RAIN: /* actually other things as well */
+ {
+ struct obj *otmp;
+ int weap, i;
+ if (!rn2(3)) weap = ARROW;
+ else if (!rn2(3)) weap = DAGGER;
+ else if (!rn2(3)) weap = SPEAR;
+ else if (!rn2(3)) weap = KNIFE;
+ else if (!rn2(3)) weap = JAVELIN;
+ else if (!rn2(3)) weap = AXE;
+ else {
+ weap = rnd_class(ARROW,WORM_TOOTH-1);
+ if (weap == TRIDENT) weap = JAVELIN;
+ }
+ otmp = mksobj(weap, TRUE, FALSE);
+ otmp->quan = (long) rn1(7,mtmp->m_lev/2);
+ otmp->owt = weight(otmp);
+ You("are hit from all directions by a %s of %s!",
+ rn2(2) ? "shower" : "hail", xname(otmp));
+ dmg = 0;
+ for (i = 0; i < otmp->quan; i++) {
+ dmg += dmgval(otmp, &youmonst);
+ }
+ if (!flooreffects(otmp, u.ux, u.uy, "fall")) {
+ place_object(otmp, u.ux, u.uy);
+ stackobj(otmp);
+ newsym(u.ux, u.uy);
+ }
+ if (Half_physical_damage) dmg = (dmg + 1) / 2;
+ } break;
+ case DROP_BOULDER:
+ {
+ struct obj *otmp;
+ boolean iron = (!rn2(4) ||
+#ifdef REINCARNATION
+ Is_rogue_level(&u.uz) ||
+#endif
+ (In_endgame(&u.uz) && !Is_earthlevel(&u.uz)));
+ otmp = mksobj(iron ? HEAVY_IRON_BALL : BOULDER,
+ FALSE, FALSE);
+ otmp->quan = 1;
+ otmp->owt = weight(otmp);
+ if (iron) otmp->owt += 160 * rn2(2);
+ pline("%s drops out of %s and hits you!", An(xname(otmp)),
+ iron ? "nowhere" : the(ceiling(u.ux,u.uy)));
+ dmg = dmgval(otmp, &youmonst);
+ if (uarmh) {
+ if (is_metallic(uarmh)) {
+ pline("Fortunately, you are wearing a hard helmet.");
+ if (dmg > 2) dmg = 2;
+ } else if (flags.verbose) {
+ Your("%s does not protect you.",
+ xname(uarmh));
+ }
+ }
+ if (!flooreffects(otmp, u.ux, u.uy, "fall")) {
+ place_object(otmp, u.ux, u.uy);
+ stackobj(otmp);
+ newsym(u.ux, u.uy);
+ }
+ if (Half_physical_damage) dmg = (dmg + 1) / 2;
+ break;
+ }
+ case DESTRY_WEPN:
+ {
+ struct obj *otmp = uwep;
+ const char *hands;
+ hands = bimanual(otmp) ? makeplural(body_part(HAND)) : body_part(HAND);
+ if (otmp->oclass == WEAPON_CLASS && !Antimagic && !otmp->oartifact) {
+ /* Quest nemesis maledictions */
+ if (rn2(3)) {
+ if (malediction)
+ verbalize("%s, your %s broken!", plname, aobjnam(otmp,"are"));
+ Your("%s to pieces in your %s!", aobjnam(otmp, "shatter"), hands);
+ setuwep((struct obj *)0);
+ useup(otmp);
+ } else {
+ Your("%s shape in your %s.", aobjnam(otmp, "change"), hands);
+ poly_obj(otmp, BANANA);
+ }
+ } else if (otmp && !welded(otmp) && otmp->otyp != LOADSTONE &&
+ rn2(acurrstr()) < (((int)mtmp->m_lev+1)/2)) {
+ Your("%s knocked out of your %s!",
+ aobjnam(otmp,"are"), hands);
+ setuwep((struct obj *)0);
+ dropx(otmp);
+ } else {
+ shieldeff(u.ux, u.uy);
+ Your("%s for a moment.", aobjnam(otmp, "shudder"));
+ } dmg = 0;
+ break;
+ }
+ case DESTRY_ARMR:
+ if (Antimagic) {
+ shieldeff(u.ux, u.uy);
+ pline("A field of force surrounds you!");
+ } else if (!destroy_arm(some_armor(&youmonst))) {
+ Your("skin itches.");
+ /* Quest nemesis maledictions */
+ } else if (malediction) {
+ if (rn2(2)) verbalize("Thy defenses are useless!");
+ else verbalize("Thou might as well be naked!");
+ }
+ dmg = 0;
+ break;
+ case DRAIN_LIFE: /* simulates player spell "drain life" */
+ if (Drain_resistance) {
+ /* note: magic resistance doesn't protect
+ * against "drain life" spell
+ */
+ shieldeff(u.ux, u.uy);
+ You_feel("momentarily frail.");
+ } else {
+ Your("body deteriorates!");
+ exercise(A_CON, FALSE);
+ losexp("life drainage");
+ }
+ dmg = 0;
+ break;
+ case WEAKEN_YOU: /* drain any stat */
+ if (Fixed_abil) {
+ You_feel("momentarily weakened.");
+ } else if (is_prince(mtmp->data)) {
+ int typ = 0;
+ boolean change = FALSE;
+ do {
+ if (adjattrib(typ, -rnd(ACURR(typ))+3, -1)) change = TRUE;
+ } while (typ++ < A_MAX);
+ if (!change) goto drainhp;
+ } else {
+ int typ = rn2(A_MAX);
+ dmg = mtmp->m_lev - 6;
+ if (Half_spell_damage) dmg = (dmg + 1) / 2;
+ if (dmg < 1) dmg = 1;
+ /* try for a random stat */
+ if (adjattrib(typ, -rnd(dmg), -1)) {
+ /* Quest nemesis maledictions */
+ if (malediction) verbalize("Thy powers are waning, %s!", plname);
+ } else { /* if that fails, drain max HP a bit */
+drainhp:
+ You_feel("your life force draining away...");
+ if (dmg > 20) dmg = 20;
+ if (Upolyd) {
+ u.mh -= dmg;
+ u.mhmax -= dmg;
+ } else {
+ u.uhp -= dmg;
+ u.uhpmax -= dmg;
+ }
+ if (u.uhp < 1) done_in_by(mtmp);
+ /* Quest nemesis maledictions */
+ if (malediction)
+ verbalize("Verily, thou art no mightier than the merest newt.");
+ }
+ }
+ dmg = 0;
+ break;
+ case NIGHTMARE:
+ You_hear("%s laugh menacingly as the world blurs around you...", mon_nam(mtmp));
+ dmg = (dmg + 1) / ((Antimagic + Half_spell_damage) * 2);
+ make_confused(HConfusion + dmg*10, FALSE);
+ make_stunned(HStun + dmg*5, FALSE);
+ make_hallucinated(HHallucination + dmg*15, FALSE, 0L);
+ dmg = 0;
+ break;
+ case MAKE_WEB:
+ You("become entangled in hundreds of %s!",
+ Hallucination ? "two-minute noodles" : "thick cobwebs");
+ /* We've already made sure this is safe */
+ dotrap(maketrap(u.ux,u.uy,WEB), NOWEBMSG);
+ newsym(u.ux,u.uy);
+ /* Quest nemesis maledictions */
+ if (malediction) {
+ if (rn2(ACURR(A_STR)) > 15) verbalize("Thou art dressed like a meal for %s!",
+ rn2(2) ? "Ungoliant" : "Arachne");
+ else verbalize("Struggle all you might, but it will get thee nowhere.");
+ }
+ dmg = 0;
+ break;
+ case DISAPPEAR: /* makes self invisible */
+ if (!mtmp->minvis && !mtmp->invis_blkd) {
+ if (canseemon(mtmp))
+ pline("%s suddenly %s!", Monnam(mtmp),
+ !See_invisible ? "disappears" : "becomes transparent");
+ mon_set_minvis(mtmp);
+ if (malediction && !canspotmon(mtmp))
+ You("hear %s fiendish laughter all around you.", s_suffix(mon_nam(mtmp)));
+ dmg = 0;
+ } else
+ impossible("no reason for monster to cast disappear spell?");
+ break;
+ case DRAIN_ENERGY: /* stronger than antimagic field */
+ if(Antimagic) {
+ shieldeff(u.ux, u.uy);
+ You_feel("momentarily lethargic.");
+ } else drain_en(rn1(u.ulevel,dmg));
+ dmg = 0;
+ break;
+ case SLEEP:
+ zap = AD_SLEE;
+ goto ray;
+ case MAGIC_MISSILE:
+ zap = AD_MAGM;
+ray:
+ nomul(0);
+ if(canspotmon(mtmp))
+ pline("%s zaps you with a %s!", Monnam(mtmp),
+ flash_types[10+zap-1]);
+ buzz(-(10+zap-1),(mtmp->m_lev/2)+1, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
+ dmg = 0;
+ break;
+ case BLIND_YOU:
/* note: resists_blnd() doesn't apply here */
if (!Blinded) {
int num_eyes = eyecount(youmonst.data);
+ if (dmgtype(mtmp->data, AD_CLRC))
pline("Scales cover your %s!",
(num_eyes == 1) ?
body_part(EYE) : makeplural(body_part(EYE)));
+ else if (Hallucination)
+ pline("Oh, bummer! Everything is dark! Help!");
+ else pline("A cloud of darkness falls upon you.");
make_blinded(Half_spell_damage ? 100L : 200L, FALSE);
if (!Blind) Your(vision_clears);
dmg = 0;
} else
impossible("no reason for monster to cast blindness spell?");
break;
- case CLC_PARALYZE:
+ case PARALYZE:
if (Antimagic || Free_action) {
shieldeff(u.ux, u.uy);
if (multi >= 0)
@@ -610,14 +969,14 @@
}
dmg = 0;
break;
- case CLC_CONFUSE_YOU:
+ case CONFUSE_YOU:
if (Antimagic) {
shieldeff(u.ux, u.uy);
You_feel("momentarily dizzy.");
} else {
boolean oldprop = !!Confusion;
- dmg = (int)mtmp->m_lev;
+ dmg = 4 + (int)mtmp->m_lev;
if (Half_spell_damage) dmg = (dmg + 1) / 2;
make_confused(HConfusion + dmg, TRUE);
if (Hallucination)
@@ -627,21 +986,62 @@
}
dmg = 0;
break;
- case CLC_CURE_SELF:
+ case STUN_YOU:
+ if (Antimagic || Free_action) {
+ shieldeff(u.ux, u.uy);
+ if (!Stunned)
+ You_feel("momentarily disoriented.");
+ make_stunned(1L, FALSE);
+ } else {
+ You(Stunned ? "struggle to keep your balance." : "reel...");
+ dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
+ if (Half_spell_damage) dmg = (dmg + 1) / 2;
+ make_stunned(HStun + dmg, FALSE);
+ }
+ dmg = 0;
+ break;
+ case SUMMON_SPHERE:
+ {
+ /* For a change, let's not assume the spheres are together. : ) */
+ int sphere = (!rn2(3) ? PM_FLAMING_SPHERE : (!rn2(2) ?
+ PM_FREEZING_SPHERE : PM_SHOCKING_SPHERE));
+ boolean created = FALSE;
+ struct monst *mon;
+ if (!(mvitals[sphere].mvflags & G_GONE) &&
+ (mon = makemon(&mons[sphere],
+ u.ux, u.uy, NO_MINVENT)) != 0)
+ if (canspotmon(mon)) created++;
+ if (created)
+ pline("%s is created!",
+ Hallucination ? rndmonnam() : Amonnam(mon));
+ dmg = 0;
+ break;
+ }
+ case DARKNESS:
+ litroom(FALSE, (struct obj *)0);
+ dmg = 0;
+ break;
+ case HASTE_SELF:
+ mon_adjust_speed(mtmp, 1, (struct obj *)0);
+ dmg = 0;
+ break;
+ case CURE_SELF:
if (mtmp->mhp < mtmp->mhpmax) {
if (canseemon(mtmp))
- pline("%s looks better.", Monnam(mtmp));
+ pline("%s looks %s.", Monnam(mtmp),
+ is_prince(mtmp->data) ? "completely healed" : "better");
/* note: player healing does 6d4; this used to do 1d8 */
- if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax)
+ if (((mtmp->mhp += d(3,6)) > mtmp->mhpmax) || is_prince(mtmp->data))
mtmp->mhp = mtmp->mhpmax;
dmg = 0;
}
break;
- case CLC_OPEN_WOUNDS:
+ case DAMAGE:
if (Antimagic) {
shieldeff(u.ux, u.uy);
dmg = (dmg + 1) / 2;
}
+ if (dmgtype(mtmp->data, AD_CLRC)) {
if (dmg <= 5)
Your("skin itches badly for a moment.");
else if (dmg <= 10)
@@ -650,9 +1050,18 @@
pline("Severe wounds appear on your body!");
else
Your("body is covered with painful wounds!");
- break;
+ } else {
+ if (dmg <= 5)
+ You("get a slight %sache.", body_part(HEAD));
+ else if (dmg <= 10)
+ Your("brain is on fire!");
+ else if (dmg <= 20)
+ Your("%s suddenly aches painfully!", body_part(HEAD));
+ else
+ Your("%s suddenly aches very painfully!", body_part(HEAD));
+ } break;
default:
- impossible("mcastu: invalid clerical spell (%d)", spellnum);
+ impossible("mcastu: invalid magic spell (%d)", spellnum);
dmg = 0;
break;
}
@@ -666,36 +1075,29 @@
unsigned int adtyp;
int spellnum;
{
- if (adtyp == AD_SPEL) {
switch (spellnum) {
- case MGC_CLONE_WIZ:
- case MGC_SUMMON_MONS:
- case MGC_AGGRAVATION:
- case MGC_DISAPPEAR:
- case MGC_HASTE_SELF:
- case MGC_CURE_SELF:
+ case CLONE_WIZ:
+ case RAISE_DEAD:
+ case EARTHQUAKE:
+ case SUMMON_ANGEL:
+ case SUMMON_SPHERE:
+ case SUMMON_MONS:
+ case DISAPPEAR:
+ case HASTE_SELF:
+ case CURE_SELF:
+ case INSECTS:
return TRUE;
default:
break;
}
- } else if (adtyp == AD_CLRC) {
- switch (spellnum) {
- case CLC_INSECTS:
- case CLC_CURE_SELF:
- return TRUE;
- default:
- break;
- }
- }
return FALSE;
}
/* Some spells are useless under some circumstances. */
STATIC_DCL
boolean
-spell_would_be_useless(mtmp, adtyp, spellnum)
+spell_would_be_useless(mtmp, spellnum)
struct monst *mtmp;
-unsigned int adtyp;
int spellnum;
{
/* Some spells don't require the player to really be there and can be cast
@@ -706,47 +1108,107 @@
*/
boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my);
- if (adtyp == AD_SPEL) {
- /* aggravate monsters, etc. won't be cast by peaceful monsters */
- if (mtmp->mpeaceful && (spellnum == MGC_AGGRAVATION ||
- spellnum == MGC_SUMMON_MONS || spellnum == MGC_CLONE_WIZ))
+ /* don't make "ruler" monsters cast ineffective spells */
+ if (is_prince(mtmp->data) &&
+ (((spellnum == MAGIC_MISSILE || spellnum == DESTRY_ARMR ||
+ spellnum == PARALYZE || spellnum == CONFUSE_YOU ||
+ spellnum == STUN_YOU || spellnum == DRAIN_ENERGY) && Antimagic) ||
+ ((spellnum == MAGIC_MISSILE || spellnum == SLEEP ||
+ spellnum == CONE_OF_COLD || spellnum == LIGHTNING) && Reflecting) ||
+ ((spellnum == STUN_YOU || spellnum == PARALYZE) && Free_action) ||
+ (spellnum == FIRE_PILLAR && Fire_resistance) ||
+ (spellnum == CONE_OF_COLD && Cold_resistance) ||
+ (spellnum == SLEEP && Sleep_resistance) ||
+ (spellnum == LIGHTNING && Shock_resistance) ||
+ (spellnum == ACID_RAIN && Acid_resistance) ||
+ (spellnum == DRAIN_LIFE && Drain_resistance) ||
+ (spellnum == PLAGUE && Sick_resistance) ||
+ (spellnum == WEAKEN_YOU && Fixed_abil)))
+ return TRUE;
+ /* the wiz won't use the following cleric-specific or otherwise weak spells */
+ if (mtmp->iswiz && (spellnum == SUMMON_SPHERE || spellnum == DARKNESS ||
+ spellnum == PUNISH || spellnum == INSECTS ||
+ spellnum == SUMMON_ANGEL || spellnum == DROP_BOULDER))
+ return TRUE;
+ /* ray attack when monster isn't lined up */
+ if(!lined_up(mtmp) && (spellnum == MAGIC_MISSILE ||
+ spellnum == SLEEP || spellnum == CONE_OF_COLD || spellnum == LIGHTNING))
+ return TRUE;
+ /* drain energy when you have less than 5 */
+ if(spellnum == DRAIN_ENERGY && u.uen < 5) return TRUE;
+ /* don't cast acid rain if the player is petrifying */
+ if (spellnum == ACID_RAIN && Stoned) return TRUE;
+ /* don't destroy weapon if not wielding anything */
+ if (spellnum == DESTRY_WEPN && !uwep) return TRUE;
+ /* don't do strangulation if already strangled or there's no room in inventory */
+ if (((inv_cnt() == 52 && (!uamul || uamul->oartifact ||
+ uamul->otyp == AMULET_OF_YENDOR)) || Strangled) && spellnum == STRANGLE)
+ return TRUE;
+ /* sleep ray when already asleep */
+ if (Sleeping && spellnum == SLEEP)
+ return TRUE;
+ /* hallucination when already hallucinating */
+ if ((u.umonnum == PM_BLACK_LIGHT || u.umonnum == PM_VIOLET_FUNGUS ||
+ Hallucination) && spellnum == NIGHTMARE)
+ return TRUE;
+ /* turn to stone when already/can't be stoned */
+ if ((Stoned || Stone_resistance) && spellnum == TURN_TO_STONE)
+ return TRUE;
+ /* earthquake where the pits won't be effective */
+ if ((Underwater || Levitation || Flying || In_endgame(&u.uz) ||
+ (u.utrap && u.utraptype == TT_PIT)) && spellnum == EARTHQUAKE)
+ return TRUE;
+ /* various conditions where webs won't be effective */
+ if ((levl[u.ux][u.uy].typ <= IRONBARS || levl[u.ux][u.uy].typ > ICE ||
+ t_at(u.ux,u.uy) || amorphous(youmonst.data) ||
+ is_whirly(youmonst.data) || flaming(youmonst.data) ||
+ unsolid(youmonst.data) || uwep && uwep->oartifact == ART_STING ||
+ ACURR(A_STR) >= 18) && spellnum == MAKE_WEB)
+ return TRUE;
+ /* don't summon spheres when one type is gone */
+ if (spellnum == SUMMON_SPHERE &&
+ (mvitals[PM_FLAMING_SPHERE].mvflags & G_GONE) ||
+ (mvitals[PM_FREEZING_SPHERE].mvflags & G_GONE) ||
+ (mvitals[PM_SHOCKING_SPHERE].mvflags & G_GONE))
return TRUE;
/* haste self when already fast */
- if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF)
+ if (mtmp->permspeed == MFAST && spellnum == HASTE_SELF)
return TRUE;
/* invisibility when already invisible */
- if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR)
+ if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == DISAPPEAR)
return TRUE;
/* peaceful monster won't cast invisibility if you can't see invisible,
same as when monsters drink potions of invisibility. This doesn't
really make a lot of sense, but lets the player avoid hitting
peaceful monsters by mistake */
- if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR)
+ if (mtmp->mpeaceful && !See_invisible && spellnum == DISAPPEAR)
return TRUE;
/* healing when already healed */
- if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF)
- return TRUE;
- /* don't summon monsters if it doesn't think you're around */
- if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS ||
- (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ)))
+ if (mtmp->mhp == mtmp->mhpmax && spellnum == CURE_SELF)
return TRUE;
- if ((!mtmp->iswiz || flags.no_of_wizards > 1)
- && spellnum == MGC_CLONE_WIZ)
+ /* don't summon anything if it doesn't think you're around
+ or the caster is peaceful */
+ if ((!mcouldseeu || mtmp->mpeaceful) &&
+ (spellnum == SUMMON_MONS || spellnum == INSECTS ||
+ spellnum == SUMMON_SPHERE || spellnum == RAISE_DEAD ||
+ spellnum == CLONE_WIZ || spellnum == SUMMON_ANGEL))
return TRUE;
- } else if (adtyp == AD_CLRC) {
- /* summon insects/sticks to snakes won't be cast by peaceful monsters */
- if (mtmp->mpeaceful && spellnum == CLC_INSECTS)
+ /* angels can't be summoned in Gehennom or by quest nemeses */
+ if (spellnum == SUMMON_ANGEL && (In_hell(&u.uz) ||
+ monsndx(mtmp->data) == MS_NEMESIS))
return TRUE;
- /* healing when already healed */
- if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF)
+ /* only the wiz makes a clone */
+ if ((!mtmp->iswiz || flags.no_of_wizards > 1)
+ && spellnum == CLONE_WIZ)
return TRUE;
- /* don't summon insects if it doesn't think you're around */
- if (!mcouldseeu && spellnum == CLC_INSECTS)
+ /* make visible spell by spellcaster with see invisible. */
+ /* also won't cast it if your invisibility isn't intrinsic. */
+ if ((!(HInvis & INTRINSIC) || perceives(mtmp->data))
+ && spellnum == MAKE_VISIBLE)
return TRUE;
/* blindness spell on blinded player */
- if (Blinded && spellnum == CLC_BLIND_YOU)
+ if (Blinded && spellnum == BLIND_YOU)
return TRUE;
- }
return FALSE;
}
diff -Nurb nethack-3.4.3-original/src/music.c nethack-3.4.3/src/music.c
--- nethack-3.4.3-original/src/music.c Mon Dec 8 09:39:13 2003
+++ nethack-3.4.3/src/music.c Tue Jan 10 12:14:07 2006
@@ -33,7 +33,6 @@
STATIC_DCL void FDECL(charm_snakes,(int));
STATIC_DCL void FDECL(calm_nymphs,(int));
STATIC_DCL void FDECL(charm_monsters,(int));
-STATIC_DCL void FDECL(do_earthquake,(int));
STATIC_DCL int FDECL(do_improvisation,(struct obj *));
#ifdef UNIX386MUSIC
@@ -210,13 +209,18 @@
/* Generate earthquake :-) of desired force.
* That is: create random chasms (pits).
+ * Also a monster wizard spell.
+ * cursed drums (and spells) unleash monsters
+ * mon indicates which monster cast the spell
*/
-STATIC_OVL void
-do_earthquake(force)
+void
+do_earthquake(force, cursed, mon)
int force;
+boolean cursed;
+struct monst *mon;
{
- register int x,y;
+ register int x,y, horrors = 0;
struct monst *mtmp;
struct obj *otmp;
struct trap *chasm;
@@ -232,7 +236,7 @@
if (end_y >= ROWNO) end_y = ROWNO - 1;
for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
if ((mtmp = m_at(x,y)) != 0) {
- wakeup(mtmp); /* peaceful monster will become hostile */
+ if (!mon) wakeup(mtmp); /* peaceful monster will become hostile */
if (mtmp->mundetected && is_hider(mtmp->data)) {
mtmp->mundetected = 0;
if (cansee(x,y))
@@ -246,7 +250,8 @@
newsym(x,y);
}
}
- if (!rn2(14 - force)) switch (levl[x][y].typ) {
+ if ((!rn2(14 - force) || (cursed && x == u.ux && y == u.uy)) && m_at(x,y) != mon)
+ switch (levl[x][y].typ) {
case FOUNTAIN : /* Make the fountain disappear */
if (cansee(x,y))
pline_The("fountain falls into a chasm.");
@@ -305,15 +310,19 @@
mselftouch(mtmp, "Falling, ", TRUE);
if (mtmp->mhp > 0)
if ((mtmp->mhp -= rnd(6)) <= 0) {
- if(!cansee(x,y))
- pline("It is destroyed!");
+ if(!cansee(x,y) || mon)
+ pline("%s is %sed!",
+ cansee(x,y) ? "It" : Monnam(mtmp),
+ nonliving(mtmp->data) ? "destroy" : "kill");
else {
- You("destroy %s!", mtmp->mtame ?
+ You("%s %s!", nonliving(mtmp->data) ? "destroy" :
+ "kill", mtmp->mtame ?
x_monnam(mtmp, ARTICLE_THE, "poor",
mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
mon_nam(mtmp));
}
- xkilled(mtmp,0);
+ if (!mon) xkilled(mtmp,0);
+ else mondied(mtmp);
}
}
} else if (x == u.ux && y == u.uy) {
@@ -329,6 +338,18 @@
NO_KILLER_PREFIX);
selftouch("Falling, you");
}
+ } else if ((mon || cursed) && !rn2(2)) {
+ /* make some chthonic nasties */
+ switch(rn2(In_hell(&u.uz) ? 7 : 5)) {
+ case 2:(void) makemon(&mons[PM_ROCK_MOLE], x, y, NO_MM_FLAGS);
+ case 3:(void) makemon(&mons[PM_EARTH_ELEMENTAL], x, y, NO_MM_FLAGS);
+ case 4:(void) makemon(mkclass(S_XORN, 0), x, y, NO_MM_FLAGS);
+ case 5:(void) makemon(mkclass(S_DEMON, 0), x, y, NO_MM_FLAGS);
+ case 6:(void) makemon(&mons[PM_UMBER_HULK], x, y, NO_MM_FLAGS);
+ default:(void) makemon(mkclass(S_ZOMBIE, 0), x, y, NO_MM_FLAGS);
+ }
+ mtmp = m_at(x,y);
+ if (mtmp && canseemon(mtmp)) horrors++;
} else newsym(x,y);
break;
case DOOR : /* Make the door collapse */
@@ -343,6 +364,10 @@
break;
}
}
+ if (horrors > 1)
+ pline("Monsters emerge from the chasms!");
+ else if (horrors)
+ pline("A monster emerges from a chasm!");
}
/*
@@ -450,7 +475,7 @@
You("produce a heavy, thunderous rolling!");
pline_The("entire dungeon is shaking around you!");
- do_earthquake((u.ulevel - 1) / 3 + 1);
+ do_earthquake((u.ulevel - 1) / 3 + 1, instr->cursed, (struct monst *)0);
/* shake up monsters in a much larger radius... */
awaken_monsters(ROWNO * COLNO);
makeknown(DRUM_OF_EARTHQUAKE);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment