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]);
49 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
50 (void) strsubst(buf, "limbs", "extremities");
52 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
53 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
58 case 5: /* slowing down */
63 case 4: /* limbs stiffening */
64 /* just one move left to save oneself so quit fiddling around;
65 don't stop attempt to eat tin--might be lizard or acidic */
71 case 3: /* limbs turned to stone */
73 nomul(-3); /* can't move anymore */
74 multi_reason = "getting stoned";
75 nomovemsg = You_can_move_again; /* not unconscious */
80 exercise(A_DEX, FALSE);
83 /* He is getting sicker and sicker prior to vomiting */
84 static NEARDATA const char *const vomiting_texts[] = {
86 "are feeling mildly nauseated.", /* 14 */
87 "feel slightly confused.", /* 11 */
88 "can't seem to think straight.", /* 8 */
89 "feel incredibly sick.", /* 5 */
90 "suddenly vomit!" /* 2 */
92 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
93 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
94 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
95 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
96 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81I" /* 2 */
104 long v = (Vomiting & TIMEOUT);
106 /* note: nhtimeout() hasn't decremented timed properties for the
107 current turn yet, so we use Vomiting-1 here */
108 switch ((int) (v - 1L)) {
110 txt = vomiting_texts[0];
113 txt = vomiting_texts[1];
116 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
117 if (!Popeye(VOMITING))
121 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
126 txt = vomiting_texts[2];
129 txt = vomiting_texts[3];
132 txt = vomiting_texts[4];
133 if (cantvomit(youmonst.data))
135 txt = "gag uncontrolably.";
137 txt = "
\8bC
\95ª
\82Ì
\88«
\82³
\82ª
\97}
\82¦
\82ç
\82ê
\82È
\82
\82È
\82Á
\82½
\81D";
141 if (!cantvomit(youmonst.data))
150 exercise(A_CON, FALSE);
153 static NEARDATA const char *const choke_texts[] = {
155 "You find it hard to breathe.", "You're gasping for air.",
156 "You can no longer breathe.", "You're turning %s.", "You suffocate."
158 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
159 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
160 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
161 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
162 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
166 static NEARDATA const char *const choke_texts2[] = {
168 "Your %s is becoming constricted.",
169 "Your blood is having trouble reaching your brain.",
170 "The pressure on your %s increases.", "Your consciousness is fading.",
173 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
174 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
175 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
176 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
177 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
184 register long i = (Strangled & TIMEOUT);
186 if (i > 0 && i <= SIZE(choke_texts)) {
187 if (Breathless || !rn2(50))
188 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
190 const char *str = choke_texts[SIZE(choke_texts) - i];
194 pline(str, hcolor(NH_BLUE));
196 pline(str, jconj_adj(hcolor(NH_BLUE)));
201 exercise(A_STR, FALSE);
204 static NEARDATA const char *const slime_texts[] = {
206 "You are turning a little %s.", /* 5 */
207 "Your limbs are getting oozy.", /* 4 */
208 "Your skin begins to peel away.", /* 3 */
209 "You are turning into %s.", /* 2 */
210 "You have become %s." /* 1 */
212 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
213 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
214 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
215 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
216 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
223 register long i = (Slimed & TIMEOUT) / 2L;
225 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
228 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
230 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
231 (void) strsubst(buf, "limbs", "extremities");
233 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
234 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
237 if (index(buf, '%')) {
238 if (i == 4L) { /* "you are turning green" */
239 if (!Blind) /* [what if you're already green?] */
241 pline(buf, hcolor(NH_GREEN));
243 pline(buf, jconj_adj(hcolor(NH_GREEN)));
247 an(Hallucination ? rndmonnam(NULL) : "green slime"));
249 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
253 if (i == 3L) { /* limbs becoming oozy */
254 HFast = 0L; /* lose intrinsic speed */
260 exercise(A_DEX, FALSE);
268 make_slimed(0L, "The slime that covers you is burned away!");
270 pline("
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
277 register struct prop *upp;
281 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
286 if (u.uluck != baseluck
287 && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
288 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
289 * stop good luck from timing out; normal luckstones stop both;
290 * neither is stopped if you don't have a luckstone.
291 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
293 register int time_luck = stone_luck(FALSE);
294 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
296 if (u.uluck > baseluck && (nostone || time_luck < 0))
298 else if (u.uluck < baseluck && (nostone || time_luck > 0))
302 return; /* things past this point could kill you */
311 if (u.mtimedone && !--u.mtimedone) {
313 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
320 /* Dissipate spell-based protection. */
322 if (--u.usptime == 0 && u.uspellprot) {
323 u.usptime = u.uspmtime;
328 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
329 u.uspellprot ? "becomes less dense" : "disappears");
331 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
332 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
338 if (--u.ugallop == 0L && u.usteed)
340 pline("%s stops galloping.", Monnam(u.usteed));
342 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
345 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
346 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
347 kptr = find_delayed_killer((int) (upp - u.uprops));
348 switch (upp - u.uprops) {
350 if (kptr && kptr->name[0]) {
351 killer.format = kptr->format;
353 Strcpy(killer.name, kptr->name);
355 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
359 killer.format = NO_KILLER_PREFIX;
360 Strcpy(killer.name, "killed by petrification");
362 killer.format = KILLED_BY;
363 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
366 dealloc_killer(kptr);
367 /* (unlike sliming, you aren't changing form here) */
371 if (kptr && kptr->name[0]) {
372 killer.format = kptr->format;
373 Strcpy(killer.name, kptr->name);
375 killer.format = NO_KILLER_PREFIX;
377 Strcpy(killer.name, "turned into green slime");
379 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
381 dealloc_killer(kptr);
382 /* involuntarily break "never changed form" conduct */
383 u.uconduct.polyselfs++;
387 make_vomiting(0L, TRUE);
391 You("die from your illness.");
393 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
394 if (kptr && kptr->name[0]) {
395 killer.format = kptr->format;
396 Strcpy(killer.name, kptr->name);
398 killer.format = KILLED_BY_AN;
399 killer.name[0] = 0; /* take the default */
401 dealloc_killer(kptr);
403 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
404 if (type_is_pname(&mons[m_idx])) {
405 killer.format = KILLED_BY;
406 } else if (mons[m_idx].geno & G_UNIQ) {
407 Strcpy(killer.name, the(killer.name));
408 killer.format = KILLED_BY;
417 You_feel("yourself slowing down%s.",
418 Fast ? " a bit" : "");
420 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
421 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
425 /* So make_confused works properly */
426 set_itimeout(&HConfusion, 1L);
427 make_confused(0L, TRUE);
432 set_itimeout(&HStun, 1L);
433 make_stunned(0L, TRUE);
438 set_itimeout(&Blinded, 1L);
439 make_blinded(0L, TRUE);
444 set_itimeout(&HDeaf, 1L);
451 if (!Invis && !BInvis && !Blind) {
454 ? "are no longer invisible."
455 : "can no longer see through yourself.");
458 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
459 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
465 set_mimic_blocking(); /* do special mimic handling */
466 see_monsters(); /* make invis mons appear */
467 newsym(u.ux, u.uy); /* make self appear */
477 make_totter(0L, TRUE);
482 set_itimeout(&HHallucination, 1L);
483 (void) make_hallucinated(0L, TRUE, 0L);
488 if (unconscious() || Sleep_resistance) {
489 incr_itimeout(&HSleepy, rnd(100));
494 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
496 fall_asleep(-sleeptime, TRUE);
497 incr_itimeout(&HSleepy, sleeptime + rnd(100));
501 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
504 killer.format = KILLED_BY;
507 (u.uburied) ? "suffocation" : "strangulation");
510 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
513 /* must be declining to die in explore|wizard mode;
514 treat like being cured of strangulation by prayer */
515 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
517 Your("amulet vanishes!");
519 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
524 /* call this only when a move took place. */
525 /* otherwise handle fumbling msgs locally. */
526 if (u.umoved && !Levitation) {
529 multi_reason = "fumbling";
531 /* The more you are carrying the more likely you
532 * are to make noise when you fumble. Adjustments
533 * to this number must be thoroughly play tested.
535 if ((inv_weight() > -500)) {
537 You("make a lot of noise!");
539 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
543 /* from outside means slippery ice; don't reset
544 counter if that's the only fumble reason */
545 HFumbling &= ~FROMOUTSIDE;
547 incr_itimeout(&HFumbling, rnd(20));
549 case DETECT_MONSTERS:
559 fall_asleep(how_long, wakeup_msg)
565 multi_reason = "sleeping";
566 /* generally don't notice sounds while sleeping */
567 if (wakeup_msg && multi == how_long) {
568 /* caller can follow with a direct call to Hear_again() if
569 there's a need to override this when wakeup_msg is true */
570 incr_itimeout(&HDeaf, how_long);
571 afternmv = Hear_again; /* this won't give any messages */
573 /* early wakeup from combat won't be possible until next monster turn */
574 u.usleep = monstermoves;
576 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
578 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
581 /* Attach an egg hatch timeout to the given egg.
582 * when = Time to hatch, usually only passed if re-creating an
583 * existing hatch timer. Pass 0L for random hatch time.
586 attach_egg_hatch_timeout(egg, when)
592 /* stop previous timer, if any */
593 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
596 * Decide if and when to hatch the egg. The old hatch_it() code tried
597 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
598 * a number x, 1<=x<=age, where x>150. This yields a chance of
599 * hatching > 99.9993%. Mimic that here.
602 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
610 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
614 /* prevent an egg from ever hatching */
619 /* stop previous timer, if any */
620 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
623 /* timer callback routine: hatch the given egg */
625 hatch_egg(arg, timeout)
630 struct monst *mon, *mon2;
633 boolean yours, silent, knows_egg = FALSE;
634 boolean cansee_hatchspot = FALSE;
635 int i, mnum, hatchcount = 0;
638 /* sterilized while waiting */
639 if (egg->corpsenm == NON_PM)
642 mon = mon2 = (struct monst *) 0;
643 mnum = big_to_little(egg->corpsenm);
644 /* The identity of one's father is learned, not innate */
645 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
646 silent = (timeout != monstermoves); /* hatched while away */
648 /* only can hatch when in INVENT, FLOOR, MINVENT */
649 if (get_obj_location(egg, &x, &y, 0)) {
650 hatchcount = rnd((int) egg->quan);
651 cansee_hatchspot = cansee(x, y) && !silent;
652 if (!(mons[mnum].geno & G_UNIQ)
653 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
654 for (i = hatchcount; i > 0; i--) {
655 if (!enexto(&cc, x, y, &mons[mnum])
656 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
658 /* tame if your own egg hatches while you're on the
659 same dungeon level, or any dragon egg which hatches
660 while it's in your inventory */
661 if ((yours && !silent)
662 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
663 if (tamedog(mon, (struct obj *) 0)) {
664 if (carried(egg) && mon->data->mlet != S_DRAGON)
668 if (mvitals[mnum].mvflags & G_EXTINCT)
669 break; /* just made last one */
670 mon2 = mon; /* in case makemon() fails on 2nd egg */
675 egg->quan -= (long) hatchcount;
679 * We could possibly hatch while migrating, but the code isn't
682 } else if (obj->where == OBJ_MIGRATING) {
684 * We can do several things. The first ones that come to
686 * + Create the hatched monster then place it on the migrating
687 * mons list. This is tough because all makemon() is made
688 * to place the monster as well. Makemon() also doesn't lend
689 * itself well to splitting off a "not yet placed" subroutine.
690 * + Mark the egg as hatched, then place the monster when we
691 * place the migrating objects.
692 * + Or just kill any egg which gets sent to another level.
693 * Falling is the usual reason such transportation occurs.
695 cansee_hatchspot = FALSE;
701 char monnambuf[BUFSZ], carriedby[BUFSZ];
702 boolean siblings = (hatchcount > 1), redraw = FALSE;
704 if (cansee_hatchspot) {
706 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
707 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
709 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
712 /* we don't learn the egg type here because learning
713 an egg type requires either seeing the egg hatch
714 or being familiar with the egg already,
715 as well as being able to see the resulting
716 monster, checked below
719 switch (egg->where) {
721 knows_egg = TRUE; /* true even if you are blind */
722 if (!cansee_hatchspot)
724 You_feel("%s %s from your pack!", something,
725 locomotion(mon->data, "drop"));
727 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
728 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
732 You_see("%s %s out of your pack!", monnambuf,
733 locomotion(mon->data, "drop"));
735 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
736 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
740 pline("%s cries sound like \"%s%s\"",
741 siblings ? "Their" : "Its",
742 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
744 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
745 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
747 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
749 verbalize("Gleep!"); /* Mything eggs :-) */
751 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
757 if (cansee_hatchspot) {
760 You_see("%s hatch.", monnambuf);
762 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
763 redraw = TRUE; /* update egg's map location */
768 if (cansee_hatchspot) {
769 /* egg carrying monster might be invisible */
770 if (canseemon(egg->ocarry)) {
772 Sprintf(carriedby, "%s pack",
774 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
775 s_suffix(a_monnam(egg->ocarry)));
777 } else if (is_pool(mon->mx, mon->my))
779 Strcpy(carriedby, "empty water");
781 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
784 Strcpy(carriedby, "thin air");
786 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
788 You_see("%s %s out of %s!", monnambuf,
789 locomotion(mon->data, "drop"), carriedby);
791 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
792 locomotion(mon->data, "
\97\8e\82¿
\82é"));
801 impossible("egg hatched where? (%d)", (int) egg->where);
805 if (cansee_hatchspot && knows_egg)
806 learn_egg_type(mnum);
809 /* still some eggs left */
810 /* Instead of ordinary egg timeout use a short one */
811 attach_egg_hatch_timeout(egg, (long) rnd(12));
812 } else if (carried(egg)) {
815 /* free egg here because we use it above */
816 obj_extract_self(egg);
817 obfree(egg, (struct obj *) 0);
824 /* Learn to recognize eggs of the given type. */
829 /* baby monsters hatch from grown-up eggs */
830 mnum = little_to_big(mnum);
831 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
832 /* we might have just learned about other eggs being carried */
836 /* Attach a fig_transform timeout to the given figurine. */
838 attach_fig_transform_timeout(figurine)
839 struct obj *figurine;
843 /* stop previous timer, if any */
844 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
847 * Decide when to transform the figurine.
850 /* figurine will transform */
851 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
852 obj_to_any(figurine));
855 /* give a fumble message */
859 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
862 boolean on_foot = TRUE;
866 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
869 if (otmp && on_foot) { /* trip over something in particular */
871 If there is only one item, it will have just been named
872 during the move, so refer to by via pronoun; otherwise,
873 if the top item has been or can be seen, refer to it by
874 name; if not, look for rocks to trip over; trip over
875 anonymous "something" if there aren't any rocks.
878 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
879 ? ((otmp->quan == 1L) ? "it"
880 : Hallucination ? "they" : "them")
881 : (otmp->dknown || !Blind)
883 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
885 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
887 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
889 : (otmp->dknown || !Blind)
891 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
896 what = strcpy(buf, what);
897 buf[0] = highc(buf[0]);
899 pline("Egads! %s bite%s your %s!", what,
900 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
902 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
906 You("trip over %s.", what);
908 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
910 if (!uarmf && otmp->otyp == CORPSE
911 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
913 Sprintf(killer.name, "tripping over %s corpse",
914 an(mons[otmp->corpsenm].mname));
916 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
917 mons[otmp->corpsenm].mname);
919 instapetrify(killer.name);
921 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
923 pline("%s %s%s on the ice.",
924 u.usteed ? upstart(x_monnam(u.usteed,
925 (has_mname(u.usteed)) ? ARTICLE_NONE
927 (char *) 0, SUPPRESS_SADDLE, FALSE))
929 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
931 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
932 u.usteed ? upstart(x_monnam(u.usteed,
933 (has_mname(u.usteed)) ? ARTICLE_NONE
935 (char *) 0, SUPPRESS_SADDLE, FALSE))
943 You("trip over your own %s.",
944 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
946 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
947 Hallucination ? "
\95I" : body_part(FOOT));
953 Hallucination ? "on a banana peel" : "and nearly fall");
955 You("%s
\81D", Hallucination ?
956 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
963 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
969 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
976 Your("%s slip out of the stirrups.",
977 makeplural(body_part(FOOT)));
979 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
984 You("let go of the reins.");
986 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
990 You("bang into the saddle-horn.");
992 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
996 You("slide to one side of the saddle.");
998 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1001 dismount_steed(DISMOUNT_FELL);
1006 /* Print a lamp flicker message with tailer. */
1008 see_lamp_flicker(obj, tailer)
1012 switch (obj->where) {
1016 pline("%s flickers%s.", Yname2(obj), tailer);
1018 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1022 You_see("%s flicker%s.", an(xname(obj)), tailer);
1024 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1029 /* Print a dimming message for brass lanterns. */
1031 lantern_message(obj)
1034 /* from adventure */
1035 switch (obj->where) {
1038 Your("lantern is getting dim.");
1040 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1043 pline("Batteries have not been invented yet.");
1045 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1049 You_see("a lantern getting dim.");
1051 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1055 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1057 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1063 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1064 * See begin_burn() for meanings of obj->age and obj->spe.
1067 burn_object(arg, timeout)
1071 struct obj *obj = arg->a_obj;
1072 boolean canseeit, many, menorah, need_newsym;
1076 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1077 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1079 /* timeout while away */
1080 if (timeout != monstermoves) {
1081 long how_long = monstermoves - timeout;
1083 if (how_long >= obj->age) {
1085 end_burn(obj, FALSE);
1088 obj->spe = 0; /* no more candles */
1089 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1090 /* get rid of candles and burning oil potions;
1091 we know this object isn't carried by hero,
1092 nor is it migrating */
1093 obj_extract_self(obj);
1094 obfree(obj, (struct obj *) 0);
1095 obj = (struct obj *) 0;
1099 obj->age -= how_long;
1100 begin_burn(obj, TRUE);
1105 /* only interested in INVENT, FLOOR, and MINVENT */
1106 if (get_obj_location(obj, &x, &y, 0)) {
1107 canseeit = !Blind && cansee(x, y);
1108 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1109 (void) Shk_Your(whose, obj);
1113 need_newsym = FALSE;
1115 /* obj->age is the age remaining at this point. */
1116 switch (obj->otyp) {
1118 /* this should only be called when we run out */
1120 switch (obj->where) {
1124 pline("%spotion of oil has burnt away.", whose);
1126 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1130 You_see("a burning potion of oil go out.");
1132 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1137 end_burn(obj, FALSE); /* turn off light source */
1141 /* clear migrating obj's destination code before obfree
1142 to avoid false complaint of deleting worn item */
1143 if (obj->where == OBJ_MIGRATING)
1144 obj->owornmask = 0L;
1145 obj_extract_self(obj);
1146 obfree(obj, (struct obj *) 0);
1148 obj = (struct obj *) 0;
1153 switch ((int) obj->age) {
1158 if (obj->otyp == BRASS_LANTERN)
1159 lantern_message(obj);
1161 see_lamp_flicker(obj,
1163 obj->age == 50L ? " considerably" : "");
1165 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1171 if (obj->otyp == BRASS_LANTERN)
1172 lantern_message(obj);
1174 switch (obj->where) {
1178 pline("%s seems about to go out.", Yname2(obj));
1180 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1184 You_see("%s about to go out.", an(xname(obj)));
1186 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1194 /* even if blind you'll know if holding it */
1195 if (canseeit || obj->where == OBJ_INVENT) {
1196 switch (obj->where) {
1199 if (obj->otyp == BRASS_LANTERN)
1201 pline("%slantern has run out of power.", whose);
1203 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1206 pline("%s has gone out.", Yname2(obj));
1208 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1211 if (obj->otyp == BRASS_LANTERN)
1213 You_see("a lantern run out of power.");
1215 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1218 You_see("%s go out.", an(xname(obj)));
1220 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1224 end_burn(obj, FALSE);
1229 * Someone added fuel to the lamp while it was
1230 * lit. Just fall through and let begin burn
1231 * handle the new age.
1237 begin_burn(obj, TRUE);
1241 case CANDELABRUM_OF_INVOCATION:
1247 switch (obj->where) {
1251 pline("%s%scandle%s getting short.", whose,
1252 menorah ? "candelabrum's " : "",
1253 many ? "s are" : " is");
1255 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1256 menorah ? "
\90C
\91ä
\82Ì" : "");
1261 You_see("%scandle%s getting short.",
1262 menorah ? "a candelabrum's " : many ? "some "
1266 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1267 menorah ? "
\90C
\91ä
\82Ì" : "");
1275 switch (obj->where) {
1279 pline("%s%scandle%s flame%s flicker%s low!", whose,
1280 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1281 many ? "s" : "", many ? "" : "s");
1283 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1284 menorah ? "
\90C
\91ä
\82Ì" : "");
1289 You_see("%scandle%s flame%s flicker low!",
1290 menorah ? "a candelabrum's " : many ? "some "
1292 many ? "s'" : "'s", many ? "s" : "");
1294 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1295 menorah ? "
\90C
\91ä
\82Ì" : "");
1302 /* we know even if blind and in our inventory */
1303 if (canseeit || obj->where == OBJ_INVENT) {
1305 switch (obj->where) {
1309 pline("%scandelabrum's flame%s.", whose,
1310 many ? "s die" : " dies");
1312 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1317 You_see("a candelabrum's flame%s die.",
1320 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1325 switch (obj->where) {
1329 pline("%s %s consumed!", Yname2(obj),
1330 many ? "are" : "is");
1332 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1337 You see some wax candles consumed!
1338 You see a wax candle consumed!
1341 You_see("%s%s consumed!", many ? "some " : "",
1342 many ? xname(obj) : an(xname(obj)));
1344 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1353 ? (many ? "They shriek!" : "It shrieks!")
1354 : Blind ? "" : (many ? "Their flames die."
1355 : "Its flame dies."));
1357 pline(Hallucination ? "
\82»
\82ê
\82Í
\90k
\82¦
\82½
\81D"
1359 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1363 end_burn(obj, FALSE);
1371 /* clear migrating obj's destination code
1372 so obfree won't think this item is worn */
1373 if (obj->where == OBJ_MIGRATING)
1374 obj->owornmask = 0L;
1375 obj_extract_self(obj);
1376 obfree(obj, (struct obj *) 0);
1378 obj = (struct obj *) 0;
1384 * Someone added fuel (candles) to the menorah while
1385 * it was lit. Just fall through and let begin burn
1386 * handle the new age.
1391 if (obj && obj->age)
1392 begin_burn(obj, TRUE);
1397 impossible("burn_object: unexpeced obj %s", xname(obj));
1405 * Start a burn timeout on the given object. If not "already lit" then
1406 * create a light source for the vision system. There had better not
1407 * be a burn already running on the object.
1409 * Magic lamps stay lit as long as there's a genie inside, so don't start
1413 * potions of oil, lamps & candles:
1414 * age = # of turns of fuel left
1418 * spe = 0 not lightable, 1 lightable forever
1420 * age = # of turns of fuel left
1421 * spe = # of candles
1423 * Once the burn begins, the age will be set to the amount of fuel
1424 * remaining _once_the_burn_finishes_. If the burn is terminated
1425 * early then fuel is added back.
1427 * This use of age differs from the use of age for corpses and eggs.
1428 * For the latter items, age is when the object was created, so we
1429 * know when it becomes "bad".
1431 * This is a "silent" routine - it should not print anything out.
1434 begin_burn(obj, already_lit)
1436 boolean already_lit;
1440 boolean do_timer = TRUE;
1442 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1445 switch (obj->otyp) {
1453 radius = 1; /* very dim light */
1458 /* magic times are 150, 100, 50, 25, and 0 */
1459 if (obj->age > 150L)
1460 turns = obj->age - 150L;
1461 else if (obj->age > 100L)
1462 turns = obj->age - 100L;
1463 else if (obj->age > 50L)
1464 turns = obj->age - 50L;
1465 else if (obj->age > 25L)
1466 turns = obj->age - 25L;
1471 case CANDELABRUM_OF_INVOCATION:
1474 /* magic times are 75, 15, and 0 */
1476 turns = obj->age - 75L;
1477 else if (obj->age > 15L)
1478 turns = obj->age - 15L;
1481 radius = candle_light_range(obj);
1485 /* [ALI] Support artifact light sources */
1486 if (artifact_light(obj)) {
1489 radius = arti_light_radius(obj);
1491 impossible("begin burn: unexpected %s", xname(obj));
1498 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1501 if (carried(obj) && !already_lit)
1507 if (carried(obj) && !already_lit)
1511 if (obj->lamplit && !already_lit) {
1514 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1515 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1517 impossible("begin_burn: can't get obj position");
1522 * Stop a burn timeout on the given object if timer attached. Darken
1526 end_burn(obj, timer_attached)
1528 boolean timer_attached;
1530 if (!obj->lamplit) {
1531 impossible("end_burn: obj %s not lit", xname(obj));
1535 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1536 timer_attached = FALSE;
1538 if (!timer_attached) {
1539 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1540 del_light_source(LS_OBJECT, obj_to_any(obj));
1542 if (obj->where == OBJ_INVENT)
1544 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1545 impossible("end_burn: obj %s not timed!", xname(obj));
1549 * Cleanup a burning object if timer stopped.
1552 cleanup_burn(arg, expire_time)
1556 struct obj *obj = arg->a_obj;
1557 if (!obj->lamplit) {
1558 impossible("cleanup_burn: obj %s not lit", xname(obj));
1562 del_light_source(LS_OBJECT, obj_to_any(obj));
1564 /* restore unused time */
1565 obj->age += expire_time - monstermoves;
1569 if (obj->where == OBJ_INVENT)
1581 /* no lightning if not the air level or too often, even then */
1582 if (!Is_airlevel(&u.uz) || rn2(8))
1585 /* the number of strikes is 8-log2(nstrike) */
1586 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1591 } while (++count < 100 && levl[x][y].typ != CLOUD);
1596 if (dirx != 0 || diry != 0)
1597 buzz(-15, /* "monster" LIGHTNING spell */
1598 8, x, y, dirx, diry);
1602 if (levl[u.ux][u.uy].typ == CLOUD) {
1603 /* Inside a cloud during a thunder storm is deafening. */
1604 /* Even if already deaf, we sense the thunder's vibrations. */
1606 pline("Kaboom!!! Boom!! Boom!!");
1608 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");
1609 incr_itimeout(&HDeaf, rn1(20, 30));
1610 if (!u.uinvulnerable) {
1613 multi_reason = "hiding from thunderstorm";
1618 You_hear("a rumbling noise.");
1620 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1623 /* -------------------------------------------------------------------------
1626 * Generic Timeout Functions.
1631 * boolean start_timer(long timeout,short kind,short func_index,
1633 * Start a timer of kind 'kind' that will expire at time
1634 * monstermoves+'timeout'. Call the function at 'func_index'
1635 * in the timeout table using argument 'arg'. Return TRUE if
1636 * a timer was started. This places the timer on a list ordered
1637 * "sooner" to "later". If an object, increment the object's
1640 * long stop_timer(short func_index, anything *arg)
1641 * Stop a timer specified by the (func_index, arg) pair. This
1642 * assumes that such a pair is unique. Return the time the
1643 * timer would have gone off. If no timer is found, return 0.
1644 * If an object, decrement the object's timer count.
1646 * long peek_timer(short func_index, anything *arg)
1647 * Return time specified timer will go off (0 if no such timer).
1649 * void run_timers(void)
1650 * Call timers that have timed out.
1653 * void save_timers(int fd, int mode, int range)
1654 * Save all timers of range 'range'. Range is either global
1655 * or local. Global timers follow game play, local timers
1656 * are saved with a level. Object and monster timers are
1657 * saved using their respective id's instead of pointers.
1659 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1660 * Restore timers of range 'range'. If from a ghost pile,
1661 * adjust the timeout by 'adjust'. The object and monster
1662 * ids are not restored until later.
1664 * void relink_timers(boolean ghostly)
1665 * Relink all object and monster timers that had been saved
1666 * using their object's or monster's id number.
1669 * void obj_move_timers(struct obj *src, struct obj *dest)
1670 * Reassign all timers from src to dest.
1672 * void obj_split_timers(struct obj *src, struct obj *dest)
1673 * Duplicate all timers assigned to src and attach them to dest.
1675 * void obj_stop_timers(struct obj *obj)
1676 * Stop all timers attached to obj.
1678 * boolean obj_has_timer(struct obj *object, short timer_type)
1679 * Check whether object has a timer of type timer_type.
1682 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1683 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1684 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1685 STATIC_DCL timer_element *FDECL(remove_timer,
1686 (timer_element **, SHORT_P, ANY_P *));
1687 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1688 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1689 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1690 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1692 /* ordered timer list */
1693 static timer_element *timer_base; /* "active" */
1694 static unsigned long timer_id = 1;
1696 /* If defined, then include names when printing out the timer queue */
1697 #define VERBOSE_TIMER
1700 timeout_proc f, cleanup;
1701 #ifdef VERBOSE_TIMER
1703 #define TTAB(a, b, c) \
1708 #define TTAB(a, b, c) \
1715 /* table of timeout functions */
1716 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1717 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
1718 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
1719 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
1720 TTAB(burn_object, cleanup_burn, "burn_object"),
1721 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
1722 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
1723 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
1727 STATIC_OVL const char *
1745 print_queue(win, base)
1747 timer_element *base;
1749 timer_element *curr;
1753 putstr(win, 0, "<empty>");
1755 putstr(win, 0, "timeout id kind call");
1756 for (curr = base; curr; curr = curr->next) {
1757 #ifdef VERBOSE_TIMER
1758 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
1759 curr->tid, kind_name(curr->kind),
1760 timeout_funcs[curr->func_index].name,
1761 fmt_ptr((genericptr_t) curr->arg.a_void));
1763 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
1764 curr->tid, kind_name(curr->kind), curr->func_index,
1765 fmt_ptr((genericptr_t) curr->arg.a_void));
1767 putstr(win, 0, buf);
1778 win = create_nhwindow(NHW_MENU); /* corner text window */
1782 Sprintf(buf, "Current time = %ld.", monstermoves);
1783 putstr(win, 0, buf);
1785 putstr(win, 0, "Active timeout queue:");
1787 print_queue(win, timer_base);
1789 display_nhwindow(win, FALSE);
1790 destroy_nhwindow(win);
1796 timer_sanity_check()
1798 timer_element *curr;
1800 /* this should be much more complete */
1801 for (curr = timer_base; curr; curr = curr->next)
1802 if (curr->kind == TIMER_OBJECT) {
1803 struct obj *obj = curr->arg.a_obj;
1804 if (obj->timed == 0) {
1805 pline("timer sanity: untimed obj %s, timer %ld",
1806 fmt_ptr((genericptr_t) obj), curr->tid);
1812 * Pick off timeout elements from the global queue and call their functions.
1813 * Do this until their time is less than or equal to the move count.
1818 timer_element *curr;
1821 * Always use the first element. Elements may be added or deleted at
1822 * any time. The list is ordered, we are done when the first element
1825 while (timer_base && timer_base->timeout <= monstermoves) {
1827 timer_base = curr->next;
1829 if (curr->kind == TIMER_OBJECT)
1830 (curr->arg.a_obj)->timed--;
1831 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
1832 free((genericptr_t) curr);
1837 * Start a timer. Return TRUE if successful.
1840 start_timer(when, kind, func_index, arg)
1848 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1849 panic("start_timer");
1851 gnu = (timer_element *) alloc(sizeof(timer_element));
1853 gnu->tid = timer_id++;
1854 gnu->timeout = monstermoves + when;
1856 gnu->needs_fixup = 0;
1857 gnu->func_index = func_index;
1861 if (kind == TIMER_OBJECT) /* increment object's timed count */
1862 (arg->a_obj)->timed++;
1864 /* should check for duplicates and fail if any */
1869 * Remove the timer from the current list and free it up. Return the time
1870 * remaining until it would have gone off, 0 if not found.
1873 stop_timer(func_index, arg)
1877 timer_element *doomed;
1880 doomed = remove_timer(&timer_base, func_index, arg);
1883 timeout = doomed->timeout;
1884 if (doomed->kind == TIMER_OBJECT)
1885 (arg->a_obj)->timed--;
1886 if (timeout_funcs[doomed->func_index].cleanup)
1887 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
1888 free((genericptr_t) doomed);
1889 return (timeout - monstermoves);
1895 * Find the timeout of specified timer; return 0 if none.
1898 peek_timer(type, arg)
1902 timer_element *curr;
1904 for (curr = timer_base; curr; curr = curr->next) {
1905 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
1906 return curr->timeout;
1912 * Move all object timers from src to dest, leaving src untimed.
1915 obj_move_timers(src, dest)
1916 struct obj *src, *dest;
1919 timer_element *curr;
1921 for (count = 0, curr = timer_base; curr; curr = curr->next)
1922 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1923 curr->arg.a_obj = dest;
1927 if (count != src->timed)
1928 panic("obj_move_timers");
1933 * Find all object timers and duplicate them for the new object "dest".
1936 obj_split_timers(src, dest)
1937 struct obj *src, *dest;
1939 timer_element *curr, *next_timer = 0;
1941 for (curr = timer_base; curr; curr = next_timer) {
1942 next_timer = curr->next; /* things may be inserted */
1943 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1944 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
1945 curr->func_index, obj_to_any(dest));
1951 * Stop all timers attached to this object. We can get away with this because
1952 * all object pointers are unique.
1955 obj_stop_timers(obj)
1958 timer_element *curr, *prev, *next_timer = 0;
1960 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1961 next_timer = curr->next;
1962 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
1964 prev->next = curr->next;
1966 timer_base = curr->next;
1967 if (timeout_funcs[curr->func_index].cleanup)
1968 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1970 free((genericptr_t) curr);
1979 * Check whether object has a timer of type timer_type.
1982 obj_has_timer(object, timer_type)
1986 long timeout = peek_timer(timer_type, obj_to_any(object));
1988 return (boolean) (timeout != 0L);
1992 * Stop all timers of index func_index at this spot.
1996 spot_stop_timers(x, y, func_index)
2000 timer_element *curr, *prev, *next_timer = 0;
2001 long where = (((long) x << 16) | ((long) y));
2003 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2004 next_timer = curr->next;
2005 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2006 && curr->arg.a_long == where) {
2008 prev->next = curr->next;
2010 timer_base = curr->next;
2011 if (timeout_funcs[curr->func_index].cleanup)
2012 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2014 free((genericptr_t) curr);
2022 * When is the spot timer of type func_index going to expire?
2023 * Returns 0L if no such timer.
2026 spot_time_expires(x, y, func_index)
2030 timer_element *curr;
2031 long where = (((long) x << 16) | ((long) y));
2033 for (curr = timer_base; curr; curr = curr->next) {
2034 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2035 && curr->arg.a_long == where)
2036 return curr->timeout;
2042 spot_time_left(x, y, func_index)
2046 long expires = spot_time_expires(x, y, func_index);
2047 return (expires > 0L) ? expires - monstermoves : 0L;
2050 /* Insert timer into the global queue */
2055 timer_element *curr, *prev;
2057 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2058 if (curr->timeout >= gnu->timeout)
2068 STATIC_OVL timer_element *
2069 remove_timer(base, func_index, arg)
2070 timer_element **base;
2074 timer_element *prev, *curr;
2076 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2077 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2082 prev->next = curr->next;
2091 write_timer(fd, timer)
2093 timer_element *timer;
2098 switch (timer->kind) {
2101 /* assume no pointers in arg */
2102 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2106 if (timer->needs_fixup)
2107 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2109 /* replace object pointer with id */
2110 arg_save.a_obj = timer->arg.a_obj;
2111 timer->arg = zeroany;
2112 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2113 timer->needs_fixup = 1;
2114 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2115 timer->arg.a_obj = arg_save.a_obj;
2116 timer->needs_fixup = 0;
2121 if (timer->needs_fixup)
2122 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2124 /* replace monster pointer with id */
2125 arg_save.a_monst = timer->arg.a_monst;
2126 timer->arg = zeroany;
2127 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2128 timer->needs_fixup = 1;
2129 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2130 timer->arg.a_monst = arg_save.a_monst;
2131 timer->needs_fixup = 0;
2136 panic("write_timer");
2142 * Return TRUE if the object will stay on the level when the level is
2149 switch (obj->where) {
2157 return obj_is_local(obj->ocontainer);
2159 return mon_is_local(obj->ocarry);
2161 panic("obj_is_local");
2166 * Return TRUE if the given monster will stay on the level when the
2175 for (curr = migrating_mons; curr; curr = curr->nmon)
2178 /* `mydogs' is used during level changes, never saved and restored */
2179 for (curr = mydogs; curr; curr = curr->nmon)
2186 * Return TRUE if the timer is attached to something that will stay on the
2187 * level when the level is saved.
2190 timer_is_local(timer)
2191 timer_element *timer;
2193 switch (timer->kind) {
2199 return obj_is_local(timer->arg.a_obj);
2201 return mon_is_local(timer->arg.a_monst);
2203 panic("timer_is_local");
2208 * Part of the save routine. Count up the number of timers that would
2209 * be written. If write_it is true, actually write the timer.
2212 maybe_write_timer(fd, range, write_it)
2217 timer_element *curr;
2219 for (curr = timer_base; curr; curr = curr->next) {
2220 if (range == RANGE_GLOBAL) {
2223 if (!timer_is_local(curr)) {
2226 write_timer(fd, curr);
2232 if (timer_is_local(curr)) {
2235 write_timer(fd, curr);
2244 * Save part of the timer list. The parameter 'range' specifies either
2245 * global or level timers to save. The timer ID is saved with the global
2249 * + timeouts that follow the hero (global)
2250 * + timeouts that follow obj & monst that are migrating
2253 * + timeouts that are level specific (e.g. storms)
2254 * + timeouts that stay with the level (obj & monst)
2257 save_timers(fd, mode, range)
2258 int fd, mode, range;
2260 timer_element *curr, *prev, *next_timer = 0;
2263 if (perform_bwrite(mode)) {
2264 if (range == RANGE_GLOBAL)
2265 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2267 count = maybe_write_timer(fd, range, FALSE);
2268 bwrite(fd, (genericptr_t) &count, sizeof count);
2269 (void) maybe_write_timer(fd, range, TRUE);
2272 if (release_data(mode)) {
2273 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2274 next_timer = curr->next; /* in case curr is removed */
2276 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2278 prev->next = curr->next;
2280 timer_base = curr->next;
2281 free((genericptr_t) curr);
2282 /* prev stays the same */
2291 * Pull in the structures from disk, but don't recalculate the object and
2295 restore_timers(fd, range, ghostly, adjust)
2297 boolean ghostly; /* restoring from a ghost level */
2298 long adjust; /* how much to adjust timeout */
2301 timer_element *curr;
2303 if (range == RANGE_GLOBAL)
2304 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2306 /* restore elements */
2307 mread(fd, (genericptr_t) &count, sizeof count);
2308 while (count-- > 0) {
2309 curr = (timer_element *) alloc(sizeof(timer_element));
2310 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2312 curr->timeout += adjust;
2317 /* reset all timers that are marked for reseting */
2319 relink_timers(ghostly)
2322 timer_element *curr;
2325 for (curr = timer_base; curr; curr = curr->next) {
2326 if (curr->needs_fixup) {
2327 if (curr->kind == TIMER_OBJECT) {
2329 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2330 panic("relink_timers 1");
2332 nid = curr->arg.a_uint;
2333 curr->arg.a_obj = find_oid(nid);
2334 if (!curr->arg.a_obj)
2335 panic("cant find o_id %d", nid);
2336 curr->needs_fixup = 0;
2337 } else if (curr->kind == TIMER_MONSTER) {
2338 panic("relink_timers: no monster timer implemented");
2340 panic("relink_timers 2");