1 /* NetHack 3.6 timeout.c $NHDT-Date: 1446861771 2015/11/07 02:02:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
8 /* JNetHack may be freely redistributed. See license for details. */
11 #include "lev.h" /* for checking save modes */
13 STATIC_DCL void NDECL(stoned_dialogue);
14 STATIC_DCL void NDECL(vomiting_dialogue);
15 STATIC_DCL void NDECL(choke_dialogue);
16 STATIC_DCL void NDECL(slime_dialogue);
17 STATIC_DCL void NDECL(slip_or_trip);
18 STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
19 STATIC_DCL void FDECL(lantern_message, (struct obj *));
20 STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long));
22 /* He is being petrified - dialogue by inmet!tower */
23 static NEARDATA const char *const stoned_texts[] = {
25 "You are slowing down.", /* 5 */
26 "Your limbs are stiffening.", /* 4 */
27 "Your limbs have turned to stone.", /* 3 */
28 "You have turned to stone.", /* 2 */
29 "You are a statue." /* 1 */
31 "
\82 \82È
\82½
\82Í
\82Ì
\82ë
\82
\82È
\82Á
\82½
\81D", /* 5 */
32 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\8dd
\92¼
\82µ
\82½
\81D", /* 4 */
33 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\90Î
\89»
\82µ
\82½
\81D", /* 3 */
34 "
\82 \82È
\82½
\82Í
\90Î
\82É
\82È
\82Á
\82½
\81D", /* 2 */
35 "
\82 \82È
\82½
\82Í
\92¤
\91\9c\82É
\82È
\82Á
\82½
\81D" /* 1 */
42 register long i = (Stoned & TIMEOUT);
44 if (i > 0L && i <= SIZE(stoned_texts)) {
47 Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
48 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
49 (void) strsubst(buf, "limbs", "extremities");
53 case 5: /* slowing down */
58 case 4: /* limbs stiffening */
59 /* just one move left to save oneself so quit fiddling around;
60 don't stop attempt to eat tin--might be lizard or acidic */
66 case 3: /* limbs turned to stone */
68 nomul(-3); /* can't move anymore */
69 multi_reason = "getting stoned";
70 nomovemsg = You_can_move_again; /* not unconscious */
75 exercise(A_DEX, FALSE);
78 /* He is getting sicker and sicker prior to vomiting */
79 static NEARDATA const char *const vomiting_texts[] = {
81 "are feeling mildly nauseated.", /* 14 */
82 "feel slightly confused.", /* 11 */
83 "can't seem to think straight.", /* 8 */
84 "feel incredibly sick.", /* 5 */
85 "suddenly vomit!" /* 2 */
87 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
88 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
89 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
90 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
91 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81I" /* 2 */
99 long v = (Vomiting & TIMEOUT);
101 /* note: nhtimeout() hasn't decremented timed properties for the
102 current turn yet, so we use Vomiting-1 here */
103 switch ((int) (v - 1L)) {
105 txt = vomiting_texts[0];
108 txt = vomiting_texts[1];
111 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
112 if (!Popeye(VOMITING))
116 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
121 txt = vomiting_texts[2];
124 txt = vomiting_texts[3];
127 txt = vomiting_texts[4];
128 if (cantvomit(youmonst.data))
129 txt = "gag uncontrolably.";
133 if (!cantvomit(youmonst.data))
142 exercise(A_CON, FALSE);
145 static NEARDATA const char *const choke_texts[] = {
147 "You find it hard to breathe.", "You're gasping for air.",
148 "You can no longer breathe.", "You're turning %s.", "You suffocate."
150 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
151 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
152 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
153 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
154 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
158 static NEARDATA const char *const choke_texts2[] = {
160 "Your %s is becoming constricted.",
161 "Your blood is having trouble reaching your brain.",
162 "The pressure on your %s increases.", "Your consciousness is fading.",
165 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
166 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
167 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
168 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
169 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
176 register long i = (Strangled & TIMEOUT);
178 if (i > 0 && i <= SIZE(choke_texts)) {
179 if (Breathless || !rn2(50))
180 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
182 const char *str = choke_texts[SIZE(choke_texts) - i];
186 pline(str, hcolor(NH_BLUE));
188 pline(str, jconj_adj(hcolor(NH_BLUE)));
193 exercise(A_STR, FALSE);
196 static NEARDATA const char *const slime_texts[] = {
198 "You are turning a little %s.", /* 5 */
199 "Your limbs are getting oozy.", /* 4 */
200 "Your skin begins to peel away.", /* 3 */
201 "You are turning into %s.", /* 2 */
202 "You have become %s." /* 1 */
204 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
205 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
206 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
207 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
208 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
215 register long i = (Slimed & TIMEOUT) / 2L;
217 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
220 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
221 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
222 (void) strsubst(buf, "limbs", "extremities");
224 if (index(buf, '%')) {
225 if (i == 4L) { /* "you are turning green" */
226 if (!Blind) /* [what if you're already green?] */
228 pline(buf, hcolor(NH_GREEN));
230 pline(buf, jconj_adj(hcolor(NH_GREEN)));
234 an(Hallucination ? rndmonnam(NULL) : "green slime"));
236 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
240 if (i == 3L) { /* limbs becoming oozy */
241 HFast = 0L; /* lose intrinsic speed */
247 exercise(A_DEX, FALSE);
255 make_slimed(0L, "The slime that covers you is burned away!");
257 pline("
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
264 register struct prop *upp;
268 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
273 if (u.uluck != baseluck
274 && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
275 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
276 * stop good luck from timing out; normal luckstones stop both;
277 * neither is stopped if you don't have a luckstone.
278 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
280 register int time_luck = stone_luck(FALSE);
281 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
283 if (u.uluck > baseluck && (nostone || time_luck < 0))
285 else if (u.uluck < baseluck && (nostone || time_luck > 0))
289 return; /* things past this point could kill you */
298 if (u.mtimedone && !--u.mtimedone) {
300 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
307 /* Dissipate spell-based protection. */
309 if (--u.usptime == 0 && u.uspellprot) {
310 u.usptime = u.uspmtime;
315 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
316 u.uspellprot ? "becomes less dense" : "disappears");
318 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
319 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
325 if (--u.ugallop == 0L && u.usteed)
327 pline("%s stops galloping.", Monnam(u.usteed));
329 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
332 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
333 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
334 kptr = find_delayed_killer((int) (upp - u.uprops));
335 switch (upp - u.uprops) {
337 if (kptr && kptr->name[0]) {
338 killer.format = kptr->format;
340 Strcpy(killer.name, kptr->name);
342 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
346 killer.format = NO_KILLER_PREFIX;
347 Strcpy(killer.name, "killed by petrification");
349 killer.format = KILLED_BY;
350 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
353 dealloc_killer(kptr);
354 /* (unlike sliming, you aren't changing form here) */
358 if (kptr && kptr->name[0]) {
359 killer.format = kptr->format;
360 Strcpy(killer.name, kptr->name);
362 killer.format = NO_KILLER_PREFIX;
364 Strcpy(killer.name, "turned into green slime");
366 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
368 dealloc_killer(kptr);
369 /* involuntarily break "never changed form" conduct */
370 u.uconduct.polyselfs++;
374 make_vomiting(0L, TRUE);
378 You("die from your illness.");
380 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
381 if (kptr && kptr->name[0]) {
382 killer.format = kptr->format;
383 Strcpy(killer.name, kptr->name);
385 killer.format = KILLED_BY_AN;
386 killer.name[0] = 0; /* take the default */
388 dealloc_killer(kptr);
390 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
391 if (type_is_pname(&mons[m_idx])) {
392 killer.format = KILLED_BY;
393 } else if (mons[m_idx].geno & G_UNIQ) {
394 Strcpy(killer.name, the(killer.name));
395 killer.format = KILLED_BY;
404 You_feel("yourself slowing down%s.",
405 Fast ? " a bit" : "");
407 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
408 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
412 /* So make_confused works properly */
413 set_itimeout(&HConfusion, 1L);
414 make_confused(0L, TRUE);
419 set_itimeout(&HStun, 1L);
420 make_stunned(0L, TRUE);
425 set_itimeout(&Blinded, 1L);
426 make_blinded(0L, TRUE);
431 set_itimeout(&HDeaf, 1L);
438 if (!Invis && !BInvis && !Blind) {
441 ? "are no longer invisible."
442 : "can no longer see through yourself.");
445 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
446 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
452 set_mimic_blocking(); /* do special mimic handling */
453 see_monsters(); /* make invis mons appear */
454 newsym(u.ux, u.uy); /* make self appear */
464 make_totter(0L, TRUE);
469 set_itimeout(&HHallucination, 1L);
470 (void) make_hallucinated(0L, TRUE, 0L);
475 if (unconscious() || Sleep_resistance) {
476 incr_itimeout(&HSleepy, rnd(100));
481 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
483 fall_asleep(-sleeptime, TRUE);
484 incr_itimeout(&HSleepy, sleeptime + rnd(100));
488 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
491 killer.format = KILLED_BY;
494 (u.uburied) ? "suffocation" : "strangulation");
497 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
500 /* must be declining to die in explore|wizard mode;
501 treat like being cured of strangulation by prayer */
502 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
503 Your("amulet vanishes!");
508 /* call this only when a move took place. */
509 /* otherwise handle fumbling msgs locally. */
510 if (u.umoved && !Levitation) {
513 multi_reason = "fumbling";
515 /* The more you are carrying the more likely you
516 * are to make noise when you fumble. Adjustments
517 * to this number must be thoroughly play tested.
519 if ((inv_weight() > -500)) {
521 You("make a lot of noise!");
523 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
527 /* from outside means slippery ice; don't reset
528 counter if that's the only fumble reason */
529 HFumbling &= ~FROMOUTSIDE;
531 incr_itimeout(&HFumbling, rnd(20));
533 case DETECT_MONSTERS:
543 fall_asleep(how_long, wakeup_msg)
549 multi_reason = "sleeping";
550 /* generally don't notice sounds while sleeping */
551 if (wakeup_msg && multi == how_long) {
552 /* caller can follow with a direct call to Hear_again() if
553 there's a need to override this when wakeup_msg is true */
554 incr_itimeout(&HDeaf, how_long);
555 afternmv = Hear_again; /* this won't give any messages */
557 /* early wakeup from combat won't be possible until next monster turn */
558 u.usleep = monstermoves;
560 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
562 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
565 /* Attach an egg hatch timeout to the given egg.
566 * when = Time to hatch, usually only passed if re-creating an
567 * existing hatch timer. Pass 0L for random hatch time.
570 attach_egg_hatch_timeout(egg, when)
576 /* stop previous timer, if any */
577 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
580 * Decide if and when to hatch the egg. The old hatch_it() code tried
581 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
582 * a number x, 1<=x<=age, where x>150. This yields a chance of
583 * hatching > 99.9993%. Mimic that here.
586 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
594 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
598 /* prevent an egg from ever hatching */
603 /* stop previous timer, if any */
604 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
607 /* timer callback routine: hatch the given egg */
609 hatch_egg(arg, timeout)
614 struct monst *mon, *mon2;
617 boolean yours, silent, knows_egg = FALSE;
618 boolean cansee_hatchspot = FALSE;
619 int i, mnum, hatchcount = 0;
622 /* sterilized while waiting */
623 if (egg->corpsenm == NON_PM)
626 mon = mon2 = (struct monst *) 0;
627 mnum = big_to_little(egg->corpsenm);
628 /* The identity of one's father is learned, not innate */
629 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
630 silent = (timeout != monstermoves); /* hatched while away */
632 /* only can hatch when in INVENT, FLOOR, MINVENT */
633 if (get_obj_location(egg, &x, &y, 0)) {
634 hatchcount = rnd((int) egg->quan);
635 cansee_hatchspot = cansee(x, y) && !silent;
636 if (!(mons[mnum].geno & G_UNIQ)
637 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
638 for (i = hatchcount; i > 0; i--) {
639 if (!enexto(&cc, x, y, &mons[mnum])
640 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
642 /* tame if your own egg hatches while you're on the
643 same dungeon level, or any dragon egg which hatches
644 while it's in your inventory */
645 if ((yours && !silent)
646 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
647 if (tamedog(mon, (struct obj *) 0)) {
648 if (carried(egg) && mon->data->mlet != S_DRAGON)
652 if (mvitals[mnum].mvflags & G_EXTINCT)
653 break; /* just made last one */
654 mon2 = mon; /* in case makemon() fails on 2nd egg */
659 egg->quan -= (long) hatchcount;
663 * We could possibly hatch while migrating, but the code isn't
666 } else if (obj->where == OBJ_MIGRATING) {
668 * We can do several things. The first ones that come to
670 * + Create the hatched monster then place it on the migrating
671 * mons list. This is tough because all makemon() is made
672 * to place the monster as well. Makemon() also doesn't lend
673 * itself well to splitting off a "not yet placed" subroutine.
674 * + Mark the egg as hatched, then place the monster when we
675 * place the migrating objects.
676 * + Or just kill any egg which gets sent to another level.
677 * Falling is the usual reason such transportation occurs.
679 cansee_hatchspot = FALSE;
685 char monnambuf[BUFSZ], carriedby[BUFSZ];
686 boolean siblings = (hatchcount > 1), redraw = FALSE;
688 if (cansee_hatchspot) {
690 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
691 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
693 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
696 /* we don't learn the egg type here because learning
697 an egg type requires either seeing the egg hatch
698 or being familiar with the egg already,
699 as well as being able to see the resulting
700 monster, checked below
703 switch (egg->where) {
705 knows_egg = TRUE; /* true even if you are blind */
706 if (!cansee_hatchspot)
708 You_feel("%s %s from your pack!", something,
709 locomotion(mon->data, "drop"));
711 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
712 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
716 You_see("%s %s out of your pack!", monnambuf,
717 locomotion(mon->data, "drop"));
719 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
720 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
724 pline("%s cries sound like \"%s%s\"",
725 siblings ? "Their" : "Its",
726 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
728 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
729 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
731 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
733 verbalize("Gleep!"); /* Mything eggs :-) */
735 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
741 if (cansee_hatchspot) {
744 You_see("%s hatch.", monnambuf);
746 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
747 redraw = TRUE; /* update egg's map location */
752 if (cansee_hatchspot) {
753 /* egg carrying monster might be invisible */
754 if (canseemon(egg->ocarry)) {
756 Sprintf(carriedby, "%s pack",
758 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
759 s_suffix(a_monnam(egg->ocarry)));
761 } else if (is_pool(mon->mx, mon->my))
763 Strcpy(carriedby, "empty water");
765 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
768 Strcpy(carriedby, "thin air");
770 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
772 You_see("%s %s out of %s!", monnambuf,
773 locomotion(mon->data, "drop"), carriedby);
775 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
776 locomotion(mon->data, "
\97\8e\82¿
\82é"));
785 impossible("egg hatched where? (%d)", (int) egg->where);
789 if (cansee_hatchspot && knows_egg)
790 learn_egg_type(mnum);
793 /* still some eggs left */
794 /* Instead of ordinary egg timeout use a short one */
795 attach_egg_hatch_timeout(egg, (long) rnd(12));
796 } else if (carried(egg)) {
799 /* free egg here because we use it above */
800 obj_extract_self(egg);
801 obfree(egg, (struct obj *) 0);
808 /* Learn to recognize eggs of the given type. */
813 /* baby monsters hatch from grown-up eggs */
814 mnum = little_to_big(mnum);
815 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
816 /* we might have just learned about other eggs being carried */
820 /* Attach a fig_transform timeout to the given figurine. */
822 attach_fig_transform_timeout(figurine)
823 struct obj *figurine;
827 /* stop previous timer, if any */
828 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
831 * Decide when to transform the figurine.
834 /* figurine will transform */
835 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
836 obj_to_any(figurine));
839 /* give a fumble message */
843 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
846 boolean on_foot = TRUE;
850 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
853 if (otmp && on_foot) { /* trip over something in particular */
855 If there is only one item, it will have just been named
856 during the move, so refer to by via pronoun; otherwise,
857 if the top item has been or can be seen, refer to it by
858 name; if not, look for rocks to trip over; trip over
859 anonymous "something" if there aren't any rocks.
862 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
863 ? ((otmp->quan == 1L) ? "it"
864 : Hallucination ? "they" : "them")
865 : (otmp->dknown || !Blind)
867 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
869 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
871 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
873 : (otmp->dknown || !Blind)
875 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
880 what = strcpy(buf, what);
881 buf[0] = highc(buf[0]);
883 pline("Egads! %s bite%s your %s!", what,
884 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
886 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
890 You("trip over %s.", what);
892 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
894 if (!uarmf && otmp->otyp == CORPSE
895 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
896 Sprintf(killer.name, "tripping over %s corpse",
897 an(mons[otmp->corpsenm].mname));
898 instapetrify(killer.name);
900 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
902 pline("%s %s%s on the ice.",
903 u.usteed ? upstart(x_monnam(u.usteed,
904 (has_mname(u.usteed)) ? ARTICLE_NONE
906 (char *) 0, SUPPRESS_SADDLE, FALSE))
908 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
910 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
911 u.usteed ? upstart(x_monnam(u.usteed,
912 (has_mname(u.usteed)) ? ARTICLE_NONE
914 (char *) 0, SUPPRESS_SADDLE, FALSE))
922 You("trip over your own %s.",
923 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
925 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
926 Hallucination ? "
\95I" : body_part(FOOT));
932 Hallucination ? "on a banana peel" : "and nearly fall");
934 You("%s
\81D", Hallucination ?
935 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
942 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
948 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
955 Your("%s slip out of the stirrups.",
956 makeplural(body_part(FOOT)));
958 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
963 You("let go of the reins.");
965 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
969 You("bang into the saddle-horn.");
971 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
975 You("slide to one side of the saddle.");
977 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
980 dismount_steed(DISMOUNT_FELL);
985 /* Print a lamp flicker message with tailer. */
987 see_lamp_flicker(obj, tailer)
991 switch (obj->where) {
995 pline("%s flickers%s.", Yname2(obj), tailer);
997 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1001 You_see("%s flicker%s.", an(xname(obj)), tailer);
1003 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1008 /* Print a dimming message for brass lanterns. */
1010 lantern_message(obj)
1013 /* from adventure */
1014 switch (obj->where) {
1017 Your("lantern is getting dim.");
1019 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1022 pline("Batteries have not been invented yet.");
1024 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1028 You_see("a lantern getting dim.");
1030 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1034 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1036 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1042 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1043 * See begin_burn() for meanings of obj->age and obj->spe.
1046 burn_object(arg, timeout)
1050 struct obj *obj = arg->a_obj;
1051 boolean canseeit, many, menorah, need_newsym;
1055 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1056 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1058 /* timeout while away */
1059 if (timeout != monstermoves) {
1060 long how_long = monstermoves - timeout;
1062 if (how_long >= obj->age) {
1064 end_burn(obj, FALSE);
1067 obj->spe = 0; /* no more candles */
1068 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1069 /* get rid of candles and burning oil potions;
1070 we know this object isn't carried by hero,
1071 nor is it migrating */
1072 obj_extract_self(obj);
1073 obfree(obj, (struct obj *) 0);
1074 obj = (struct obj *) 0;
1078 obj->age -= how_long;
1079 begin_burn(obj, TRUE);
1084 /* only interested in INVENT, FLOOR, and MINVENT */
1085 if (get_obj_location(obj, &x, &y, 0)) {
1086 canseeit = !Blind && cansee(x, y);
1087 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1088 (void) Shk_Your(whose, obj);
1092 need_newsym = FALSE;
1094 /* obj->age is the age remaining at this point. */
1095 switch (obj->otyp) {
1097 /* this should only be called when we run out */
1099 switch (obj->where) {
1103 pline("%spotion of oil has burnt away.", whose);
1105 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1109 You_see("a burning potion of oil go out.");
1111 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1116 end_burn(obj, FALSE); /* turn off light source */
1120 /* clear migrating obj's destination code before obfree
1121 to avoid false complaint of deleting worn item */
1122 if (obj->where == OBJ_MIGRATING)
1123 obj->owornmask = 0L;
1124 obj_extract_self(obj);
1125 obfree(obj, (struct obj *) 0);
1127 obj = (struct obj *) 0;
1132 switch ((int) obj->age) {
1137 if (obj->otyp == BRASS_LANTERN)
1138 lantern_message(obj);
1140 see_lamp_flicker(obj,
1142 obj->age == 50L ? " considerably" : "");
1144 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1150 if (obj->otyp == BRASS_LANTERN)
1151 lantern_message(obj);
1153 switch (obj->where) {
1157 pline("%s seems about to go out.", Yname2(obj));
1159 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1163 You_see("%s about to go out.", an(xname(obj)));
1165 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1173 /* even if blind you'll know if holding it */
1174 if (canseeit || obj->where == OBJ_INVENT) {
1175 switch (obj->where) {
1178 if (obj->otyp == BRASS_LANTERN)
1180 pline("%slantern has run out of power.", whose);
1182 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1185 pline("%s has gone out.", Yname2(obj));
1187 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1190 if (obj->otyp == BRASS_LANTERN)
1192 You_see("a lantern run out of power.");
1194 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1197 You_see("%s go out.", an(xname(obj)));
1199 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1203 end_burn(obj, FALSE);
1208 * Someone added fuel to the lamp while it was
1209 * lit. Just fall through and let begin burn
1210 * handle the new age.
1216 begin_burn(obj, TRUE);
1220 case CANDELABRUM_OF_INVOCATION:
1226 switch (obj->where) {
1230 pline("%s%scandle%s getting short.", whose,
1231 menorah ? "candelabrum's " : "",
1232 many ? "s are" : " is");
1234 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1235 menorah ? "
\90C
\91ä
\82Ì" : "");
1240 You_see("%scandle%s getting short.",
1241 menorah ? "a candelabrum's " : many ? "some "
1245 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1246 menorah ? "
\90C
\91ä
\82Ì" : "");
1254 switch (obj->where) {
1258 pline("%s%scandle%s flame%s flicker%s low!", whose,
1259 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1260 many ? "s" : "", many ? "" : "s");
1262 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1263 menorah ? "
\90C
\91ä
\82Ì" : "");
1268 You_see("%scandle%s flame%s flicker low!",
1269 menorah ? "a candelabrum's " : many ? "some "
1271 many ? "s'" : "'s", many ? "s" : "");
1273 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1274 menorah ? "
\90C
\91ä
\82Ì" : "");
1281 /* we know even if blind and in our inventory */
1282 if (canseeit || obj->where == OBJ_INVENT) {
1284 switch (obj->where) {
1288 pline("%scandelabrum's flame%s.", whose,
1289 many ? "s die" : " dies");
1291 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1296 You_see("a candelabrum's flame%s die.",
1299 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1304 switch (obj->where) {
1308 pline("%s %s consumed!", Yname2(obj),
1309 many ? "are" : "is");
1311 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1316 You see some wax candles consumed!
1317 You see a wax candle consumed!
1320 You_see("%s%s consumed!", many ? "some " : "",
1321 many ? xname(obj) : an(xname(obj)));
1323 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1332 ? (many ? "They shriek!" : "It shrieks!")
1333 : Blind ? "" : (many ? "Their flames die."
1334 : "Its flame dies."));
1336 pline(Hallucination ? "
\82»
\82ê
\82Í
\90k
\82¦
\82½
\81D"
1338 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1342 end_burn(obj, FALSE);
1350 /* clear migrating obj's destination code
1351 so obfree won't think this item is worn */
1352 if (obj->where == OBJ_MIGRATING)
1353 obj->owornmask = 0L;
1354 obj_extract_self(obj);
1355 obfree(obj, (struct obj *) 0);
1357 obj = (struct obj *) 0;
1363 * Someone added fuel (candles) to the menorah while
1364 * it was lit. Just fall through and let begin burn
1365 * handle the new age.
1370 if (obj && obj->age)
1371 begin_burn(obj, TRUE);
1376 impossible("burn_object: unexpeced obj %s", xname(obj));
1384 * Start a burn timeout on the given object. If not "already lit" then
1385 * create a light source for the vision system. There had better not
1386 * be a burn already running on the object.
1388 * Magic lamps stay lit as long as there's a genie inside, so don't start
1392 * potions of oil, lamps & candles:
1393 * age = # of turns of fuel left
1397 * spe = 0 not lightable, 1 lightable forever
1399 * age = # of turns of fuel left
1400 * spe = # of candles
1402 * Once the burn begins, the age will be set to the amount of fuel
1403 * remaining _once_the_burn_finishes_. If the burn is terminated
1404 * early then fuel is added back.
1406 * This use of age differs from the use of age for corpses and eggs.
1407 * For the latter items, age is when the object was created, so we
1408 * know when it becomes "bad".
1410 * This is a "silent" routine - it should not print anything out.
1413 begin_burn(obj, already_lit)
1415 boolean already_lit;
1419 boolean do_timer = TRUE;
1421 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1424 switch (obj->otyp) {
1432 radius = 1; /* very dim light */
1437 /* magic times are 150, 100, 50, 25, and 0 */
1438 if (obj->age > 150L)
1439 turns = obj->age - 150L;
1440 else if (obj->age > 100L)
1441 turns = obj->age - 100L;
1442 else if (obj->age > 50L)
1443 turns = obj->age - 50L;
1444 else if (obj->age > 25L)
1445 turns = obj->age - 25L;
1450 case CANDELABRUM_OF_INVOCATION:
1453 /* magic times are 75, 15, and 0 */
1455 turns = obj->age - 75L;
1456 else if (obj->age > 15L)
1457 turns = obj->age - 15L;
1460 radius = candle_light_range(obj);
1464 /* [ALI] Support artifact light sources */
1465 if (artifact_light(obj)) {
1468 radius = arti_light_radius(obj);
1470 impossible("begin burn: unexpected %s", xname(obj));
1477 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1480 if (carried(obj) && !already_lit)
1486 if (carried(obj) && !already_lit)
1490 if (obj->lamplit && !already_lit) {
1493 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1494 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1496 impossible("begin_burn: can't get obj position");
1501 * Stop a burn timeout on the given object if timer attached. Darken
1505 end_burn(obj, timer_attached)
1507 boolean timer_attached;
1509 if (!obj->lamplit) {
1510 impossible("end_burn: obj %s not lit", xname(obj));
1514 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1515 timer_attached = FALSE;
1517 if (!timer_attached) {
1518 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1519 del_light_source(LS_OBJECT, obj_to_any(obj));
1521 if (obj->where == OBJ_INVENT)
1523 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1524 impossible("end_burn: obj %s not timed!", xname(obj));
1528 * Cleanup a burning object if timer stopped.
1531 cleanup_burn(arg, expire_time)
1535 struct obj *obj = arg->a_obj;
1536 if (!obj->lamplit) {
1537 impossible("cleanup_burn: obj %s not lit", xname(obj));
1541 del_light_source(LS_OBJECT, obj_to_any(obj));
1543 /* restore unused time */
1544 obj->age += expire_time - monstermoves;
1548 if (obj->where == OBJ_INVENT)
1560 /* no lightning if not the air level or too often, even then */
1561 if (!Is_airlevel(&u.uz) || rn2(8))
1564 /* the number of strikes is 8-log2(nstrike) */
1565 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1570 } while (++count < 100 && levl[x][y].typ != CLOUD);
1575 if (dirx != 0 || diry != 0)
1576 buzz(-15, /* "monster" LIGHTNING spell */
1577 8, x, y, dirx, diry);
1581 if (levl[u.ux][u.uy].typ == CLOUD) {
1582 /* Inside a cloud during a thunder storm is deafening. */
1583 /* Even if already deaf, we sense the thunder's vibrations. */
1585 pline("Kaboom!!! Boom!! Boom!!");
1587 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");
1588 incr_itimeout(&HDeaf, rn1(20, 30));
1589 if (!u.uinvulnerable) {
1592 multi_reason = "hiding from thunderstorm";
1597 You_hear("a rumbling noise.");
1599 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1602 /* -------------------------------------------------------------------------
1605 * Generic Timeout Functions.
1610 * boolean start_timer(long timeout,short kind,short func_index,
1612 * Start a timer of kind 'kind' that will expire at time
1613 * monstermoves+'timeout'. Call the function at 'func_index'
1614 * in the timeout table using argument 'arg'. Return TRUE if
1615 * a timer was started. This places the timer on a list ordered
1616 * "sooner" to "later". If an object, increment the object's
1619 * long stop_timer(short func_index, anything *arg)
1620 * Stop a timer specified by the (func_index, arg) pair. This
1621 * assumes that such a pair is unique. Return the time the
1622 * timer would have gone off. If no timer is found, return 0.
1623 * If an object, decrement the object's timer count.
1625 * long peek_timer(short func_index, anything *arg)
1626 * Return time specified timer will go off (0 if no such timer).
1628 * void run_timers(void)
1629 * Call timers that have timed out.
1632 * void save_timers(int fd, int mode, int range)
1633 * Save all timers of range 'range'. Range is either global
1634 * or local. Global timers follow game play, local timers
1635 * are saved with a level. Object and monster timers are
1636 * saved using their respective id's instead of pointers.
1638 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1639 * Restore timers of range 'range'. If from a ghost pile,
1640 * adjust the timeout by 'adjust'. The object and monster
1641 * ids are not restored until later.
1643 * void relink_timers(boolean ghostly)
1644 * Relink all object and monster timers that had been saved
1645 * using their object's or monster's id number.
1648 * void obj_move_timers(struct obj *src, struct obj *dest)
1649 * Reassign all timers from src to dest.
1651 * void obj_split_timers(struct obj *src, struct obj *dest)
1652 * Duplicate all timers assigned to src and attach them to dest.
1654 * void obj_stop_timers(struct obj *obj)
1655 * Stop all timers attached to obj.
1657 * boolean obj_has_timer(struct obj *object, short timer_type)
1658 * Check whether object has a timer of type timer_type.
1661 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1662 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1663 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1664 STATIC_DCL timer_element *FDECL(remove_timer,
1665 (timer_element **, SHORT_P, ANY_P *));
1666 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1667 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1668 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1669 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1671 /* ordered timer list */
1672 static timer_element *timer_base; /* "active" */
1673 static unsigned long timer_id = 1;
1675 /* If defined, then include names when printing out the timer queue */
1676 #define VERBOSE_TIMER
1679 timeout_proc f, cleanup;
1680 #ifdef VERBOSE_TIMER
1682 #define TTAB(a, b, c) \
1687 #define TTAB(a, b, c) \
1694 /* table of timeout functions */
1695 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1696 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
1697 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
1698 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
1699 TTAB(burn_object, cleanup_burn, "burn_object"),
1700 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
1701 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
1702 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
1706 STATIC_OVL const char *
1724 print_queue(win, base)
1726 timer_element *base;
1728 timer_element *curr;
1732 putstr(win, 0, "<empty>");
1734 putstr(win, 0, "timeout id kind call");
1735 for (curr = base; curr; curr = curr->next) {
1736 #ifdef VERBOSE_TIMER
1737 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
1738 curr->tid, kind_name(curr->kind),
1739 timeout_funcs[curr->func_index].name,
1740 fmt_ptr((genericptr_t) curr->arg.a_void));
1742 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
1743 curr->tid, kind_name(curr->kind), curr->func_index,
1744 fmt_ptr((genericptr_t) curr->arg.a_void));
1746 putstr(win, 0, buf);
1757 win = create_nhwindow(NHW_MENU); /* corner text window */
1761 Sprintf(buf, "Current time = %ld.", monstermoves);
1762 putstr(win, 0, buf);
1764 putstr(win, 0, "Active timeout queue:");
1766 print_queue(win, timer_base);
1768 display_nhwindow(win, FALSE);
1769 destroy_nhwindow(win);
1775 timer_sanity_check()
1777 timer_element *curr;
1779 /* this should be much more complete */
1780 for (curr = timer_base; curr; curr = curr->next)
1781 if (curr->kind == TIMER_OBJECT) {
1782 struct obj *obj = curr->arg.a_obj;
1783 if (obj->timed == 0) {
1784 pline("timer sanity: untimed obj %s, timer %ld",
1785 fmt_ptr((genericptr_t) obj), curr->tid);
1791 * Pick off timeout elements from the global queue and call their functions.
1792 * Do this until their time is less than or equal to the move count.
1797 timer_element *curr;
1800 * Always use the first element. Elements may be added or deleted at
1801 * any time. The list is ordered, we are done when the first element
1804 while (timer_base && timer_base->timeout <= monstermoves) {
1806 timer_base = curr->next;
1808 if (curr->kind == TIMER_OBJECT)
1809 (curr->arg.a_obj)->timed--;
1810 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
1811 free((genericptr_t) curr);
1816 * Start a timer. Return TRUE if successful.
1819 start_timer(when, kind, func_index, arg)
1827 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1828 panic("start_timer");
1830 gnu = (timer_element *) alloc(sizeof(timer_element));
1832 gnu->tid = timer_id++;
1833 gnu->timeout = monstermoves + when;
1835 gnu->needs_fixup = 0;
1836 gnu->func_index = func_index;
1840 if (kind == TIMER_OBJECT) /* increment object's timed count */
1841 (arg->a_obj)->timed++;
1843 /* should check for duplicates and fail if any */
1848 * Remove the timer from the current list and free it up. Return the time
1849 * remaining until it would have gone off, 0 if not found.
1852 stop_timer(func_index, arg)
1856 timer_element *doomed;
1859 doomed = remove_timer(&timer_base, func_index, arg);
1862 timeout = doomed->timeout;
1863 if (doomed->kind == TIMER_OBJECT)
1864 (arg->a_obj)->timed--;
1865 if (timeout_funcs[doomed->func_index].cleanup)
1866 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
1867 free((genericptr_t) doomed);
1868 return (timeout - monstermoves);
1874 * Find the timeout of specified timer; return 0 if none.
1877 peek_timer(type, arg)
1881 timer_element *curr;
1883 for (curr = timer_base; curr; curr = curr->next) {
1884 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
1885 return curr->timeout;
1891 * Move all object timers from src to dest, leaving src untimed.
1894 obj_move_timers(src, dest)
1895 struct obj *src, *dest;
1898 timer_element *curr;
1900 for (count = 0, curr = timer_base; curr; curr = curr->next)
1901 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1902 curr->arg.a_obj = dest;
1906 if (count != src->timed)
1907 panic("obj_move_timers");
1912 * Find all object timers and duplicate them for the new object "dest".
1915 obj_split_timers(src, dest)
1916 struct obj *src, *dest;
1918 timer_element *curr, *next_timer = 0;
1920 for (curr = timer_base; curr; curr = next_timer) {
1921 next_timer = curr->next; /* things may be inserted */
1922 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1923 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
1924 curr->func_index, obj_to_any(dest));
1930 * Stop all timers attached to this object. We can get away with this because
1931 * all object pointers are unique.
1934 obj_stop_timers(obj)
1937 timer_element *curr, *prev, *next_timer = 0;
1939 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1940 next_timer = curr->next;
1941 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
1943 prev->next = curr->next;
1945 timer_base = curr->next;
1946 if (timeout_funcs[curr->func_index].cleanup)
1947 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1949 free((genericptr_t) curr);
1958 * Check whether object has a timer of type timer_type.
1961 obj_has_timer(object, timer_type)
1965 long timeout = peek_timer(timer_type, obj_to_any(object));
1967 return (boolean) (timeout != 0L);
1971 * Stop all timers of index func_index at this spot.
1975 spot_stop_timers(x, y, func_index)
1979 timer_element *curr, *prev, *next_timer = 0;
1980 long where = (((long) x << 16) | ((long) y));
1982 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1983 next_timer = curr->next;
1984 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
1985 && curr->arg.a_long == where) {
1987 prev->next = curr->next;
1989 timer_base = curr->next;
1990 if (timeout_funcs[curr->func_index].cleanup)
1991 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1993 free((genericptr_t) curr);
2001 * When is the spot timer of type func_index going to expire?
2002 * Returns 0L if no such timer.
2005 spot_time_expires(x, y, func_index)
2009 timer_element *curr;
2010 long where = (((long) x << 16) | ((long) y));
2012 for (curr = timer_base; curr; curr = curr->next) {
2013 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2014 && curr->arg.a_long == where)
2015 return curr->timeout;
2021 spot_time_left(x, y, func_index)
2025 long expires = spot_time_expires(x, y, func_index);
2026 return (expires > 0L) ? expires - monstermoves : 0L;
2029 /* Insert timer into the global queue */
2034 timer_element *curr, *prev;
2036 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2037 if (curr->timeout >= gnu->timeout)
2047 STATIC_OVL timer_element *
2048 remove_timer(base, func_index, arg)
2049 timer_element **base;
2053 timer_element *prev, *curr;
2055 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2056 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2061 prev->next = curr->next;
2070 write_timer(fd, timer)
2072 timer_element *timer;
2077 switch (timer->kind) {
2080 /* assume no pointers in arg */
2081 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2085 if (timer->needs_fixup)
2086 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2088 /* replace object pointer with id */
2089 arg_save.a_obj = timer->arg.a_obj;
2090 timer->arg = zeroany;
2091 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2092 timer->needs_fixup = 1;
2093 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2094 timer->arg.a_obj = arg_save.a_obj;
2095 timer->needs_fixup = 0;
2100 if (timer->needs_fixup)
2101 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2103 /* replace monster pointer with id */
2104 arg_save.a_monst = timer->arg.a_monst;
2105 timer->arg = zeroany;
2106 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2107 timer->needs_fixup = 1;
2108 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2109 timer->arg.a_monst = arg_save.a_monst;
2110 timer->needs_fixup = 0;
2115 panic("write_timer");
2121 * Return TRUE if the object will stay on the level when the level is
2128 switch (obj->where) {
2136 return obj_is_local(obj->ocontainer);
2138 return mon_is_local(obj->ocarry);
2140 panic("obj_is_local");
2145 * Return TRUE if the given monster will stay on the level when the
2154 for (curr = migrating_mons; curr; curr = curr->nmon)
2157 /* `mydogs' is used during level changes, never saved and restored */
2158 for (curr = mydogs; curr; curr = curr->nmon)
2165 * Return TRUE if the timer is attached to something that will stay on the
2166 * level when the level is saved.
2169 timer_is_local(timer)
2170 timer_element *timer;
2172 switch (timer->kind) {
2178 return obj_is_local(timer->arg.a_obj);
2180 return mon_is_local(timer->arg.a_monst);
2182 panic("timer_is_local");
2187 * Part of the save routine. Count up the number of timers that would
2188 * be written. If write_it is true, actually write the timer.
2191 maybe_write_timer(fd, range, write_it)
2196 timer_element *curr;
2198 for (curr = timer_base; curr; curr = curr->next) {
2199 if (range == RANGE_GLOBAL) {
2202 if (!timer_is_local(curr)) {
2205 write_timer(fd, curr);
2211 if (timer_is_local(curr)) {
2214 write_timer(fd, curr);
2223 * Save part of the timer list. The parameter 'range' specifies either
2224 * global or level timers to save. The timer ID is saved with the global
2228 * + timeouts that follow the hero (global)
2229 * + timeouts that follow obj & monst that are migrating
2232 * + timeouts that are level specific (e.g. storms)
2233 * + timeouts that stay with the level (obj & monst)
2236 save_timers(fd, mode, range)
2237 int fd, mode, range;
2239 timer_element *curr, *prev, *next_timer = 0;
2242 if (perform_bwrite(mode)) {
2243 if (range == RANGE_GLOBAL)
2244 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2246 count = maybe_write_timer(fd, range, FALSE);
2247 bwrite(fd, (genericptr_t) &count, sizeof count);
2248 (void) maybe_write_timer(fd, range, TRUE);
2251 if (release_data(mode)) {
2252 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2253 next_timer = curr->next; /* in case curr is removed */
2255 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2257 prev->next = curr->next;
2259 timer_base = curr->next;
2260 free((genericptr_t) curr);
2261 /* prev stays the same */
2270 * Pull in the structures from disk, but don't recalculate the object and
2274 restore_timers(fd, range, ghostly, adjust)
2276 boolean ghostly; /* restoring from a ghost level */
2277 long adjust; /* how much to adjust timeout */
2280 timer_element *curr;
2282 if (range == RANGE_GLOBAL)
2283 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2285 /* restore elements */
2286 mread(fd, (genericptr_t) &count, sizeof count);
2287 while (count-- > 0) {
2288 curr = (timer_element *) alloc(sizeof(timer_element));
2289 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2291 curr->timeout += adjust;
2296 /* reset all timers that are marked for reseting */
2298 relink_timers(ghostly)
2301 timer_element *curr;
2304 for (curr = timer_base; curr; curr = curr->next) {
2305 if (curr->needs_fixup) {
2306 if (curr->kind == TIMER_OBJECT) {
2308 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2309 panic("relink_timers 1");
2311 nid = curr->arg.a_uint;
2312 curr->arg.a_obj = find_oid(nid);
2313 if (!curr->arg.a_obj)
2314 panic("cant find o_id %d", nid);
2315 curr->needs_fixup = 0;
2316 } else if (curr->kind == TIMER_MONSTER) {
2317 panic("relink_timers: no monster timer implemented");
2319 panic("relink_timers 2");