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

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