From bbb81700f543c85f8209e6c05ce77d7e5b3e5f46 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 22 Sep 2018 14:08:28 -0400 Subject: [PATCH] sunsword vs gremlin The original report complained that gremlins seemed impervious to Sunsword's light yet a flash from a camera caused them to cry out in pain despite "The long sword named Sunsword begins to shine brilliantly!" This commit does two things: 1. A dmg bonus is applied against gremlins using a lit Sunsword. 2. Gremlins will generally avoid the light emitted by Sunsword. There's a few minor flavor bits thrown in also. It is understood that this effectively makes Sunsword provide "gremlin-proofing", but the gremlin myth and Sunsword's characteristic feature pretty much demand it. bug 42 --- doc/fixes36.2 | 2 ++ include/extern.h | 1 + include/mondata.h | 2 ++ src/mondata.c | 8 ++++++++ src/monmove.c | 23 ++++++++++++++++++++--- src/uhitm.c | 31 ++++++++++++++++++++++++++++++- src/weapon.c | 2 ++ 7 files changed, 65 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 29280ce7a..ecb6baa93 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -131,6 +131,8 @@ wishing for "orange" could yield orange or orange colored gem/potion/spellbook a sleeping or paralyzed mon would be frightened by its reflection when applying a mirror prevent leash showing unseen monster as "attached to it" +gremlins seemed impervious to Sunsword's light yet a flash from a camera + caused them to cry out in pain Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 7e1fb1270..b241ac074 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1438,6 +1438,7 @@ FDECL(can_blnd, (struct monst *, struct monst *, UCHAR_P, struct obj *)); E boolean FDECL(ranged_attk, (struct permonst *)); E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(mon_hates_silver, (struct monst *)); +E boolean FDECL(mon_hates_light, (struct monst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_blow, (struct monst *)); E boolean FDECL(can_chant, (struct monst *)); diff --git a/include/mondata.h b/include/mondata.h index 95153ce5d..0b1df5ccc 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -175,6 +175,8 @@ #define is_vampire(ptr) ((ptr)->mlet == S_VAMPIRE) +#define hates_light(ptr) ((ptr) == &mons[PM_GREMLIN]) + /* used to vary a few messages */ #define weirdnonliving(ptr) (is_golem(ptr) || (ptr)->mlet == S_VORTEX) #define nonliving(ptr) \ diff --git a/src/mondata.c b/src/mondata.c index 2a6134863..9a65c1480 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -312,6 +312,14 @@ register struct permonst *ptr; || (ptr->mlet == S_IMP && ptr != &mons[PM_TENGU])); } +/* True if specific monster is especially affected by light-emitting weapons */ +boolean +mon_hates_light(mon) +struct monst *mon; +{ + return (boolean) (hates_light(mon->data)); +} + /* True iff the type of monster pass through iron bars */ boolean passes_bars(mptr) diff --git a/src/monmove.c b/src/monmove.c index 90b4f33c1..762b4ecb9 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -255,6 +255,14 @@ struct monst *mon; } } +#define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN] && \ + (uwep && artifact_light(uwep) && uwep->lamplit)) + +/* we could include this in the above macro, but probably overkill/overhead */ +/* (!((which_armor((mon), W_ARMC) != 0) && ((which_armor((mon), W_ARMH) != 0))) && */ + + + /* monster begins fleeing for the specified time, 0 means untimed flee * if first, only adds fleetime if monster isn't already fleeing * if fleemsg, prints a message about new flight, otherwise, caller should */ @@ -289,9 +297,15 @@ boolean fleemsg; /* unfortunately we can't distinguish between temporary sleep and temporary paralysis, so both conditions receive the same alternate message */ - if (!mtmp->mcanmove || !mtmp->data->mmove) + if (!mtmp->mcanmove || !mtmp->data->mmove) { pline("%s seems to flinch.", Adjmonnam(mtmp, "immobile")); - else + } else if (flees_light(mtmp)) { + if (rn2(10) || Deaf) + pline("%s flees from the painful light of %s.", + Monnam(mtmp), bare_artifactname(uwep)); + else + verbalize("Bright light!"); + } else pline("%s turns to flee.", Monnam(mtmp)); } mtmp->mflee = 1; @@ -306,7 +320,7 @@ register struct monst *mtmp; int *inrange, *nearby, *scared; { int seescaryx, seescaryy; - boolean sawscary = FALSE; + boolean sawscary = FALSE, bravegremlin = (rn2(5) == 0); *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (BOLT_LIM * BOLT_LIM)); @@ -329,6 +343,7 @@ int *inrange, *nearby, *scared; sawscary = onscary(seescaryx, seescaryy, mtmp); if (*nearby && (sawscary + || (flees_light(mtmp) && !bravegremlin) || (!mtmp->mpeaceful && in_your_sanctuary(mtmp, 0, 0)))) { *scared = 1; monflee(mtmp, rnd(rn2(7) ? 10 : 100), TRUE, TRUE); @@ -336,6 +351,8 @@ int *inrange, *nearby, *scared; *scared = 0; } +#undef flees_light + /* perform a special one-time action for a monster; returns -1 if nothing special happened, 0 if monster uses up its turn, 1 if monster is killed */ STATIC_OVL int diff --git a/src/uhitm.c b/src/uhitm.c index b240eef26..5dd5b8623 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -658,6 +658,7 @@ int dieroll; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE, unpoisonmsg = FALSE; boolean silvermsg = FALSE, silverobj = FALSE; + boolean lightobj = FALSE; boolean valid_weapon_attack = FALSE; boolean unarmed = !uwep && !uarm && !uarms; boolean hand_to_hand = (thrown == HMON_MELEE @@ -699,7 +700,10 @@ int dieroll; } } } else { - Strcpy(saved_oname, cxname(obj)); + if (!(artifact_light(obj) && obj->lamplit)) + Strcpy(saved_oname, cxname(obj)); + else + Strcpy(saved_oname, bare_artifactname(obj)); if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { /* is it not a melee weapon? */ @@ -803,6 +807,8 @@ int dieroll; silvermsg = TRUE; silverobj = TRUE; } + if (artifact_light(obj) && obj->lamplit && mon_hates_light(mon)) + lightobj = TRUE; if (u.usteed && !thrown && tmp > 0 && weapon_type(obj) == P_LANCE && mon != u.ustuck) { jousting = joust(mon, obj); @@ -1251,6 +1257,29 @@ int dieroll; whom = strcat(s_suffix(whom), " flesh"); pline(fmt, whom); } + if (lightobj) { + const char *fmt; + char *whom = mon_nam(mon); + char emitlightobjbuf[BUFSZ]; + + if (canspotmon(mon)) { + if (saved_oname[0]) { + Sprintf(emitlightobjbuf, + "%s radiance penetrates deep into", + s_suffix(saved_oname)); + Strcat(emitlightobjbuf, " %s!"); + fmt = emitlightobjbuf; + } else + fmt = "The light sears %s!"; + } else { + *whom = highc(*whom); /* "it" -> "It" */ + fmt = "%s is seared!"; + } + /* note: s_suffix returns a modifiable buffer */ + if (!noncorporeal(mdat) && !amorphous(mdat)) + whom = strcat(s_suffix(whom), " flesh"); + pline(fmt, whom); + } /* if a "no longer poisoned" message is coming, it will be last; obj->opoisoned was cleared above and any message referring to "poisoned " has now been given; we want just "" for diff --git a/src/weapon.c b/src/weapon.c index 2b7b3bf0a..b680f864c 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -329,6 +329,8 @@ struct monst *mon; bonus += rnd(4); if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon)) bonus += rnd(20); + if (artifact_light(otmp) && otmp->lamplit && hates_light(ptr)) + bonus += rnd(8); /* if the weapon is going to get a double damage bonus, adjust this bonus so that effectively it's added after the doubling */ -- 2.40.0