-/* NetHack 3.6 timeout.c $NHDT-Date: 1446861771 2015/11/07 02:02:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */
+/* NetHack 3.6 timeout.c $NHDT-Date: 1573290422 2019/11/09 09:07:02 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.93 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2018. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2023 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
STATIC_DCL void NDECL(stoned_dialogue);
STATIC_DCL void NDECL(vomiting_dialogue);
STATIC_DCL void NDECL(choke_dialogue);
+STATIC_DCL void NDECL(levitation_dialogue);
STATIC_DCL void NDECL(slime_dialogue);
+STATIC_DCL void FDECL(slimed_to_death, (struct kinfo *));
+STATIC_DCL void NDECL(phaze_dialogue);
+STATIC_DCL void FDECL(done_timeout, (int, int));
STATIC_DCL void NDECL(slip_or_trip);
STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
STATIC_DCL void FDECL(lantern_message, (struct obj *));
STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long));
+/* used by wizard mode #timeout and #wizintrinsic; order by 'interest'
+ for timeout countdown, where most won't occur in normal play */
+/*JP \83E\83B\83U\81[\83h\83\82\81[\83h\82Å\82µ\82©\8eg\82í\82ê\82È\82¢\82æ\82¤\82È\82Ì\82Å\96|\96ó\82µ\82È\82¢ */
+const struct propname {
+ int prop_num;
+ const char *prop_name;
+} propertynames[] = {
+ { INVULNERABLE, "invulnerable" },
+ { STONED, "petrifying" },
+ { SLIMED, "becoming slime" },
+ { STRANGLED, "strangling" },
+ { SICK, "fatally sick" },
+ { STUNNED, "stunned" },
+ { CONFUSION, "confused" },
+ { HALLUC, "hallucinating" },
+ { BLINDED, "blinded" },
+ { DEAF, "deafness" },
+ { VOMITING, "vomiting" },
+ { GLIB, "slippery fingers" },
+ { WOUNDED_LEGS, "wounded legs" },
+ { SLEEPY, "sleepy" },
+ { TELEPORT, "teleporting" },
+ { POLYMORPH, "polymorphing" },
+ { LEVITATION, "levitating" },
+ { FAST, "very fast" }, /* timed 'FAST' is very fast */
+ { CLAIRVOYANT, "clairvoyant" },
+ { DETECT_MONSTERS, "monster detection" },
+ { SEE_INVIS, "see invisible" },
+ { INVIS, "invisible" },
+ /* properties beyond here don't have timed values during normal play,
+ so there's not much point in trying to order them sensibly;
+ they're either on or off based on equipment, role, actions, &c */
+ { FIRE_RES, "fire resistance" },
+ { COLD_RES, "cold resistance" },
+ { SLEEP_RES, "sleep resistance" },
+ { DISINT_RES, "disintegration resistance" },
+ { SHOCK_RES, "shock resistance" },
+ { POISON_RES, "poison resistance" },
+ { ACID_RES, "acid resistance" },
+ { STONE_RES, "stoning resistance" },
+ { DRAIN_RES, "drain resistance" },
+ { SICK_RES, "sickness resistance" },
+ { ANTIMAGIC, "magic resistance" },
+ { HALLUC_RES, "hallucination resistance" },
+ { FUMBLING, "fumbling" },
+ { HUNGER, "voracious hunger" },
+ { TELEPAT, "telepathic" },
+ { WARNING, "warning" },
+ { WARN_OF_MON, "warn: monster type or class" },
+ { WARN_UNDEAD, "warn: undead" },
+ { SEARCHING, "searching" },
+ { INFRAVISION, "infravision" },
+ { ADORNED, "adorned (+/- Cha)" },
+ { DISPLACED, "displaced" },
+ { STEALTH, "stealthy" },
+ { AGGRAVATE_MONSTER, "monster aggravation" },
+ { CONFLICT, "conflict" },
+ { JUMPING, "jumping" },
+ { TELEPORT_CONTROL, "teleport control" },
+ { FLYING, "flying" },
+ { WWALKING, "water walking" },
+ { SWIMMING, "swimming" },
+ { MAGICAL_BREATHING, "magical breathing" },
+ { PASSES_WALLS, "pass thru walls" },
+ { SLOW_DIGESTION, "slow digestion" },
+ { HALF_SPDAM, "half spell damage" },
+ { HALF_PHDAM, "half physical damage" },
+ { REGENERATION, "HP regeneration" },
+ { ENERGY_REGENERATION, "energy regeneration" },
+ { PROTECTION, "extra protection" },
+ { PROT_FROM_SHAPE_CHANGERS, "protection from shape changers" },
+ { POLYMORPH_CONTROL, "polymorph control" },
+ { UNCHANGING, "unchanging" },
+ { REFLECTING, "reflecting" },
+ { FREE_ACTION, "free action" },
+ { FIXED_ABIL, "fixed abilities" },
+ { LIFESAVED, "life will be saved" },
+ { 0, 0 },
+};
+
/* He is being petrified - dialogue by inmet!tower */
static NEARDATA const char *const stoned_texts[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"You are slowing down.", /* 5 */
"Your limbs are stiffening.", /* 4 */
"Your limbs have turned to stone.", /* 3 */
char buf[BUFSZ];
Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
(void) strsubst(buf, "limbs", "extremities");
#else
*/
multi_reason = "\90Î\89»\82µ\82Â\82Â\82 \82é\8e\9e\82É";
nomovemsg = You_can_move_again; /* not unconscious */
+ /* "your limbs have turned to stone" so terminate wounded legs */
+ if (Wounded_legs && !u.usteed)
+ heal_legs(2);
+ break;
+ case 2: /* turned to stone */
+ if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
+ set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
+ /* if also vomiting or turning into slime, stop those (no messages) */
+ if (Vomiting)
+ make_vomiting(0L, FALSE);
+ if (Slimed)
+ make_slimed(0L, (char *) 0);
break;
default:
break;
exercise(A_DEX, FALSE);
}
-/* He is getting sicker and sicker prior to vomiting */
+/* hero is getting sicker and sicker prior to vomiting */
static NEARDATA const char *const vomiting_texts[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"are feeling mildly nauseated.", /* 14 */
"feel slightly confused.", /* 11 */
"can't seem to think straight.", /* 8 */
"feel incredibly sick.", /* 5 */
- "suddenly vomit!" /* 2 */
+ "are about to vomit." /* 2 */
#else
"\82¿\82å\82Á\82Æ\93f\82«\8bC\82ª\82µ\82½\81D", /* 14 */
"\8f\82µ\8d¬\97\90\82µ\82½\81D", /* 11 */
"\82Ü\82Æ\82à\82É\8ev\8dl\82Å\82«\82È\82\82È\82Á\82½\81D", /* 8 */
"\82Æ\82Ä\82à\8bC\95ª\82ª\88«\82\82È\82Á\82½\81D", /* 5 */
- "\93Ë\91R\9aq\93f\82µ\82½\81I" /* 2 */
+ "\93Ë\91R\9aq\93f\82µ\82½\81D" /* 2 */
#endif
};
txt = vomiting_texts[4];
if (cantvomit(youmonst.data))
/*JP
- txt = "gag uncontrolably.";
+ txt = "gag uncontrollably.";
*/
txt = "\8bC\95ª\82Ì\88«\82³\82ª\97}\82¦\82ç\82ê\82È\82\82È\82Á\82½\81D";
+ else if (Hallucination)
+ /* "hurl" is short for "hurl chunks" which is slang for
+ relatively violent vomiting... */
+/*JP
+ txt = "are about to hurl!";
+*/
+ txt = "\83\8a\83o\81[\83X\90¡\91O\82¾\81I";
break;
case 0:
stop_occupation();
- if (!cantvomit(youmonst.data))
+ if (!cantvomit(youmonst.data)) {
morehungry(20);
+ /* case 2 used to be "You suddenly vomit!" but it wasn't sudden
+ since you've just been through the earlier messages of the
+ countdown, and it was still possible to move around between
+ that message and "You can move again." (from vomit()'s
+ nomul(-2)) with no intervening message; give one here to
+ have more specific point at which hero became unable to move
+ [vomit() issues its own message for the cantvomit() case
+ and for the FAINTING-or-worse case where stomach is empty] */
+ if (u.uhs < FAINTING)
+/*JP
+ You("%s!", !Hallucination ? "vomit" : "hurl chunks");
+*/
+ You("%s\81I", !Hallucination ? "\93f\82¢\82½" : "\83\8a\83o\81[\83X\82µ\82½");
+ }
vomit();
break;
default:
}
static NEARDATA const char *const choke_texts[] = {
-#if 0 /*JP*/
- "You find it hard to breathe.", "You're gasping for air.",
- "You can no longer breathe.", "You're turning %s.", "You suffocate."
+#if 0 /*JP:T*/
+ "You find it hard to breathe.",
+ "You're gasping for air.",
+ "You can no longer breathe.",
+ "You're turning %s.",
+ "You suffocate."
#else
"\82 \82È\82½\82Í\8cÄ\8bz\82ª\8d¢\93ï\82É\82È\82Á\82½\81D",
"\82 \82È\82½\82Í\8bê\82µ\82\82Ä\82 \82¦\82¢\82¾\81D",
};
static NEARDATA const char *const choke_texts2[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"Your %s is becoming constricted.",
"Your blood is having trouble reaching your brain.",
- "The pressure on your %s increases.", "Your consciousness is fading.",
+ "The pressure on your %s increases.",
+ "Your consciousness is fading.",
"You suffocate."
#else
"\82 \82È\82½\82Ì%s\82Í\8di\82ß\82Â\82¯\82ç\82ê\82½\81D",
/*JP
pline(str, hcolor(NH_BLUE));
*/
- pline(str, jconj_adj(hcolor(NH_BLUE)));
+ pline(str, hcolor_adv(NH_BLUE));
else
pline1(str);
}
exercise(A_STR, FALSE);
}
+static NEARDATA const char *const levi_texts[] = {
+#if 0 /*JP*//* %s\82Í\8eg\82í\82È\82¢ */
+ "You float slightly lower.",
+ "You wobble unsteadily %s the %s."
+#else
+ "\82 \82È\82½\82Ì\95\82\82«\8bï\8d\87\82Í\8f\82µ\92á\82\82È\82Á\82½\81D",
+ "\82 \82È\82½\82Í\82®\82ç\82®\82ç\97h\82ê\82Í\82¶\82ß\82½\81D"
+#endif
+};
+
+STATIC_OVL void
+levitation_dialogue()
+{
+ /* -1 because the last message comes via float_down() */
+ long i = (((HLevitation & TIMEOUT) - 1L) / 2L);
+
+ if (ELevitation)
+ return;
+
+ if (!ACCESSIBLE(levl[u.ux][u.uy].typ)
+ && !is_pool_or_lava(u.ux,u.uy))
+ return;
+
+ if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) {
+ const char *s = levi_texts[SIZE(levi_texts) - i];
+
+#if 0 /*JP*//* %s \82Í\8eg\82Á\82Ä\82¢\82È\82¢\82Ì\82Å\92P\8f\83\89» */
+ if (index(s, '%')) {
+ boolean danger = (is_pool_or_lava(u.ux, u.uy)
+ && !Is_waterlevel(&u.uz));
+
+ pline(s, danger ? "over" : "in",
+ danger ? surface(u.ux, u.uy) : "air");
+ } else
+#endif
+ pline1(s);
+ }
+}
+
static NEARDATA const char *const slime_texts[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
"You are turning a little %s.", /* 5 */
"Your limbs are getting oozy.", /* 4 */
"Your skin begins to peel away.", /* 3 */
{
register long i = (Slimed & TIMEOUT) / 2L;
+ if (i == 1L) {
+ /* display as green slime during "You have become green slime."
+ but don't worry about not being able to see self; if already
+ mimicking something else at the time, implicitly be revealed */
+ youmonst.m_ap_type = M_AP_MONSTER;
+ youmonst.mappearance = PM_GREEN_SLIME;
+ }
if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
char buf[BUFSZ];
Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
(void) strsubst(buf, "limbs", "extremities");
#else
/*JP
pline(buf, hcolor(NH_GREEN));
*/
- pline(buf, jconj_adj(hcolor(NH_GREEN)));
+ pline(buf, hcolor_adv(NH_GREEN));
} else
pline(buf,
/*JP
} else
pline1(buf);
}
- if (i == 3L) { /* limbs becoming oozy */
+
+ switch (i) {
+ case 3L: /* limbs becoming oozy */
HFast = 0L; /* lose intrinsic speed */
if (!Popeye(SLIMED))
stop_occupation();
if (multi > 0)
nomul(0);
+ break;
+ case 2L: /* skin begins to peel */
+ if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
+ set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
+ break;
+ case 1L: /* turning into slime */
+ /* if also turning to stone, stop doing that (no message) */
+ if (Stoned)
+ make_stoned(0L, (char *) 0, KILLED_BY_AN, (char *) 0);
+ break;
}
exercise(A_DEX, FALSE);
}
/*JP
make_slimed(0L, "The slime that covers you is burned away!");
*/
- pline("\82 \82È\82½\82ð\95¢\82Á\82Ä\82¢\82½\83X\83\89\83C\83\80\82Í\8fÄ\82¯\97\8e\82¿\82½\81I");
+ make_slimed(0L, "\82 \82È\82½\82ð\95¢\82Á\82Ä\82¢\82½\83X\83\89\83C\83\80\82Í\8fÄ\82¯\97\8e\82¿\82½\81I");
+ }
+}
+
+/* countdown timer for turning into green slime has run out; kill our hero */
+STATIC_OVL void
+slimed_to_death(kptr)
+struct kinfo *kptr;
+{
+ uchar save_mvflags;
+
+ /* redundant: polymon() cures sliming when polying into green slime */
+ if (Upolyd && youmonst.data == &mons[PM_GREEN_SLIME]) {
+ dealloc_killer(kptr);
+ return;
+ }
+ /* more sure killer reason is set up */
+ if (kptr && kptr->name[0]) {
+ killer.format = kptr->format;
+ Strcpy(killer.name, kptr->name);
+ } else {
+ killer.format = NO_KILLER_PREFIX;
+/*JP
+ Strcpy(killer.name, "turned into green slime");
+*/
+ Strcpy(killer.name, "\97Î\83X\83\89\83C\83\80\82É\82È\82Á\82½");
+ }
+ dealloc_killer(kptr);
+
+ /*
+ * Polymorph into a green slime, which might destroy some worn armor
+ * (potentially affecting bones) and dismount from steed.
+ * Can't be Unchanging; wouldn't have turned into slime if we were.
+ * Despite lack of Unchanging, neither done() nor savelife() calls
+ * rehumanize() if hero dies while polymorphed.
+ * polymon() undoes the slime countdown's mimick-green-slime hack
+ * but does not perform polyself()'s light source bookkeeping.
+ * No longer need to manually increment uconduct.polyselfs to reflect
+ * [formerly implicit] change of form; polymon() takes care of that.
+ * Temporarily ungenocide if necessary.
+ */
+ if (emits_light(youmonst.data))
+ del_light_source(LS_MONSTER, monst_to_any(&youmonst));
+ save_mvflags = mvitals[PM_GREEN_SLIME].mvflags;
+ mvitals[PM_GREEN_SLIME].mvflags = save_mvflags & ~G_GENOD;
+ /* become a green slime; also resets youmonst.m_ap_type+.mappearance */
+ (void) polymon(PM_GREEN_SLIME);
+ mvitals[PM_GREEN_SLIME].mvflags = save_mvflags;
+ done_timeout(TURNED_SLIME, SLIMED);
+
+ /* life-saved; even so, hero still has turned into green slime;
+ player may have genocided green slimes after being infected */
+ if ((mvitals[PM_GREEN_SLIME].mvflags & G_GENOD) != 0) {
+ char slimebuf[BUFSZ];
+
+ killer.format = KILLED_BY;
+/*JP
+ Strcpy(killer.name, "slimicide");
+*/
+ Strcpy(killer.name, "\83X\83\89\83C\83\80\8bs\8eE");
+ /* vary the message depending upon whether life-save was due to
+ amulet or due to declining to die in explore or wizard mode */
+/*JP
+ Strcpy(slimebuf, "green slime has been genocided...");
+*/
+ Strcpy(slimebuf, "\97Î\83X\83\89\83C\83\80\82Í\8bs\8eE\82³\82ê\82Ü\82µ\82½\81D\81D\81D");
+ if (iflags.last_msg == PLNMSG_OK_DONT_DIE)
+ /* follows "OK, so you don't die." and arg is second sentence */
+/*JP
+ pline("Yes, you do. %s", upstart(slimebuf));
+*/
+ pline("\82Í\82¢\81C\82»\82¤\82Å\82·\81D%s", upstart(slimebuf));
+ else
+ /* follows "The medallion crumbles to dust." */
+/*JP
+ pline("Unfortunately, %s", slimebuf);
+*/
+ pline("\82´\82ñ\82Ë\82ñ\82Å\82·\82ª%s", slimebuf);
+ /* die again; no possibility of amulet this time */
+ done(GENOCIDED); /* [should it be done_timeout(GENOCIDED, SLIMED)?] */
+ /* could be life-saved again (only in explore or wizard mode)
+ but green slimes are gone; just stay in current form */
}
+ return;
+}
+
+/* Intrinsic Passes_walls is temporary when your god is trying to fix
+ all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
+ it can't find anywhere to place you. If that happens you get a small
+ value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
+ Message given is "you feel much slimmer" as a joke hint that you can
+ move between things which are closely packed--like the substance of
+ solid rock! */
+static NEARDATA const char *const phaze_texts[] = {
+#if 0 /*JP:T*/
+ "You start to feel bloated.",
+ "You are feeling rather flabby.",
+#else
+ "\82 \82È\82½\82Í\96c\82ç\82Ý\82Í\82¶\82ß\82½\8bC\82ª\82·\82é\81D",
+ "\82 \82È\82½\82Í\8f\82µ\82½\82é\82ñ\82¾\8bC\82ª\82·\82é\81D",
+#endif
+};
+
+STATIC_OVL void
+phaze_dialogue()
+{
+ long i = ((HPasses_walls & TIMEOUT) / 2L);
+
+ if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
+ return;
+
+ if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
+ pline1(phaze_texts[SIZE(phaze_texts) - i]);
+}
+
+/* when a status timeout is fatal, keep the status line indicator shown
+ during end of game rundown (and potential dumplog);
+ timeout has already counted down to 0 by the time we get here */
+STATIC_OVL void
+done_timeout(how, which)
+int how, which;
+{
+ long *intrinsic_p = &u.uprops[which].intrinsic;
+
+ *intrinsic_p |= I_SPECIAL; /* affects final disclosure */
+ done(how);
+
+ /* life-saved */
+ *intrinsic_p &= ~I_SPECIAL;
+ context.botl = TRUE;
}
void
{
register struct prop *upp;
struct kinfo *kptr;
+ boolean was_flying;
int sleeptime;
int m_idx;
int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
baseluck -= 1;
if (u.uluck != baseluck
- && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
+ && moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
/* Cursed luckstones stop bad luck from timing out; blessed luckstones
* stop good luck from timing out; normal luckstones stop both;
* neither is stopped if you don't have a luckstone.
vomiting_dialogue();
if (Strangled)
choke_dialogue();
+ if (HLevitation & TIMEOUT)
+ levitation_dialogue();
+ if (HPasses_walls & TIMEOUT)
+ phaze_dialogue();
if (u.mtimedone && !--u.mtimedone) {
if (Unchanging)
u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
+ else if (is_were(youmonst.data))
+ you_unwere(FALSE); /* if polycontrl, asks whether to rehumanize */
else
rehumanize();
}
u.uspellprot--;
find_ac();
if (!Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
u.uspellprot ? "becomes less dense" : "disappears");
#else
pline("%s\82Í\91¬\8bì\82¯\82ð\82â\82ß\82½\81D", Monnam(u.usteed));
}
+ was_flying = Flying;
for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
kptr = find_delayed_killer((int) (upp - u.uprops));
}
dealloc_killer(kptr);
/* (unlike sliming, you aren't changing form here) */
- done(STONING);
+ done_timeout(STONING, STONED);
break;
case SLIMED:
- if (kptr && kptr->name[0]) {
- killer.format = kptr->format;
- Strcpy(killer.name, kptr->name);
- } else {
- killer.format = NO_KILLER_PREFIX;
-/*JP
- Strcpy(killer.name, "turned into green slime");
-*/
- Strcpy(killer.name, "\97Î\83X\83\89\83C\83\80\82É\82È\82Á\82½");
- }
- dealloc_killer(kptr);
- /* involuntarily break "never changed form" conduct */
- u.uconduct.polyselfs++;
- done(TURNED_SLIME);
+ slimed_to_death(kptr); /* done_timeout(TURNED_SLIME,SLIMED) */
break;
case VOMITING:
make_vomiting(0L, TRUE);
killer.format = KILLED_BY;
}
}
+ done_timeout(POISONING, SICK);
u.usick_type = 0;
- done(POISONING);
break;
case FAST:
if (!Very_fast)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_feel("yourself slowing down%s.",
Fast ? " a bit" : "");
#else
case DEAF:
set_itimeout(&HDeaf, 1L);
make_deaf(0L, TRUE);
+ context.botl = TRUE;
if (!Deaf)
stop_occupation();
break;
case INVIS:
newsym(u.ux, u.uy);
if (!Invis && !BInvis && !Blind) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You(!See_invisible
? "are no longer invisible."
: "can no longer see through yourself.");
stop_occupation();
break;
case WOUNDED_LEGS:
- heal_legs();
+ heal_legs(0);
stop_occupation();
break;
#ifdef JPEXTENSION
case LEVITATION:
(void) float_down(I_SPECIAL | TIMEOUT, 0L);
break;
+ case FLYING:
+ /* timed Flying is via #wizintrinsic only */
+ if (was_flying && !Flying) {
+ context.botl = 1;
+/*JP
+ You("land.");
+*/
+ You("\92\85\92n\82µ\82½\81D");
+ spoteffects(TRUE);
+ }
+ break;
+ case WARN_OF_MON:
+ /* timed Warn_of_mon is via #wizintrinsic only */
+ if (!Warn_of_mon) {
+ context.warntype.speciesidx = NON_PM;
+ if (context.warntype.species) {
+#if 0 /*JP:T*/
+ You("are no longer warned about %s.",
+ makeplural(context.warntype.species->mname));
+#else
+ You("\82à\82Í\82â%s\82ð\8cx\8d\90\82µ\82È\82\82È\82Á\82½\81D",
+ makeplural(context.warntype.species->mname));
+#endif
+ context.warntype.species = (struct permonst *) 0;
+ }
+ }
+ break;
+ case PASSES_WALLS:
+ if (!Passes_walls) {
+ if (stuck_in_wall())
+/*JP
+ You_feel("hemmed in again.");
+*/
+ You_feel("\82Ü\82½\95Â\82¶\8d\9e\82ß\82ç\82ê\82½\82æ\82¤\82¾\81D");
+ else
+#if 0 /*JP:T*/
+ pline("You're back to your %s self again.",
+ !Upolyd ? "normal" : "unusual");
+#else
+ pline("\82 \82È\82½\82Í\8dÄ\82Ñ\92Ê\8fí%s\82Ì\8fó\91Ô\82É\82È\82Á\82½\81D",
+ !Upolyd ? "" : "\82Å\82Í\82È\82¢");
+#endif
+ }
+ break;
case STRANGLED:
killer.format = KILLED_BY;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Strcpy(killer.name,
(u.uburied) ? "suffocation" : "strangulation");
#else
Strcpy(killer.name,
(u.uburied) ? "\92\82\91§\82µ\82Ä" : "\8eñ\82ð\8di\82ß\82ç\82ê\82Ä");
#endif
- done(DIED);
+ done_timeout(DIED, STRANGLED);
/* must be declining to die in explore|wizard mode;
treat like being cured of strangulation by prayer */
if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
case DETECT_MONSTERS:
see_monsters();
break;
+ case GLIB:
+ make_glib(0); /* might update persistent inventory */
+ break;
}
}
/* caller can follow with a direct call to Hear_again() if
there's a need to override this when wakeup_msg is true */
incr_itimeout(&HDeaf, how_long);
+ context.botl = TRUE;
afternmv = Hear_again; /* this won't give any messages */
}
/* early wakeup from combat won't be possible until next monster turn */
boolean siblings = (hatchcount > 1), redraw = FALSE;
if (cansee_hatchspot) {
-#if 0 /*JP*/
+ /* [bug? m_monnam() yields accurate monster type
+ regardless of hallucination] */
+#if 0 /*JP:T*/
Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
#else
case OBJ_INVENT:
knows_egg = TRUE; /* true even if you are blind */
if (!cansee_hatchspot)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_feel("%s %s from your pack!", something,
locomotion(mon->data, "drop"));
#else
jpast(locomotion(mon->data, "\97\8e\82¿\82é")));
#endif
else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_see("%s %s out of your pack!", monnambuf,
locomotion(mon->data, "drop"));
#else
jpast(locomotion(mon->data, "\97\8e\82¿\82é")));
#endif
if (yours) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s cries sound like \"%s%s\"",
siblings ? "Their" : "Its",
flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
flags.female ? "\83}\83}" : "\83p\83p", egg->spe ? "" : "\81H");
#endif
} else if (mon->data->mlet == S_DRAGON && !Deaf) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
verbalize("Gleep!"); /* Mything eggs :-) */
#else
verbalize("\83u\83H\81[\81I"); /* Mything eggs :-) */
case OBJ_MINVENT:
if (cansee_hatchspot) {
/* egg carrying monster might be invisible */
- if (canseemon(egg->ocarry)) {
-/*JP
+ mon2 = egg->ocarry;
+ if (canseemon(mon2)
+ && (!mon2->wormno || cansee(mon2->mx, mon2->my))) {
+#if 0 /*JP:T*/
Sprintf(carriedby, "%s pack",
-*/
+ s_suffix(a_monnam(mon2)));
+#else
Sprintf(carriedby, "%s\82Ì\94w\95\89\82¢\91Ü\82©\82ç",
- s_suffix(a_monnam(egg->ocarry)));
+ a_monnam(mon2));
+#endif
knows_egg = TRUE;
- } else if (is_pool(mon->mx, mon->my))
+ } else if (is_pool(mon->mx, mon->my)) {
/*JP
Strcpy(carriedby, "empty water");
*/
Strcpy(carriedby, "\89½\82à\82È\82¢\90\85\92\86\82©\82ç");
- else
+ } else {
/*JP
Strcpy(carriedby, "thin air");
*/
Strcpy(carriedby, "\89½\82à\82È\82¢\8bó\8aÔ\82©\82ç");
-#if 0 /*JP*/
+ }
+#if 0 /*JP:T*/
You_see("%s %s out of %s!", monnambuf,
locomotion(mon->data, "drop"), carriedby);
#else
name; if not, look for rocks to trip over; trip over
anonymous "something" if there aren't any rocks.
*/
-#if 0 /*JP*/
+#if 0 /*JP:T*/
what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
? ((otmp->quan == 1L) ? "it"
: Hallucination ? "they" : "them")
if (Hallucination) {
what = strcpy(buf, what);
buf[0] = highc(buf[0]);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("Egads! %s bite%s your %s!", what,
(!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
#else
}
if (!uarmf && otmp->otyp == CORPSE
&& touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(killer.name, "tripping over %s corpse",
an(mons[otmp->corpsenm].mname));
#else
instapetrify(killer.name);
}
} else if (rn2(3) && is_ice(u.ux, u.uy)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s%s on the ice.",
u.usteed ? upstart(x_monnam(u.usteed,
(has_mname(u.usteed)) ? ARTICLE_NONE
if (on_foot) {
switch (rn2(4)) {
case 1:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("trip over your own %s.",
Hallucination ? "elbow" : makeplural(body_part(FOOT)));
#else
#endif
break;
case 2:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("slip %s.",
Hallucination ? "on a banana peel" : "and nearly fall");
#else
} else {
switch (rn2(4)) {
case 1:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Your("%s slip out of the stirrups.",
makeplural(body_part(FOOT)));
#else
long timeout;
{
struct obj *obj = arg->a_obj;
- boolean canseeit, many, menorah, need_newsym;
+#if 0 /*JP*/
+ boolean canseeit, many, menorah, need_newsym, need_invupdate;
+#else
+ boolean canseeit, menorah, need_newsym, need_invupdate;
+#endif
xchar x, y;
char whose[BUFSZ];
menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
+#if 0 /*JP*/
many = menorah ? obj->spe > 1 : obj->quan > 1L;
+#endif
/* timeout while away */
if (timeout != monstermoves) {
if (menorah) {
obj->spe = 0; /* no more candles */
+ obj->owt = weight(obj);
} else if (Is_candle(obj) || obj->otyp == POT_OIL) {
/* get rid of candles and burning oil potions;
we know this object isn't carried by hero,
} else {
canseeit = FALSE;
}
- need_newsym = FALSE;
+ need_newsym = need_invupdate = FALSE;
/* obj->age is the age remaining at this point. */
switch (obj->otyp) {
if (canseeit) {
switch (obj->where) {
case OBJ_INVENT:
+ need_invupdate = TRUE;
+ /*FALLTHRU*/
case OBJ_MINVENT:
/*JP
pline("%spotion of oil has burnt away.", whose);
if (canseeit || obj->where == OBJ_INVENT) {
switch (obj->where) {
case OBJ_INVENT:
+ need_invupdate = TRUE;
+ /*FALLTHRU*/
case OBJ_MINVENT:
if (obj->otyp == BRASS_LANTERN)
/*JP
switch (obj->where) {
case OBJ_INVENT:
case OBJ_MINVENT:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s%scandle%s getting short.", whose,
menorah ? "candelabrum's " : "",
many ? "s are" : " is");
#endif
break;
case OBJ_FLOOR:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_see("%scandle%s getting short.",
menorah ? "a candelabrum's " : many ? "some "
: "a ",
switch (obj->where) {
case OBJ_INVENT:
case OBJ_MINVENT:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s%scandle%s flame%s flicker%s low!", whose,
menorah ? "candelabrum's " : "", many ? "s'" : "'s",
many ? "s" : "", many ? "" : "s");
#endif
break;
case OBJ_FLOOR:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_see("%scandle%s flame%s flicker low!",
menorah ? "a candelabrum's " : many ? "some "
: "a ",
if (menorah) {
switch (obj->where) {
case OBJ_INVENT:
+ need_invupdate = TRUE;
+ /*FALLTHRU*/
case OBJ_MINVENT:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%scandelabrum's flame%s.", whose,
many ? "s die" : " dies");
#else
#endif
break;
case OBJ_FLOOR:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_see("a candelabrum's flame%s die.",
many ? "s" : "");
#else
} else {
switch (obj->where) {
case OBJ_INVENT:
+ /* no need_invupdate for update_inventory() necessary;
+ useupall() -> freeinv() handles it */
+ /*FALLTHRU*/
case OBJ_MINVENT:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s consumed!", Yname2(obj),
many ? "are" : "is");
#else
break;
case OBJ_FLOOR:
/*
- You see some wax candles consumed!
- You see a wax candle consumed!
- */
-#if 0 /*JP*/
+ You see some wax candles consumed!
+ You see a wax candle consumed!
+ */
+#if 0 /*JP:T*/
You_see("%s%s consumed!", many ? "some " : "",
many ? xname(obj) : an(xname(obj)));
#else
}
/* post message */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline(Hallucination
? (many ? "They shriek!" : "It shrieks!")
: Blind ? "" : (many ? "Their flames die."
: "Its flame dies."));
#else
- pline(Hallucination ? "\82»\82ê\82Í\90k\82¦\82½\81D"
- : Blind ? ""
- : "\89\8a\82Í\8fÁ\82¦\82½\81D");
+ pline(Hallucination ? "\82»\82ê\82Í\8bà\90Ø\82è\90º\82ð\82 \82°\82½\81I"
+ : Blind ? ""
+ : "\89\8a\82Í\8fÁ\82¦\82½\81D");
#endif
}
}
if (menorah) {
obj->spe = 0;
+ obj->owt = weight(obj);
} else {
if (carried(obj)) {
useupall(obj);
}
obj = (struct obj *) 0;
}
- break;
+ break; /* case [age ==] 0 */
default:
/*
if (obj && obj->age)
begin_burn(obj, TRUE);
-
- break;
+ break; /* case [otyp ==] candelabrum|tallow_candle|wax_candle */
default:
- impossible("burn_object: unexpeced obj %s", xname(obj));
+ impossible("burn_object: unexpected obj %s", xname(obj));
break;
}
if (need_newsym)
newsym(x, y);
+ if (need_invupdate)
+ update_inventory();
}
/*
case POT_OIL:
turns = obj->age;
+ if (obj->odiluted)
+ turns = (3L * turns + 2L) / 4L;
radius = 1; /* very dim light */
break;
*/
pline("\83s\83J\83b\81I\81I\83S\83\8d\83S\83\8d\83S\83\8d\83S\83\8d\81I\81I\83h\81[\83\93\81I");
incr_itimeout(&HDeaf, rn1(20, 30));
+ context.botl = TRUE;
if (!u.uinvulnerable) {
stop_occupation();
nomul(-3);
char buf[BUFSZ];
if (!base) {
- putstr(win, 0, "<empty>");
+ putstr(win, 0, " <empty>");
} else {
putstr(win, 0, "timeout id kind call");
for (curr = base; curr; curr = curr->next) {
{
winid win;
char buf[BUFSZ];
+ const char *propname;
+ long intrinsic;
+ int i, p, count, longestlen, ln, specindx = 0;
win = create_nhwindow(NHW_MENU); /* corner text window */
if (win == WIN_ERR)
putstr(win, 0, "");
print_queue(win, timer_base);
+ /* Timed properies:
+ * check every one; the majority can't obtain temporary timeouts in
+ * normal play but those can be forced via the #wizintrinsic command.
+ */
+ count = longestlen = 0;
+ for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
+ p = propertynames[i].prop_num;
+ intrinsic = u.uprops[p].intrinsic;
+ if (intrinsic & TIMEOUT) {
+ ++count;
+ if ((ln = (int) strlen(propname)) > longestlen)
+ longestlen = ln;
+ }
+ if (specindx == 0 && p == FIRE_RES)
+ specindx = i;
+ }
+ putstr(win, 0, "");
+ if (!count) {
+ putstr(win, 0, "No timed properties.");
+ } else {
+ putstr(win, 0, "Timed properties:");
+ putstr(win, 0, "");
+ for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
+ p = propertynames[i].prop_num;
+ intrinsic = u.uprops[p].intrinsic;
+ if (intrinsic & TIMEOUT) {
+ if (specindx > 0 && i >= specindx) {
+ putstr(win, 0, " -- settable via #wizinstrinc only --");
+ specindx = 0;
+ }
+ /* timeout value can be up to 16777215 (0x00ffffff) but
+ width of 4 digits should result in values lining up
+ almost all the time (if/when they don't, it won't
+ look nice but the information will still be accurate) */
+ Sprintf(buf, " %*s %4ld", -longestlen, propname,
+ (intrinsic & TIMEOUT));
+ putstr(win, 0, buf);
+ }
+ }
+ }
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
for (curr = timer_base; curr; curr = curr->next)
if (curr->kind == TIMER_OBJECT) {
struct obj *obj = curr->arg.a_obj;
+
if (obj->timed == 0) {
- pline("timer sanity: untimed obj %s, timer %ld",
+ impossible("timer sanity: untimed obj %s, timer %ld",
fmt_ptr((genericptr_t) obj), curr->tid);
}
}
short func_index;
anything *arg;
{
- timer_element *gnu;
+ timer_element *gnu, *dup;
+
+ if (kind < 0 || kind >= NUM_TIMER_KINDS
+ || func_index < 0 || func_index >= NUM_TIME_FUNCS)
+ panic("start_timer (%s: %d)", kind_name(kind), (int) func_index);
- if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
- panic("start_timer");
+ /* fail if <arg> already has a <func_index> timer running */
+ for (dup = timer_base; dup; dup = dup->next)
+ if (dup->kind == kind
+ && dup->func_index == func_index
+ && dup->arg.a_void == arg->a_void)
+ break;
+ if (dup) {
+ char idbuf[QBUFSZ];
- gnu = (timer_element *) alloc(sizeof(timer_element));
+#ifdef VERBOSE_TIMER
+ Sprintf(idbuf, "%s timer", timeout_funcs[func_index].name);
+#else
+ Sprintf(idbuf, "%s timer (%d)", kind_name(kind), (int) func_index);
+#endif
+ impossible("Attempted to start duplicate %s, aborted.", idbuf);
+ return FALSE;
+ }
+
+ gnu = (timer_element *) alloc(sizeof *gnu);
+ (void) memset((genericptr_t) gnu, 0, sizeof *gnu);
gnu->next = 0;
gnu->tid = timer_id++;
gnu->timeout = monstermoves + when;
if (kind == TIMER_OBJECT) /* increment object's timed count */
(arg->a_obj)->timed++;
- /* should check for duplicates and fail if any */
return TRUE;
}
}
}
+/* to support '#stats' wizard-mode command */
+void
+timer_stats(hdrfmt, hdrbuf, count, size)
+const char *hdrfmt;
+char *hdrbuf;
+long *count, *size;
+{
+ timer_element *te;
+
+ Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
+ *count = *size = 0L;
+ for (te = timer_base; te; te = te->next) {
+ ++*count;
+ *size += (long) sizeof *te;
+ }
+}
+
/* reset all timers that are marked for reseting */
void
relink_timers(ghostly)