fix #2495 - light vs gremlins (trunk only)

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.
This commit is contained in:
nethack.rankin
2011-10-17 01:32:23 +00:00
parent 2402f43776
commit 897d527837
5 changed files with 94 additions and 13 deletions

View 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

View 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 */

View 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

View 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*/

View File

@@ -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;