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 */
75 multi_reason = "getting stoned";
77 multi_reason = "
\90Î
\89»
\82µ
\82Â
\82Â
\82 \82é
\8e\9e\82É";
78 nomovemsg = You_can_move_again; /* not unconscious */
83 exercise(A_DEX, FALSE);
86 /* He is getting sicker and sicker prior to vomiting */
87 static NEARDATA const char *const vomiting_texts[] = {
89 "are feeling mildly nauseated.", /* 14 */
90 "feel slightly confused.", /* 11 */
91 "can't seem to think straight.", /* 8 */
92 "feel incredibly sick.", /* 5 */
93 "suddenly vomit!" /* 2 */
95 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
96 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
97 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
98 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
99 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81I" /* 2 */
107 long v = (Vomiting & TIMEOUT);
109 /* note: nhtimeout() hasn't decremented timed properties for the
110 current turn yet, so we use Vomiting-1 here */
111 switch ((int) (v - 1L)) {
113 txt = vomiting_texts[0];
116 txt = vomiting_texts[1];
119 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
120 if (!Popeye(VOMITING))
124 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
129 txt = vomiting_texts[2];
132 txt = vomiting_texts[3];
135 txt = vomiting_texts[4];
136 if (cantvomit(youmonst.data))
138 txt = "gag uncontrolably.";
140 txt = "
\8bC
\95ª
\82Ì
\88«
\82³
\82ª
\97}
\82¦
\82ç
\82ê
\82È
\82
\82È
\82Á
\82½
\81D";
144 if (!cantvomit(youmonst.data))
153 exercise(A_CON, FALSE);
156 static NEARDATA const char *const choke_texts[] = {
158 "You find it hard to breathe.", "You're gasping for air.",
159 "You can no longer breathe.", "You're turning %s.", "You suffocate."
161 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
162 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
163 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
164 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
165 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
169 static NEARDATA const char *const choke_texts2[] = {
171 "Your %s is becoming constricted.",
172 "Your blood is having trouble reaching your brain.",
173 "The pressure on your %s increases.", "Your consciousness is fading.",
176 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
177 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
178 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
179 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
180 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
187 register long i = (Strangled & TIMEOUT);
189 if (i > 0 && i <= SIZE(choke_texts)) {
190 if (Breathless || !rn2(50))
191 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
193 const char *str = choke_texts[SIZE(choke_texts) - i];
197 pline(str, hcolor(NH_BLUE));
199 pline(str, jconj_adj(hcolor(NH_BLUE)));
204 exercise(A_STR, FALSE);
207 static NEARDATA const char *const slime_texts[] = {
209 "You are turning a little %s.", /* 5 */
210 "Your limbs are getting oozy.", /* 4 */
211 "Your skin begins to peel away.", /* 3 */
212 "You are turning into %s.", /* 2 */
213 "You have become %s." /* 1 */
215 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
216 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
217 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
218 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
219 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
226 register long i = (Slimed & TIMEOUT) / 2L;
228 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
231 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
233 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
234 (void) strsubst(buf, "limbs", "extremities");
236 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
237 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
240 if (index(buf, '%')) {
241 if (i == 4L) { /* "you are turning green" */
242 if (!Blind) /* [what if you're already green?] */
244 pline(buf, hcolor(NH_GREEN));
246 pline(buf, jconj_adj(hcolor(NH_GREEN)));
250 an(Hallucination ? rndmonnam(NULL) : "green slime"));
252 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
256 if (i == 3L) { /* limbs becoming oozy */
257 HFast = 0L; /* lose intrinsic speed */
263 exercise(A_DEX, FALSE);
271 make_slimed(0L, "The slime that covers you is burned away!");
273 pline("
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
280 register struct prop *upp;
284 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
289 if (u.uluck != baseluck
290 && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
291 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
292 * stop good luck from timing out; normal luckstones stop both;
293 * neither is stopped if you don't have a luckstone.
294 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
296 register int time_luck = stone_luck(FALSE);
297 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
299 if (u.uluck > baseluck && (nostone || time_luck < 0))
301 else if (u.uluck < baseluck && (nostone || time_luck > 0))
305 return; /* things past this point could kill you */
314 if (u.mtimedone && !--u.mtimedone) {
316 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
323 /* Dissipate spell-based protection. */
325 if (--u.usptime == 0 && u.uspellprot) {
326 u.usptime = u.uspmtime;
331 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
332 u.uspellprot ? "becomes less dense" : "disappears");
334 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
335 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
341 if (--u.ugallop == 0L && u.usteed)
343 pline("%s stops galloping.", Monnam(u.usteed));
345 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
348 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
349 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
350 kptr = find_delayed_killer((int) (upp - u.uprops));
351 switch (upp - u.uprops) {
353 if (kptr && kptr->name[0]) {
354 killer.format = kptr->format;
356 Strcpy(killer.name, kptr->name);
358 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
362 killer.format = NO_KILLER_PREFIX;
363 Strcpy(killer.name, "killed by petrification");
365 killer.format = KILLED_BY;
366 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
369 dealloc_killer(kptr);
370 /* (unlike sliming, you aren't changing form here) */
374 if (kptr && kptr->name[0]) {
375 killer.format = kptr->format;
376 Strcpy(killer.name, kptr->name);
378 killer.format = NO_KILLER_PREFIX;
380 Strcpy(killer.name, "turned into green slime");
382 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
384 dealloc_killer(kptr);
385 /* involuntarily break "never changed form" conduct */
386 u.uconduct.polyselfs++;
390 make_vomiting(0L, TRUE);
394 You("die from your illness.");
396 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
397 if (kptr && kptr->name[0]) {
398 killer.format = kptr->format;
399 Strcpy(killer.name, kptr->name);
401 killer.format = KILLED_BY_AN;
402 killer.name[0] = 0; /* take the default */
404 dealloc_killer(kptr);
406 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
407 if (type_is_pname(&mons[m_idx])) {
408 killer.format = KILLED_BY;
409 } else if (mons[m_idx].geno & G_UNIQ) {
410 Strcpy(killer.name, the(killer.name));
411 killer.format = KILLED_BY;
420 You_feel("yourself slowing down%s.",
421 Fast ? " a bit" : "");
423 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
424 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
428 /* So make_confused works properly */
429 set_itimeout(&HConfusion, 1L);
430 make_confused(0L, TRUE);
435 set_itimeout(&HStun, 1L);
436 make_stunned(0L, TRUE);
441 set_itimeout(&Blinded, 1L);
442 make_blinded(0L, TRUE);
447 set_itimeout(&HDeaf, 1L);
454 if (!Invis && !BInvis && !Blind) {
457 ? "are no longer invisible."
458 : "can no longer see through yourself.");
461 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
462 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
468 set_mimic_blocking(); /* do special mimic handling */
469 see_monsters(); /* make invis mons appear */
470 newsym(u.ux, u.uy); /* make self appear */
480 make_totter(0L, TRUE);
485 set_itimeout(&HHallucination, 1L);
486 (void) make_hallucinated(0L, TRUE, 0L);
491 if (unconscious() || Sleep_resistance) {
492 incr_itimeout(&HSleepy, rnd(100));
497 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
499 fall_asleep(-sleeptime, TRUE);
500 incr_itimeout(&HSleepy, sleeptime + rnd(100));
504 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
507 killer.format = KILLED_BY;
510 (u.uburied) ? "suffocation" : "strangulation");
513 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
516 /* must be declining to die in explore|wizard mode;
517 treat like being cured of strangulation by prayer */
518 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
520 Your("amulet vanishes!");
522 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
527 /* call this only when a move took place. */
528 /* otherwise handle fumbling msgs locally. */
529 if (u.umoved && !Levitation) {
533 multi_reason = "fumbling";
535 multi_reason = "
\82Ö
\82Ü
\82ð
\82µ
\82½
\8c\84\82É";
537 /* The more you are carrying the more likely you
538 * are to make noise when you fumble. Adjustments
539 * to this number must be thoroughly play tested.
541 if ((inv_weight() > -500)) {
543 You("make a lot of noise!");
545 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
549 /* from outside means slippery ice; don't reset
550 counter if that's the only fumble reason */
551 HFumbling &= ~FROMOUTSIDE;
553 incr_itimeout(&HFumbling, rnd(20));
555 case DETECT_MONSTERS:
565 fall_asleep(how_long, wakeup_msg)
572 multi_reason = "sleeping";
574 multi_reason = "
\96°
\82è
\82Ì
\82³
\82È
\82©
\82É";
575 /* generally don't notice sounds while sleeping */
576 if (wakeup_msg && multi == how_long) {
577 /* caller can follow with a direct call to Hear_again() if
578 there's a need to override this when wakeup_msg is true */
579 incr_itimeout(&HDeaf, how_long);
580 afternmv = Hear_again; /* this won't give any messages */
582 /* early wakeup from combat won't be possible until next monster turn */
583 u.usleep = monstermoves;
585 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
587 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
590 /* Attach an egg hatch timeout to the given egg.
591 * when = Time to hatch, usually only passed if re-creating an
592 * existing hatch timer. Pass 0L for random hatch time.
595 attach_egg_hatch_timeout(egg, when)
601 /* stop previous timer, if any */
602 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
605 * Decide if and when to hatch the egg. The old hatch_it() code tried
606 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
607 * a number x, 1<=x<=age, where x>150. This yields a chance of
608 * hatching > 99.9993%. Mimic that here.
611 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
619 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
623 /* prevent an egg from ever hatching */
628 /* stop previous timer, if any */
629 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
632 /* timer callback routine: hatch the given egg */
634 hatch_egg(arg, timeout)
639 struct monst *mon, *mon2;
642 boolean yours, silent, knows_egg = FALSE;
643 boolean cansee_hatchspot = FALSE;
644 int i, mnum, hatchcount = 0;
647 /* sterilized while waiting */
648 if (egg->corpsenm == NON_PM)
651 mon = mon2 = (struct monst *) 0;
652 mnum = big_to_little(egg->corpsenm);
653 /* The identity of one's father is learned, not innate */
654 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
655 silent = (timeout != monstermoves); /* hatched while away */
657 /* only can hatch when in INVENT, FLOOR, MINVENT */
658 if (get_obj_location(egg, &x, &y, 0)) {
659 hatchcount = rnd((int) egg->quan);
660 cansee_hatchspot = cansee(x, y) && !silent;
661 if (!(mons[mnum].geno & G_UNIQ)
662 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
663 for (i = hatchcount; i > 0; i--) {
664 if (!enexto(&cc, x, y, &mons[mnum])
665 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
667 /* tame if your own egg hatches while you're on the
668 same dungeon level, or any dragon egg which hatches
669 while it's in your inventory */
670 if ((yours && !silent)
671 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
672 if (tamedog(mon, (struct obj *) 0)) {
673 if (carried(egg) && mon->data->mlet != S_DRAGON)
677 if (mvitals[mnum].mvflags & G_EXTINCT)
678 break; /* just made last one */
679 mon2 = mon; /* in case makemon() fails on 2nd egg */
684 egg->quan -= (long) hatchcount;
688 * We could possibly hatch while migrating, but the code isn't
691 } else if (obj->where == OBJ_MIGRATING) {
693 * We can do several things. The first ones that come to
695 * + Create the hatched monster then place it on the migrating
696 * mons list. This is tough because all makemon() is made
697 * to place the monster as well. Makemon() also doesn't lend
698 * itself well to splitting off a "not yet placed" subroutine.
699 * + Mark the egg as hatched, then place the monster when we
700 * place the migrating objects.
701 * + Or just kill any egg which gets sent to another level.
702 * Falling is the usual reason such transportation occurs.
704 cansee_hatchspot = FALSE;
710 char monnambuf[BUFSZ], carriedby[BUFSZ];
711 boolean siblings = (hatchcount > 1), redraw = FALSE;
713 if (cansee_hatchspot) {
715 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
716 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
718 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
721 /* we don't learn the egg type here because learning
722 an egg type requires either seeing the egg hatch
723 or being familiar with the egg already,
724 as well as being able to see the resulting
725 monster, checked below
728 switch (egg->where) {
730 knows_egg = TRUE; /* true even if you are blind */
731 if (!cansee_hatchspot)
733 You_feel("%s %s from your pack!", something,
734 locomotion(mon->data, "drop"));
736 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
737 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
741 You_see("%s %s out of your pack!", monnambuf,
742 locomotion(mon->data, "drop"));
744 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
745 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
749 pline("%s cries sound like \"%s%s\"",
750 siblings ? "Their" : "Its",
751 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
753 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
754 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
756 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
758 verbalize("Gleep!"); /* Mything eggs :-) */
760 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
766 if (cansee_hatchspot) {
769 You_see("%s hatch.", monnambuf);
771 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
772 redraw = TRUE; /* update egg's map location */
777 if (cansee_hatchspot) {
778 /* egg carrying monster might be invisible */
779 if (canseemon(egg->ocarry)) {
781 Sprintf(carriedby, "%s pack",
783 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
784 s_suffix(a_monnam(egg->ocarry)));
786 } else if (is_pool(mon->mx, mon->my))
788 Strcpy(carriedby, "empty water");
790 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
793 Strcpy(carriedby, "thin air");
795 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
797 You_see("%s %s out of %s!", monnambuf,
798 locomotion(mon->data, "drop"), carriedby);
800 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
801 locomotion(mon->data, "
\97\8e\82¿
\82é"));
810 impossible("egg hatched where? (%d)", (int) egg->where);
814 if (cansee_hatchspot && knows_egg)
815 learn_egg_type(mnum);
818 /* still some eggs left */
819 /* Instead of ordinary egg timeout use a short one */
820 attach_egg_hatch_timeout(egg, (long) rnd(12));
821 } else if (carried(egg)) {
824 /* free egg here because we use it above */
825 obj_extract_self(egg);
826 obfree(egg, (struct obj *) 0);
833 /* Learn to recognize eggs of the given type. */
838 /* baby monsters hatch from grown-up eggs */
839 mnum = little_to_big(mnum);
840 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
841 /* we might have just learned about other eggs being carried */
845 /* Attach a fig_transform timeout to the given figurine. */
847 attach_fig_transform_timeout(figurine)
848 struct obj *figurine;
852 /* stop previous timer, if any */
853 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
856 * Decide when to transform the figurine.
859 /* figurine will transform */
860 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
861 obj_to_any(figurine));
864 /* give a fumble message */
868 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
871 boolean on_foot = TRUE;
875 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
878 if (otmp && on_foot) { /* trip over something in particular */
880 If there is only one item, it will have just been named
881 during the move, so refer to by via pronoun; otherwise,
882 if the top item has been or can be seen, refer to it by
883 name; if not, look for rocks to trip over; trip over
884 anonymous "something" if there aren't any rocks.
887 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
888 ? ((otmp->quan == 1L) ? "it"
889 : Hallucination ? "they" : "them")
890 : (otmp->dknown || !Blind)
892 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
894 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
896 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
898 : (otmp->dknown || !Blind)
900 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
905 what = strcpy(buf, what);
906 buf[0] = highc(buf[0]);
908 pline("Egads! %s bite%s your %s!", what,
909 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
911 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
915 You("trip over %s.", what);
917 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
919 if (!uarmf && otmp->otyp == CORPSE
920 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
922 Sprintf(killer.name, "tripping over %s corpse",
923 an(mons[otmp->corpsenm].mname));
925 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
926 mons[otmp->corpsenm].mname);
928 instapetrify(killer.name);
930 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
932 pline("%s %s%s on the ice.",
933 u.usteed ? upstart(x_monnam(u.usteed,
934 (has_mname(u.usteed)) ? ARTICLE_NONE
936 (char *) 0, SUPPRESS_SADDLE, FALSE))
938 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
940 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
941 u.usteed ? upstart(x_monnam(u.usteed,
942 (has_mname(u.usteed)) ? ARTICLE_NONE
944 (char *) 0, SUPPRESS_SADDLE, FALSE))
952 You("trip over your own %s.",
953 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
955 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
956 Hallucination ? "
\95I" : body_part(FOOT));
962 Hallucination ? "on a banana peel" : "and nearly fall");
964 You("%s
\81D", Hallucination ?
965 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
972 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
978 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
985 Your("%s slip out of the stirrups.",
986 makeplural(body_part(FOOT)));
988 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
993 You("let go of the reins.");
995 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
999 You("bang into the saddle-horn.");
1001 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1005 You("slide to one side of the saddle.");
1007 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1010 dismount_steed(DISMOUNT_FELL);
1015 /* Print a lamp flicker message with tailer. */
1017 see_lamp_flicker(obj, tailer)
1021 switch (obj->where) {
1025 pline("%s flickers%s.", Yname2(obj), tailer);
1027 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1031 You_see("%s flicker%s.", an(xname(obj)), tailer);
1033 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1038 /* Print a dimming message for brass lanterns. */
1040 lantern_message(obj)
1043 /* from adventure */
1044 switch (obj->where) {
1047 Your("lantern is getting dim.");
1049 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1052 pline("Batteries have not been invented yet.");
1054 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1058 You_see("a lantern getting dim.");
1060 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1064 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1066 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1072 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1073 * See begin_burn() for meanings of obj->age and obj->spe.
1076 burn_object(arg, timeout)
1080 struct obj *obj = arg->a_obj;
1081 boolean canseeit, many, menorah, need_newsym;
1085 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1086 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1088 /* timeout while away */
1089 if (timeout != monstermoves) {
1090 long how_long = monstermoves - timeout;
1092 if (how_long >= obj->age) {
1094 end_burn(obj, FALSE);
1097 obj->spe = 0; /* no more candles */
1098 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1099 /* get rid of candles and burning oil potions;
1100 we know this object isn't carried by hero,
1101 nor is it migrating */
1102 obj_extract_self(obj);
1103 obfree(obj, (struct obj *) 0);
1104 obj = (struct obj *) 0;
1108 obj->age -= how_long;
1109 begin_burn(obj, TRUE);
1114 /* only interested in INVENT, FLOOR, and MINVENT */
1115 if (get_obj_location(obj, &x, &y, 0)) {
1116 canseeit = !Blind && cansee(x, y);
1117 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1118 (void) Shk_Your(whose, obj);
1122 need_newsym = FALSE;
1124 /* obj->age is the age remaining at this point. */
1125 switch (obj->otyp) {
1127 /* this should only be called when we run out */
1129 switch (obj->where) {
1133 pline("%spotion of oil has burnt away.", whose);
1135 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1139 You_see("a burning potion of oil go out.");
1141 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1146 end_burn(obj, FALSE); /* turn off light source */
1150 /* clear migrating obj's destination code before obfree
1151 to avoid false complaint of deleting worn item */
1152 if (obj->where == OBJ_MIGRATING)
1153 obj->owornmask = 0L;
1154 obj_extract_self(obj);
1155 obfree(obj, (struct obj *) 0);
1157 obj = (struct obj *) 0;
1162 switch ((int) obj->age) {
1167 if (obj->otyp == BRASS_LANTERN)
1168 lantern_message(obj);
1170 see_lamp_flicker(obj,
1172 obj->age == 50L ? " considerably" : "");
1174 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1180 if (obj->otyp == BRASS_LANTERN)
1181 lantern_message(obj);
1183 switch (obj->where) {
1187 pline("%s seems about to go out.", Yname2(obj));
1189 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1193 You_see("%s about to go out.", an(xname(obj)));
1195 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1203 /* even if blind you'll know if holding it */
1204 if (canseeit || obj->where == OBJ_INVENT) {
1205 switch (obj->where) {
1208 if (obj->otyp == BRASS_LANTERN)
1210 pline("%slantern has run out of power.", whose);
1212 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1215 pline("%s has gone out.", Yname2(obj));
1217 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1220 if (obj->otyp == BRASS_LANTERN)
1222 You_see("a lantern run out of power.");
1224 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1227 You_see("%s go out.", an(xname(obj)));
1229 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1233 end_burn(obj, FALSE);
1238 * Someone added fuel to the lamp while it was
1239 * lit. Just fall through and let begin burn
1240 * handle the new age.
1246 begin_burn(obj, TRUE);
1250 case CANDELABRUM_OF_INVOCATION:
1256 switch (obj->where) {
1260 pline("%s%scandle%s getting short.", whose,
1261 menorah ? "candelabrum's " : "",
1262 many ? "s are" : " is");
1264 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1265 menorah ? "
\90C
\91ä
\82Ì" : "");
1270 You_see("%scandle%s getting short.",
1271 menorah ? "a candelabrum's " : many ? "some "
1275 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1276 menorah ? "
\90C
\91ä
\82Ì" : "");
1284 switch (obj->where) {
1288 pline("%s%scandle%s flame%s flicker%s low!", whose,
1289 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1290 many ? "s" : "", many ? "" : "s");
1292 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1293 menorah ? "
\90C
\91ä
\82Ì" : "");
1298 You_see("%scandle%s flame%s flicker low!",
1299 menorah ? "a candelabrum's " : many ? "some "
1301 many ? "s'" : "'s", many ? "s" : "");
1303 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1304 menorah ? "
\90C
\91ä
\82Ì" : "");
1311 /* we know even if blind and in our inventory */
1312 if (canseeit || obj->where == OBJ_INVENT) {
1314 switch (obj->where) {
1318 pline("%scandelabrum's flame%s.", whose,
1319 many ? "s die" : " dies");
1321 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1326 You_see("a candelabrum's flame%s die.",
1329 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1334 switch (obj->where) {
1338 pline("%s %s consumed!", Yname2(obj),
1339 many ? "are" : "is");
1341 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1346 You see some wax candles consumed!
1347 You see a wax candle consumed!
1350 You_see("%s%s consumed!", many ? "some " : "",
1351 many ? xname(obj) : an(xname(obj)));
1353 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1362 ? (many ? "They shriek!" : "It shrieks!")
1363 : Blind ? "" : (many ? "Their flames die."
1364 : "Its flame dies."));
1366 pline(Hallucination ? "
\82»
\82ê
\82Í
\90k
\82¦
\82½
\81D"
1368 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1372 end_burn(obj, FALSE);
1380 /* clear migrating obj's destination code
1381 so obfree won't think this item is worn */
1382 if (obj->where == OBJ_MIGRATING)
1383 obj->owornmask = 0L;
1384 obj_extract_self(obj);
1385 obfree(obj, (struct obj *) 0);
1387 obj = (struct obj *) 0;
1393 * Someone added fuel (candles) to the menorah while
1394 * it was lit. Just fall through and let begin burn
1395 * handle the new age.
1400 if (obj && obj->age)
1401 begin_burn(obj, TRUE);
1406 impossible("burn_object: unexpeced obj %s", xname(obj));
1414 * Start a burn timeout on the given object. If not "already lit" then
1415 * create a light source for the vision system. There had better not
1416 * be a burn already running on the object.
1418 * Magic lamps stay lit as long as there's a genie inside, so don't start
1422 * potions of oil, lamps & candles:
1423 * age = # of turns of fuel left
1427 * spe = 0 not lightable, 1 lightable forever
1429 * age = # of turns of fuel left
1430 * spe = # of candles
1432 * Once the burn begins, the age will be set to the amount of fuel
1433 * remaining _once_the_burn_finishes_. If the burn is terminated
1434 * early then fuel is added back.
1436 * This use of age differs from the use of age for corpses and eggs.
1437 * For the latter items, age is when the object was created, so we
1438 * know when it becomes "bad".
1440 * This is a "silent" routine - it should not print anything out.
1443 begin_burn(obj, already_lit)
1445 boolean already_lit;
1449 boolean do_timer = TRUE;
1451 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1454 switch (obj->otyp) {
1462 radius = 1; /* very dim light */
1467 /* magic times are 150, 100, 50, 25, and 0 */
1468 if (obj->age > 150L)
1469 turns = obj->age - 150L;
1470 else if (obj->age > 100L)
1471 turns = obj->age - 100L;
1472 else if (obj->age > 50L)
1473 turns = obj->age - 50L;
1474 else if (obj->age > 25L)
1475 turns = obj->age - 25L;
1480 case CANDELABRUM_OF_INVOCATION:
1483 /* magic times are 75, 15, and 0 */
1485 turns = obj->age - 75L;
1486 else if (obj->age > 15L)
1487 turns = obj->age - 15L;
1490 radius = candle_light_range(obj);
1494 /* [ALI] Support artifact light sources */
1495 if (artifact_light(obj)) {
1498 radius = arti_light_radius(obj);
1500 impossible("begin burn: unexpected %s", xname(obj));
1507 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1510 if (carried(obj) && !already_lit)
1516 if (carried(obj) && !already_lit)
1520 if (obj->lamplit && !already_lit) {
1523 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1524 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1526 impossible("begin_burn: can't get obj position");
1531 * Stop a burn timeout on the given object if timer attached. Darken
1535 end_burn(obj, timer_attached)
1537 boolean timer_attached;
1539 if (!obj->lamplit) {
1540 impossible("end_burn: obj %s not lit", xname(obj));
1544 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1545 timer_attached = FALSE;
1547 if (!timer_attached) {
1548 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1549 del_light_source(LS_OBJECT, obj_to_any(obj));
1551 if (obj->where == OBJ_INVENT)
1553 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1554 impossible("end_burn: obj %s not timed!", xname(obj));
1558 * Cleanup a burning object if timer stopped.
1561 cleanup_burn(arg, expire_time)
1565 struct obj *obj = arg->a_obj;
1566 if (!obj->lamplit) {
1567 impossible("cleanup_burn: obj %s not lit", xname(obj));
1571 del_light_source(LS_OBJECT, obj_to_any(obj));
1573 /* restore unused time */
1574 obj->age += expire_time - monstermoves;
1578 if (obj->where == OBJ_INVENT)
1590 /* no lightning if not the air level or too often, even then */
1591 if (!Is_airlevel(&u.uz) || rn2(8))
1594 /* the number of strikes is 8-log2(nstrike) */
1595 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1600 } while (++count < 100 && levl[x][y].typ != CLOUD);
1605 if (dirx != 0 || diry != 0)
1606 buzz(-15, /* "monster" LIGHTNING spell */
1607 8, x, y, dirx, diry);
1611 if (levl[u.ux][u.uy].typ == CLOUD) {
1612 /* Inside a cloud during a thunder storm is deafening. */
1613 /* Even if already deaf, we sense the thunder's vibrations. */
1615 pline("Kaboom!!! Boom!! Boom!!");
1617 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");
1618 incr_itimeout(&HDeaf, rn1(20, 30));
1619 if (!u.uinvulnerable) {
1623 multi_reason = "hiding from thunderstorm";
1625 multi_reason = "
\97\8b\82Ì
\97\92\82ð
\94ð
\82¯
\82Ä
\82¢
\82é
\8e\9e\82É";
1630 You_hear("a rumbling noise.");
1632 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1635 /* -------------------------------------------------------------------------
1638 * Generic Timeout Functions.
1643 * boolean start_timer(long timeout,short kind,short func_index,
1645 * Start a timer of kind 'kind' that will expire at time
1646 * monstermoves+'timeout'. Call the function at 'func_index'
1647 * in the timeout table using argument 'arg'. Return TRUE if
1648 * a timer was started. This places the timer on a list ordered
1649 * "sooner" to "later". If an object, increment the object's
1652 * long stop_timer(short func_index, anything *arg)
1653 * Stop a timer specified by the (func_index, arg) pair. This
1654 * assumes that such a pair is unique. Return the time the
1655 * timer would have gone off. If no timer is found, return 0.
1656 * If an object, decrement the object's timer count.
1658 * long peek_timer(short func_index, anything *arg)
1659 * Return time specified timer will go off (0 if no such timer).
1661 * void run_timers(void)
1662 * Call timers that have timed out.
1665 * void save_timers(int fd, int mode, int range)
1666 * Save all timers of range 'range'. Range is either global
1667 * or local. Global timers follow game play, local timers
1668 * are saved with a level. Object and monster timers are
1669 * saved using their respective id's instead of pointers.
1671 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1672 * Restore timers of range 'range'. If from a ghost pile,
1673 * adjust the timeout by 'adjust'. The object and monster
1674 * ids are not restored until later.
1676 * void relink_timers(boolean ghostly)
1677 * Relink all object and monster timers that had been saved
1678 * using their object's or monster's id number.
1681 * void obj_move_timers(struct obj *src, struct obj *dest)
1682 * Reassign all timers from src to dest.
1684 * void obj_split_timers(struct obj *src, struct obj *dest)
1685 * Duplicate all timers assigned to src and attach them to dest.
1687 * void obj_stop_timers(struct obj *obj)
1688 * Stop all timers attached to obj.
1690 * boolean obj_has_timer(struct obj *object, short timer_type)
1691 * Check whether object has a timer of type timer_type.
1694 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1695 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1696 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1697 STATIC_DCL timer_element *FDECL(remove_timer,
1698 (timer_element **, SHORT_P, ANY_P *));
1699 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1700 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1701 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1702 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1704 /* ordered timer list */
1705 static timer_element *timer_base; /* "active" */
1706 static unsigned long timer_id = 1;
1708 /* If defined, then include names when printing out the timer queue */
1709 #define VERBOSE_TIMER
1712 timeout_proc f, cleanup;
1713 #ifdef VERBOSE_TIMER
1715 #define TTAB(a, b, c) \
1720 #define TTAB(a, b, c) \
1727 /* table of timeout functions */
1728 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1729 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
1730 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
1731 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
1732 TTAB(burn_object, cleanup_burn, "burn_object"),
1733 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
1734 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
1735 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
1739 STATIC_OVL const char *
1757 print_queue(win, base)
1759 timer_element *base;
1761 timer_element *curr;
1765 putstr(win, 0, "<empty>");
1767 putstr(win, 0, "timeout id kind call");
1768 for (curr = base; curr; curr = curr->next) {
1769 #ifdef VERBOSE_TIMER
1770 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
1771 curr->tid, kind_name(curr->kind),
1772 timeout_funcs[curr->func_index].name,
1773 fmt_ptr((genericptr_t) curr->arg.a_void));
1775 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
1776 curr->tid, kind_name(curr->kind), curr->func_index,
1777 fmt_ptr((genericptr_t) curr->arg.a_void));
1779 putstr(win, 0, buf);
1790 win = create_nhwindow(NHW_MENU); /* corner text window */
1794 Sprintf(buf, "Current time = %ld.", monstermoves);
1795 putstr(win, 0, buf);
1797 putstr(win, 0, "Active timeout queue:");
1799 print_queue(win, timer_base);
1801 display_nhwindow(win, FALSE);
1802 destroy_nhwindow(win);
1808 timer_sanity_check()
1810 timer_element *curr;
1812 /* this should be much more complete */
1813 for (curr = timer_base; curr; curr = curr->next)
1814 if (curr->kind == TIMER_OBJECT) {
1815 struct obj *obj = curr->arg.a_obj;
1816 if (obj->timed == 0) {
1817 pline("timer sanity: untimed obj %s, timer %ld",
1818 fmt_ptr((genericptr_t) obj), curr->tid);
1824 * Pick off timeout elements from the global queue and call their functions.
1825 * Do this until their time is less than or equal to the move count.
1830 timer_element *curr;
1833 * Always use the first element. Elements may be added or deleted at
1834 * any time. The list is ordered, we are done when the first element
1837 while (timer_base && timer_base->timeout <= monstermoves) {
1839 timer_base = curr->next;
1841 if (curr->kind == TIMER_OBJECT)
1842 (curr->arg.a_obj)->timed--;
1843 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
1844 free((genericptr_t) curr);
1849 * Start a timer. Return TRUE if successful.
1852 start_timer(when, kind, func_index, arg)
1860 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1861 panic("start_timer");
1863 gnu = (timer_element *) alloc(sizeof(timer_element));
1865 gnu->tid = timer_id++;
1866 gnu->timeout = monstermoves + when;
1868 gnu->needs_fixup = 0;
1869 gnu->func_index = func_index;
1873 if (kind == TIMER_OBJECT) /* increment object's timed count */
1874 (arg->a_obj)->timed++;
1876 /* should check for duplicates and fail if any */
1881 * Remove the timer from the current list and free it up. Return the time
1882 * remaining until it would have gone off, 0 if not found.
1885 stop_timer(func_index, arg)
1889 timer_element *doomed;
1892 doomed = remove_timer(&timer_base, func_index, arg);
1895 timeout = doomed->timeout;
1896 if (doomed->kind == TIMER_OBJECT)
1897 (arg->a_obj)->timed--;
1898 if (timeout_funcs[doomed->func_index].cleanup)
1899 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
1900 free((genericptr_t) doomed);
1901 return (timeout - monstermoves);
1907 * Find the timeout of specified timer; return 0 if none.
1910 peek_timer(type, arg)
1914 timer_element *curr;
1916 for (curr = timer_base; curr; curr = curr->next) {
1917 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
1918 return curr->timeout;
1924 * Move all object timers from src to dest, leaving src untimed.
1927 obj_move_timers(src, dest)
1928 struct obj *src, *dest;
1931 timer_element *curr;
1933 for (count = 0, curr = timer_base; curr; curr = curr->next)
1934 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1935 curr->arg.a_obj = dest;
1939 if (count != src->timed)
1940 panic("obj_move_timers");
1945 * Find all object timers and duplicate them for the new object "dest".
1948 obj_split_timers(src, dest)
1949 struct obj *src, *dest;
1951 timer_element *curr, *next_timer = 0;
1953 for (curr = timer_base; curr; curr = next_timer) {
1954 next_timer = curr->next; /* things may be inserted */
1955 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1956 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
1957 curr->func_index, obj_to_any(dest));
1963 * Stop all timers attached to this object. We can get away with this because
1964 * all object pointers are unique.
1967 obj_stop_timers(obj)
1970 timer_element *curr, *prev, *next_timer = 0;
1972 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1973 next_timer = curr->next;
1974 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
1976 prev->next = curr->next;
1978 timer_base = curr->next;
1979 if (timeout_funcs[curr->func_index].cleanup)
1980 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1982 free((genericptr_t) curr);
1991 * Check whether object has a timer of type timer_type.
1994 obj_has_timer(object, timer_type)
1998 long timeout = peek_timer(timer_type, obj_to_any(object));
2000 return (boolean) (timeout != 0L);
2004 * Stop all timers of index func_index at this spot.
2008 spot_stop_timers(x, y, func_index)
2012 timer_element *curr, *prev, *next_timer = 0;
2013 long where = (((long) x << 16) | ((long) y));
2015 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2016 next_timer = curr->next;
2017 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2018 && curr->arg.a_long == where) {
2020 prev->next = curr->next;
2022 timer_base = curr->next;
2023 if (timeout_funcs[curr->func_index].cleanup)
2024 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2026 free((genericptr_t) curr);
2034 * When is the spot timer of type func_index going to expire?
2035 * Returns 0L if no such timer.
2038 spot_time_expires(x, y, func_index)
2042 timer_element *curr;
2043 long where = (((long) x << 16) | ((long) y));
2045 for (curr = timer_base; curr; curr = curr->next) {
2046 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2047 && curr->arg.a_long == where)
2048 return curr->timeout;
2054 spot_time_left(x, y, func_index)
2058 long expires = spot_time_expires(x, y, func_index);
2059 return (expires > 0L) ? expires - monstermoves : 0L;
2062 /* Insert timer into the global queue */
2067 timer_element *curr, *prev;
2069 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2070 if (curr->timeout >= gnu->timeout)
2080 STATIC_OVL timer_element *
2081 remove_timer(base, func_index, arg)
2082 timer_element **base;
2086 timer_element *prev, *curr;
2088 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2089 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2094 prev->next = curr->next;
2103 write_timer(fd, timer)
2105 timer_element *timer;
2110 switch (timer->kind) {
2113 /* assume no pointers in arg */
2114 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2118 if (timer->needs_fixup)
2119 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2121 /* replace object pointer with id */
2122 arg_save.a_obj = timer->arg.a_obj;
2123 timer->arg = zeroany;
2124 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2125 timer->needs_fixup = 1;
2126 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2127 timer->arg.a_obj = arg_save.a_obj;
2128 timer->needs_fixup = 0;
2133 if (timer->needs_fixup)
2134 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2136 /* replace monster pointer with id */
2137 arg_save.a_monst = timer->arg.a_monst;
2138 timer->arg = zeroany;
2139 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2140 timer->needs_fixup = 1;
2141 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2142 timer->arg.a_monst = arg_save.a_monst;
2143 timer->needs_fixup = 0;
2148 panic("write_timer");
2154 * Return TRUE if the object will stay on the level when the level is
2161 switch (obj->where) {
2169 return obj_is_local(obj->ocontainer);
2171 return mon_is_local(obj->ocarry);
2173 panic("obj_is_local");
2178 * Return TRUE if the given monster will stay on the level when the
2187 for (curr = migrating_mons; curr; curr = curr->nmon)
2190 /* `mydogs' is used during level changes, never saved and restored */
2191 for (curr = mydogs; curr; curr = curr->nmon)
2198 * Return TRUE if the timer is attached to something that will stay on the
2199 * level when the level is saved.
2202 timer_is_local(timer)
2203 timer_element *timer;
2205 switch (timer->kind) {
2211 return obj_is_local(timer->arg.a_obj);
2213 return mon_is_local(timer->arg.a_monst);
2215 panic("timer_is_local");
2220 * Part of the save routine. Count up the number of timers that would
2221 * be written. If write_it is true, actually write the timer.
2224 maybe_write_timer(fd, range, write_it)
2229 timer_element *curr;
2231 for (curr = timer_base; curr; curr = curr->next) {
2232 if (range == RANGE_GLOBAL) {
2235 if (!timer_is_local(curr)) {
2238 write_timer(fd, curr);
2244 if (timer_is_local(curr)) {
2247 write_timer(fd, curr);
2256 * Save part of the timer list. The parameter 'range' specifies either
2257 * global or level timers to save. The timer ID is saved with the global
2261 * + timeouts that follow the hero (global)
2262 * + timeouts that follow obj & monst that are migrating
2265 * + timeouts that are level specific (e.g. storms)
2266 * + timeouts that stay with the level (obj & monst)
2269 save_timers(fd, mode, range)
2270 int fd, mode, range;
2272 timer_element *curr, *prev, *next_timer = 0;
2275 if (perform_bwrite(mode)) {
2276 if (range == RANGE_GLOBAL)
2277 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2279 count = maybe_write_timer(fd, range, FALSE);
2280 bwrite(fd, (genericptr_t) &count, sizeof count);
2281 (void) maybe_write_timer(fd, range, TRUE);
2284 if (release_data(mode)) {
2285 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2286 next_timer = curr->next; /* in case curr is removed */
2288 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2290 prev->next = curr->next;
2292 timer_base = curr->next;
2293 free((genericptr_t) curr);
2294 /* prev stays the same */
2303 * Pull in the structures from disk, but don't recalculate the object and
2307 restore_timers(fd, range, ghostly, adjust)
2309 boolean ghostly; /* restoring from a ghost level */
2310 long adjust; /* how much to adjust timeout */
2313 timer_element *curr;
2315 if (range == RANGE_GLOBAL)
2316 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2318 /* restore elements */
2319 mread(fd, (genericptr_t) &count, sizeof count);
2320 while (count-- > 0) {
2321 curr = (timer_element *) alloc(sizeof(timer_element));
2322 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2324 curr->timeout += adjust;
2329 /* reset all timers that are marked for reseting */
2331 relink_timers(ghostly)
2334 timer_element *curr;
2337 for (curr = timer_base; curr; curr = curr->next) {
2338 if (curr->needs_fixup) {
2339 if (curr->kind == TIMER_OBJECT) {
2341 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2342 panic("relink_timers 1");
2344 nid = curr->arg.a_uint;
2345 curr->arg.a_obj = find_oid(nid);
2346 if (!curr->arg.a_obj)
2347 panic("cant find o_id %d", nid);
2348 curr->needs_fixup = 0;
2349 } else if (curr->kind == TIMER_MONSTER) {
2350 panic("relink_timers: no monster timer implemented");
2352 panic("relink_timers 2");