opening magic vs holding monster
Zapping wand of opening or spell of knock at engulfer while swallowed would make the engulfer expel the hero; this change makes zapping other holders release their hold. Zapping self now achieves the same effect, as does breaking a non-empty wand of opening. When poly'd hero is holding a monster rather than being held, that monster will be released. Engulfers can't re-engulf for 1 or 2 turns after releasing the hero in order to prevent hero from being immediately re-engulfed. Impose the same limitation on other holders.
This commit is contained in:
@@ -452,6 +452,8 @@ turn off input autocompletion for '#twoweapon' since simple 'X' invokes it;
|
|||||||
if a branch has only one level (Fort Ludios), prevent creation of any level
|
if a branch has only one level (Fort Ludios), prevent creation of any level
|
||||||
teleporters there (level definition doesn't have any but wizard mode
|
teleporters there (level definition doesn't have any but wizard mode
|
||||||
wishing could attempt to place one)
|
wishing could attempt to place one)
|
||||||
|
opening/unlocking magic zapped at monster holding the hero will release hold
|
||||||
|
(zap at engulfer already expels hero); zapping at self has same effect
|
||||||
|
|
||||||
|
|
||||||
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
|
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
|
||||||
|
|||||||
@@ -3123,6 +3123,7 @@ extern int dowrite(struct obj *);
|
|||||||
|
|
||||||
extern void learnwand(struct obj *);
|
extern void learnwand(struct obj *);
|
||||||
extern int bhitm(struct monst *, struct obj *);
|
extern int bhitm(struct monst *, struct obj *);
|
||||||
|
extern void release_hold(void);
|
||||||
extern void probe_monster(struct monst *);
|
extern void probe_monster(struct monst *);
|
||||||
extern boolean get_obj_location(struct obj *, xchar *, xchar *, int);
|
extern boolean get_obj_location(struct obj *, xchar *, xchar *, int);
|
||||||
extern boolean get_mon_location(struct monst *, xchar *, xchar *, int);
|
extern boolean get_mon_location(struct monst *, xchar *, xchar *, int);
|
||||||
|
|||||||
13
src/apply.c
13
src/apply.c
@@ -3480,12 +3480,19 @@ do_break_wand(struct obj *obj)
|
|||||||
affects_objects = FALSE;
|
affects_objects = FALSE;
|
||||||
|
|
||||||
switch (obj->otyp) {
|
switch (obj->otyp) {
|
||||||
|
case WAN_OPENING:
|
||||||
|
if (u.ustuck) {
|
||||||
|
release_hold();
|
||||||
|
if (obj->dknown)
|
||||||
|
makeknown(WAN_OPENING);
|
||||||
|
goto discard_broken_wand;
|
||||||
|
}
|
||||||
|
/*FALLTHRU*/
|
||||||
case WAN_WISHING:
|
case WAN_WISHING:
|
||||||
case WAN_NOTHING:
|
case WAN_NOTHING:
|
||||||
case WAN_LOCKING:
|
case WAN_LOCKING:
|
||||||
case WAN_PROBING:
|
case WAN_PROBING:
|
||||||
case WAN_ENLIGHTENMENT:
|
case WAN_ENLIGHTENMENT:
|
||||||
case WAN_OPENING:
|
|
||||||
case WAN_SECRET_DOOR_DETECTION:
|
case WAN_SECRET_DOOR_DETECTION:
|
||||||
pline(nothing_else_happens);
|
pline(nothing_else_happens);
|
||||||
goto discard_broken_wand;
|
goto discard_broken_wand;
|
||||||
@@ -3502,7 +3509,7 @@ do_break_wand(struct obj *obj)
|
|||||||
dmg *= 2;
|
dmg *= 2;
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
case WAN_MAGIC_MISSILE:
|
case WAN_MAGIC_MISSILE:
|
||||||
wanexpl:
|
wanexpl:
|
||||||
explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype);
|
explode(u.ux, u.uy, -(obj->otyp), dmg, WAND_CLASS, expltype);
|
||||||
makeknown(obj->otyp); /* explode describes the effect */
|
makeknown(obj->otyp); /* explode describes the effect */
|
||||||
goto discard_broken_wand;
|
goto discard_broken_wand;
|
||||||
@@ -3633,7 +3640,7 @@ do_break_wand(struct obj *obj)
|
|||||||
if (obj->otyp == WAN_LIGHT)
|
if (obj->otyp == WAN_LIGHT)
|
||||||
litroom(TRUE, obj); /* only needs to be done once */
|
litroom(TRUE, obj); /* only needs to be done once */
|
||||||
|
|
||||||
discard_broken_wand:
|
discard_broken_wand:
|
||||||
obj = g.current_wand; /* [see dozap() and destroy_item()] */
|
obj = g.current_wand; /* [see dozap() and destroy_item()] */
|
||||||
g.current_wand = 0;
|
g.current_wand = 0;
|
||||||
if (obj)
|
if (obj)
|
||||||
|
|||||||
14
src/mhitu.c
14
src/mhitu.c
@@ -298,8 +298,14 @@ getmattk(struct monst *magr, struct monst *mdef,
|
|||||||
/* note: 3d9 is slightly higher than previous 4d6 */
|
/* note: 3d9 is slightly higher than previous 4d6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
|
/* holders/engulfers who release the hero have mspec_used set to rnd(2)
|
||||||
/* can't re-engulf yet; switch to simpler attack */
|
and can't re-hold/re-engulf until it has been decremented to zero */
|
||||||
|
} else if (magr->mspec_used && (attk->aatyp == AT_ENGL
|
||||||
|
|| attk->aatyp == AT_HUGS
|
||||||
|
|| attk->adtyp == AD_STCK)) {
|
||||||
|
boolean wimpy = (attk->damd == 0); /* lichen, violet fungus */
|
||||||
|
|
||||||
|
/* can't re-engulf or re-grab yet; switch to simpler attack */
|
||||||
*alt_attk_buf = *attk;
|
*alt_attk_buf = *attk;
|
||||||
attk = alt_attk_buf;
|
attk = alt_attk_buf;
|
||||||
if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
|
if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
|
||||||
@@ -311,6 +317,10 @@ getmattk(struct monst *magr, struct monst *mdef,
|
|||||||
}
|
}
|
||||||
attk->damn = 1; /* relatively weak: 1d6 */
|
attk->damn = 1; /* relatively weak: 1d6 */
|
||||||
attk->damd = 6;
|
attk->damd = 6;
|
||||||
|
if (wimpy && attk->aatyp == AT_CLAW) {
|
||||||
|
attk->aatyp = AT_TUCH;
|
||||||
|
attk->damn = attk->damd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* barrow wight, Nazgul, erinys have weapon attack for non-physical
|
/* barrow wight, Nazgul, erinys have weapon attack for non-physical
|
||||||
damage; force physical damage if attacker has been cancelled or
|
damage; force physical damage if attacker has been cancelled or
|
||||||
|
|||||||
15
src/mon.c
15
src/mon.c
@@ -2725,6 +2725,8 @@ void
|
|||||||
unstuck(struct monst* mtmp)
|
unstuck(struct monst* mtmp)
|
||||||
{
|
{
|
||||||
if (u.ustuck == mtmp) {
|
if (u.ustuck == mtmp) {
|
||||||
|
struct permonst *ptr = mtmp->data;
|
||||||
|
|
||||||
/* do this first so that docrt()'s botl update is accurate;
|
/* do this first so that docrt()'s botl update is accurate;
|
||||||
safe to do as long as u.uswallow is also cleared before docrt() */
|
safe to do as long as u.uswallow is also cleared before docrt() */
|
||||||
set_ustuck((struct monst *) 0);
|
set_ustuck((struct monst *) 0);
|
||||||
@@ -2738,11 +2740,16 @@ unstuck(struct monst* mtmp)
|
|||||||
placebc();
|
placebc();
|
||||||
g.vision_full_recalc = 1;
|
g.vision_full_recalc = 1;
|
||||||
docrt();
|
docrt();
|
||||||
/* prevent swallower (mtmp might have just poly'd into something
|
|
||||||
without an engulf attack) from immediately re-engulfing */
|
|
||||||
if (attacktype(mtmp->data, AT_ENGL) && !mtmp->mspec_used)
|
|
||||||
mtmp->mspec_used = rnd(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prevent holder/engulfer from immediately re-holding/re-engulfing
|
||||||
|
[note: this call to unstuck() might be because u.ustuck has just
|
||||||
|
changed shape and doesn't have a holding attack any more, hence
|
||||||
|
don't set mspec_used uncondtionally] */
|
||||||
|
if (!mtmp->mspec_used && (dmgtype(ptr, AD_STCK)
|
||||||
|
|| attacktype(ptr, AT_ENGL)
|
||||||
|
|| attacktype(ptr, AT_HUGS)))
|
||||||
|
mtmp->mspec_used = rnd(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2689,7 +2689,7 @@ mhitm_ad_stck(struct monst *magr, struct attack *mattk, struct monst *mdef,
|
|||||||
boolean negated = !(rn2(10) >= 3 * armpro);
|
boolean negated = !(rn2(10) >= 3 * armpro);
|
||||||
|
|
||||||
if (!negated && !sticks(pd) && distu(mdef->mx, mdef->my) <= 2)
|
if (!negated && !sticks(pd) && distu(mdef->mx, mdef->my) <= 2)
|
||||||
u.ustuck = mdef; /* it's now stuck to you */
|
set_ustuck(mdef); /* it's now stuck to you */
|
||||||
} else if (mdef == &g.youmonst) {
|
} else if (mdef == &g.youmonst) {
|
||||||
/* mhitu */
|
/* mhitu */
|
||||||
int armpro = magic_negation(mdef);
|
int armpro = magic_negation(mdef);
|
||||||
|
|||||||
62
src/zap.c
62
src/zap.c
@@ -318,17 +318,15 @@ bhitm(struct monst *mtmp, struct obj *otmp)
|
|||||||
case WAN_OPENING:
|
case WAN_OPENING:
|
||||||
case SPE_KNOCK:
|
case SPE_KNOCK:
|
||||||
wake = FALSE; /* don't want immediate counterattack */
|
wake = FALSE; /* don't want immediate counterattack */
|
||||||
if (u.uswallow && mtmp == u.ustuck) {
|
if (mtmp == u.ustuck) {
|
||||||
if (is_animal(mtmp->data)) {
|
/* zapping either holder/holdee or self [zapyourself()] will
|
||||||
if (Blind)
|
release hero from holder's grasp or holdee from hero's grasp */
|
||||||
You_feel("a sudden rush of air!");
|
release_hold();
|
||||||
else
|
learn_it = TRUE;
|
||||||
pline("%s opens its mouth!", Monnam(mtmp));
|
|
||||||
}
|
/* zap which hits steed will only release saddle if it
|
||||||
expels(mtmp, mtmp->data, TRUE);
|
doesn't hit a holding or falling trap; playability
|
||||||
/* zap which hits steed will only release saddle if it
|
here overrides the more logical target ordering */
|
||||||
doesn't hit a holding or falling trap; playability
|
|
||||||
here overrides the more logical target ordering */
|
|
||||||
} else if (openholdingtrap(mtmp, &learn_it)) {
|
} else if (openholdingtrap(mtmp, &learn_it)) {
|
||||||
break;
|
break;
|
||||||
} else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
|
} else if (openfallingtrap(mtmp, TRUE, &learn_it)) {
|
||||||
@@ -471,6 +469,42 @@ bhitm(struct monst *mtmp, struct obj *otmp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hero is held by a monster or engulfed or holding a monster and has zapped
|
||||||
|
opening/unlocking magic at holder/engulfer/holdee or at self */
|
||||||
|
void
|
||||||
|
release_hold()
|
||||||
|
{
|
||||||
|
struct monst *mtmp = u.ustuck;
|
||||||
|
|
||||||
|
if (!mtmp) {
|
||||||
|
impossible("release_hold when not held?");
|
||||||
|
} else if (sticks(g.youmonst.data)) {
|
||||||
|
/* order matters if 'holding' status condition is enabled;
|
||||||
|
set_ustuck() will set flag for botl update, You() pline will
|
||||||
|
trigger a status update with "UHold" removed */
|
||||||
|
set_ustuck((struct monst *) 0);
|
||||||
|
You("release %s.", mon_nam(mtmp));
|
||||||
|
} else if (u.uswallow) {
|
||||||
|
if (is_animal(mtmp->data)) {
|
||||||
|
if (!Blind)
|
||||||
|
pline("%s opens its mouth!", Monnam(mtmp));
|
||||||
|
else
|
||||||
|
You_feel("a sudden rush of air!");
|
||||||
|
}
|
||||||
|
/* gives "you get regurgitated" or "you get expelled from <mon>" */
|
||||||
|
expels(mtmp, mtmp->data, TRUE);
|
||||||
|
} else { /* held but not swallowed */
|
||||||
|
char relbuf[BUFSZ];
|
||||||
|
|
||||||
|
unstuck(u.ustuck);
|
||||||
|
if (!nohands(mtmp->data))
|
||||||
|
Sprintf(relbuf, "from %s grasp", s_suffix(mon_nam(mtmp)));
|
||||||
|
else
|
||||||
|
Sprintf(relbuf, "by %s", mon_nam(mtmp));
|
||||||
|
You("are released %s.", relbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
probe_monster(struct monst *mtmp)
|
probe_monster(struct monst *mtmp)
|
||||||
{
|
{
|
||||||
@@ -2577,6 +2611,12 @@ zapyourself(struct obj *obj, boolean ordinary)
|
|||||||
break;
|
break;
|
||||||
case WAN_OPENING:
|
case WAN_OPENING:
|
||||||
case SPE_KNOCK:
|
case SPE_KNOCK:
|
||||||
|
if (u.ustuck) {
|
||||||
|
/* zapping either self or holder/holdee [bhitm()] will release
|
||||||
|
holder's grasp from the hero or hero's grasp from holdee */
|
||||||
|
release_hold();
|
||||||
|
learn_it = TRUE;
|
||||||
|
}
|
||||||
if (Punished) {
|
if (Punished) {
|
||||||
learn_it = TRUE;
|
learn_it = TRUE;
|
||||||
unpunish();
|
unpunish();
|
||||||
|
|||||||
Reference in New Issue
Block a user