1 /* NetHack 3.6 timeout.c $NHDT-Date: 1505214876 2017/09/12 11:14:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.75 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
9 /* JNetHack may be freely redistributed. See license for details. */
12 #include "lev.h" /* for checking save modes */
14 STATIC_DCL void NDECL(stoned_dialogue);
15 STATIC_DCL void NDECL(vomiting_dialogue);
16 STATIC_DCL void NDECL(choke_dialogue);
17 STATIC_DCL void NDECL(levitation_dialogue);
18 STATIC_DCL void NDECL(slime_dialogue);
19 STATIC_DCL void NDECL(slip_or_trip);
20 STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
21 STATIC_DCL void FDECL(lantern_message, (struct obj *));
22 STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long));
24 /* used by wizard mode #timeout and #wizintrinsic; order by 'interest'
25 for timeout countdown, where most won't occur in normal play */
26 const struct propname {
28 const char *prop_name;
30 { INVULNERABLE, "invulnerable" },
31 { STONED, "petrifying" },
32 { SLIMED, "becoming slime" },
33 { STRANGLED, "strangling" },
34 { SICK, "fatally sick" },
35 { STUNNED, "stunned" },
36 { CONFUSION, "confused" },
37 { HALLUC, "hallucinating" },
38 { BLINDED, "blinded" },
40 { VOMITING, "vomiting" },
41 { GLIB, "slippery fingers" },
42 { WOUNDED_LEGS, "wounded legs" },
44 { TELEPORT, "teleporting" },
45 { POLYMORPH, "polymorphing" },
46 { LEVITATION, "levitating" },
47 { FAST, "very fast" }, /* timed 'FAST' is very fast */
48 { CLAIRVOYANT, "clairvoyant" },
49 { DETECT_MONSTERS, "monster detection" },
50 { SEE_INVIS, "see invisible" },
51 { INVIS, "invisible" },
52 /* properties beyond here don't have timed values during normal play,
53 so there's no much point in trying to order them sensibly;
54 they're either on or off based on equipment, role, actions, &c */
55 { FIRE_RES, "fire resistance" },
56 { COLD_RES, "cold resistance" },
57 { SLEEP_RES, "sleep resistance" },
58 { DISINT_RES, "disintegration resistance" },
59 { SHOCK_RES, "shock resistance" },
60 { POISON_RES, "poison resistance" },
61 { ACID_RES, "acid resistance" },
62 { STONE_RES, "stoning resistance" },
63 { DRAIN_RES, "drain resistance" },
64 { SICK_RES, "sickness resistance" },
65 { ANTIMAGIC, "magic resistance" },
66 { HALLUC_RES, "hallucination resistance" },
67 { FUMBLING, "fumbling" },
68 { HUNGER, "voracious hunger" },
69 { TELEPAT, "telepathic" },
70 { WARNING, "warning" },
71 { WARN_OF_MON, "warn: monster type or class" },
72 { WARN_UNDEAD, "warn: undead" },
73 { SEARCHING, "searching" },
74 { INFRAVISION, "infravision" },
75 { ADORNED, "adorned (+/- Cha)" },
76 { DISPLACED, "displaced" },
77 { STEALTH, "stealthy" },
78 { AGGRAVATE_MONSTER, "monster aggravation" },
79 { CONFLICT, "conflict" },
80 { JUMPING, "jumping" },
81 { TELEPORT_CONTROL, "teleport control" },
83 { WWALKING, "water walking" },
84 { SWIMMING, "swimming" },
85 { MAGICAL_BREATHING, "magical breathing" },
86 { PASSES_WALLS, "pass thru walls" },
87 { SLOW_DIGESTION, "slow digestion" },
88 { HALF_SPDAM, "half spell damage" },
89 { HALF_PHDAM, "half physical damage" },
90 { REGENERATION, "HP regeneration" },
91 { ENERGY_REGENERATION, "energy regeneration" },
92 { PROTECTION, "extra protection" },
93 { PROT_FROM_SHAPE_CHANGERS, "protection from shape changers" },
94 { POLYMORPH_CONTROL, "polymorph control" },
95 { UNCHANGING, "unchanging" },
96 { REFLECTING, "reflecting" },
97 { FREE_ACTION, "free action" },
98 { FIXED_ABIL, "fixed abilites" },
99 { LIFESAVED, "life will be saved" },
103 /* He is being petrified - dialogue by inmet!tower */
104 static NEARDATA const char *const stoned_texts[] = {
106 "You are slowing down.", /* 5 */
107 "Your limbs are stiffening.", /* 4 */
108 "Your limbs have turned to stone.", /* 3 */
109 "You have turned to stone.", /* 2 */
110 "You are a statue." /* 1 */
112 "
\82 \82È
\82½
\82Í
\82Ì
\82ë
\82
\82È
\82Á
\82½
\81D", /* 5 */
113 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\8dd
\92¼
\82µ
\82½
\81D", /* 4 */
114 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\90Î
\89»
\82µ
\82½
\81D", /* 3 */
115 "
\82 \82È
\82½
\82Í
\90Î
\82É
\82È
\82Á
\82½
\81D", /* 2 */
116 "
\82 \82È
\82½
\82Í
\92¤
\91\9c\82É
\82È
\82Á
\82½
\81D" /* 1 */
123 register long i = (Stoned & TIMEOUT);
125 if (i > 0L && i <= SIZE(stoned_texts)) {
128 Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
130 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
131 (void) strsubst(buf, "limbs", "extremities");
133 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
134 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
139 case 5: /* slowing down */
144 case 4: /* limbs stiffening */
145 /* just one move left to save oneself so quit fiddling around;
146 don't stop attempt to eat tin--might be lizard or acidic */
152 case 3: /* limbs turned to stone */
154 nomul(-3); /* can't move anymore */
156 multi_reason = "getting stoned";
158 multi_reason = "
\90Î
\89»
\82µ
\82Â
\82Â
\82 \82é
\8e\9e\82É";
159 nomovemsg = You_can_move_again; /* not unconscious */
162 if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
163 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
167 exercise(A_DEX, FALSE);
170 /* hero is getting sicker and sicker prior to vomiting */
171 static NEARDATA const char *const vomiting_texts[] = {
173 "are feeling mildly nauseated.", /* 14 */
174 "feel slightly confused.", /* 11 */
175 "can't seem to think straight.", /* 8 */
176 "feel incredibly sick.", /* 5 */
177 "are about to vomit." /* 2 */
179 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
180 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
181 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
182 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
183 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81D" /* 2 */
191 long v = (Vomiting & TIMEOUT);
193 /* note: nhtimeout() hasn't decremented timed properties for the
194 current turn yet, so we use Vomiting-1 here */
195 switch ((int) (v - 1L)) {
197 txt = vomiting_texts[0];
200 txt = vomiting_texts[1];
203 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
204 if (!Popeye(VOMITING))
208 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
213 txt = vomiting_texts[2];
216 txt = vomiting_texts[3];
219 txt = vomiting_texts[4];
220 if (cantvomit(youmonst.data))
222 txt = "gag uncontrollably.";
224 txt = "
\8bC
\95ª
\82Ì
\88«
\82³
\82ª
\97}
\82¦
\82ç
\82ê
\82È
\82
\82È
\82Á
\82½
\81D";
225 else if (Hallucination)
226 /* "hurl" is short for "hurl chunks" which is slang for
227 relatively violent vomiting... */
228 txt = "are about to hurl!";
232 if (!cantvomit(youmonst.data)) {
234 /* case 2 used to be "You suddenly vomit!" but it wasn't sudden
235 since you've just been through the earlier messages of the
236 countdown, and it was still possible to move around between
237 that message and "You can move again." (from vomit()'s
238 nomul(-2)) with no intervening message; give one here to
239 have more specific point at which hero became unable to move
240 [vomit() issues its own message for the cantvomit() case
241 and for the FAINTING-or-worse case where stomach is empty] */
242 if (u.uhs < FAINTING)
243 You("%s!", !Hallucination ? "vomit" : "hurl chunks");
252 exercise(A_CON, FALSE);
255 static NEARDATA const char *const choke_texts[] = {
257 "You find it hard to breathe.",
258 "You're gasping for air.",
259 "You can no longer breathe.",
260 "You're turning %s.",
263 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
264 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
265 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
266 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
267 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
271 static NEARDATA const char *const choke_texts2[] = {
273 "Your %s is becoming constricted.",
274 "Your blood is having trouble reaching your brain.",
275 "The pressure on your %s increases.",
276 "Your consciousness is fading.",
279 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
280 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
281 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
282 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
283 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
290 register long i = (Strangled & TIMEOUT);
292 if (i > 0 && i <= SIZE(choke_texts)) {
293 if (Breathless || !rn2(50))
294 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
296 const char *str = choke_texts[SIZE(choke_texts) - i];
300 pline(str, hcolor(NH_BLUE));
302 pline(str, jconj_adj(hcolor(NH_BLUE)));
307 exercise(A_STR, FALSE);
310 static NEARDATA const char *const levi_texts[] = {
311 "You float slightly lower.",
312 "You wobble unsteadily %s the %s."
316 levitation_dialogue()
318 /* -1 because the last message comes via float_down() */
319 long i = (((HLevitation & TIMEOUT) - 1L) / 2L);
324 if (!ACCESSIBLE(levl[u.ux][u.uy].typ)
325 && !is_pool_or_lava(u.ux,u.uy))
328 if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) {
329 const char *s = levi_texts[SIZE(levi_texts) - i];
332 boolean danger = (is_pool_or_lava(u.ux, u.uy)
333 && !Is_waterlevel(&u.uz));
335 pline(s, danger ? "over" : "in",
336 danger ? surface(u.ux, u.uy) : "air");
342 static NEARDATA const char *const slime_texts[] = {
344 "You are turning a little %s.", /* 5 */
345 "Your limbs are getting oozy.", /* 4 */
346 "Your skin begins to peel away.", /* 3 */
347 "You are turning into %s.", /* 2 */
348 "You have become %s." /* 1 */
350 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
351 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
352 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
353 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
354 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
361 register long i = (Slimed & TIMEOUT) / 2L;
363 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
366 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
368 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
369 (void) strsubst(buf, "limbs", "extremities");
371 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
372 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
375 if (index(buf, '%')) {
376 if (i == 4L) { /* "you are turning green" */
377 if (!Blind) /* [what if you're already green?] */
379 pline(buf, hcolor(NH_GREEN));
381 pline(buf, jconj_adj(hcolor(NH_GREEN)));
385 an(Hallucination ? rndmonnam(NULL) : "green slime"));
387 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
391 if (i == 3L) { /* limbs becoming oozy */
392 HFast = 0L; /* lose intrinsic speed */
398 if (i == 2L && (HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
399 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
400 exercise(A_DEX, FALSE);
408 make_slimed(0L, "The slime that covers you is burned away!");
410 pline("
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
414 /* Intrinsic Passes_walls is temporary when your god is trying to fix
415 all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
416 it can't find anywhere to place you. If that happens you get a small
417 value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
418 Message given is "you feel much slimmer" as a joke hint that you can
419 move between things which are closely packed--like the substance of
421 static NEARDATA const char *const phaze_texts[] = {
422 "You start to feel bloated.",
423 "You are feeling rather flabby.",
429 long i = ((HPasses_walls & TIMEOUT) / 2L);
431 if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
434 if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
435 pline1(phaze_texts[SIZE(phaze_texts) - i]);
441 register struct prop *upp;
445 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
450 if (u.uluck != baseluck
451 && moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
452 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
453 * stop good luck from timing out; normal luckstones stop both;
454 * neither is stopped if you don't have a luckstone.
455 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
457 register int time_luck = stone_luck(FALSE);
458 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
460 if (u.uluck > baseluck && (nostone || time_luck < 0))
462 else if (u.uluck < baseluck && (nostone || time_luck > 0))
466 return; /* things past this point could kill you */
475 if (HLevitation & TIMEOUT)
476 levitation_dialogue();
477 if (HPasses_walls & TIMEOUT)
479 if (u.mtimedone && !--u.mtimedone) {
481 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
482 else if (is_were(youmonst.data))
483 you_unwere(FALSE); /* if polycontrl, asks whether to rehumanize */
490 /* Dissipate spell-based protection. */
492 if (--u.usptime == 0 && u.uspellprot) {
493 u.usptime = u.uspmtime;
498 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
499 u.uspellprot ? "becomes less dense" : "disappears");
501 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
502 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
508 if (--u.ugallop == 0L && u.usteed)
510 pline("%s stops galloping.", Monnam(u.usteed));
512 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
515 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
516 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
517 kptr = find_delayed_killer((int) (upp - u.uprops));
518 switch (upp - u.uprops) {
520 if (kptr && kptr->name[0]) {
521 killer.format = kptr->format;
523 Strcpy(killer.name, kptr->name);
525 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
529 killer.format = NO_KILLER_PREFIX;
530 Strcpy(killer.name, "killed by petrification");
532 killer.format = KILLED_BY;
533 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
536 dealloc_killer(kptr);
537 /* (unlike sliming, you aren't changing form here) */
541 if (kptr && kptr->name[0]) {
542 killer.format = kptr->format;
543 Strcpy(killer.name, kptr->name);
545 killer.format = NO_KILLER_PREFIX;
547 Strcpy(killer.name, "turned into green slime");
549 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
551 dealloc_killer(kptr);
552 /* involuntarily break "never changed form" conduct */
553 u.uconduct.polyselfs++;
557 make_vomiting(0L, TRUE);
561 You("die from your illness.");
563 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
564 if (kptr && kptr->name[0]) {
565 killer.format = kptr->format;
566 Strcpy(killer.name, kptr->name);
568 killer.format = KILLED_BY_AN;
569 killer.name[0] = 0; /* take the default */
571 dealloc_killer(kptr);
573 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
574 if (type_is_pname(&mons[m_idx])) {
575 killer.format = KILLED_BY;
576 } else if (mons[m_idx].geno & G_UNIQ) {
577 Strcpy(killer.name, the(killer.name));
578 killer.format = KILLED_BY;
587 You_feel("yourself slowing down%s.",
588 Fast ? " a bit" : "");
590 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
591 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
595 /* So make_confused works properly */
596 set_itimeout(&HConfusion, 1L);
597 make_confused(0L, TRUE);
602 set_itimeout(&HStun, 1L);
603 make_stunned(0L, TRUE);
608 set_itimeout(&Blinded, 1L);
609 make_blinded(0L, TRUE);
614 set_itimeout(&HDeaf, 1L);
622 if (!Invis && !BInvis && !Blind) {
625 ? "are no longer invisible."
626 : "can no longer see through yourself.");
629 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
630 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
636 set_mimic_blocking(); /* do special mimic handling */
637 see_monsters(); /* make invis mons appear */
638 newsym(u.ux, u.uy); /* make self appear */
648 make_totter(0L, TRUE);
653 set_itimeout(&HHallucination, 1L);
654 (void) make_hallucinated(0L, TRUE, 0L);
659 if (unconscious() || Sleep_resistance) {
660 incr_itimeout(&HSleepy, rnd(100));
665 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
667 fall_asleep(-sleeptime, TRUE);
668 incr_itimeout(&HSleepy, sleeptime + rnd(100));
672 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
677 You_feel("hemmed in again.");
679 pline("You're back to your %s self again.",
680 !Upolyd ? "normal" : "unusual");
684 killer.format = KILLED_BY;
687 (u.uburied) ? "suffocation" : "strangulation");
690 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
693 /* must be declining to die in explore|wizard mode;
694 treat like being cured of strangulation by prayer */
695 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
697 Your("amulet vanishes!");
699 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
704 /* call this only when a move took place. */
705 /* otherwise handle fumbling msgs locally. */
706 if (u.umoved && !Levitation) {
710 multi_reason = "fumbling";
712 multi_reason = "
\82Ö
\82Ü
\82ð
\82µ
\82½
\8c\84\82É";
714 /* The more you are carrying the more likely you
715 * are to make noise when you fumble. Adjustments
716 * to this number must be thoroughly play tested.
718 if ((inv_weight() > -500)) {
720 You("make a lot of noise!");
722 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
726 /* from outside means slippery ice; don't reset
727 counter if that's the only fumble reason */
728 HFumbling &= ~FROMOUTSIDE;
730 incr_itimeout(&HFumbling, rnd(20));
732 case DETECT_MONSTERS:
742 fall_asleep(how_long, wakeup_msg)
749 multi_reason = "sleeping";
751 multi_reason = "
\96°
\82è
\82Ì
\82³
\82È
\82©
\82É";
752 /* generally don't notice sounds while sleeping */
753 if (wakeup_msg && multi == how_long) {
754 /* caller can follow with a direct call to Hear_again() if
755 there's a need to override this when wakeup_msg is true */
756 incr_itimeout(&HDeaf, how_long);
758 afternmv = Hear_again; /* this won't give any messages */
760 /* early wakeup from combat won't be possible until next monster turn */
761 u.usleep = monstermoves;
763 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
765 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
768 /* Attach an egg hatch timeout to the given egg.
769 * when = Time to hatch, usually only passed if re-creating an
770 * existing hatch timer. Pass 0L for random hatch time.
773 attach_egg_hatch_timeout(egg, when)
779 /* stop previous timer, if any */
780 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
783 * Decide if and when to hatch the egg. The old hatch_it() code tried
784 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
785 * a number x, 1<=x<=age, where x>150. This yields a chance of
786 * hatching > 99.9993%. Mimic that here.
789 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
797 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
801 /* prevent an egg from ever hatching */
806 /* stop previous timer, if any */
807 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
810 /* timer callback routine: hatch the given egg */
812 hatch_egg(arg, timeout)
817 struct monst *mon, *mon2;
820 boolean yours, silent, knows_egg = FALSE;
821 boolean cansee_hatchspot = FALSE;
822 int i, mnum, hatchcount = 0;
825 /* sterilized while waiting */
826 if (egg->corpsenm == NON_PM)
829 mon = mon2 = (struct monst *) 0;
830 mnum = big_to_little(egg->corpsenm);
831 /* The identity of one's father is learned, not innate */
832 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
833 silent = (timeout != monstermoves); /* hatched while away */
835 /* only can hatch when in INVENT, FLOOR, MINVENT */
836 if (get_obj_location(egg, &x, &y, 0)) {
837 hatchcount = rnd((int) egg->quan);
838 cansee_hatchspot = cansee(x, y) && !silent;
839 if (!(mons[mnum].geno & G_UNIQ)
840 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
841 for (i = hatchcount; i > 0; i--) {
842 if (!enexto(&cc, x, y, &mons[mnum])
843 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
845 /* tame if your own egg hatches while you're on the
846 same dungeon level, or any dragon egg which hatches
847 while it's in your inventory */
848 if ((yours && !silent)
849 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
850 if (tamedog(mon, (struct obj *) 0)) {
851 if (carried(egg) && mon->data->mlet != S_DRAGON)
855 if (mvitals[mnum].mvflags & G_EXTINCT)
856 break; /* just made last one */
857 mon2 = mon; /* in case makemon() fails on 2nd egg */
862 egg->quan -= (long) hatchcount;
866 * We could possibly hatch while migrating, but the code isn't
869 } else if (obj->where == OBJ_MIGRATING) {
871 * We can do several things. The first ones that come to
873 * + Create the hatched monster then place it on the migrating
874 * mons list. This is tough because all makemon() is made
875 * to place the monster as well. Makemon() also doesn't lend
876 * itself well to splitting off a "not yet placed" subroutine.
877 * + Mark the egg as hatched, then place the monster when we
878 * place the migrating objects.
879 * + Or just kill any egg which gets sent to another level.
880 * Falling is the usual reason such transportation occurs.
882 cansee_hatchspot = FALSE;
888 char monnambuf[BUFSZ], carriedby[BUFSZ];
889 boolean siblings = (hatchcount > 1), redraw = FALSE;
891 if (cansee_hatchspot) {
892 /* [bug? m_monnam() yields accurate monster type
893 regardless of hallucination] */
895 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
896 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
898 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
901 /* we don't learn the egg type here because learning
902 an egg type requires either seeing the egg hatch
903 or being familiar with the egg already,
904 as well as being able to see the resulting
905 monster, checked below
908 switch (egg->where) {
910 knows_egg = TRUE; /* true even if you are blind */
911 if (!cansee_hatchspot)
913 You_feel("%s %s from your pack!", something,
914 locomotion(mon->data, "drop"));
916 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
917 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
921 You_see("%s %s out of your pack!", monnambuf,
922 locomotion(mon->data, "drop"));
924 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
925 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
929 pline("%s cries sound like \"%s%s\"",
930 siblings ? "Their" : "Its",
931 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
933 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
934 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
936 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
938 verbalize("Gleep!"); /* Mything eggs :-) */
940 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
946 if (cansee_hatchspot) {
949 You_see("%s hatch.", monnambuf);
951 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
952 redraw = TRUE; /* update egg's map location */
957 if (cansee_hatchspot) {
958 /* egg carrying monster might be invisible */
961 && (!mon2->wormno || cansee(mon2->mx, mon2->my))) {
963 Sprintf(carriedby, "%s pack",
964 s_suffix(a_monnam(mon2)));
966 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
970 } else if (is_pool(mon->mx, mon->my)) {
972 Strcpy(carriedby, "empty water");
974 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
977 Strcpy(carriedby, "thin air");
979 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
982 You_see("%s %s out of %s!", monnambuf,
983 locomotion(mon->data, "drop"), carriedby);
985 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
986 locomotion(mon->data, "
\97\8e\82¿
\82é"));
995 impossible("egg hatched where? (%d)", (int) egg->where);
999 if (cansee_hatchspot && knows_egg)
1000 learn_egg_type(mnum);
1002 if (egg->quan > 0) {
1003 /* still some eggs left */
1004 /* Instead of ordinary egg timeout use a short one */
1005 attach_egg_hatch_timeout(egg, (long) rnd(12));
1006 } else if (carried(egg)) {
1009 /* free egg here because we use it above */
1010 obj_extract_self(egg);
1011 obfree(egg, (struct obj *) 0);
1018 /* Learn to recognize eggs of the given type. */
1020 learn_egg_type(mnum)
1023 /* baby monsters hatch from grown-up eggs */
1024 mnum = little_to_big(mnum);
1025 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
1026 /* we might have just learned about other eggs being carried */
1030 /* Attach a fig_transform timeout to the given figurine. */
1032 attach_fig_transform_timeout(figurine)
1033 struct obj *figurine;
1037 /* stop previous timer, if any */
1038 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
1041 * Decide when to transform the figurine.
1043 i = rnd(9000) + 200;
1044 /* figurine will transform */
1045 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
1046 obj_to_any(figurine));
1049 /* give a fumble message */
1053 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
1056 boolean on_foot = TRUE;
1060 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
1063 if (otmp && on_foot) { /* trip over something in particular */
1065 If there is only one item, it will have just been named
1066 during the move, so refer to by via pronoun; otherwise,
1067 if the top item has been or can be seen, refer to it by
1068 name; if not, look for rocks to trip over; trip over
1069 anonymous "something" if there aren't any rocks.
1072 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1073 ? ((otmp->quan == 1L) ? "it"
1074 : Hallucination ? "they" : "them")
1075 : (otmp->dknown || !Blind)
1077 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1079 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
1081 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1083 : (otmp->dknown || !Blind)
1085 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1089 if (Hallucination) {
1090 what = strcpy(buf, what);
1091 buf[0] = highc(buf[0]);
1093 pline("Egads! %s bite%s your %s!", what,
1094 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
1096 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
1100 You("trip over %s.", what);
1102 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
1104 if (!uarmf && otmp->otyp == CORPSE
1105 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
1107 Sprintf(killer.name, "tripping over %s corpse",
1108 an(mons[otmp->corpsenm].mname));
1110 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
1111 mons[otmp->corpsenm].mname);
1113 instapetrify(killer.name);
1115 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
1117 pline("%s %s%s on the ice.",
1118 u.usteed ? upstart(x_monnam(u.usteed,
1119 (has_mname(u.usteed)) ? ARTICLE_NONE
1121 (char *) 0, SUPPRESS_SADDLE, FALSE))
1123 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
1125 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
1126 u.usteed ? upstart(x_monnam(u.usteed,
1127 (has_mname(u.usteed)) ? ARTICLE_NONE
1129 (char *) 0, SUPPRESS_SADDLE, FALSE))
1137 You("trip over your own %s.",
1138 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
1140 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
1141 Hallucination ? "
\95I" : body_part(FOOT));
1147 Hallucination ? "on a banana peel" : "and nearly fall");
1149 You("%s
\81D", Hallucination ?
1150 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
1157 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
1163 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
1170 Your("%s slip out of the stirrups.",
1171 makeplural(body_part(FOOT)));
1173 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1178 You("let go of the reins.");
1180 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1184 You("bang into the saddle-horn.");
1186 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1190 You("slide to one side of the saddle.");
1192 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1195 dismount_steed(DISMOUNT_FELL);
1200 /* Print a lamp flicker message with tailer. */
1202 see_lamp_flicker(obj, tailer)
1206 switch (obj->where) {
1210 pline("%s flickers%s.", Yname2(obj), tailer);
1212 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1216 You_see("%s flicker%s.", an(xname(obj)), tailer);
1218 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1223 /* Print a dimming message for brass lanterns. */
1225 lantern_message(obj)
1228 /* from adventure */
1229 switch (obj->where) {
1232 Your("lantern is getting dim.");
1234 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1237 pline("Batteries have not been invented yet.");
1239 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1243 You_see("a lantern getting dim.");
1245 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1249 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1251 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1257 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1258 * See begin_burn() for meanings of obj->age and obj->spe.
1261 burn_object(arg, timeout)
1265 struct obj *obj = arg->a_obj;
1266 boolean canseeit, many, menorah, need_newsym, need_invupdate;
1270 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1271 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1273 /* timeout while away */
1274 if (timeout != monstermoves) {
1275 long how_long = monstermoves - timeout;
1277 if (how_long >= obj->age) {
1279 end_burn(obj, FALSE);
1282 obj->spe = 0; /* no more candles */
1283 obj->owt = weight(obj);
1284 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1285 /* get rid of candles and burning oil potions;
1286 we know this object isn't carried by hero,
1287 nor is it migrating */
1288 obj_extract_self(obj);
1289 obfree(obj, (struct obj *) 0);
1290 obj = (struct obj *) 0;
1294 obj->age -= how_long;
1295 begin_burn(obj, TRUE);
1300 /* only interested in INVENT, FLOOR, and MINVENT */
1301 if (get_obj_location(obj, &x, &y, 0)) {
1302 canseeit = !Blind && cansee(x, y);
1303 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1304 (void) Shk_Your(whose, obj);
1308 need_newsym = need_invupdate = FALSE;
1310 /* obj->age is the age remaining at this point. */
1311 switch (obj->otyp) {
1313 /* this should only be called when we run out */
1315 switch (obj->where) {
1317 need_invupdate = TRUE;
1321 pline("%spotion of oil has burnt away.", whose);
1323 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1327 You_see("a burning potion of oil go out.");
1329 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1334 end_burn(obj, FALSE); /* turn off light source */
1338 /* clear migrating obj's destination code before obfree
1339 to avoid false complaint of deleting worn item */
1340 if (obj->where == OBJ_MIGRATING)
1341 obj->owornmask = 0L;
1342 obj_extract_self(obj);
1343 obfree(obj, (struct obj *) 0);
1345 obj = (struct obj *) 0;
1350 switch ((int) obj->age) {
1355 if (obj->otyp == BRASS_LANTERN)
1356 lantern_message(obj);
1358 see_lamp_flicker(obj,
1360 obj->age == 50L ? " considerably" : "");
1362 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1368 if (obj->otyp == BRASS_LANTERN)
1369 lantern_message(obj);
1371 switch (obj->where) {
1375 pline("%s seems about to go out.", Yname2(obj));
1377 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1381 You_see("%s about to go out.", an(xname(obj)));
1383 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1391 /* even if blind you'll know if holding it */
1392 if (canseeit || obj->where == OBJ_INVENT) {
1393 switch (obj->where) {
1395 need_invupdate = TRUE;
1398 if (obj->otyp == BRASS_LANTERN)
1400 pline("%slantern has run out of power.", whose);
1402 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1405 pline("%s has gone out.", Yname2(obj));
1407 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1410 if (obj->otyp == BRASS_LANTERN)
1412 You_see("a lantern run out of power.");
1414 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1417 You_see("%s go out.", an(xname(obj)));
1419 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1423 end_burn(obj, FALSE);
1428 * Someone added fuel to the lamp while it was
1429 * lit. Just fall through and let begin burn
1430 * handle the new age.
1436 begin_burn(obj, TRUE);
1440 case CANDELABRUM_OF_INVOCATION:
1446 switch (obj->where) {
1450 pline("%s%scandle%s getting short.", whose,
1451 menorah ? "candelabrum's " : "",
1452 many ? "s are" : " is");
1454 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1455 menorah ? "
\90C
\91ä
\82Ì" : "");
1460 You_see("%scandle%s getting short.",
1461 menorah ? "a candelabrum's " : many ? "some "
1465 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1466 menorah ? "
\90C
\91ä
\82Ì" : "");
1474 switch (obj->where) {
1478 pline("%s%scandle%s flame%s flicker%s low!", whose,
1479 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1480 many ? "s" : "", many ? "" : "s");
1482 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1483 menorah ? "
\90C
\91ä
\82Ì" : "");
1488 You_see("%scandle%s flame%s flicker low!",
1489 menorah ? "a candelabrum's " : many ? "some "
1491 many ? "s'" : "'s", many ? "s" : "");
1493 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1494 menorah ? "
\90C
\91ä
\82Ì" : "");
1501 /* we know even if blind and in our inventory */
1502 if (canseeit || obj->where == OBJ_INVENT) {
1504 switch (obj->where) {
1506 need_invupdate = TRUE;
1510 pline("%scandelabrum's flame%s.", whose,
1511 many ? "s die" : " dies");
1513 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1518 You_see("a candelabrum's flame%s die.",
1521 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1526 switch (obj->where) {
1528 /* no need_invupdate for update_inventory() necessary;
1529 useupall() -> freeinv() handles it */
1533 pline("%s %s consumed!", Yname2(obj),
1534 many ? "are" : "is");
1536 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1541 You see some wax candles consumed!
1542 You see a wax candle consumed!
1545 You_see("%s%s consumed!", many ? "some " : "",
1546 many ? xname(obj) : an(xname(obj)));
1548 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1557 ? (many ? "They shriek!" : "It shrieks!")
1558 : Blind ? "" : (many ? "Their flames die."
1559 : "Its flame dies."));
1561 pline(Hallucination ? "
\82»
\82ê
\82Í
\8bà
\90Ø
\82è
\90º
\82ð
\82 \82°
\82½
\81I"
1563 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1567 end_burn(obj, FALSE);
1571 obj->owt = weight(obj);
1576 /* clear migrating obj's destination code
1577 so obfree won't think this item is worn */
1578 if (obj->where == OBJ_MIGRATING)
1579 obj->owornmask = 0L;
1580 obj_extract_self(obj);
1581 obfree(obj, (struct obj *) 0);
1583 obj = (struct obj *) 0;
1585 break; /* case [age ==] 0 */
1589 * Someone added fuel (candles) to the menorah while
1590 * it was lit. Just fall through and let begin burn
1591 * handle the new age.
1596 if (obj && obj->age)
1597 begin_burn(obj, TRUE);
1598 break; /* case [otyp ==] candelabrum|tallow_candle|wax_candle */
1601 impossible("burn_object: unexpeced obj %s", xname(obj));
1611 * Start a burn timeout on the given object. If not "already lit" then
1612 * create a light source for the vision system. There had better not
1613 * be a burn already running on the object.
1615 * Magic lamps stay lit as long as there's a genie inside, so don't start
1619 * potions of oil, lamps & candles:
1620 * age = # of turns of fuel left
1624 * spe = 0 not lightable, 1 lightable forever
1626 * age = # of turns of fuel left
1627 * spe = # of candles
1629 * Once the burn begins, the age will be set to the amount of fuel
1630 * remaining _once_the_burn_finishes_. If the burn is terminated
1631 * early then fuel is added back.
1633 * This use of age differs from the use of age for corpses and eggs.
1634 * For the latter items, age is when the object was created, so we
1635 * know when it becomes "bad".
1637 * This is a "silent" routine - it should not print anything out.
1640 begin_burn(obj, already_lit)
1642 boolean already_lit;
1646 boolean do_timer = TRUE;
1648 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1651 switch (obj->otyp) {
1659 radius = 1; /* very dim light */
1664 /* magic times are 150, 100, 50, 25, and 0 */
1665 if (obj->age > 150L)
1666 turns = obj->age - 150L;
1667 else if (obj->age > 100L)
1668 turns = obj->age - 100L;
1669 else if (obj->age > 50L)
1670 turns = obj->age - 50L;
1671 else if (obj->age > 25L)
1672 turns = obj->age - 25L;
1677 case CANDELABRUM_OF_INVOCATION:
1680 /* magic times are 75, 15, and 0 */
1682 turns = obj->age - 75L;
1683 else if (obj->age > 15L)
1684 turns = obj->age - 15L;
1687 radius = candle_light_range(obj);
1691 /* [ALI] Support artifact light sources */
1692 if (artifact_light(obj)) {
1695 radius = arti_light_radius(obj);
1697 impossible("begin burn: unexpected %s", xname(obj));
1704 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1707 if (carried(obj) && !already_lit)
1713 if (carried(obj) && !already_lit)
1717 if (obj->lamplit && !already_lit) {
1720 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1721 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1723 impossible("begin_burn: can't get obj position");
1728 * Stop a burn timeout on the given object if timer attached. Darken
1732 end_burn(obj, timer_attached)
1734 boolean timer_attached;
1736 if (!obj->lamplit) {
1737 impossible("end_burn: obj %s not lit", xname(obj));
1741 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1742 timer_attached = FALSE;
1744 if (!timer_attached) {
1745 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1746 del_light_source(LS_OBJECT, obj_to_any(obj));
1748 if (obj->where == OBJ_INVENT)
1750 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1751 impossible("end_burn: obj %s not timed!", xname(obj));
1755 * Cleanup a burning object if timer stopped.
1758 cleanup_burn(arg, expire_time)
1762 struct obj *obj = arg->a_obj;
1763 if (!obj->lamplit) {
1764 impossible("cleanup_burn: obj %s not lit", xname(obj));
1768 del_light_source(LS_OBJECT, obj_to_any(obj));
1770 /* restore unused time */
1771 obj->age += expire_time - monstermoves;
1775 if (obj->where == OBJ_INVENT)
1787 /* no lightning if not the air level or too often, even then */
1788 if (!Is_airlevel(&u.uz) || rn2(8))
1791 /* the number of strikes is 8-log2(nstrike) */
1792 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1797 } while (++count < 100 && levl[x][y].typ != CLOUD);
1802 if (dirx != 0 || diry != 0)
1803 buzz(-15, /* "monster" LIGHTNING spell */
1804 8, x, y, dirx, diry);
1808 if (levl[u.ux][u.uy].typ == CLOUD) {
1809 /* Inside a cloud during a thunder storm is deafening. */
1810 /* Even if already deaf, we sense the thunder's vibrations. */
1812 pline("Kaboom!!! Boom!! Boom!!");
1814 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");
1815 incr_itimeout(&HDeaf, rn1(20, 30));
1816 context.botl = TRUE;
1817 if (!u.uinvulnerable) {
1821 multi_reason = "hiding from thunderstorm";
1823 multi_reason = "
\97\8b\82Ì
\97\92\82ð
\94ð
\82¯
\82Ä
\82¢
\82é
\8e\9e\82É";
1828 You_hear("a rumbling noise.");
1830 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1833 /* -------------------------------------------------------------------------
1836 * Generic Timeout Functions.
1841 * boolean start_timer(long timeout,short kind,short func_index,
1843 * Start a timer of kind 'kind' that will expire at time
1844 * monstermoves+'timeout'. Call the function at 'func_index'
1845 * in the timeout table using argument 'arg'. Return TRUE if
1846 * a timer was started. This places the timer on a list ordered
1847 * "sooner" to "later". If an object, increment the object's
1850 * long stop_timer(short func_index, anything *arg)
1851 * Stop a timer specified by the (func_index, arg) pair. This
1852 * assumes that such a pair is unique. Return the time the
1853 * timer would have gone off. If no timer is found, return 0.
1854 * If an object, decrement the object's timer count.
1856 * long peek_timer(short func_index, anything *arg)
1857 * Return time specified timer will go off (0 if no such timer).
1859 * void run_timers(void)
1860 * Call timers that have timed out.
1863 * void save_timers(int fd, int mode, int range)
1864 * Save all timers of range 'range'. Range is either global
1865 * or local. Global timers follow game play, local timers
1866 * are saved with a level. Object and monster timers are
1867 * saved using their respective id's instead of pointers.
1869 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1870 * Restore timers of range 'range'. If from a ghost pile,
1871 * adjust the timeout by 'adjust'. The object and monster
1872 * ids are not restored until later.
1874 * void relink_timers(boolean ghostly)
1875 * Relink all object and monster timers that had been saved
1876 * using their object's or monster's id number.
1879 * void obj_move_timers(struct obj *src, struct obj *dest)
1880 * Reassign all timers from src to dest.
1882 * void obj_split_timers(struct obj *src, struct obj *dest)
1883 * Duplicate all timers assigned to src and attach them to dest.
1885 * void obj_stop_timers(struct obj *obj)
1886 * Stop all timers attached to obj.
1888 * boolean obj_has_timer(struct obj *object, short timer_type)
1889 * Check whether object has a timer of type timer_type.
1892 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1893 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1894 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1895 STATIC_DCL timer_element *FDECL(remove_timer,
1896 (timer_element **, SHORT_P, ANY_P *));
1897 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1898 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1899 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1900 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1902 /* ordered timer list */
1903 static timer_element *timer_base; /* "active" */
1904 static unsigned long timer_id = 1;
1906 /* If defined, then include names when printing out the timer queue */
1907 #define VERBOSE_TIMER
1910 timeout_proc f, cleanup;
1911 #ifdef VERBOSE_TIMER
1913 #define TTAB(a, b, c) \
1918 #define TTAB(a, b, c) \
1925 /* table of timeout functions */
1926 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1927 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
1928 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
1929 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
1930 TTAB(burn_object, cleanup_burn, "burn_object"),
1931 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
1932 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
1933 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
1937 STATIC_OVL const char *
1955 print_queue(win, base)
1957 timer_element *base;
1959 timer_element *curr;
1963 putstr(win, 0, " <empty>");
1965 putstr(win, 0, "timeout id kind call");
1966 for (curr = base; curr; curr = curr->next) {
1967 #ifdef VERBOSE_TIMER
1968 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
1969 curr->tid, kind_name(curr->kind),
1970 timeout_funcs[curr->func_index].name,
1971 fmt_ptr((genericptr_t) curr->arg.a_void));
1973 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
1974 curr->tid, kind_name(curr->kind), curr->func_index,
1975 fmt_ptr((genericptr_t) curr->arg.a_void));
1977 putstr(win, 0, buf);
1987 const char *propname;
1989 int i, p, count, longestlen, ln, specindx = 0;
1991 win = create_nhwindow(NHW_MENU); /* corner text window */
1995 Sprintf(buf, "Current time = %ld.", monstermoves);
1996 putstr(win, 0, buf);
1998 putstr(win, 0, "Active timeout queue:");
2000 print_queue(win, timer_base);
2003 * check every one; the majority can't obtain temporary timeouts in
2004 * normal play but those can be forced via the #wizintrinsic command.
2006 count = longestlen = 0;
2007 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2008 p = propertynames[i].prop_num;
2009 intrinsic = u.uprops[p].intrinsic;
2010 if (intrinsic & TIMEOUT) {
2012 if ((ln = (int) strlen(propname)) > longestlen)
2015 if (specindx == 0 && p == FIRE_RES)
2020 putstr(win, 0, "No timed properties.");
2022 putstr(win, 0, "Timed properties:");
2024 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2025 p = propertynames[i].prop_num;
2026 intrinsic = u.uprops[p].intrinsic;
2027 if (intrinsic & TIMEOUT) {
2028 if (specindx > 0 && i >= specindx) {
2029 putstr(win, 0, " -- settable via #wizinstrinc only --");
2032 /* timeout value can be up to 16777215 (0x00ffffff) but
2033 width of 4 digits should result in values lining up
2034 almost all the time (if/when they don't, it won't
2035 look nice but the information will still be accurate) */
2036 Sprintf(buf, " %*s %4ld", -longestlen, propname,
2037 (intrinsic & TIMEOUT));
2038 putstr(win, 0, buf);
2042 display_nhwindow(win, FALSE);
2043 destroy_nhwindow(win);
2049 timer_sanity_check()
2051 timer_element *curr;
2053 /* this should be much more complete */
2054 for (curr = timer_base; curr; curr = curr->next)
2055 if (curr->kind == TIMER_OBJECT) {
2056 struct obj *obj = curr->arg.a_obj;
2058 if (obj->timed == 0) {
2059 pline("timer sanity: untimed obj %s, timer %ld",
2060 fmt_ptr((genericptr_t) obj), curr->tid);
2066 * Pick off timeout elements from the global queue and call their functions.
2067 * Do this until their time is less than or equal to the move count.
2072 timer_element *curr;
2075 * Always use the first element. Elements may be added or deleted at
2076 * any time. The list is ordered, we are done when the first element
2079 while (timer_base && timer_base->timeout <= monstermoves) {
2081 timer_base = curr->next;
2083 if (curr->kind == TIMER_OBJECT)
2084 (curr->arg.a_obj)->timed--;
2085 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
2086 free((genericptr_t) curr);
2091 * Start a timer. Return TRUE if successful.
2094 start_timer(when, kind, func_index, arg)
2102 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
2103 panic("start_timer");
2105 gnu = (timer_element *) alloc(sizeof(timer_element));
2106 (void) memset((genericptr_t)gnu, 0, sizeof(timer_element));
2108 gnu->tid = timer_id++;
2109 gnu->timeout = monstermoves + when;
2111 gnu->needs_fixup = 0;
2112 gnu->func_index = func_index;
2116 if (kind == TIMER_OBJECT) /* increment object's timed count */
2117 (arg->a_obj)->timed++;
2119 /* should check for duplicates and fail if any */
2124 * Remove the timer from the current list and free it up. Return the time
2125 * remaining until it would have gone off, 0 if not found.
2128 stop_timer(func_index, arg)
2132 timer_element *doomed;
2135 doomed = remove_timer(&timer_base, func_index, arg);
2138 timeout = doomed->timeout;
2139 if (doomed->kind == TIMER_OBJECT)
2140 (arg->a_obj)->timed--;
2141 if (timeout_funcs[doomed->func_index].cleanup)
2142 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
2143 free((genericptr_t) doomed);
2144 return (timeout - monstermoves);
2150 * Find the timeout of specified timer; return 0 if none.
2153 peek_timer(type, arg)
2157 timer_element *curr;
2159 for (curr = timer_base; curr; curr = curr->next) {
2160 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
2161 return curr->timeout;
2167 * Move all object timers from src to dest, leaving src untimed.
2170 obj_move_timers(src, dest)
2171 struct obj *src, *dest;
2174 timer_element *curr;
2176 for (count = 0, curr = timer_base; curr; curr = curr->next)
2177 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2178 curr->arg.a_obj = dest;
2182 if (count != src->timed)
2183 panic("obj_move_timers");
2188 * Find all object timers and duplicate them for the new object "dest".
2191 obj_split_timers(src, dest)
2192 struct obj *src, *dest;
2194 timer_element *curr, *next_timer = 0;
2196 for (curr = timer_base; curr; curr = next_timer) {
2197 next_timer = curr->next; /* things may be inserted */
2198 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2199 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
2200 curr->func_index, obj_to_any(dest));
2206 * Stop all timers attached to this object. We can get away with this because
2207 * all object pointers are unique.
2210 obj_stop_timers(obj)
2213 timer_element *curr, *prev, *next_timer = 0;
2215 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2216 next_timer = curr->next;
2217 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
2219 prev->next = curr->next;
2221 timer_base = curr->next;
2222 if (timeout_funcs[curr->func_index].cleanup)
2223 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2225 free((genericptr_t) curr);
2234 * Check whether object has a timer of type timer_type.
2237 obj_has_timer(object, timer_type)
2241 long timeout = peek_timer(timer_type, obj_to_any(object));
2243 return (boolean) (timeout != 0L);
2247 * Stop all timers of index func_index at this spot.
2251 spot_stop_timers(x, y, func_index)
2255 timer_element *curr, *prev, *next_timer = 0;
2256 long where = (((long) x << 16) | ((long) y));
2258 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2259 next_timer = curr->next;
2260 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2261 && curr->arg.a_long == where) {
2263 prev->next = curr->next;
2265 timer_base = curr->next;
2266 if (timeout_funcs[curr->func_index].cleanup)
2267 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2269 free((genericptr_t) curr);
2277 * When is the spot timer of type func_index going to expire?
2278 * Returns 0L if no such timer.
2281 spot_time_expires(x, y, func_index)
2285 timer_element *curr;
2286 long where = (((long) x << 16) | ((long) y));
2288 for (curr = timer_base; curr; curr = curr->next) {
2289 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2290 && curr->arg.a_long == where)
2291 return curr->timeout;
2297 spot_time_left(x, y, func_index)
2301 long expires = spot_time_expires(x, y, func_index);
2302 return (expires > 0L) ? expires - monstermoves : 0L;
2305 /* Insert timer into the global queue */
2310 timer_element *curr, *prev;
2312 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2313 if (curr->timeout >= gnu->timeout)
2323 STATIC_OVL timer_element *
2324 remove_timer(base, func_index, arg)
2325 timer_element **base;
2329 timer_element *prev, *curr;
2331 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2332 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2337 prev->next = curr->next;
2346 write_timer(fd, timer)
2348 timer_element *timer;
2353 switch (timer->kind) {
2356 /* assume no pointers in arg */
2357 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2361 if (timer->needs_fixup)
2362 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2364 /* replace object pointer with id */
2365 arg_save.a_obj = timer->arg.a_obj;
2366 timer->arg = zeroany;
2367 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2368 timer->needs_fixup = 1;
2369 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2370 timer->arg.a_obj = arg_save.a_obj;
2371 timer->needs_fixup = 0;
2376 if (timer->needs_fixup)
2377 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2379 /* replace monster pointer with id */
2380 arg_save.a_monst = timer->arg.a_monst;
2381 timer->arg = zeroany;
2382 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2383 timer->needs_fixup = 1;
2384 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2385 timer->arg.a_monst = arg_save.a_monst;
2386 timer->needs_fixup = 0;
2391 panic("write_timer");
2397 * Return TRUE if the object will stay on the level when the level is
2404 switch (obj->where) {
2412 return obj_is_local(obj->ocontainer);
2414 return mon_is_local(obj->ocarry);
2416 panic("obj_is_local");
2421 * Return TRUE if the given monster will stay on the level when the
2430 for (curr = migrating_mons; curr; curr = curr->nmon)
2433 /* `mydogs' is used during level changes, never saved and restored */
2434 for (curr = mydogs; curr; curr = curr->nmon)
2441 * Return TRUE if the timer is attached to something that will stay on the
2442 * level when the level is saved.
2445 timer_is_local(timer)
2446 timer_element *timer;
2448 switch (timer->kind) {
2454 return obj_is_local(timer->arg.a_obj);
2456 return mon_is_local(timer->arg.a_monst);
2458 panic("timer_is_local");
2463 * Part of the save routine. Count up the number of timers that would
2464 * be written. If write_it is true, actually write the timer.
2467 maybe_write_timer(fd, range, write_it)
2472 timer_element *curr;
2474 for (curr = timer_base; curr; curr = curr->next) {
2475 if (range == RANGE_GLOBAL) {
2478 if (!timer_is_local(curr)) {
2481 write_timer(fd, curr);
2487 if (timer_is_local(curr)) {
2490 write_timer(fd, curr);
2499 * Save part of the timer list. The parameter 'range' specifies either
2500 * global or level timers to save. The timer ID is saved with the global
2504 * + timeouts that follow the hero (global)
2505 * + timeouts that follow obj & monst that are migrating
2508 * + timeouts that are level specific (e.g. storms)
2509 * + timeouts that stay with the level (obj & monst)
2512 save_timers(fd, mode, range)
2513 int fd, mode, range;
2515 timer_element *curr, *prev, *next_timer = 0;
2518 if (perform_bwrite(mode)) {
2519 if (range == RANGE_GLOBAL)
2520 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2522 count = maybe_write_timer(fd, range, FALSE);
2523 bwrite(fd, (genericptr_t) &count, sizeof count);
2524 (void) maybe_write_timer(fd, range, TRUE);
2527 if (release_data(mode)) {
2528 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2529 next_timer = curr->next; /* in case curr is removed */
2531 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2533 prev->next = curr->next;
2535 timer_base = curr->next;
2536 free((genericptr_t) curr);
2537 /* prev stays the same */
2546 * Pull in the structures from disk, but don't recalculate the object and
2550 restore_timers(fd, range, ghostly, adjust)
2552 boolean ghostly; /* restoring from a ghost level */
2553 long adjust; /* how much to adjust timeout */
2556 timer_element *curr;
2558 if (range == RANGE_GLOBAL)
2559 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2561 /* restore elements */
2562 mread(fd, (genericptr_t) &count, sizeof count);
2563 while (count-- > 0) {
2564 curr = (timer_element *) alloc(sizeof(timer_element));
2565 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2567 curr->timeout += adjust;
2572 /* to support '#stats' wizard-mode command */
2574 timer_stats(hdrfmt, hdrbuf, count, size)
2581 Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
2582 *count = *size = 0L;
2583 for (te = timer_base; te; te = te->next) {
2585 *size += (long) sizeof *te;
2589 /* reset all timers that are marked for reseting */
2591 relink_timers(ghostly)
2594 timer_element *curr;
2597 for (curr = timer_base; curr; curr = curr->next) {
2598 if (curr->needs_fixup) {
2599 if (curr->kind == TIMER_OBJECT) {
2601 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2602 panic("relink_timers 1");
2604 nid = curr->arg.a_uint;
2605 curr->arg.a_obj = find_oid(nid);
2606 if (!curr->arg.a_obj)
2607 panic("cant find o_id %d", nid);
2608 curr->needs_fixup = 0;
2609 } else if (curr->kind == TIMER_MONSTER) {
2610 panic("relink_timers: no monster timer implemented");
2612 panic("relink_timers 2");