From c741d6c7c950c023c8135b2211064ee0d29c5c77 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 8 Jun 2019 04:50:40 -0700 Subject: [PATCH 1/2] missile light sources Throwing or kicking a lit lamp, lit candle, or lit potion of oil wasn't giving off any light as it travelled to its destination. Now it does, and dungeon features, objects, or monsters that are temporarily seen as it moves from square to square till appear on the map. In the monster case, they go away as soon as the light moves beyond range, but when it finishes moving the "remembered, unseen monster" glyph will be drawn at their location. I think that part has some room for improvement, but mapping temporarily seen terrain features is the primary impetus for this change. Also, any message delivery while the "lit missile" travelled still showed its light around the hero. Noticeable for lamps or stacks of sufficient candles if hero has no other light source. This cannibalizes the monst->mburied bit for temporarily seeing a monster. It has been present but unused for ages. I needed to replace a couple of vision macros to make sure they didn't examine it any more so that overloading for transient lighting doesn't introduce any vision oddities. For version $NEXT, monst->mtemplit can be given its own bit. It is only set during bhit() execution and cleared by the time that returns, so has no effect on save files. --- doc/fixes36.3 | 6 +++- include/display.h | 9 ++++- include/extern.h | 4 ++- include/monst.h | 8 +++-- include/rm.h | 6 +++- include/vision.h | 26 +++++++++------ src/light.c | 84 ++++++++++++++++++++++++++++++++++++++++++++--- src/save.c | 4 ++- src/zap.c | 56 ++++++++++++++++++------------- 9 files changed, 158 insertions(+), 45 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index f538bf3b5..42e7a49cf 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.42 $ $NHDT-Date: 1559851954 2019/06/06 20:12:34 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.43 $ $NHDT-Date: 1559994620 2019/06/08 11:50:20 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -59,6 +59,10 @@ when finding a place to put a monster on the Plane of Water, don't pick a water location for flyers or floaters (levitate) or clingers (ceiling) #turn worked when unable to speak despite "you chant an arcane formula" #turn implicitly required sight due to wrong check for avoiding spanning walls +thrown or kicked light source (lit lamp, candle, oil) should emit light as it + traverses the map; dungeon features, objects, or monsters seen while + it's in transit will become part of hero's memory of the level, and + any messages delivered won't have stale light from it around the hero Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/include/display.h b/include/display.h index 9da288d67..233b84061 100644 --- a/include/display.h +++ b/include/display.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 display.h $NHDT-Date: 1546212620 2018/12/30 23:30:20 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.29 $ */ +/* NetHack 3.6 display.h $NHDT-Date: 1559994621 2019/06/08 11:50:21 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -58,11 +58,18 @@ * vobj_at() returns a pointer to an object that the hero can see there. * Infravision is not taken into account. */ +#if 0 #define mon_visible(mon) \ (/* The hero can see the monster IF the monster */ \ (!mon->minvis || See_invisible) /* 1. is not invisible */ \ && !mon->mundetected /* AND 2. not an undetected hider */ \ && !(mon->mburied || u.uburied)) /* AND 3. neither you nor it is buried */ +#else /* without 'mburied' and 'uburied' */ +#define mon_visible(mon) \ + (/* The hero can see the monster IF the monster */ \ + (!mon->minvis || See_invisible) /* 1. is not invisible */ \ + && !mon->mundetected) /* AND 2. not an undetected hider */ +#endif /* * see_with_infrared() diff --git a/include/extern.h b/include/extern.h index 5f78cb5e7..072fe60ac 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1559670600 2019/06/04 17:50:00 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.709 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1559994622 2019/06/08 11:50:22 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.711 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1064,6 +1064,8 @@ E int NDECL(dosuspend); E void FDECL(new_light_source, (XCHAR_P, XCHAR_P, int, int, ANY_P *)); E void FDECL(del_light_source, (int, ANY_P *)); E void FDECL(do_light_sources, (char **)); +E void FDECL(show_transient_light, (struct obj *, int, int)); +E void NDECL(transient_light_cleanup); E struct monst *FDECL(find_mid, (unsigned, unsigned)); E void FDECL(save_light_sources, (int, int, int)); E void FDECL(restore_light_sources, (int)); diff --git a/include/monst.h b/include/monst.h index 328bb4996..717b4eb6e 100644 --- a/include/monst.h +++ b/include/monst.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 monst.h $NHDT-Date: 1559422218 2019/06/01 20:50:18 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.31 $ */ +/* NetHack 3.6 monst.h $NHDT-Date: 1559994623 2019/06/08 11:50:23 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -97,11 +97,13 @@ struct monst { Bitfield(perminvis, 1); /* intrinsic minvis value */ Bitfield(mcan, 1); /* has been cancelled */ Bitfield(mburied, 1); /* has been buried */ +#define mtemplit mburied /* since buried isn't implemented, use bit for + * monsters shown by transcient light source; + * only valid during bhit() execution */ Bitfield(mundetected, 1); /* not seen in present hiding place; * implies one of M1_CONCEAL or M1_HIDE, * but not mimic (that is, snake, spider, - * trapper, piercer, eel) - */ + * trapper, piercer, eel) */ Bitfield(mcansee, 1); /* cansee 1, temp.blinded 0, blind 0 */ Bitfield(mspeed, 2); /* current speed */ diff --git a/include/rm.h b/include/rm.h index d6ec07819..1190a355b 100644 --- a/include/rm.h +++ b/include/rm.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 rm.h $NHDT-Date: 1547255911 2019/01/12 01:18:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */ +/* NetHack 3.6 rm.h $NHDT-Date: 1559994624 2019/06/08 11:50:24 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.61 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -624,12 +624,16 @@ extern dlevel_t level; /* structure describing the current level */ /* * Macros for encapsulation of level.monsters references. */ +#if 0 #define MON_AT(x, y) \ (level.monsters[x][y] != (struct monst *) 0 \ && !(level.monsters[x][y])->mburied) #define MON_BURIED_AT(x, y) \ (level.monsters[x][y] != (struct monst *) 0 \ && (level.monsters[x][y])->mburied) +#else /* without 'mburied' */ +#define MON_AT(x, y) (level.monsters[x][y] != (struct monst *) 0) +#endif #ifdef EXTRA_SANITY_CHECKS #define place_worm_seg(m, x, y) \ do { \ diff --git a/include/vision.h b/include/vision.h index 562f542a1..4b1f1a746 100644 --- a/include/vision.h +++ b/include/vision.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 vision.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.6 vision.h $NHDT-Date: 1559994624 2019/06/08 11:50:24 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -43,11 +43,17 @@ extern char *viz_rmax; /* max could see indices */ */ #define m_cansee(mtmp, x2, y2) clear_path((mtmp)->mx, (mtmp)->my, (x2), (y2)) -#define m_canseeu(m) \ +#if 0 +#define m_canseeu(m) \ ((!Invis || perceives((m)->data)) \ - && !(Underwater || u.uburied || (m)->mburied) \ - ? couldsee((m)->mx, (m)->my) \ - : 0) + && !(Underwater || u.uburied || (m)->mburied) \ + && couldsee((m)->mx, (m)->my)) +#else /* without 'uburied' and 'mburied' */ +#define m_canseeu(m) \ + ((!Invis || perceives((m)->data)) \ + && !Underwater \ + && couldsee((m)->mx, (m)->my)) +#endif /* * Circle information @@ -58,12 +64,12 @@ extern char *viz_rmax; /* max could see indices */ #define circle_ptr(z) (&circle_data[(int) circle_start[z]]) /* howmonseen() bitmask values */ -#define MONSEEN_NORMAL 0x0001 /* normal vision */ +#define MONSEEN_NORMAL 0x0001 /* normal vision */ #define MONSEEN_SEEINVIS 0x0002 /* seeing invisible */ #define MONSEEN_INFRAVIS 0x0004 /* via infravision */ -#define MONSEEN_TELEPAT 0x0008 /* via telepathy */ -#define MONSEEN_XRAYVIS 0x0010 /* via Xray vision */ -#define MONSEEN_DETECT 0x0020 /* via extended monster detection */ -#define MONSEEN_WARNMON 0x0040 /* via type-specific warning */ +#define MONSEEN_TELEPAT 0x0008 /* via telepathy */ +#define MONSEEN_XRAYVIS 0x0010 /* via Xray vision */ +#define MONSEEN_DETECT 0x0020 /* via extended monster detection */ +#define MONSEEN_WARNMON 0x0040 /* via type-specific warning */ #endif /* VISION_H */ diff --git a/src/light.c b/src/light.c index 446dc390e..7c2dc1f2d 100644 --- a/src/light.c +++ b/src/light.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 light.c $NHDT-Date: 1446191876 2015/10/30 07:57:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ +/* NetHack 3.6 light.c $NHDT-Date: 1559994625 2019/06/08 11:50:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Dean Luick, 1994 */ /* NetHack may be freely redistributed. See license for details. */ @@ -65,7 +65,7 @@ anything *id; return; } - ls = (light_source *) alloc(sizeof(light_source)); + ls = (light_source *) alloc(sizeof *ls); ls->next = light_base; ls->x = x; @@ -154,8 +154,8 @@ char **cs_rows; ls->flags |= LSF_SHOW; } - /* minor optimization: don't bother with duplicate light sources */ - /* at hero */ + /* minor optimization: don't bother with duplicate light sources + at hero */ if (ls->x == u.ux && ls->y == u.uy) { if (at_hero_range >= ls->range) ls->flags &= ~LSF_SHOW; @@ -192,7 +192,7 @@ char **cs_rows; * this optimization, is that it allows the vision * system to correct problems with clear_path(). * The function clear_path() is a simple LOS - * path checker that doesn't go out of its way + * path checker that doesn't go out of its way to * make things look "correct". The vision system * does this. */ @@ -210,6 +210,80 @@ char **cs_rows; } } +/* lit 'obj' has been thrown or kicked and is passing through x,y on the + way to its destination; show its light so that hero has a chance to + remember terrain, objects, and monsters being revealed */ +void +show_transient_light(obj, x, y) +struct obj *obj; +int x, y; +{ + light_source *ls; + struct monst *mon; + int radius_squared; + + /* caller has verified obj->lamplit and that hero is not Blind; + validate light source and obtain its radius (for monster sightings) */ + for (ls = light_base; ls; ls = ls->next) { + if (ls->type != LS_OBJECT) + continue; + if (ls->id.a_obj == obj) + break; + } + if (!ls || obj->where != OBJ_FREE) { + impossible("transient light %s %s is not %s?", + obj->lamplit ? "lit" : "unlit", xname(obj), + !ls ? "a light source" : "free"); + } else { + /* "expensive" but rare */ + place_object(obj, bhitpos.x, bhitpos.y); /* temporarily put on map */ + vision_recalc(0); + flush_screen(0); + delay_output(); + remove_object(obj); /* take back off of map */ + + radius_squared = ls->range * ls->range; + for (mon = fmon; mon; mon = mon->nmon) { + if (DEADMONSTER(mon)) + continue; + /* light range is the radius of a circle and we're limiting + canseemon() to a square exclosing that circle, but setting + mtemplit 'erroneously' for a seen monster is not a problem; + it just flags monsters for another canseemon() check when + 'obj' has reached its destination after missile traversal */ + if (dist2(mon->mx, mon->my, x, y) <= radius_squared + && canseemon(mon)) + mon->mtemplit = 1; + /* [what about worm tails?] */ + } + } +} + +/* draw "remembered, unseen monster" glyph at locations where a monster + was flagged for being visible during transient light movement but can't + be seen now */ +void +transient_light_cleanup() +{ + struct monst *mon; + int mtempcount = 0; + + for (mon = fmon; mon; mon = mon->nmon) { + if (DEADMONSTER(mon)) + continue; + if (mon->mtemplit) { + mon->mtemplit = 0; + ++mtempcount; + if (!canseemon(mon)) + map_invisible(mon->mx, mon->my); + } + } + if (mtempcount) { + vision_recalc(0); + flush_screen(0); + } +} + /* (mon->mx == 0) implies migrating */ #define mon_is_local(mon) ((mon)->mx > 0) diff --git a/src/save.c b/src/save.c index b1e31bc49..8bca5964a 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 save.c $NHDT-Date: 1558880688 2019/05/26 14:24:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.120 $ */ +/* NetHack 3.6 save.c $NHDT-Date: 1559994625 2019/06/08 11:50:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.121 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1078,6 +1078,8 @@ struct monst *mtmp; { int buflen; + mtmp->mtemplit = 0; /* normally clear; if set here then a panic save + * is being written while bhit() was executing */ buflen = (int) sizeof (struct monst); bwrite(fd, (genericptr_t) &buflen, sizeof buflen); bwrite(fd, (genericptr_t) mtmp, buflen); diff --git a/src/zap.c b/src/zap.c index 724dc3189..1563d434c 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1559685281 2019/06/04 21:54:41 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.310 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1559994626 2019/06/08 11:50:26 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.311 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3223,7 +3223,7 @@ int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */ struct obj **pobj; /* object tossed/used, set to NULL * if object is destroyed */ { - struct monst *mtmp; + struct monst *mtmp, *result = (struct monst *) 0; struct obj *obj = *pobj; uchar typ; boolean shopdoor = FALSE, point_blank = TRUE; @@ -3249,9 +3249,9 @@ struct obj **pobj; /* object tossed/used, set to NULL if (weapon == FLASHED_LIGHT) { tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam)); } else if (weapon == THROWN_TETHERED_WEAPON && obj) { - tethered_weapon = TRUE; - weapon = THROWN_WEAPON; /* simplify if's that follow below */ - tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng)); + tethered_weapon = TRUE; + weapon = THROWN_WEAPON; /* simplify 'if's that follow below */ + tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng)); } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng)); @@ -3272,21 +3272,25 @@ struct obj **pobj; /* object tossed/used, set to NULL if (is_pick(obj) && inside_shop(x, y) && (mtmp = shkcatch(obj, x, y)) != 0) { tmp_at(DISP_END, 0); - return mtmp; + result = mtmp; + goto bhit_done; } typ = levl[bhitpos.x][bhitpos.y].typ; - /* iron bars will block anything big enough */ - if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) - && typ == IRONBARS - && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y, - point_blank ? 0 : !rn2(5), 1)) { - /* caveat: obj might now be null... */ - obj = *pobj; - bhitpos.x -= ddx; - bhitpos.y -= ddy; - break; + /* iron bars will block anything big enough and break some things */ + if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) { + if (typ == IRONBARS + && hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y, + point_blank ? 0 : !rn2(5), 1)) { + /* caveat: obj might now be null... */ + obj = *pobj; + bhitpos.x -= ddx; + bhitpos.y -= ddy; + break; + } else if (obj->lamplit && !Blind) { + show_transient_light(obj, bhitpos.x, bhitpos.y); + } } if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) { @@ -3366,7 +3370,8 @@ struct obj **pobj; /* object tossed/used, set to NULL (void) flash_hits_mon(mtmp, obj); } else { tmp_at(DISP_END, 0); - return mtmp; /* caller will call flash_hits_mon */ + result = mtmp; /* caller will call flash_hits_mon */ + goto bhit_done; } } else if (weapon == INVIS_BEAM) { /* Like FLASHED_LIGHT, INVIS_BEAM should continue @@ -3374,8 +3379,10 @@ struct obj **pobj; /* object tossed/used, set to NULL prepared for multiple hits so just get first one that's either visible or could see its invisible self. [No tmp_at() cleanup is needed here.] */ - if (!mtmp->minvis || perceives(mtmp->data)) - return mtmp; + if (!mtmp->minvis || perceives(mtmp->data)) { + result = mtmp; + goto bhit_done; + } } else if (weapon != ZAPPED_WAND) { /* THROWN_WEAPON, KICKED_WEAPON */ @@ -3384,7 +3391,8 @@ struct obj **pobj; /* object tossed/used, set to NULL if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); - return mtmp; + result = mtmp; + goto bhit_done; } else { /* ZAPPED_WAND */ (*fhitm)(mtmp, obj); @@ -3407,7 +3415,7 @@ struct obj **pobj; /* object tossed/used, set to NULL || ship_object(obj, bhitpos.x, bhitpos.y, costly_spot(bhitpos.x, bhitpos.y)))) { tmp_at(DISP_END, 0); - return (struct monst *) 0; + goto bhit_done; /* result == (struct monst *) 0 */ } } if (weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) { @@ -3490,7 +3498,11 @@ struct obj **pobj; /* object tossed/used, set to NULL if (shopdoor) pay_for_damage("destroy", FALSE); - return (struct monst *) 0; + bhit_done: + if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) + transient_light_cleanup(); + + return result; } /* process thrown boomerang, which travels a curving path... From 7ea69225e992aa9dbcf8cae73b8b3cf7863a34b7 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 8 Jun 2019 05:58:42 -0700 Subject: [PATCH 2/2] fix github issue #198 - mon wielding cursed weapon Fixes #198 Watching a monster try to switch from a cursed weapon to some other weapon (of any bless/curse state) reported that the old weapon was welded to the monster's hand and wouldn't switch to the new one. But watching a monster try to wield a cursed weapon didn't say that it was becoming welded at the time. Report correctly pointed out that the weld-to-hand check wouldn't work unless the weapon was already flagged as wielded, and the code in question was deferring wielding so that the message wouldn't include "(weapon in hand)" in the formatted object description. There was also another problem: it was erroneously testing the monster's old weapon (if any, after unwielding it), instead of the new one being wielded. Also, Sunsword starting to emit light when first wielded by a monster only reported that it was shining if hero could see the monster. Give an alternate message if hero sees the location instead. (Just the monster's/Sunsword's location rather than any newly lit spot within Sunsword's radius.) --- doc/fixes36.3 | 5 ++++- src/weapon.c | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 42e7a49cf..2a267fe74 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.43 $ $NHDT-Date: 1559994620 2019/06/08 11:50:20 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.44 $ $NHDT-Date: 1559998716 2019/06/08 12:58:36 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -63,6 +63,9 @@ thrown or kicked light source (lit lamp, candle, oil) should emit light as it traverses the map; dungeon features, objects, or monsters seen while it's in transit will become part of hero's memory of the level, and any messages delivered won't have stale light from it around the hero +unlike watching a monster trying to swap out a cursed weapon for some other + weapon and failing, watching it wield a cursed weapon didn't report + that weapon becoming welded to the monster's hand/claw/whatever Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/src/weapon.c b/src/weapon.c index 3e817a7a3..102740933 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 weapon.c $NHDT-Date: 1548209744 2019/01/23 02:15:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.69 $ */ +/* NetHack 3.6 weapon.c $NHDT-Date: 1559998716 2019/06/08 12:58:36 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -831,8 +831,18 @@ register struct monst *mon; setmnotwielded(mon, mw_tmp); mon->weapon_check = NEED_WEAPON; if (canseemon(mon)) { + boolean newly_welded; + pline("%s wields %s!", Monnam(mon), doname(obj)); - if (mwelded(mw_tmp)) { + /* 3.6.3: mwelded() predicate expects the object to have its + W_WEP bit set in owormmask, but the pline here and for + artifact_light don't want that because they'd have '(weapon + in hand/claw)' appended; so we set it for the mwelded test + and then clear it, until finally setting it for good below */ + obj->owornmask |= W_WEP; + newly_welded = mwelded(obj); + obj->owornmask &= ~W_WEP; + if (newly_welded) { pline("%s %s to %s %s!", Tobjnam(obj, "weld"), is_plural(obj) ? "themselves" : "itself", s_suffix(mon_nam(mon)), mbodypart(mon, HAND)); @@ -845,6 +855,12 @@ register struct monst *mon; pline("%s %s in %s %s!", Tobjnam(obj, "shine"), arti_light_description(obj), s_suffix(mon_nam(mon)), mbodypart(mon, HAND)); + /* 3.6.3: artifact might be getting wielded by invisible monst */ + else if (cansee(mon->mx, mon->my)) + pline("Light begins shining %s.", + (distu(mon->mx, mon->my) <= 5 * 5) + ? "nearby" + : "in the distance"); } obj->owornmask = W_WEP; return 1;