Buff Grimtooth with poison
Grimtooth is now permanently poisoned, protects the wielder from poison, and can be invoked to throw poison. Permapoison code comes from xNetHack by copperwater <aosdict@gmail.com>.
This commit is contained in:
@@ -1507,6 +1507,7 @@ since introduction in 3.1.0, the definition for Mitre of Holiness has specified
|
||||
if a tree and a boulder or statue were at the same location, applying an axe
|
||||
would break the boulder or statue rather than chop the tree
|
||||
avoid premapping outside Sokoban map to prevent showing stone glyphs
|
||||
Grimtooth is permanently poisoned, protects from poison, and can fling poison
|
||||
|
||||
|
||||
Fixes to 3.7.0-x General Problems Exposed Via git Repository
|
||||
|
||||
@@ -67,6 +67,7 @@ enum invoke_prop_types {
|
||||
ENLIGHTENING,
|
||||
CREATE_AMMO,
|
||||
BANISH,
|
||||
FLING_POISON,
|
||||
BLINDING_RAY
|
||||
};
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ static const char *const artifact_names[] = {
|
||||
#define FIRE(a,b) {0,AD_FIRE,a,b}
|
||||
#define ELEC(a,b) {0,AD_ELEC,a,b} /* electrical shock */
|
||||
#define STUN(a,b) {0,AD_STUN,a,b} /* magical attack */
|
||||
#define POIS(a,b) {0,AD_DRST,a,b} /* poison */
|
||||
/* clang-format on */
|
||||
|
||||
static NEARDATA struct artifact artilist[] = {
|
||||
@@ -120,9 +121,9 @@ static NEARDATA struct artifact artilist[] = {
|
||||
* (handled as special case in spec_dbon()).
|
||||
*/
|
||||
A("Grimtooth", ORCISH_DAGGER, (SPFX_RESTR | SPFX_WARN | SPFX_DFLAG2),
|
||||
0, M2_ELF, PHYS(2, 6), NO_DFNS,
|
||||
NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC,
|
||||
0, 5, 300L, CLR_RED, GRIMTOOTH),
|
||||
0, M2_ELF, PHYS(2, 6), POIS(0,0),
|
||||
NO_CARY, FLING_POISON, A_CHAOTIC, NON_PM, PM_ORC,
|
||||
0, 5, 1200L, CLR_RED, GRIMTOOTH),
|
||||
/*
|
||||
* Orcrist and Sting have same alignment as elves.
|
||||
*
|
||||
|
||||
@@ -183,6 +183,7 @@ extern void mkot_trap_warn(void);
|
||||
extern boolean is_magic_key(struct monst *, struct obj *);
|
||||
extern struct obj *has_magic_key(struct monst *);
|
||||
extern boolean is_art(struct obj *, int);
|
||||
extern boolean permapoisoned(struct obj *);
|
||||
|
||||
/* ### attrib.c ### */
|
||||
|
||||
|
||||
@@ -254,10 +254,11 @@ struct obj {
|
||||
(otmp->oclass == WEAPON_CLASS \
|
||||
&& objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
|
||||
&& objects[otmp->otyp].oc_skill <= -P_BOW)
|
||||
#define is_poisonable(otmp) \
|
||||
(otmp->oclass == WEAPON_CLASS \
|
||||
&& objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
|
||||
&& objects[otmp->otyp].oc_skill <= -P_BOW)
|
||||
#define is_poisonable(otmp) \
|
||||
((otmp->oclass == WEAPON_CLASS \
|
||||
&& objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
|
||||
&& objects[otmp->otyp].oc_skill <= -P_BOW) \
|
||||
|| permapoisoned(otmp))
|
||||
#define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
|
||||
/* 'is_quest_artifact()' only applies to the current role's artifact */
|
||||
#define any_quest_artifact(o) ((o)->oartifact >= ART_ORB_OF_DETECTION)
|
||||
|
||||
@@ -283,6 +283,8 @@ mk_artifact(
|
||||
otmp = 0;
|
||||
} /* otherwise, otmp has not changed; just fallthrough to return it */
|
||||
}
|
||||
if (permapoisoned(otmp))
|
||||
otmp->opoisoned = 1;
|
||||
return otmp;
|
||||
}
|
||||
|
||||
@@ -2009,6 +2011,19 @@ arti_invoke(struct obj *obj)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FLING_POISON:
|
||||
if (getdir((char *) 0)) {
|
||||
int venom = rn2(2) ? BLINDING_VENOM : ACID_VENOM;
|
||||
struct obj *otmp = mksobj(venom, TRUE, FALSE);
|
||||
|
||||
otmp->spe = 1; /* the poison is yours */
|
||||
throwit(otmp, 0L, FALSE, (struct obj *) 0);
|
||||
} else {
|
||||
/* no direction picked */
|
||||
pline("%s", Never_mind);
|
||||
obj->age = svm.moves;
|
||||
}
|
||||
break;
|
||||
case BLINDING_RAY:
|
||||
if (getdir((char *) 0)) {
|
||||
if (u.dx || u.dy) {
|
||||
@@ -2699,4 +2714,11 @@ get_artifact(struct obj *obj)
|
||||
}
|
||||
return &artilist[ART_NONARTIFACT];
|
||||
}
|
||||
|
||||
/* is object permanently poisoned? (currently only Grimtooth) */
|
||||
boolean
|
||||
permapoisoned(struct obj *obj)
|
||||
{
|
||||
return (obj && is_art(obj, ART_GRIMTOOTH));
|
||||
}
|
||||
/*artifact.c*/
|
||||
|
||||
@@ -1160,6 +1160,8 @@ mksobj_init(struct obj **obj, boolean artif)
|
||||
}
|
||||
|
||||
mkobj_erosions(otmp);
|
||||
if (permapoisoned(otmp))
|
||||
otmp->opoisoned = 1;
|
||||
}
|
||||
|
||||
/* mksobj(): create a specific type of object; result is always non-Null */
|
||||
|
||||
@@ -5338,6 +5338,9 @@ readobjnam(char *bp, struct obj *no_wish)
|
||||
}
|
||||
}
|
||||
|
||||
if (permapoisoned(d.otmp))
|
||||
d.otmp->opoisoned = 1;
|
||||
|
||||
/* more wishing abuse: don't allow wishing for certain artifacts */
|
||||
/* and make them pay; charge them for the wish anyway! */
|
||||
if ((is_quest_artifact(d.otmp)
|
||||
|
||||
@@ -2595,9 +2595,10 @@ potion_dip(struct obj *obj, struct obj *potion)
|
||||
obj->opoisoned = TRUE;
|
||||
poof(potion);
|
||||
return ECMD_TIME;
|
||||
} else if (obj->opoisoned && (potion->otyp == POT_HEALING
|
||||
|| potion->otyp == POT_EXTRA_HEALING
|
||||
|| potion->otyp == POT_FULL_HEALING)) {
|
||||
} else if (obj->opoisoned && !permapoisoned(obj)
|
||||
&& (potion->otyp == POT_HEALING
|
||||
|| potion->otyp == POT_EXTRA_HEALING
|
||||
|| potion->otyp == POT_FULL_HEALING)) {
|
||||
pline("A coating wears off %s.", the(xname(obj)));
|
||||
obj->opoisoned = 0;
|
||||
poof(potion);
|
||||
|
||||
70
src/uhitm.c
70
src/uhitm.c
@@ -13,6 +13,8 @@ staticfn boolean mhitm_mgc_atk_negated(struct monst *, struct monst *,
|
||||
staticfn boolean known_hitum(struct monst *, struct obj *, int *, int, int,
|
||||
struct attack *, int) NONNULLARG13;
|
||||
staticfn boolean theft_petrifies(struct obj *) NONNULLARG1;
|
||||
staticfn void mhitm_really_poison(struct monst *, struct attack *,
|
||||
struct monst *, struct mhitm_data *);
|
||||
staticfn void steal_it(struct monst *, struct attack *) NONNULLARG1;
|
||||
/* hitum_cleave() has contradictory information. There's a comment
|
||||
* beside the 1st arg 'target' stating non-null, but later on there
|
||||
@@ -1036,6 +1038,9 @@ hmon_hitmon_weapon_melee(
|
||||
if (obj->opoisoned && is_poisonable(obj))
|
||||
hmd->ispoisoned = TRUE;
|
||||
}
|
||||
/* permapoisoned is non-ammo/missile, limit the poison */
|
||||
if (permapoisoned(obj) && hmd->dieroll <= 5)
|
||||
hmd->ispoisoned = TRUE;
|
||||
}
|
||||
|
||||
staticfn void
|
||||
@@ -1484,7 +1489,7 @@ hmon_hitmon_poison(
|
||||
You_feel("like an evil coward for using a poisoned weapon.");
|
||||
adjalign(-1);
|
||||
}
|
||||
if (!rn2(nopoison)) {
|
||||
if (!permapoisoned(obj) && !rn2(nopoison)) {
|
||||
/* remove poison now in case obj ends up in a bones file */
|
||||
obj->opoisoned = FALSE;
|
||||
/* defer "obj is no longer poisoned" until after hit message */
|
||||
@@ -3026,6 +3031,29 @@ mhitm_ad_curs(
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper for mhitm_ad_drst(), containing some code that is also called from
|
||||
* mhitm_ad_phys (for poisoned weapons) and shouldn't be subject to magic
|
||||
* cancellation or a 1/8 chance roll.
|
||||
* In this specific case, the "mhitm" in the name ACTUALLY means just that -
|
||||
* this should be called only for monster versus monster situations. */
|
||||
staticfn void
|
||||
mhitm_really_poison(struct monst *magr, struct attack *mattk,
|
||||
struct monst *mdef, struct mhitm_data *mhm)
|
||||
{
|
||||
if (gv.vis && canspotmon(magr))
|
||||
pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
|
||||
mpoisons_subj(magr, mattk));
|
||||
if (resists_poison(mdef)) {
|
||||
if (gv.vis && canspotmon(mdef) && canspotmon(magr))
|
||||
pline_The("poison doesn't seem to affect %s.",
|
||||
mon_nam(mdef));
|
||||
} else {
|
||||
mhm->damage += rn1(10, 6);
|
||||
if (mhm->damage >= mdef->mhp && gv.vis && canspotmon(mdef))
|
||||
pline_The("poison was deadly...");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mhitm_ad_drst(
|
||||
struct monst *magr, struct attack *mattk,
|
||||
@@ -3067,22 +3095,7 @@ mhitm_ad_drst(
|
||||
} else {
|
||||
/* mhitm */
|
||||
if (!negated && !rn2(8)) {
|
||||
if (gv.vis && canspotmon(magr))
|
||||
pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
|
||||
mpoisons_subj(magr, mattk));
|
||||
if (resists_poison(mdef)) {
|
||||
if (gv.vis && canspotmon(mdef) && canspotmon(magr))
|
||||
pline_The("poison doesn't seem to affect %s.",
|
||||
mon_nam(mdef));
|
||||
} else {
|
||||
if (rn2(10)) {
|
||||
mhm->damage += rn1(10, 6);
|
||||
} else {
|
||||
if (gv.vis && canspotmon(mdef))
|
||||
pline_The("poison was deadly...");
|
||||
mhm->damage = mdef->mhp;
|
||||
}
|
||||
}
|
||||
mhitm_really_poison(magr, mattk, mdef, mhm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3957,6 +3970,7 @@ mhitm_ad_phys(
|
||||
if (mattk->aatyp == AT_WEAP && otmp) {
|
||||
struct obj *marmg;
|
||||
int tmp;
|
||||
boolean was_poisoned = (otmp->opoisoned || permapoisoned(otmp));
|
||||
|
||||
if (otmp->otyp == CORPSE
|
||||
&& touch_petrifies(&mons[otmp->corpsenm])) {
|
||||
@@ -4015,6 +4029,21 @@ mhitm_ad_phys(
|
||||
You("divide as %s hits you!", mon_nam(magr));
|
||||
}
|
||||
rustm(&gy.youmonst, otmp);
|
||||
if (was_poisoned && gm.mhitu_dieroll <= 5) {
|
||||
char buf[BUFSZ];
|
||||
|
||||
/* similar to mhitm_really_poison, but we don't use the
|
||||
* exact same values, nor do we want the same 1/8 chance of
|
||||
* the poison taking (use 1/4, same as in the mhitm case). */
|
||||
Sprintf(buf, "%s %s", s_suffix(Monnam(magr)),
|
||||
mpoisons_subj(magr, mattk));
|
||||
/* arbitrary, but most poison sources in the game are
|
||||
* strength-based. With hpdamchance = 10, HP damage occurs
|
||||
* 1/2 of the time and it will hit Str the rest of the time.
|
||||
* (This is the same as poisoned ammo.) */
|
||||
poisoned(buf, A_STR, pmname(magr->data, Mgender(magr)),
|
||||
10, FALSE);
|
||||
}
|
||||
} else if (mattk->aatyp != AT_TUCH || mhm->damage != 0
|
||||
|| magr != u.ustuck) {
|
||||
hitmsg(magr, mattk);
|
||||
@@ -4077,6 +4106,13 @@ mhitm_ad_phys(
|
||||
}
|
||||
if (mhm->damage)
|
||||
rustm(mdef, mwep);
|
||||
if ((mwep->opoisoned || permapoisoned(mwep)) && !rn2(4)) {
|
||||
/* 1/4 chance of weapon poison applying is the same as in
|
||||
* uhitm and mhitu cases. But since we don't need to call
|
||||
* any special functions or go through tangled hmon_hitmon
|
||||
* code, we can just jump straight to the poisoning. */
|
||||
mhitm_really_poison(magr, mattk, mdef, mhm);
|
||||
}
|
||||
} else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) {
|
||||
/* hack to enhance mm_aggression(); we don't want purple
|
||||
worm's bite attack to kill a shrieker because then it
|
||||
|
||||
Reference in New Issue
Block a user