]> granicus.if.org Git - nethack/commitdiff
monster spells
authorarromdee <arromdee>
Sun, 20 Jan 2002 06:17:20 +0000 (06:17 +0000)
committerarromdee <arromdee>
Sun, 20 Jan 2002 06:17:20 +0000 (06:17 +0000)
This fixes the problem with my monster spell changes which let monsters
summon monsters around you when they don't even know you're around.

The summoned monsters should appear where the monster thinks you are, if
you're invisible or displaced.

I have not prevented them from summoning monsters when you are in a temple,
nor have I prevented them from aggravating monsters several times when you're
out of sight.

Messages should be a little smarter, taking into account number of monsters
and invisibility/displacement.

--Ken A

include/extern.h
src/mcastu.c
src/wizard.c

index 7671052f8b605016815264d97bf51416baa740ef..a52365e9e1ec93d3c49f6bba807d86ed0eac9fbd 100644 (file)
@@ -2201,7 +2201,7 @@ E int FDECL(tactics, (struct monst *));
 E void NDECL(aggravate);
 E void NDECL(clonewiz);
 E int NDECL(pick_nasty);
-E void FDECL(nasty, (struct monst*));
+E int FDECL(nasty, (struct monst*));
 E void NDECL(resurrect);
 E void NDECL(intervene);
 E void NDECL(wizdead);
index 1cc6a12b2b6b06ad5aaf7705c7fa815d388e880c..707570a768cbdcf4e7b2864313295da76672d125 100644 (file)
@@ -226,7 +226,13 @@ castmu(mtmp, mattk, thinks_it_foundyou, foundyou)
            return(0);
        }
        pline("%s casts a spell%s!", Monnam(mtmp),
-           is_undirected_spell(mattk->adtyp, spellnum) ? "" : " at you");
+           is_undirected_spell(mattk->adtyp, spellnum) ? "" :
+           (Invisible && !perceives(mtmp->data) && 
+                   (mtmp->mux != u.ux || mtmp->muy != u.uy)) ?
+               " at a spot near you" :
+           (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ?
+               " at your displaced image" :
+               " at you");
 
 /*
  *     As these are spells, the damage is related to the level
@@ -337,12 +343,29 @@ int spellnum;
        }
        /* else FALLTHRU */
     case MGC_SUMMON_MONS:              /* also aggravates */
+    {
+       int count;
+
+       count = nasty(mtmp);    /* summon something nasty */
        if (mtmp->iswiz)
-           verbalize("Destroy the thief, my pets!");
-       else
-           pline("A monster appears!");
-       nasty(mtmp);    /* summon something nasty */
-       /* FALLTHRU */
+           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 MGC_AGGRAVATION:
        You_feel("that monsters are aware of your presence.");
        aggravate();
@@ -502,31 +525,45 @@ int spellnum;
        /* 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 *mtmp2 = (struct monst *)0;
        char let = (pm ? S_ANT : S_SNAKE);
        boolean success;
        int i;
+       coord bypos;
 
        success = pm ? TRUE : FALSE;
        for (i = 0; i <= (int) mtmp->m_lev; i++) {
-          if ((pm = mkclass(let,0)) != 0 &&
-                   (mtmp2 = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0) {
+           if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
+               break;
+           if ((pm = mkclass(let,0)) != 0 &&
+                   (mtmp2 = makemon(pm, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
                success = TRUE;
                mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
                set_malign(mtmp2);
            }
        }
-       if (canseemon(mtmp)) {
-           /* wrong--should check if you can see the insects/snakes */
-           if (!success)
-               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));
-           else
-               pline("%s summons insects!", Monnam(mtmp));
-       }
+       /* Not quite right:
+         * -- message doesn't always make sense for unseen caster (particularly
+        *    the first message)
+         * -- message assumes plural monsters summoned (non-plural should be
+         *    very rare, unlike in nasty())
+         * -- message assumes plural monsters seen
+         */
+       if (!success)
+           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));
+       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));
+       else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
+           pline("%s summons insects around your displaced image!",
+               Monnam(mtmp));
+       else
+           pline("%s summons insects!", Monnam(mtmp));
        dmg = 0;
        break;
       }
@@ -563,9 +600,15 @@ int spellnum;
            shieldeff(u.ux, u.uy);
            You_feel("momentarily dizzy.");
        } else {
+           boolean oldprop = Confusion;
+
            dmg = (int)mtmp->m_lev;
            if (Half_spell_damage) dmg = (dmg + 1) / 2;
            make_confused(HConfusion + dmg, TRUE);
+           if (Hallucination)
+               You_feel("%s!", oldprop ? "trippier" : "trippy");
+           else
+               You_feel("%sconfused!", oldprop ? "more " : "");
        }
        dmg = 0;
        break;
@@ -633,7 +676,9 @@ int spellnum;
     return FALSE;
 }
 
-/* Some undirected spells are useless under some circumstances */
+/* Some undirected spells are useless under some circumstances. */
+/* This isn't called when the monster is deliberately casting at you; we
+   handle that using fallthroughs. */
 STATIC_DCL
 boolean
 spell_would_be_useless(mtmp, adtyp, spellnum)
@@ -641,6 +686,14 @@ struct monst *mtmp;
 int spellnum;
 int adtyp;
 {
+    /* Some spells don't require the player to really be there and can be cast
+     * by the monster when you're invisible, yet still shouldn't be cast when
+     * the monster doesn't even think you're there.
+     * This check isn't quite right because it always uses your real position.
+     * We really want something like "if the monster could see mux, muy".
+     */
+    boolean couldsee = 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 ||
@@ -661,6 +714,10 @@ int adtyp;
        /* 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 (!couldsee && (spellnum == MGC_SUMMON_MONS ||
+               (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ)))
+           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)
@@ -668,6 +725,9 @@ int adtyp;
        /* healing when already healed */
        if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF)
            return TRUE;
+       /* don't summon insects if it doesn't think you're around */
+       if (!couldsee && spellnum == CLC_INSECTS)
+           return TRUE;
     }
     return FALSE;
 }
index 8cf1ceae6fac1e3edec8cd68da3e0a909d357ca0..814609ff398e655b3b51892a61b24ef0aa19b316 100644 (file)
@@ -410,33 +410,44 @@ pick_nasty()
 
 /* create some nasty monsters, aligned or neutral with the caster */
 /* a null caster defaults to a chaotic caster (e.g. the wizard) */
-void
+int
 nasty(mcast)
        struct monst *mcast;
 {
     register struct monst      *mtmp;
     register int       i, j, tmp;
     int castalign = (mcast ? mcast->data->maligntyp : -1);
+    coord bypos;
+    int count=0;
 
-    if(!rn2(10) && Inhell) msummon(&mons[PM_WIZARD_OF_YENDOR]);
-    else {
+    if(!rn2(10) && Inhell) {
+       msummon(&mons[PM_WIZARD_OF_YENDOR]);
+       count++;
+    } else {
        tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */
-
+       /* if we don't have a casting monster, the nasties appear around you */
+       bypos.x = u.ux;
+       bypos.y = u.uy;
        for(i = rnd(tmp); i > 0; --i)
            for(j=0; j<20; j++) {
+               if (mcast &&
+                       !enexto(&bypos, mcast->mux, mcast->muy, mcast->data))
+                   continue;
                if ((mtmp = makemon(&mons[pick_nasty()],
-                                   u.ux, u.uy, NO_MM_FLAGS)) != 0) {
+                                   bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
                    mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0;
                    set_malign(mtmp);
                } else /* GENOD? */
                    mtmp = makemon((struct permonst *)0,
-                                       u.ux, u.uy, NO_MM_FLAGS);
+                                       bypos.x, bypos.y, NO_MM_FLAGS);
                if(mtmp && (mtmp->data->maligntyp == 0 ||
-                           sgn(mtmp->data->maligntyp) == sgn(castalign)) )
+                           sgn(mtmp->data->maligntyp) == sgn(castalign)) ) {
+                   count++;
                    break;
+               }
            }
     }
-    return;
+    return count;
 }
 
 /*     Let's resurrect the wizard, for some unexpected fun.    */
@@ -506,7 +517,7 @@ intervene()
                        break;
            case 3:     aggravate();
                        break;
-           case 4:     nasty((struct monst *)0);
+           case 4:     (void)nasty((struct monst *)0);
                        break;
            case 5:     resurrect();
                        break;