From 66f95ef37c11bf58ee5bb0ccedccd6f9cd515ce7 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sun, 3 Jun 2007 01:05:43 +0000 Subject: [PATCH] Heart of Ahriman hack (trunk only) From a four year old news posting: hero was levitating via #invoke on the Heart of Ahriman, then dropping that artifact yielded: You drop a gray stone named The Heart of Ahriman. You float gently to the floor. A gray stone named The Heart of Ahriman hits the floor. That might be strictly correct, assuming that both hero and stone fall at the same speed; if the stone was dropped from perhaps waist height then the hero's feet would touch first. But it looks strange, like a cartoon where something hangs in midair until someone notices that it should fall. Removing the artifact from inventory causes the #invoke property to toggle off. Unfortunately it has to be done here before the object can be placed at its destination. Modifying message order seemed unviable; this fix fiddles with the Levitation property in order to defer hero's descent until after object handling is finished. Now same setup gives: You drop a gray stone named The Heart of Ahriman. A gray stone named The Heart of Ahriman hits the floor. You float gently to the floor. You see here a gray stone named The Heart of Ahriman. --- doc/fixes35.0 | 1 + include/extern.h | 1 + src/artifact.c | 27 +++++++++++++++++++++++++++ src/do.c | 7 +++++++ 4 files changed, 36 insertions(+) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 5b5df3ded..964392143 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -241,6 +241,7 @@ engulfer under influence of conflict or confusion could swallow monster at unicorn horn restoration no longer overrides sustain ability characteristic hider monster revived from corpse would start out hidden (even if own corpse was only object around to hide under) +fix sequencing issues with dropping #invoked Heart of Ahriman Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index d31578afe..2989822d6 100644 --- a/include/extern.h +++ b/include/extern.h @@ -78,6 +78,7 @@ E int FDECL(disp_artifact_discoveries, (winid)); E boolean FDECL(artifact_hit, (struct monst *,struct monst *, struct obj *,int *,int)); E int NDECL(doinvoke); +E boolean FDECL(finesse_ahriman, (struct obj *)); E void FDECL(arti_speak, (struct obj *)); E boolean FDECL(artifact_light, (struct obj *)); E long FDECL(spec_m2, (struct obj *)); diff --git a/src/artifact.c b/src/artifact.c index aa3355f4c..9097daa74 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1475,6 +1475,33 @@ nothing_special: return 1; } +/* will freeing this object from inventory cause levitation to end? */ +boolean +finesse_ahriman(obj) +struct obj *obj; +{ + const struct artifact *oart; + struct prop save_Lev; + boolean result; + + /* if we aren't levitating or this isn't an artifact which confers + levitation via #invoke then freeinv() won't toggle levitation */ + if (!Levitation || (oart = get_artifact(obj)) == 0 || + oart->inv_prop != LEVITATION || !(ELevitation & W_ARTI)) + return FALSE; + + /* arti_invoke(off) -> float_down() clears I_SPECIAL|TIMEOUT & W_ARTI; + probe ahead to see whether that actually results in floating down; + (this assumes that there aren't two simultaneously invoked artifacts + both conferring levitation--safe, since if there were two of them, + invoking the 2nd would negate the 1st rather than stack with it) */ + save_Lev = u.uprops[LEVITATION]; + HLevitation &= ~(I_SPECIAL|TIMEOUT); + ELevitation &= ~W_ARTI; + result = (boolean)!Levitation; + u.uprops[LEVITATION] = save_Lev; + return result; +} /* WAC return TRUE if artifact is always lit */ boolean diff --git a/src/do.c b/src/do.c index 1253f506d..5a856b3e0 100644 --- a/src/do.c +++ b/src/do.c @@ -484,6 +484,12 @@ register struct obj *obj; } #endif if (!can_reach_floor(TRUE)) { + /* we might be levitating due to #invoke Heart of Ahriman; + if so, levitation would end during call to freeinv() + and we want hitfloor() to happen before float_down() */ + boolean levhack = finesse_ahriman(obj); + + if (levhack) ELevitation = W_ART; /* other than W_ARTI */ if(flags.verbose) You("drop %s.", doname(obj)); #ifndef GOLDOBJ if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); @@ -493,6 +499,7 @@ register struct obj *obj; freeinv(obj); #endif hitfloor(obj); + if (levhack) float_down(I_SPECIAL|TIMEOUT, W_ARTI|W_ART); return(1); } if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)