From 897d527837b78792bdf0d7a94983f6edc16c1f68 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Mon, 17 Oct 2011 01:32:23 +0000 Subject: [PATCH] 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. --- doc/fixes35.0 | 2 ++ include/extern.h | 4 +++- src/read.c | 38 ++++++++++++++++++++++++++++++++++++-- src/uhitm.c | 28 ++++++++++++++++++---------- src/zap.c | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 94 insertions(+), 13 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index af2e71856..7ab3cab04 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 24b4f81b6..20faeb00b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 */ diff --git a/src/read.c b/src/read.c index 55bbd7fdb..352ac42c1 100644 --- a/src/read.c +++ b/src/read.c @@ -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 diff --git a/src/uhitm.c b/src/uhitm.c index f2c65bb61..786ddb250 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -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*/ diff --git a/src/zap.c b/src/zap.c index df38947e0..f427ef9e2 100644 --- 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; -- 2.40.0