]> granicus.if.org Git - nethack/commitdiff
fix #2495 - light vs gremlins (trunk only)
authornethack.rankin <nethack.rankin>
Mon, 17 Oct 2011 01:32:23 +0000 (01:32 +0000)
committernethack.rankin <nethack.rankin>
Mon, 17 Oct 2011 01:32:23 +0000 (01:32 +0000)
     From a bug report, flashing yourself
with a camera while in gremlin form blinded as with any other form, but
didn't inflict any damage the way that flashing a monster gremlin does.
This fixes that, and also makes light from wand/scroll/spell that hits
you-as-gremlin or monster gremlins do 1d5 damage too.  It happens even
if the target is already in a lit spot, but doesn't continue afterwards:
simply being in a lit spot doesn't cause any damage, nor does lamp light.

doc/fixes35.0
include/extern.h
src/read.c
src/uhitm.c
src/zap.c

index af2e71856beb9098a90496a866ced47c1a1b8ae7..7ab3cab0423b8d08482bb100515d7591ff3a606c 100644 (file)
@@ -394,6 +394,8 @@ if hero dragged iron ball into temporary corridor and then killed vault guard,
        the portion of corridor currently in existence would become permanent
 on Plane of Water, restrict levitation and flying to air bubbles;
        elsewhere, restrict them such that they don't work inside solid rock
+wand/scroll/spell of light now hurts gremlins (lamp/candle light doesn't)
+ditto for hero in gremlin form (camera too)
 
 
 Platform- and/or Interface-Specific Fixes
index 24b4f81b62c03fcf89edf39f267c4437ae41ae4e..20faeb00b5d9bd31ee21d58eea344adfd9e36ffd 100644 (file)
@@ -2341,6 +2341,7 @@ E int FDECL(passive, (struct monst *,BOOLEAN_P,int,UCHAR_P,BOOLEAN_P));
 E void FDECL(passive_obj, (struct monst *,struct obj *,struct attack *));
 E void FDECL(stumble_onto_mimic, (struct monst *));
 E int FDECL(flash_hits_mon, (struct monst *,struct obj *));
+E void FDECL(light_hits_gremlin, (struct monst *,int));
 
 /* ### unixmain.c ### */
 
@@ -2685,6 +2686,8 @@ E void FDECL(zapnodir, (struct obj *));
 E int NDECL(dozap);
 E int FDECL(zapyourself, (struct obj *,BOOLEAN_P));
 E void FDECL(ubreatheu, (struct attack *));
+E int FDECL(lightdamage, (struct obj *,BOOLEAN_P,int));
+E boolean FDECL(flashburn, (long));
 E boolean FDECL(cancel_monst, (struct monst *,struct obj *,
                               BOOLEAN_P,BOOLEAN_P,BOOLEAN_P));
 E void NDECL(zapsetup);
@@ -2710,7 +2713,6 @@ E void FDECL(destroy_item, (int,int));
 E int FDECL(destroy_mitem, (struct monst *,int,int));
 E int FDECL(resist, (struct monst *,CHAR_P,int,int));
 E void NDECL(makewish);
-E boolean FDECL(flashburn, (long));
 
 #endif /* !MAKEDEFS_C && !LEV_LEX_C */
 
index 55bbd7fdb3c5ad3daea4abfd116671c2f15c996e..352ac42c1250e117d2516289c7867106a1f13403 100644 (file)
@@ -1158,6 +1158,9 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                if (!confused || rn2(5)) {
                        if(!Blind) known = TRUE;
                        litroom(!confused && !scursed, sobj);
+                       if (!confused && !scursed) {
+                           if (lightdamage(sobj, TRUE, 5)) known = TRUE;
+                       }
                } else {
                   /* could be scroll of create monster, don't set known ...*/
                    (void) create_critters(1, !scursed ?
@@ -1518,6 +1521,14 @@ int chg;         /* recharging */
     exercise(A_STR, FALSE);
 }
 
+/* used to collect gremlins being hit by light so that they can be processed
+   after vision for the entire lit area has been brought up to date */
+struct litmon {
+    struct monst *mon;
+    struct litmon *nxt;
+};
+STATIC_VAR struct litmon *gremlins = 0;
+
 /*
  * Low-level lit-field update routine.
  */
@@ -1526,9 +1537,18 @@ set_lit(x,y,val)
 int x, y;
 genericptr_t val;
 {
-       if (val)
+       struct monst *mtmp;
+       struct litmon *gremlin;
+
+       if (val) {
            levl[x][y].lit = 1;
-       else {
+           if ((mtmp = m_at(x, y)) != 0 && mtmp->data == &mons[PM_GREMLIN]) {
+               gremlin = (struct litmon *)alloc(sizeof *gremlin);
+               gremlin->mon = mtmp;
+               gremlin->nxt = gremlins;
+               gremlins = gremlin;
+           }
+       } else {
            levl[x][y].lit = 0;
            snuff_light_source(x, y);
        }
@@ -1627,6 +1647,20 @@ do_it:
        }
 
        vision_full_recalc = 1; /* delayed vision recalculation */
+       if (gremlins) {
+           struct litmon *gremlin;
+
+           /* can't delay vision recalc after all */
+           vision_recalc(0);
+           /* after vision has been updated, monsters who are affected
+              when hit by light can now be hit by it */
+           do {
+               gremlin = gremlins;
+               gremlins = gremlin->nxt;
+               light_hits_gremlin(gremlin->mon, rnd(5));
+               free((genericptr_t)gremlin);
+           } while (gremlins);
+       }
 }
 
 STATIC_OVL void
index f2c65bb6113a83584c70a9c88e48d2bd1700eb99..786ddb250a8213dae75cd8955b0c993312cb8f3d 100644 (file)
@@ -2609,16 +2609,7 @@ struct obj *otmp;        /* source of flash */
                    /* Rule #1: Keep them out of the light. */
                    amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) :
                          rn2(min(mtmp->mhp,4));
-                   pline("%s %s!", Monnam(mtmp), amt > mtmp->mhp / 2 ?
-                         "wails in agony" : "cries out in pain");
-                   if ((mtmp->mhp -= amt) <= 0) {
-                       if (context.mon_moving)
-                           monkilled(mtmp, (char *)0, AD_BLND);
-                       else
-                           killed(mtmp);
-                   } else if (cansee(mtmp->mx,mtmp->my) && !canspotmon(mtmp)){
-                       map_invisible(mtmp->mx, mtmp->my);
-                   }
+                   light_hits_gremlin(mtmp, amt);
                }
                if (mtmp->mhp > 0) {
                    if (!context.mon_moving) setmangry(mtmp);
@@ -2632,4 +2623,21 @@ struct obj *otmp;        /* source of flash */
        return res;
 }
 
+void
+light_hits_gremlin(mon, dmg)
+struct monst *mon;
+int dmg;
+{
+    pline("%s %s!", Monnam(mon),
+         (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
+    if ((mon->mhp -= dmg) <= 0) {
+       if (context.mon_moving)
+           monkilled(mon, (char *)0, AD_BLND);
+       else
+           killed(mon);
+    } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) {
+       map_invisible(mon->mx, mon->my);
+    }
+}
+
 /*uhitm.c*/
index df38947e0e5ba692122399194ebaee2a2bcaed2f..f427ef9e2b360d2297d8806586d06b7c52b32b5c 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -1963,6 +1963,7 @@ register struct obj *obj;
                case SPE_LIGHT:
                        litroom(TRUE,obj);
                        if (!Blind) known = TRUE;
+                       if (lightdamage(obj, TRUE, 5)) known = TRUE;
                        break;
                case WAN_SECRET_DOOR_DETECTION:
                case SPE_DETECT_UNSEEN:
@@ -2279,7 +2280,9 @@ boolean ordinary;
                    damage = d(obj->spe, 25);
 #ifdef TOURIST
                case EXPENSIVE_CAMERA:
+                   if (!damage) damage = 5;
 #endif
+                   damage = lightdamage(obj, ordinary, damage);
                    damage += rnd(25);
                    if (flashburn((long)damage)) learn_it = TRUE;
                    damage = 0; /* reset */
@@ -2377,6 +2380,38 @@ struct attack *mattk;
        zhitu(dtyp, mattk->damn, fltxt, u.ux, u.uy);
 }
 
+/* light damages hero in gremlin form */
+int
+lightdamage(obj, ordinary, amt)
+struct obj *obj;       /* item making light (fake book if spell) */
+boolean ordinary;      /* wand/camera zap vs wand destruction */
+int amt;       /* pseudo-damage used to determine blindness duration */
+{
+    char buf[BUFSZ];
+    const char *how;
+    int dmg = amt;
+
+    if (dmg && youmonst.data == &mons[PM_GREMLIN]) {
+       /* reduce high values (from destruction of wand with many charges) */
+       dmg = rnd(dmg);
+       if (dmg > 10) dmg = 10 + rnd(dmg - 10);
+       if (dmg > 20) dmg = 20;
+       pline("Ow, that light hurts%c", (dmg > 2 || u.mh <= 5) ? '!' : '.');
+       /* [composing killer/reason is superfluous here; if fatal, cause
+          of death will always be "killed while stuck in creature form"] */
+       if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS)
+           ordinary = FALSE;   /* say blasted rather than zapped */
+       how = (obj->oclass != SPBOOK_CLASS) ?
+               (const char *)ansimpleoname(obj) : "spell of light";
+       Sprintf(buf, "%s %sself with %s",
+               ordinary ? "zapped" : "blasted", uhim(), how);
+       /* might rehumanize(); could be fatal, but only for Unchanging */
+       losehp(Maybe_Half_Phys(dmg), buf, NO_KILLER_PREFIX);
+    }
+    return dmg;
+}
+
+/* light[ning] causes blindness */
 boolean
 flashburn(duration)
 long duration;