From: PatR Date: Sat, 5 Feb 2022 00:20:03 +0000 (-0800) Subject: fix github issue #666 - cursed light vs worn light X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e8341dc9d79dbdc0013a287a9c8dfd627798883b;p=nethack fix github issue #666 - cursed light vs worn light Another gold dragon scales/mail issue, reported bu vultur-cadens: reading a cursed scroll of light extinguishes carried light sources except for wielded Sunsword and worn gold dragon scales/mail; there was a special message for Sunsword (preventing the hero from being in darkness) but no such message for gold dragon scales/mail. Replace the special message with a more generic one applicable to both cases. Also, implement the suggestion that cursed light degrade the amount of light being emitted (which varies by bless/curse state) for those two cases. Sunsword has a 75% chance to resist, gold dragon scales 25% chance. And add the inverse: blessed scroll of light might increase the amount of light by improving their bless/curse state. The resistance check applies here too and isn't inverted; Sunsword is still fairly likely to resist. Uncursed scroll of light, spell of light regardless of skill, zapped or broken wand of light have so such effect. Closes #666 --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index db268ac6a..a10ff6338 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -991,6 +991,8 @@ a change to wounded legs handling resulted in not recovering lost dexterity rather than having legs be explicitly healed turning movement into commands broke the rest_on_space option; it also interfered with using pick-axe plus autodig in downward direction +cursed scroll of light had special message when wielding Sunsword that didn't + work for wearing gold dragon scales/mail curses: 'msg_window' option wasn't functional for curses unless the binary also included tty support @@ -1370,6 +1372,9 @@ drinking blessed potion of full healing heals wounded legs, either hero's or drinking uncursed potion of full healing or blessed potion of extra healing heal hero's wounded legs when not riding; no effect on steed if riding cancellation explodes most magical traps +reading a blessed scroll of light has a chance to improve bless/curse state + of wielded Sunsword or worn gold dragon scales/mail similar to dipping + those into holy water; cursed scroll has chance to worsen the state Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 1285bf5e1..2cbe6c487 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2097,6 +2097,7 @@ extern int dopotion(struct obj *); extern int peffects(struct obj *); extern void healup(int, int, boolean, boolean); extern void strange_feeling(struct obj *, const char *); +extern void impact_arti_light(struct obj *, boolean, boolean); extern void potionhit(struct monst *, struct obj *, int); extern void potionbreathe(struct obj *); extern int dodip(void); diff --git a/src/potion.c b/src/potion.c index e21dc3548..172cfd10a 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1447,7 +1447,7 @@ H2Opotion_dip( boolean useeit, /* will hero see the glow/aura? */ const char *objphrase) /* "Your widget glows" or "Steed's saddle glows" */ { - void (*func)(struct obj *) = 0; + void (*func)(struct obj *) = (void (*)(struct obj *)) 0; const char *glowcolor = 0; #define COST_alter (-2) #define COST_none (-1) @@ -1528,6 +1528,38 @@ H2Opotion_dip( return res; } +/* used when blessed or cursed scroll of light interacts with artifact light; + if the lit object (Sunsword or gold dragon scales/mail) doesn't resist, + treat like dipping it in holy or unholy water (BUC change, glow message) */ +void +impact_arti_light( + struct obj *obj, /* wielded Sunsword or worn gold dragon scales/mail */ + boolean worsen, /* True: lower BUC state unless already cursed; + * False: raise BUC state unless already blessed */ + boolean seeit) /* True: give " glows " message */ +{ + struct obj *otmp; + + /* if already worst/best BUC it can be, or if it resists, do nothing */ + if ((worsen ? obj->cursed : obj->blessed) || obj_resists(obj, 75, 25)) + return; + + /* curse() and bless() take care of maybe_adjust_light() */ + otmp = mksobj(POT_WATER, TRUE, FALSE); + if (worsen) + curse(otmp); + else + bless(otmp); + H2Opotion_dip(otmp, obj, seeit, seeit ? Yobjnam2(obj, "glow") : ""); + dealloc_obj(otmp); +#if 0 /* defer this until caller has used up the scroll so it won't be + * visible; player was told that it disappeared as hero read it */ + if (carried(obj)) /* carried() will always be True here */ + update_inventory(); +#endif + return; +} + /* potion obj hits monster mon, which might be youmonst; obj always used up */ void potionhit(struct monst *mon, struct obj *obj, int how) diff --git a/src/read.c b/src/read.c index df09611d4..d02d848f5 100644 --- a/src/read.c +++ b/src/read.c @@ -1578,13 +1578,13 @@ seffect_light(struct obj **sobjp) pline("Tiny lights sparkle in the air momentarily."); } else { /* surround with cancelled tame lights which won't explode */ + struct monst *mon; boolean sawlights = FALSE; - int numlights = rn1(2,3) + (sblessed * 2); - int i; + int i, numlights = rn1(2, 3) + (sblessed * 2); for (i = 0; i < numlights; ++i) { - struct monst * mon = makemon(&mons[pm], u.ux, u.uy, - MM_EDOG | NO_MINVENT | MM_NOMSG); + mon = makemon(&mons[pm], u.ux, u.uy, + MM_EDOG | NO_MINVENT | MM_NOMSG); initedog(mon); mon->msleeping = 0; mon->mcan = TRUE; @@ -2279,32 +2279,65 @@ set_lit(int x, int y, genericptr_t val) } void -litroom(register boolean on, struct obj* obj) +litroom( + boolean on, /* True: make nearby area lit; False: cursed scroll */ + struct obj *obj) /* scroll, spellbook (for spell), or wand of light */ { - char is_lit; /* value is irrelevant; we use its address - as a `not null' flag for set_lit() */ + struct obj *otmp; + boolean blessed_effect = (obj && obj->oclass == SCROLL_CLASS + && obj->blessed); + char is_lit = 0; /* value is irrelevant but assign something anyway; its + * address is used as a 'not null' flag for set_lit() */ - /* first produce the text (provided you're not blind) */ + /* update object lights and produce message (provided you're not blind) */ if (!on) { - register struct obj *otmp; + int still_lit = 0; - if (!Blind) { - if (u.uswallow) { - pline("It seems even darker in here than before."); - } else { - if (uwep && artifact_light(uwep) && uwep->lamplit) - pline("Suddenly, the only light left comes from %s!", - the(xname(uwep))); + /* + * The magic douses lamps,&c too and might curse artifact lights. + * + * FIXME? + * Shouldn't this affect all lit objects in the area of effect + * rather than just those carried by the hero? + */ + for (otmp = g.invent; otmp; otmp = otmp->nobj) { + if (otmp->lamplit) { + if (!artifact_light(otmp)) + (void) snuff_lit(otmp); else - You("are surrounded by darkness!"); + /* wielded Sunsword or worn gold dragon scales/mail; + maybe lower its BUC state if not already cursed */ + impact_arti_light(otmp, TRUE, (boolean) !Blind); + + if (otmp->lamplit) + ++still_lit; } } - - /* the magic douses lamps, et al, too */ - for (otmp = g.invent; otmp; otmp = otmp->nobj) - if (otmp->lamplit) - (void) snuff_lit(otmp); + /* scroll of light becomes discovered when not blind, so some + message to justify that is needed */ + if (Blind) { + /* for the still_lit case, we don't know at this point whether + anything currently visibly lit is going to go dark; if this + message came after the darkening, we could count visibly + lit squares before and after to know; we do know that being + swallowed won't be affected--the interior is still lit */ + if (still_lit) + pline_The("ambient light seems dimmer."); + else if (u.uswallow) + pline("It seems even darker in here than before."); + else + You("are surrounded by darkness!"); + } } else { /* on */ + if (blessed_effect) { + /* might bless artifact lights; no effect on ordinary lights */ + for (otmp = g.invent; otmp; otmp = otmp->nobj) { + if (otmp->lamplit && artifact_light(otmp)) + /* wielded Sunsword or worn gold dragon scales/mail; + maybe raise its BUC state if not already blessed */ + impact_arti_light(otmp, FALSE, (boolean) !Blind); + } + } if (u.uswallow) { if (Blind) ; /* no feedback */ @@ -2338,16 +2371,15 @@ litroom(register boolean on, struct obj* obj) if (rnum >= 0) { for (rx = g.rooms[rnum].lx - 1; rx <= g.rooms[rnum].hx + 1; rx++) - for (ry = g.rooms[rnum].ly - 1; ry <= g.rooms[rnum].hy + 1; ry++) + for (ry = g.rooms[rnum].ly - 1; + ry <= g.rooms[rnum].hy + 1; ry++) set_lit(rx, ry, (genericptr_t) (on ? &is_lit : (char *) 0)); g.rooms[rnum].rlit = on; } /* hallways remain dark on the rogue level */ } else - do_clear_area(u.ux, u.uy, - (obj && obj->oclass == SCROLL_CLASS && obj->blessed) - ? 9 : 5, + do_clear_area(u.ux, u.uy, blessed_effect ? 9 : 5, set_lit, (genericptr_t) (on ? &is_lit : (char *) 0)); /* @@ -2379,6 +2411,7 @@ litroom(register boolean on, struct obj* obj) free((genericptr_t) gremlin); } while (gremlins); } + return; } static void