OSDN Git Service

fix #36223
[jnethack/source.git] / src / timeout.c
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. */
4
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. */
9
10 #include "hack.h"
11 #include "lev.h" /* for checking save modes */
12
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));
21
22 /* He is being petrified - dialogue by inmet!tower */
23 static NEARDATA const char *const stoned_texts[] = {
24 #if 0 /*JP*/
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 */
30 #else
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 */
36 #endif
37 };
38
39 STATIC_OVL void
40 stoned_dialogue()
41 {
42     register long i = (Stoned & TIMEOUT);
43
44     if (i > 0L && i <= SIZE(stoned_texts)) {
45         char buf[BUFSZ];
46
47         Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
48         if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
49             (void) strsubst(buf, "limbs", "extremities");
50         pline1(buf);
51     }
52     switch ((int) i) {
53     case 5: /* slowing down */
54         HFast = 0L;
55         if (multi > 0)
56             nomul(0);
57         break;
58     case 4: /* limbs stiffening */
59         /* just one move left to save oneself so quit fiddling around;
60            don't stop attempt to eat tin--might be lizard or acidic */
61         if (!Popeye(STONED))
62             stop_occupation();
63         if (multi > 0)
64             nomul(0);
65         break;
66     case 3: /* limbs turned to stone */
67         stop_occupation();
68         nomul(-3); /* can't move anymore */
69         multi_reason = "getting stoned";
70         nomovemsg = You_can_move_again; /* not unconscious */
71         break;
72     default:
73         break;
74     }
75     exercise(A_DEX, FALSE);
76 }
77
78 /* He is getting sicker and sicker prior to vomiting */
79 static NEARDATA const char *const vomiting_texts[] = {
80 #if 0 /*JP*/
81     "are feeling mildly nauseated.", /* 14 */
82     "feel slightly confused.",       /* 11 */
83     "can't seem to think straight.", /* 8 */
84     "feel incredibly sick.",         /* 5 */
85     "suddenly vomit!"                /* 2 */
86 #else
87     "\82¿\82å\82Á\82Æ\93f\82«\8bC\82ª\82µ\82½\81D",        /* 14 */
88     "\8f­\82µ\8d¬\97\90\82µ\82½\81D",                /* 11 */
89     "\82Ü\82Æ\82à\82É\8ev\8dl\82Å\82«\82È\82­\82È\82Á\82½\81D",  /* 8 */
90     "\82Æ\82Ä\82à\8bC\95ª\82ª\88«\82­\82È\82Á\82½\81D",      /* 5 */
91     "\93Ë\91R\9aq\93f\82µ\82½\81I"                 /* 2 */
92 #endif
93 };
94
95 STATIC_OVL void
96 vomiting_dialogue()
97 {
98     const char *txt = 0;
99     long v = (Vomiting & TIMEOUT);
100
101     /* note: nhtimeout() hasn't decremented timed properties for the
102        current turn yet, so we use Vomiting-1 here */
103     switch ((int) (v - 1L)) {
104     case 14:
105         txt = vomiting_texts[0];
106         break;
107     case 11:
108         txt = vomiting_texts[1];
109         break;
110     case 6:
111         make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
112         if (!Popeye(VOMITING))
113             stop_occupation();
114     /*FALLTHRU*/
115     case 9:
116         make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
117         if (multi > 0)
118             nomul(0);
119         break;
120     case 8:
121         txt = vomiting_texts[2];
122         break;
123     case 5:
124         txt = vomiting_texts[3];
125         break;
126     case 2:
127         txt = vomiting_texts[4];
128         if (cantvomit(youmonst.data))
129             txt = "gag uncontrolably.";
130         break;
131     case 0:
132         stop_occupation();
133         if (!cantvomit(youmonst.data))
134             morehungry(20);
135         vomit();
136         break;
137     default:
138         break;
139     }
140     if (txt)
141         You1(txt);
142     exercise(A_CON, FALSE);
143 }
144
145 static NEARDATA const char *const choke_texts[] = {
146 #if 0 /*JP*/
147     "You find it hard to breathe.", "You're gasping for air.",
148     "You can no longer breathe.", "You're turning %s.", "You suffocate."
149 #else
150     "\82 \82È\82½\82Í\8cÄ\8bz\82ª\8d¢\93ï\82É\82È\82Á\82½\81D",
151     "\82 \82È\82½\82Í\8bê\82µ\82­\82Ä\82 \82¦\82¢\82¾\81D",
152     "\82 \82È\82½\82Í\82à\82¤\8cÄ\8bz\82ª\82Å\82«\82È\82¢\81D",
153     "\82 \82È\82½\82Í%s\82È\82Á\82½\81D",
154     "\82 \82È\82½\82Í\92\82\91§\82µ\82½\81D"
155 #endif
156 };
157
158 static NEARDATA const char *const choke_texts2[] = {
159 #if 0 /*JP*/
160     "Your %s is becoming constricted.",
161     "Your blood is having trouble reaching your brain.",
162     "The pressure on your %s increases.", "Your consciousness is fading.",
163     "You suffocate."
164 #else
165     "\82 \82È\82½\82Ì%s\82Í\8di\82ß\82Â\82¯\82ç\82ê\82½\81D",
166     "\8c\8c\89t\82Ì\82ß\82®\82è\82ª\88«\82­\82È\82Á\82½\81D",
167     "%s\82Ì\88³\97Í\82ª\8d\82\82­\82È\82Á\82½\81D",
168     "\88Ó\8e¯\82ª\89\93\82­\82È\82Á\82Ä\82«\82½\81D",
169     "\82 \82È\82½\82Í\92\82\91§\82µ\82½\81D"
170 #endif
171 };
172
173 STATIC_OVL void
174 choke_dialogue()
175 {
176     register long i = (Strangled & TIMEOUT);
177
178     if (i > 0 && i <= SIZE(choke_texts)) {
179         if (Breathless || !rn2(50))
180             pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
181         else {
182             const char *str = choke_texts[SIZE(choke_texts) - i];
183
184             if (index(str, '%'))
185 /*JP
186                 pline(str, hcolor(NH_BLUE));
187 */
188                 pline(str, jconj_adj(hcolor(NH_BLUE)));
189             else
190                 pline1(str);
191         }
192     }
193     exercise(A_STR, FALSE);
194 }
195
196 static NEARDATA const char *const slime_texts[] = {
197 #if 0 /*JP*/
198     "You are turning a little %s.",   /* 5 */
199     "Your limbs are getting oozy.",   /* 4 */
200     "Your skin begins to peel away.", /* 3 */
201     "You are turning into %s.",       /* 2 */
202     "You have become %s."             /* 1 */
203 #else
204     "\8f­\82µ%s\82È\82Á\82½\81D",                 /* 5 */
205     "\8eè\91«\82ª\97n\82¯\82Í\82\82ß\82½\81D",           /* 4 */
206     "\94§\82ª\82Ç\82ë\82Ç\82ë\82É\82È\82Á\82Ä\82«\82½\81D",     /* 3 */
207     "%s\82É\82È\82è\82Í\82\82ß\82½\81D",             /* 2 */
208     "%s\82É\82È\82Á\82Ä\82µ\82Ü\82Á\82½\81D",           /* 1 */
209 #endif
210 };
211
212 STATIC_OVL void
213 slime_dialogue()
214 {
215     register long i = (Slimed & TIMEOUT) / 2L;
216
217     if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
218         char buf[BUFSZ];
219
220         Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
221         if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
222             (void) strsubst(buf, "limbs", "extremities");
223
224         if (index(buf, '%')) {
225             if (i == 4L) {  /* "you are turning green" */
226                 if (!Blind) /* [what if you're already green?] */
227 /*JP
228                     pline(buf, hcolor(NH_GREEN));
229 */
230                     pline(buf, jconj_adj(hcolor(NH_GREEN)));
231             } else
232                 pline(buf,
233 /*JP
234                       an(Hallucination ? rndmonnam(NULL) : "green slime"));
235 */
236                       Hallucination ? rndmonnam(NULL) : "\97Î\83X\83\89\83C\83\80");
237         } else
238             pline1(buf);
239     }
240     if (i == 3L) {  /* limbs becoming oozy */
241         HFast = 0L; /* lose intrinsic speed */
242         if (!Popeye(SLIMED))
243             stop_occupation();
244         if (multi > 0)
245             nomul(0);
246     }
247     exercise(A_DEX, FALSE);
248 }
249
250 void
251 burn_away_slime()
252 {
253     if (Slimed) {
254 /*JP
255         make_slimed(0L, "The slime that covers you is burned away!");
256 */
257         pline("\82 \82È\82½\82ð\95¢\82Á\82Ä\82¢\82½\83X\83\89\83C\83\80\82Í\8fÄ\82¯\97\8e\82¿\82½\81I");
258     }
259 }
260
261 void
262 nh_timeout()
263 {
264     register struct prop *upp;
265     struct kinfo *kptr;
266     int sleeptime;
267     int m_idx;
268     int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
269
270     if (flags.friday13)
271         baseluck -= 1;
272
273     if (u.uluck != baseluck
274         && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
275         /* Cursed luckstones stop bad luck from timing out; blessed luckstones
276          * stop good luck from timing out; normal luckstones stop both;
277          * neither is stopped if you don't have a luckstone.
278          * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
279          */
280         register int time_luck = stone_luck(FALSE);
281         boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
282
283         if (u.uluck > baseluck && (nostone || time_luck < 0))
284             u.uluck--;
285         else if (u.uluck < baseluck && (nostone || time_luck > 0))
286             u.uluck++;
287     }
288     if (u.uinvulnerable)
289         return; /* things past this point could kill you */
290     if (Stoned)
291         stoned_dialogue();
292     if (Slimed)
293         slime_dialogue();
294     if (Vomiting)
295         vomiting_dialogue();
296     if (Strangled)
297         choke_dialogue();
298     if (u.mtimedone && !--u.mtimedone) {
299         if (Unchanging)
300             u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
301         else
302             rehumanize();
303     }
304     if (u.ucreamed)
305         u.ucreamed--;
306
307     /* Dissipate spell-based protection. */
308     if (u.usptime) {
309         if (--u.usptime == 0 && u.uspellprot) {
310             u.usptime = u.uspmtime;
311             u.uspellprot--;
312             find_ac();
313             if (!Blind)
314 #if 0 /*JP*/
315                 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
316                       u.uspellprot ? "becomes less dense" : "disappears");
317 #else
318                 Norep("\82 \82È\82½\82Ì\89ñ\82è\82Ì%s\96\82Í%s\81D", hcolor(NH_GOLDEN),
319                       u.uspellprot ? "\8fÁ\82¦\82Í\82\82ß\82½" : "\8fÁ\82¦\82½");
320 #endif
321         }
322     }
323
324     if (u.ugallop) {
325         if (--u.ugallop == 0L && u.usteed)
326 /*JP
327             pline("%s stops galloping.", Monnam(u.usteed));
328 */
329             pline("%s\82Í\91¬\8bì\82¯\82ð\82â\82ß\82½\81D", Monnam(u.usteed));
330     }
331
332     for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
333         if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
334             kptr = find_delayed_killer((int) (upp - u.uprops));
335             switch (upp - u.uprops) {
336             case STONED:
337                 if (kptr && kptr->name[0]) {
338                     killer.format = kptr->format;
339 #if 0 /*JP*/
340                     Strcpy(killer.name, kptr->name);
341 #else
342                     Sprintf(killer.name, "%s\82Ì\8dU\8c\82\82Å", kptr->name);
343 #endif
344                 } else {
345 #if 0 /*JP*/
346                     killer.format = NO_KILLER_PREFIX;
347                     Strcpy(killer.name, "killed by petrification");
348 #else
349                     killer.format = KILLED_BY;
350                     Strcpy(killer.name, "\90Î\89»\8dU\8c\82\82Å");
351 #endif
352                 }
353                 dealloc_killer(kptr);
354                 /* (unlike sliming, you aren't changing form here) */
355                 done(STONING);
356                 break;
357             case SLIMED:
358                 if (kptr && kptr->name[0]) {
359                     killer.format = kptr->format;
360                     Strcpy(killer.name, kptr->name);
361                 } else {
362                     killer.format = NO_KILLER_PREFIX;
363 /*JP
364                     Strcpy(killer.name, "turned into green slime");
365 */
366                     Strcpy(killer.name, "\97Î\83X\83\89\83C\83\80\82É\82È\82Á\82½");
367                 }
368                 dealloc_killer(kptr);
369                 /* involuntarily break "never changed form" conduct */
370                 u.uconduct.polyselfs++;
371                 done(TURNED_SLIME);
372                 break;
373             case VOMITING:
374                 make_vomiting(0L, TRUE);
375                 break;
376             case SICK:
377 /*JP
378                 You("die from your illness.");
379 */
380                 You("\95a\8bC\82Å\8e\80\82ñ\82¾\81D");
381                 if (kptr && kptr->name[0]) {
382                     killer.format = kptr->format;
383                     Strcpy(killer.name, kptr->name);
384                 } else {
385                     killer.format = KILLED_BY_AN;
386                     killer.name[0] = 0; /* take the default */
387                 }
388                 dealloc_killer(kptr);
389
390                 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
391                     if (type_is_pname(&mons[m_idx])) {
392                         killer.format = KILLED_BY;
393                     } else if (mons[m_idx].geno & G_UNIQ) {
394                         Strcpy(killer.name, the(killer.name));
395                         killer.format = KILLED_BY;
396                     }
397                 }
398                 u.usick_type = 0;
399                 done(POISONING);
400                 break;
401             case FAST:
402                 if (!Very_fast)
403 #if 0 /*JP*/
404                     You_feel("yourself slowing down%s.",
405                              Fast ? " a bit" : "");
406 #else
407                     You("%s\92x\82­\82È\82Á\82½\82æ\82¤\82È\8bC\82ª\82µ\82½\81D",
408                         Fast ? "\82¿\82å\82Á\82Æ" : "");
409 #endif
410                 break;
411             case CONFUSION:
412                 /* So make_confused works properly */
413                 set_itimeout(&HConfusion, 1L);
414                 make_confused(0L, TRUE);
415                 if (!Confusion)
416                     stop_occupation();
417                 break;
418             case STUNNED:
419                 set_itimeout(&HStun, 1L);
420                 make_stunned(0L, TRUE);
421                 if (!Stunned)
422                     stop_occupation();
423                 break;
424             case BLINDED:
425                 set_itimeout(&Blinded, 1L);
426                 make_blinded(0L, TRUE);
427                 if (!Blind)
428                     stop_occupation();
429                 break;
430             case DEAF:
431                 set_itimeout(&HDeaf, 1L);
432                 make_deaf(0L, TRUE);
433                 if (!Deaf)
434                     stop_occupation();
435                 break;
436             case INVIS:
437                 newsym(u.ux, u.uy);
438                 if (!Invis && !BInvis && !Blind) {
439 #if 0 /*JP*/
440                     You(!See_invisible
441                             ? "are no longer invisible."
442                             : "can no longer see through yourself.");
443 #else
444                     You(!See_invisible
445                         ? "\82à\82¤\93§\96¾\82Å\82Í\82È\82¢\81D"
446                         : "\93§\82«\82Æ\82¨\82Á\82Ä\82¢\82È\82¢\81D");
447 #endif
448                     stop_occupation();
449                 }
450                 break;
451             case SEE_INVIS:
452                 set_mimic_blocking(); /* do special mimic handling */
453                 see_monsters();       /* make invis mons appear */
454                 newsym(u.ux, u.uy);   /* make self appear */
455                 stop_occupation();
456                 break;
457             case WOUNDED_LEGS:
458                 heal_legs();
459                 stop_occupation();
460                 break;
461 #ifdef JPEXTENSION
462                 case TOTTER:
463                         Totter = 0;
464                         make_totter(0L, TRUE);
465                         stop_occupation();
466                         break;
467 #endif
468             case HALLUC:
469                 set_itimeout(&HHallucination, 1L);
470                 (void) make_hallucinated(0L, TRUE, 0L);
471                 if (!Hallucination)
472                     stop_occupation();
473                 break;
474             case SLEEPY:
475                 if (unconscious() || Sleep_resistance) {
476                     incr_itimeout(&HSleepy, rnd(100));
477                 } else if (Sleepy) {
478 /*JP
479                     You("fall asleep.");
480 */
481                     You("\96°\82è\82É\97\8e\82¿\82½\81D");
482                     sleeptime = rnd(20);
483                     fall_asleep(-sleeptime, TRUE);
484                     incr_itimeout(&HSleepy, sleeptime + rnd(100));
485                 }
486                 break;
487             case LEVITATION:
488                 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
489                 break;
490             case STRANGLED:
491                 killer.format = KILLED_BY;
492 #if 0 /*JP*/
493                 Strcpy(killer.name,
494                        (u.uburied) ? "suffocation" : "strangulation");
495 #else
496                 Strcpy(killer.name,
497                        (u.uburied) ? "\92\82\91§\82µ\82Ä" : "\8eñ\82ð\8di\82ß\82ç\82ê\82Ä");
498 #endif
499                 done(DIED);
500                 /* must be declining to die in explore|wizard mode;
501                    treat like being cured of strangulation by prayer */
502                 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
503                     Your("amulet vanishes!");
504                     useup(uamul);
505                 }
506                 break;
507             case FUMBLING:
508                 /* call this only when a move took place.  */
509                 /* otherwise handle fumbling msgs locally. */
510                 if (u.umoved && !Levitation) {
511                     slip_or_trip();
512                     nomul(-2);
513                     multi_reason = "fumbling";
514                     nomovemsg = "";
515                     /* The more you are carrying the more likely you
516                      * are to make noise when you fumble.  Adjustments
517                      * to this number must be thoroughly play tested.
518                      */
519                     if ((inv_weight() > -500)) {
520 /*JP
521                         You("make a lot of noise!");
522 */
523                         You("\91å\82«\82È\89¹\82ð\82½\82Ä\82½\81I");
524                         wake_nearby();
525                     }
526                 }
527                 /* from outside means slippery ice; don't reset
528                    counter if that's the only fumble reason */
529                 HFumbling &= ~FROMOUTSIDE;
530                 if (Fumbling)
531                     incr_itimeout(&HFumbling, rnd(20));
532                 break;
533             case DETECT_MONSTERS:
534                 see_monsters();
535                 break;
536             }
537         }
538
539     run_timers();
540 }
541
542 void
543 fall_asleep(how_long, wakeup_msg)
544 int how_long;
545 boolean wakeup_msg;
546 {
547     stop_occupation();
548     nomul(how_long);
549     multi_reason = "sleeping";
550     /* generally don't notice sounds while sleeping */
551     if (wakeup_msg && multi == how_long) {
552         /* caller can follow with a direct call to Hear_again() if
553            there's a need to override this when wakeup_msg is true */
554         incr_itimeout(&HDeaf, how_long);
555         afternmv = Hear_again; /* this won't give any messages */
556     }
557     /* early wakeup from combat won't be possible until next monster turn */
558     u.usleep = monstermoves;
559 /*JP
560     nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
561 */
562     nomovemsg = wakeup_msg ? "\96Ú\82ð\8ao\82Ü\82µ\82½\81D" : You_can_move_again;
563 }
564
565 /* Attach an egg hatch timeout to the given egg.
566  *      when = Time to hatch, usually only passed if re-creating an
567  *             existing hatch timer. Pass 0L for random hatch time.
568  */
569 void
570 attach_egg_hatch_timeout(egg, when)
571 struct obj *egg;
572 long when;
573 {
574     int i;
575
576     /* stop previous timer, if any */
577     (void) stop_timer(HATCH_EGG, obj_to_any(egg));
578
579     /*
580      * Decide if and when to hatch the egg.  The old hatch_it() code tried
581      * once a turn from age 151 to 200 (inclusive), hatching if it rolled
582      * a number x, 1<=x<=age, where x>150.  This yields a chance of
583      * hatching > 99.9993%.  Mimic that here.
584      */
585     if (!when) {
586         for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
587             if (rnd(i) > 150) {
588                 /* egg will hatch */
589                 when = (long) i;
590                 break;
591             }
592     }
593     if (when) {
594         (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
595     }
596 }
597
598 /* prevent an egg from ever hatching */
599 void
600 kill_egg(egg)
601 struct obj *egg;
602 {
603     /* stop previous timer, if any */
604     (void) stop_timer(HATCH_EGG, obj_to_any(egg));
605 }
606
607 /* timer callback routine: hatch the given egg */
608 void
609 hatch_egg(arg, timeout)
610 anything *arg;
611 long timeout;
612 {
613     struct obj *egg;
614     struct monst *mon, *mon2;
615     coord cc;
616     xchar x, y;
617     boolean yours, silent, knows_egg = FALSE;
618     boolean cansee_hatchspot = FALSE;
619     int i, mnum, hatchcount = 0;
620
621     egg = arg->a_obj;
622     /* sterilized while waiting */
623     if (egg->corpsenm == NON_PM)
624         return;
625
626     mon = mon2 = (struct monst *) 0;
627     mnum = big_to_little(egg->corpsenm);
628     /* The identity of one's father is learned, not innate */
629     yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
630     silent = (timeout != monstermoves); /* hatched while away */
631
632     /* only can hatch when in INVENT, FLOOR, MINVENT */
633     if (get_obj_location(egg, &x, &y, 0)) {
634         hatchcount = rnd((int) egg->quan);
635         cansee_hatchspot = cansee(x, y) && !silent;
636         if (!(mons[mnum].geno & G_UNIQ)
637             && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
638             for (i = hatchcount; i > 0; i--) {
639                 if (!enexto(&cc, x, y, &mons[mnum])
640                     || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
641                     break;
642                 /* tame if your own egg hatches while you're on the
643                    same dungeon level, or any dragon egg which hatches
644                    while it's in your inventory */
645                 if ((yours && !silent)
646                     || (carried(egg) && mon->data->mlet == S_DRAGON)) {
647                     if (tamedog(mon, (struct obj *) 0)) {
648                         if (carried(egg) && mon->data->mlet != S_DRAGON)
649                             mon->mtame = 20;
650                     }
651                 }
652                 if (mvitals[mnum].mvflags & G_EXTINCT)
653                     break;  /* just made last one */
654                 mon2 = mon; /* in case makemon() fails on 2nd egg */
655             }
656             if (!mon)
657                 mon = mon2;
658             hatchcount -= i;
659             egg->quan -= (long) hatchcount;
660         }
661 #if 0
662     /*
663      * We could possibly hatch while migrating, but the code isn't
664      * set up for it...
665      */
666     } else if (obj->where == OBJ_MIGRATING) {
667         /*
668          * We can do several things.  The first ones that come to
669          * mind are:
670          * + Create the hatched monster then place it on the migrating
671          *   mons list.  This is tough because all makemon() is made
672          *   to place the monster as well.  Makemon() also doesn't lend
673          *   itself well to splitting off a "not yet placed" subroutine.
674          * + Mark the egg as hatched, then place the monster when we
675          *   place the migrating objects.
676          * + Or just kill any egg which gets sent to another level.
677          *   Falling is the usual reason such transportation occurs.
678          */
679         cansee_hatchspot = FALSE;
680         mon = ???;
681 #endif
682     }
683
684     if (mon) {
685         char monnambuf[BUFSZ], carriedby[BUFSZ];
686         boolean siblings = (hatchcount > 1), redraw = FALSE;
687
688         if (cansee_hatchspot) {
689 #if 0 /*JP*/
690             Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
691                     siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
692 #else
693             Sprintf(monnambuf, "%s%s", siblings ? "\82¢\82­\82Â\82©\82Ì" : "",
694                     a_monnam(mon));
695 #endif
696             /* we don't learn the egg type here because learning
697                an egg type requires either seeing the egg hatch
698                or being familiar with the egg already,
699                as well as being able to see the resulting
700                monster, checked below
701             */
702         }
703         switch (egg->where) {
704         case OBJ_INVENT:
705             knows_egg = TRUE; /* true even if you are blind */
706             if (!cansee_hatchspot)
707 #if 0 /*JP*/
708                 You_feel("%s %s from your pack!", something,
709                          locomotion(mon->data, "drop"));
710 #else
711                 pline("\89½\82©\82ª\82 \82È\82½\82Ì\94w\95\89\82¢\91Ü\82©\82ç%s\82æ\82¤\82È\8bC\82ª\82µ\82½\81D",
712                       jpast(locomotion(mon->data, "\97\8e\82¿\82é")));
713 #endif
714             else
715 #if 0 /*JP*/
716                 You_see("%s %s out of your pack!", monnambuf,
717                         locomotion(mon->data, "drop"));
718 #else
719                 You("%s\82ª\82 \82È\82½\82Ì\94w\95\89\82¢\91Ü\82©\82ç%s\82Ì\82ð\8c©\82½\81D", monnambuf,
720                     jpast(locomotion(mon->data, "\97\8e\82¿\82é")));
721 #endif
722             if (yours) {
723 #if 0 /*JP*/
724                 pline("%s cries sound like \"%s%s\"",
725                       siblings ? "Their" : "Its",
726                       flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
727 #else
728                 pline("\82»\82ê\82Í\81w%s%s\81x\82Æ\96Â\82¢\82Ä\82¢\82é\82æ\82¤\82¾\81D",
729                       flags.female ? "\83}\83}" : "\83p\83p", egg->spe ? "" : "\81H");
730 #endif
731             } else if (mon->data->mlet == S_DRAGON && !Deaf) {
732 #if 0 /*JP*/
733                 verbalize("Gleep!"); /* Mything eggs :-) */
734 #else
735                 verbalize("\83u\83H\81[\81I");          /* Mything eggs :-) */
736 #endif
737             }
738             break;
739
740         case OBJ_FLOOR:
741             if (cansee_hatchspot) {
742                 knows_egg = TRUE;
743 /*JP
744                 You_see("%s hatch.", monnambuf);
745 */
746                 You("%s\82ª\97\91\82©\82ç\82©\82¦\82é\82Ì\82ð\8c©\82½\81D", monnambuf);
747                 redraw = TRUE; /* update egg's map location */
748             }
749             break;
750
751         case OBJ_MINVENT:
752             if (cansee_hatchspot) {
753                 /* egg carrying monster might be invisible */
754                 if (canseemon(egg->ocarry)) {
755 /*JP
756                     Sprintf(carriedby, "%s pack",
757 */
758                     Sprintf(carriedby, "%s\82Ì\94w\95\89\82¢\91Ü\82©\82ç",
759                             s_suffix(a_monnam(egg->ocarry)));
760                     knows_egg = TRUE;
761                 } else if (is_pool(mon->mx, mon->my))
762 /*JP
763                     Strcpy(carriedby, "empty water");
764 */
765                     Strcpy(carriedby, "\89½\82à\82È\82¢\90\85\92\86\82©\82ç");
766                 else
767 /*JP
768                     Strcpy(carriedby, "thin air");
769 */
770                     Strcpy(carriedby, "\89½\82à\82È\82¢\8bó\8aÔ\82©\82ç");
771 #if 0 /*JP*/
772                 You_see("%s %s out of %s!", monnambuf,
773                         locomotion(mon->data, "drop"), carriedby);
774 #else
775                 You("%s\82ª%s%s\82Ì\82ð\8c©\82½\81D", monnambuf, carriedby, 
776                     locomotion(mon->data, "\97\8e\82¿\82é"));
777 #endif
778             }
779             break;
780 #if 0
781         case OBJ_MIGRATING:
782             break;
783 #endif
784         default:
785             impossible("egg hatched where? (%d)", (int) egg->where);
786             break;
787         }
788
789         if (cansee_hatchspot && knows_egg)
790             learn_egg_type(mnum);
791
792         if (egg->quan > 0) {
793             /* still some eggs left */
794             /* Instead of ordinary egg timeout use a short one */
795             attach_egg_hatch_timeout(egg, (long) rnd(12));
796         } else if (carried(egg)) {
797             useup(egg);
798         } else {
799             /* free egg here because we use it above */
800             obj_extract_self(egg);
801             obfree(egg, (struct obj *) 0);
802         }
803         if (redraw)
804             newsym(x, y);
805     }
806 }
807
808 /* Learn to recognize eggs of the given type. */
809 void
810 learn_egg_type(mnum)
811 int mnum;
812 {
813     /* baby monsters hatch from grown-up eggs */
814     mnum = little_to_big(mnum);
815     mvitals[mnum].mvflags |= MV_KNOWS_EGG;
816     /* we might have just learned about other eggs being carried */
817     update_inventory();
818 }
819
820 /* Attach a fig_transform timeout to the given figurine. */
821 void
822 attach_fig_transform_timeout(figurine)
823 struct obj *figurine;
824 {
825     int i;
826
827     /* stop previous timer, if any */
828     (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
829
830     /*
831      * Decide when to transform the figurine.
832      */
833     i = rnd(9000) + 200;
834     /* figurine will transform */
835     (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
836                        obj_to_any(figurine));
837 }
838
839 /* give a fumble message */
840 STATIC_OVL void
841 slip_or_trip()
842 {
843     struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
844     const char *what;
845     char buf[BUFSZ];
846     boolean on_foot = TRUE;
847     if (u.usteed)
848         on_foot = FALSE;
849
850     if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
851         otmp = 0;
852
853     if (otmp && on_foot) { /* trip over something in particular */
854         /*
855           If there is only one item, it will have just been named
856           during the move, so refer to by via pronoun; otherwise,
857           if the top item has been or can be seen, refer to it by
858           name; if not, look for rocks to trip over; trip over
859           anonymous "something" if there aren't any rocks.
860         */
861 #if 0 /*JP*/
862         what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
863                 ? ((otmp->quan == 1L) ? "it"
864                       : Hallucination ? "they" : "them")
865                 : (otmp->dknown || !Blind)
866                       ? doname(otmp)
867                       : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
868                              ? something
869                              : (otmp2->quan == 1L ? "a rock" : "some rocks"));
870 #else
871         what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
872                 ? "\82»\82ê"
873                 : (otmp->dknown || !Blind)
874                       ? doname(otmp)
875                       : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
876                              ? something
877                              : "\90Î");
878 #endif
879         if (Hallucination) {
880             what = strcpy(buf, what);
881             buf[0] = highc(buf[0]);
882 #if 0 /*JP*/
883             pline("Egads!  %s bite%s your %s!", what,
884                   (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
885 #else
886             pline("\82®\82í\82\9f\81I%s\82ª%s\82É\8a\9a\82Ý\82Â\82¢\82½\81I", what, body_part(FOOT));
887 #endif
888         } else {
889 /*JP
890             You("trip over %s.", what);
891 */
892             You("%s\82É\82Â\82Ü\82Ã\82¢\82½\81D", what);
893         }
894         if (!uarmf && otmp->otyp == CORPSE
895             && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
896             Sprintf(killer.name, "tripping over %s corpse",
897                     an(mons[otmp->corpsenm].mname));
898             instapetrify(killer.name);
899         }
900     } else if (rn2(3) && is_ice(u.ux, u.uy)) {
901 #if 0 /*JP*/
902         pline("%s %s%s on the ice.",
903               u.usteed ? upstart(x_monnam(u.usteed,
904                                           (has_mname(u.usteed)) ? ARTICLE_NONE
905                                                                 : ARTICLE_THE,
906                                           (char *) 0, SUPPRESS_SADDLE, FALSE))
907                        : "You",
908               rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
909 #else
910         pline("%s\82Í\95X\82Ì\8fã\82Å\8a\8a\82Á\82½\81D",
911               u.usteed ? upstart(x_monnam(u.usteed,
912                                           (has_mname(u.usteed)) ? ARTICLE_NONE
913                                                                 : ARTICLE_THE,
914                                           (char *) 0, SUPPRESS_SADDLE, FALSE))
915                        : "\82 \82È\82½");
916 #endif
917     } else {
918         if (on_foot) {
919             switch (rn2(4)) {
920             case 1:
921 #if 0 /*JP*/
922                 You("trip over your own %s.",
923                     Hallucination ? "elbow" : makeplural(body_part(FOOT)));
924 #else
925                 You("\8e©\95ª\82Ì%s\82ð\93¥\82ñ\82Å\82Â\82Ü\82Ã\82¢\82½\81D",
926                     Hallucination ? "\95I" : body_part(FOOT));
927 #endif
928                 break;
929             case 2:
930 #if 0 /*JP*/
931                 You("slip %s.",
932                     Hallucination ? "on a banana peel" : "and nearly fall");
933 #else
934                 You("%s\81D", Hallucination ?
935                     "\83o\83i\83i\82Ì\94ç\82Å\8a\8a\82Á\82½" : "\8a\8a\82Á\82Ä\93]\82Ñ\82»\82¤\82É\82È\82Á\82½");
936 #endif
937                 break;
938             case 3:
939 /*JP
940                 You("flounder.");
941 */
942                 You("\82\82½\82Î\82½\82µ\82½\81D");
943                 break;
944             default:
945 /*JP
946                 You("stumble.");
947 */
948                 You("\82æ\82ë\82ß\82¢\82½\81D");
949                 break;
950             }
951         } else {
952             switch (rn2(4)) {
953             case 1:
954 #if 0 /*JP*/
955                 Your("%s slip out of the stirrups.",
956                      makeplural(body_part(FOOT)));
957 #else
958                 You("\82 \82Ô\82Ý\82ð\93¥\82Ý\8aO\82µ\82Ä\82µ\82Ü\82Á\82½\81D");
959 #endif
960                 break;
961             case 2:
962 /*JP
963                 You("let go of the reins.");
964 */
965                 You("\8eè\8dj\82ð\95ú\82µ\82Ä\82µ\82Ü\82Á\82½\81D");
966                 break;
967             case 3:
968 /*JP
969                 You("bang into the saddle-horn.");
970 */
971                 You("\83T\83h\83\8b\83z\81[\83\93\82É\82Ô\82Â\82©\82Á\82Ä\82µ\82Ü\82Á\82½\81D");
972                 break;
973             default:
974 /*JP
975                 You("slide to one side of the saddle.");
976 */
977                 You("\82·\82×\82Á\82Ä\88Æ\82Ì\95Ð\91¤\82É\82¸\82ê\82Ä\82µ\82Ü\82Á\82½\81D");
978                 break;
979             }
980             dismount_steed(DISMOUNT_FELL);
981         }
982     }
983 }
984
985 /* Print a lamp flicker message with tailer. */
986 STATIC_OVL void
987 see_lamp_flicker(obj, tailer)
988 struct obj *obj;
989 const char *tailer;
990 {
991     switch (obj->where) {
992     case OBJ_INVENT:
993     case OBJ_MINVENT:
994 /*JP
995         pline("%s flickers%s.", Yname2(obj), tailer);
996 */
997         pline("%s\82Í%s\93_\96Å\82µ\82½\81D", Yname2(obj), tailer);
998         break;
999     case OBJ_FLOOR:
1000 /*JP
1001         You_see("%s flicker%s.", an(xname(obj)), tailer);
1002 */
1003         You("%s\82ª%s\93_\96Å\82·\82é\82Ì\82ð\8c©\82½\81D", an(xname(obj)), tailer);
1004         break;
1005     }
1006 }
1007
1008 /* Print a dimming message for brass lanterns. */
1009 STATIC_OVL void
1010 lantern_message(obj)
1011 struct obj *obj;
1012 {
1013     /* from adventure */
1014     switch (obj->where) {
1015     case OBJ_INVENT:
1016 /*JP
1017         Your("lantern is getting dim.");
1018 */
1019         Your("\83\89\83\93\83^\83\93\82Í\88Ã\82­\82È\82Á\82Ä\82«\82½\81D");
1020         if (Hallucination)
1021 /*JP
1022             pline("Batteries have not been invented yet.");
1023 */
1024             pline("\93d\92r\82Í\82Ü\82¾\94­\96¾\82³\82ê\82Ä\82È\82¢\82ñ\82¾\82Á\82¯\81D");
1025         break;
1026     case OBJ_FLOOR:
1027 /*JP
1028         You_see("a lantern getting dim.");
1029 */
1030         pline("\83\89\83\93\83^\83\93\82ª\88Ã\82­\82È\82Á\82Ä\82«\82½\82Ì\82ª\8c©\82¦\82½\81D");
1031         break;
1032     case OBJ_MINVENT:
1033 /*JP
1034         pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1035 */
1036         pline("%s\82Ì\83\89\83\93\83^\83\93\82Í\88Ã\82­\82È\82Á\82Ä\82«\82½\81D", Monnam(obj->ocarry));
1037         break;
1038     }
1039 }
1040
1041 /*
1042  * Timeout callback for for objects that are burning. E.g. lamps, candles.
1043  * See begin_burn() for meanings of obj->age and obj->spe.
1044  */
1045 void
1046 burn_object(arg, timeout)
1047 anything *arg;
1048 long timeout;
1049 {
1050     struct obj *obj = arg->a_obj;
1051     boolean canseeit, many, menorah, need_newsym;
1052     xchar x, y;
1053     char whose[BUFSZ];
1054
1055     menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1056     many = menorah ? obj->spe > 1 : obj->quan > 1L;
1057
1058     /* timeout while away */
1059     if (timeout != monstermoves) {
1060         long how_long = monstermoves - timeout;
1061
1062         if (how_long >= obj->age) {
1063             obj->age = 0;
1064             end_burn(obj, FALSE);
1065
1066             if (menorah) {
1067                 obj->spe = 0; /* no more candles */
1068             } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1069                 /* get rid of candles and burning oil potions;
1070                    we know this object isn't carried by hero,
1071                    nor is it migrating */
1072                 obj_extract_self(obj);
1073                 obfree(obj, (struct obj *) 0);
1074                 obj = (struct obj *) 0;
1075             }
1076
1077         } else {
1078             obj->age -= how_long;
1079             begin_burn(obj, TRUE);
1080         }
1081         return;
1082     }
1083
1084     /* only interested in INVENT, FLOOR, and MINVENT */
1085     if (get_obj_location(obj, &x, &y, 0)) {
1086         canseeit = !Blind && cansee(x, y);
1087         /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1088         (void) Shk_Your(whose, obj);
1089     } else {
1090         canseeit = FALSE;
1091     }
1092     need_newsym = FALSE;
1093
1094     /* obj->age is the age remaining at this point.  */
1095     switch (obj->otyp) {
1096     case POT_OIL:
1097         /* this should only be called when we run out */
1098         if (canseeit) {
1099             switch (obj->where) {
1100             case OBJ_INVENT:
1101             case OBJ_MINVENT:
1102 /*JP
1103                 pline("%spotion of oil has burnt away.", whose);
1104 */
1105                 pline("%s\83I\83C\83\8b\82Í\94R\82¦\82Â\82«\82½\81D", whose);
1106                 break;
1107             case OBJ_FLOOR:
1108 /*JP
1109                 You_see("a burning potion of oil go out.");
1110 */
1111                 You("\83I\83C\83\8b\82Ì\89Î\82ª\8fÁ\82¦\82½\82Ì\82ð\8c©\82½\81D");
1112                 need_newsym = TRUE;
1113                 break;
1114             }
1115         }
1116         end_burn(obj, FALSE); /* turn off light source */
1117         if (carried(obj)) {
1118             useupall(obj);
1119         } else {
1120             /* clear migrating obj's destination code before obfree
1121                to avoid false complaint of deleting worn item */
1122             if (obj->where == OBJ_MIGRATING)
1123                 obj->owornmask = 0L;
1124             obj_extract_self(obj);
1125             obfree(obj, (struct obj *) 0);
1126         }
1127         obj = (struct obj *) 0;
1128         break;
1129
1130     case BRASS_LANTERN:
1131     case OIL_LAMP:
1132         switch ((int) obj->age) {
1133         case 150:
1134         case 100:
1135         case 50:
1136             if (canseeit) {
1137                 if (obj->otyp == BRASS_LANTERN)
1138                     lantern_message(obj);
1139                 else
1140                     see_lamp_flicker(obj,
1141 /*JP
1142                                      obj->age == 50L ? " considerably" : "");
1143 */
1144                                      obj->age == 50L ? "\8c\83\82µ\82­" : "");
1145             }
1146             break;
1147
1148         case 25:
1149             if (canseeit) {
1150                 if (obj->otyp == BRASS_LANTERN)
1151                     lantern_message(obj);
1152                 else {
1153                     switch (obj->where) {
1154                     case OBJ_INVENT:
1155                     case OBJ_MINVENT:
1156 /*JP
1157                         pline("%s seems about to go out.", Yname2(obj));
1158 */
1159                         pline("%s\82Í\8d¡\82É\82à\8fÁ\82¦\82»\82¤\82¾\81D", Yname2(obj));
1160                         break;
1161                     case OBJ_FLOOR:
1162 /*JP
1163                         You_see("%s about to go out.", an(xname(obj)));
1164 */
1165                         pline("%s\82ª\8fÁ\82¦\82©\82¯\82Ä\82¢\82é\82Ì\82ª\8c©\82¦\82½\81D", an(xname(obj)));
1166                         break;
1167                     }
1168                 }
1169             }
1170             break;
1171
1172         case 0:
1173             /* even if blind you'll know if holding it */
1174             if (canseeit || obj->where == OBJ_INVENT) {
1175                 switch (obj->where) {
1176                 case OBJ_INVENT:
1177                 case OBJ_MINVENT:
1178                     if (obj->otyp == BRASS_LANTERN)
1179 /*JP
1180                         pline("%slantern has run out of power.", whose);
1181 */
1182                         pline("%s\83\89\83\93\83^\83\93\82Ì\97Í\82ð\8eg\82¢\90Ø\82Á\82½\81D", whose);
1183                     else
1184 /*JP
1185                         pline("%s has gone out.", Yname2(obj));
1186 */
1187                         pline("%s\82Í\8fÁ\82¦\82½\81D", Yname2(obj));
1188                     break;
1189                 case OBJ_FLOOR:
1190                     if (obj->otyp == BRASS_LANTERN)
1191 /*JP
1192                         You_see("a lantern run out of power.");
1193 */
1194                         You("\83\89\83\93\83^\83\93\82ª\8fÁ\82¦\82é\82Ì\82ð\8c©\82½\81D");
1195                     else
1196 /*JP
1197                         You_see("%s go out.", an(xname(obj)));
1198 */
1199                         You("%s\82ª\8fÁ\82¦\82é\82Ì\82ð\8c©\82½\81D", an(xname(obj)));
1200                     break;
1201                 }
1202             }
1203             end_burn(obj, FALSE);
1204             break;
1205
1206         default:
1207             /*
1208              * Someone added fuel to the lamp while it was
1209              * lit.  Just fall through and let begin burn
1210              * handle the new age.
1211              */
1212             break;
1213         }
1214
1215         if (obj->age)
1216             begin_burn(obj, TRUE);
1217
1218         break;
1219
1220     case CANDELABRUM_OF_INVOCATION:
1221     case TALLOW_CANDLE:
1222     case WAX_CANDLE:
1223         switch (obj->age) {
1224         case 75:
1225             if (canseeit)
1226                 switch (obj->where) {
1227                 case OBJ_INVENT:
1228                 case OBJ_MINVENT:
1229 #if 0 /*JP*/
1230                     pline("%s%scandle%s getting short.", whose,
1231                           menorah ? "candelabrum's " : "",
1232                           many ? "s are" : " is");
1233 #else
1234                     pline("%s%s\82ë\82¤\82»\82­\82Í\92Z\82­\82È\82Á\82½\81D", whose,
1235                           menorah ? "\90C\91ä\82Ì" : "");
1236 #endif
1237                     break;
1238                 case OBJ_FLOOR:
1239 #if 0 /*JP*/
1240                     You_see("%scandle%s getting short.",
1241                             menorah ? "a candelabrum's " : many ? "some "
1242                                                                 : "a ",
1243                             many ? "s" : "");
1244 #else
1245                     You("%s\82ë\82¤\82»\82­\82ª\92Z\82­\82È\82é\82Ì\82ð\8c©\82½\81D",
1246                         menorah ? "\90C\91ä\82Ì" : "");
1247 #endif
1248                     break;
1249                 }
1250             break;
1251
1252         case 15:
1253             if (canseeit)
1254                 switch (obj->where) {
1255                 case OBJ_INVENT:
1256                 case OBJ_MINVENT:
1257 #if 0 /*JP*/
1258                     pline("%s%scandle%s flame%s flicker%s low!", whose,
1259                           menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1260                           many ? "s" : "", many ? "" : "s");
1261 #else
1262                     pline("%s%s\82ë\82¤\82»\82­\82Ì\89\8a\82Í\93_\96Å\82µ\81C\88Ã\82­\82È\82Á\82½\81I", whose,
1263                           menorah ? "\90C\91ä\82Ì" : "");
1264 #endif
1265                     break;
1266                 case OBJ_FLOOR:
1267 #if 0 /*JP*/
1268                     You_see("%scandle%s flame%s flicker low!",
1269                             menorah ? "a candelabrum's " : many ? "some "
1270                                                                 : "a ",
1271                             many ? "s'" : "'s", many ? "s" : "");
1272 #else
1273                     You("%s\82ë\82¤\82»\82­\82Ì\89\8a\82ª\93_\96Å\82µ\81C\88Ã\82­\82È\82é\82Ì\82ð\8c©\82½\81I",
1274                         menorah ? "\90C\91ä\82Ì" : "");
1275 #endif
1276                     break;
1277                 }
1278             break;
1279
1280         case 0:
1281             /* we know even if blind and in our inventory */
1282             if (canseeit || obj->where == OBJ_INVENT) {
1283                 if (menorah) {
1284                     switch (obj->where) {
1285                     case OBJ_INVENT:
1286                     case OBJ_MINVENT:
1287 #if 0 /*JP*/
1288                         pline("%scandelabrum's flame%s.", whose,
1289                               many ? "s die" : " dies");
1290 #else
1291                         pline("%s\90C\91ä\82Ì\89\8a\82Í\8fÁ\82¦\82½\81D", whose);
1292 #endif
1293                         break;
1294                     case OBJ_FLOOR:
1295 #if 0 /*JP*/
1296                         You_see("a candelabrum's flame%s die.",
1297                                 many ? "s" : "");
1298 #else
1299                         You("\90C\91ä\82Ì\89\8a\82ª\8fÁ\82¦\82é\82Ì\82ð\8c©\82½\81D");
1300 #endif
1301                         break;
1302                     }
1303                 } else {
1304                     switch (obj->where) {
1305                     case OBJ_INVENT:
1306                     case OBJ_MINVENT:
1307 #if 0 /*JP*/
1308                         pline("%s %s consumed!", Yname2(obj),
1309                               many ? "are" : "is");
1310 #else
1311                         pline("%s\82Í\94R\82¦\82Â\82«\82½\81I", Yname2(obj));
1312 #endif
1313                         break;
1314                     case OBJ_FLOOR:
1315                         /*
1316                         You see some wax candles consumed!
1317                         You see a wax candle consumed!
1318                         */
1319 #if 0 /*JP*/
1320                         You_see("%s%s consumed!", many ? "some " : "",
1321                                 many ? xname(obj) : an(xname(obj)));
1322 #else
1323                         You("%s\82ª\94R\82¦\82Â\82«\82é\82Ì\82ð\8c©\82½\81I", xname(obj));
1324 #endif
1325                         need_newsym = TRUE;
1326                         break;
1327                     }
1328
1329                     /* post message */
1330 #if 0 /*JP*/
1331                     pline(Hallucination
1332                               ? (many ? "They shriek!" : "It shrieks!")
1333                               : Blind ? "" : (many ? "Their flames die."
1334                                                    : "Its flame dies."));
1335 #else
1336                     pline(Hallucination ? "\82»\82ê\82Í\90k\82¦\82½\81D"
1337                           : Blind ? "" 
1338                           : "\89\8a\82Í\8fÁ\82¦\82½\81D");
1339 #endif
1340                 }
1341             }
1342             end_burn(obj, FALSE);
1343
1344             if (menorah) {
1345                 obj->spe = 0;
1346             } else {
1347                 if (carried(obj)) {
1348                     useupall(obj);
1349                 } else {
1350                     /* clear migrating obj's destination code
1351                        so obfree won't think this item is worn */
1352                     if (obj->where == OBJ_MIGRATING)
1353                         obj->owornmask = 0L;
1354                     obj_extract_self(obj);
1355                     obfree(obj, (struct obj *) 0);
1356                 }
1357                 obj = (struct obj *) 0;
1358             }
1359             break;
1360
1361         default:
1362             /*
1363              * Someone added fuel (candles) to the menorah while
1364              * it was lit.  Just fall through and let begin burn
1365              * handle the new age.
1366              */
1367             break;
1368         }
1369
1370         if (obj && obj->age)
1371             begin_burn(obj, TRUE);
1372
1373         break;
1374
1375     default:
1376         impossible("burn_object: unexpeced obj %s", xname(obj));
1377         break;
1378     }
1379     if (need_newsym)
1380         newsym(x, y);
1381 }
1382
1383 /*
1384  * Start a burn timeout on the given object. If not "already lit" then
1385  * create a light source for the vision system.  There had better not
1386  * be a burn already running on the object.
1387  *
1388  * Magic lamps stay lit as long as there's a genie inside, so don't start
1389  * a timer.
1390  *
1391  * Burn rules:
1392  *      potions of oil, lamps & candles:
1393  *              age = # of turns of fuel left
1394  *              spe = <unused>
1395  *      magic lamps:
1396  *              age = <unused>
1397  *              spe = 0 not lightable, 1 lightable forever
1398  *      candelabrum:
1399  *              age = # of turns of fuel left
1400  *              spe = # of candles
1401  *
1402  * Once the burn begins, the age will be set to the amount of fuel
1403  * remaining _once_the_burn_finishes_.  If the burn is terminated
1404  * early then fuel is added back.
1405  *
1406  * This use of age differs from the use of age for corpses and eggs.
1407  * For the latter items, age is when the object was created, so we
1408  * know when it becomes "bad".
1409  *
1410  * This is a "silent" routine - it should not print anything out.
1411  */
1412 void
1413 begin_burn(obj, already_lit)
1414 struct obj *obj;
1415 boolean already_lit;
1416 {
1417     int radius = 3;
1418     long turns = 0;
1419     boolean do_timer = TRUE;
1420
1421     if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1422         return;
1423
1424     switch (obj->otyp) {
1425     case MAGIC_LAMP:
1426         obj->lamplit = 1;
1427         do_timer = FALSE;
1428         break;
1429
1430     case POT_OIL:
1431         turns = obj->age;
1432         radius = 1; /* very dim light */
1433         break;
1434
1435     case BRASS_LANTERN:
1436     case OIL_LAMP:
1437         /* magic times are 150, 100, 50, 25, and 0 */
1438         if (obj->age > 150L)
1439             turns = obj->age - 150L;
1440         else if (obj->age > 100L)
1441             turns = obj->age - 100L;
1442         else if (obj->age > 50L)
1443             turns = obj->age - 50L;
1444         else if (obj->age > 25L)
1445             turns = obj->age - 25L;
1446         else
1447             turns = obj->age;
1448         break;
1449
1450     case CANDELABRUM_OF_INVOCATION:
1451     case TALLOW_CANDLE:
1452     case WAX_CANDLE:
1453         /* magic times are 75, 15, and 0 */
1454         if (obj->age > 75L)
1455             turns = obj->age - 75L;
1456         else if (obj->age > 15L)
1457             turns = obj->age - 15L;
1458         else
1459             turns = obj->age;
1460         radius = candle_light_range(obj);
1461         break;
1462
1463     default:
1464         /* [ALI] Support artifact light sources */
1465         if (artifact_light(obj)) {
1466             obj->lamplit = 1;
1467             do_timer = FALSE;
1468             radius = arti_light_radius(obj);
1469         } else {
1470             impossible("begin burn: unexpected %s", xname(obj));
1471             turns = obj->age;
1472         }
1473         break;
1474     }
1475
1476     if (do_timer) {
1477         if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1478             obj->lamplit = 1;
1479             obj->age -= turns;
1480             if (carried(obj) && !already_lit)
1481                 update_inventory();
1482         } else {
1483             obj->lamplit = 0;
1484         }
1485     } else {
1486         if (carried(obj) && !already_lit)
1487             update_inventory();
1488     }
1489
1490     if (obj->lamplit && !already_lit) {
1491         xchar x, y;
1492
1493         if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1494             new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1495         else
1496             impossible("begin_burn: can't get obj position");
1497     }
1498 }
1499
1500 /*
1501  * Stop a burn timeout on the given object if timer attached.  Darken
1502  * light source.
1503  */
1504 void
1505 end_burn(obj, timer_attached)
1506 struct obj *obj;
1507 boolean timer_attached;
1508 {
1509     if (!obj->lamplit) {
1510         impossible("end_burn: obj %s not lit", xname(obj));
1511         return;
1512     }
1513
1514     if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1515         timer_attached = FALSE;
1516
1517     if (!timer_attached) {
1518         /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1519         del_light_source(LS_OBJECT, obj_to_any(obj));
1520         obj->lamplit = 0;
1521         if (obj->where == OBJ_INVENT)
1522             update_inventory();
1523     } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1524         impossible("end_burn: obj %s not timed!", xname(obj));
1525 }
1526
1527 /*
1528  * Cleanup a burning object if timer stopped.
1529  */
1530 static void
1531 cleanup_burn(arg, expire_time)
1532 anything *arg;
1533 long expire_time;
1534 {
1535     struct obj *obj = arg->a_obj;
1536     if (!obj->lamplit) {
1537         impossible("cleanup_burn: obj %s not lit", xname(obj));
1538         return;
1539     }
1540
1541     del_light_source(LS_OBJECT, obj_to_any(obj));
1542
1543     /* restore unused time */
1544     obj->age += expire_time - monstermoves;
1545
1546     obj->lamplit = 0;
1547
1548     if (obj->where == OBJ_INVENT)
1549         update_inventory();
1550 }
1551
1552 void
1553 do_storms()
1554 {
1555     int nstrike;
1556     register int x, y;
1557     int dirx, diry;
1558     int count;
1559
1560     /* no lightning if not the air level or too often, even then */
1561     if (!Is_airlevel(&u.uz) || rn2(8))
1562         return;
1563
1564     /* the number of strikes is 8-log2(nstrike) */
1565     for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1566         count = 0;
1567         do {
1568             x = rnd(COLNO - 1);
1569             y = rn2(ROWNO);
1570         } while (++count < 100 && levl[x][y].typ != CLOUD);
1571
1572         if (count < 100) {
1573             dirx = rn2(3) - 1;
1574             diry = rn2(3) - 1;
1575             if (dirx != 0 || diry != 0)
1576                 buzz(-15, /* "monster" LIGHTNING spell */
1577                      8, x, y, dirx, diry);
1578         }
1579     }
1580
1581     if (levl[u.ux][u.uy].typ == CLOUD) {
1582         /* Inside a cloud during a thunder storm is deafening. */
1583         /* Even if already deaf, we sense the thunder's vibrations. */
1584 /*JP
1585         pline("Kaboom!!!  Boom!!  Boom!!");
1586 */
1587         pline("\83s\83J\83b\81I\81I\83S\83\8d\83S\83\8d\83S\83\8d\83S\83\8d\81I\81I\83h\81[\83\93\81I");
1588         incr_itimeout(&HDeaf, rn1(20, 30));
1589         if (!u.uinvulnerable) {
1590             stop_occupation();
1591             nomul(-3);
1592             multi_reason = "hiding from thunderstorm";
1593             nomovemsg = 0;
1594         }
1595     } else
1596 /*JP
1597         You_hear("a rumbling noise.");
1598 */
1599         You_hear("\97\8b\82Ì\89¹\82ð\95·\82¢\82½\81D");
1600 }
1601
1602 /* -------------------------------------------------------------------------
1603  */
1604 /*
1605  * Generic Timeout Functions.
1606  *
1607  * Interface:
1608  *
1609  * General:
1610  *  boolean start_timer(long timeout,short kind,short func_index,
1611  *                      anything *arg)
1612  *      Start a timer of kind 'kind' that will expire at time
1613  *      monstermoves+'timeout'.  Call the function at 'func_index'
1614  *      in the timeout table using argument 'arg'.  Return TRUE if
1615  *      a timer was started.  This places the timer on a list ordered
1616  *      "sooner" to "later".  If an object, increment the object's
1617  *      timer count.
1618  *
1619  *  long stop_timer(short func_index, anything *arg)
1620  *      Stop a timer specified by the (func_index, arg) pair.  This
1621  *      assumes that such a pair is unique.  Return the time the
1622  *      timer would have gone off.  If no timer is found, return 0.
1623  *      If an object, decrement the object's timer count.
1624  *
1625  *  long peek_timer(short func_index, anything *arg)
1626  *      Return time specified timer will go off (0 if no such timer).
1627  *
1628  *  void run_timers(void)
1629  *      Call timers that have timed out.
1630  *
1631  * Save/Restore:
1632  *  void save_timers(int fd, int mode, int range)
1633  *      Save all timers of range 'range'.  Range is either global
1634  *      or local.  Global timers follow game play, local timers
1635  *      are saved with a level.  Object and monster timers are
1636  *      saved using their respective id's instead of pointers.
1637  *
1638  *  void restore_timers(int fd, int range, boolean ghostly, long adjust)
1639  *      Restore timers of range 'range'.  If from a ghost pile,
1640  *      adjust the timeout by 'adjust'.  The object and monster
1641  *      ids are not restored until later.
1642  *
1643  *  void relink_timers(boolean ghostly)
1644  *      Relink all object and monster timers that had been saved
1645  *      using their object's or monster's id number.
1646  *
1647  * Object Specific:
1648  *  void obj_move_timers(struct obj *src, struct obj *dest)
1649  *      Reassign all timers from src to dest.
1650  *
1651  *  void obj_split_timers(struct obj *src, struct obj *dest)
1652  *      Duplicate all timers assigned to src and attach them to dest.
1653  *
1654  *  void obj_stop_timers(struct obj *obj)
1655  *      Stop all timers attached to obj.
1656  *
1657  *  boolean obj_has_timer(struct obj *object, short timer_type)
1658  *      Check whether object has a timer of type timer_type.
1659  */
1660
1661 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1662 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1663 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1664 STATIC_DCL timer_element *FDECL(remove_timer,
1665                                 (timer_element **, SHORT_P, ANY_P *));
1666 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1667 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1668 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1669 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1670
1671 /* ordered timer list */
1672 static timer_element *timer_base; /* "active" */
1673 static unsigned long timer_id = 1;
1674
1675 /* If defined, then include names when printing out the timer queue */
1676 #define VERBOSE_TIMER
1677
1678 typedef struct {
1679     timeout_proc f, cleanup;
1680 #ifdef VERBOSE_TIMER
1681     const char *name;
1682 #define TTAB(a, b, c) \
1683     {                 \
1684         a, b, c       \
1685     }
1686 #else
1687 #define TTAB(a, b, c) \
1688     {                 \
1689         a, b          \
1690     }
1691 #endif
1692 } ttable;
1693
1694 /* table of timeout functions */
1695 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1696     TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
1697     TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
1698     TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
1699     TTAB(burn_object, cleanup_burn, "burn_object"),
1700     TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
1701     TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
1702     TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
1703 };
1704 #undef TTAB
1705
1706 STATIC_OVL const char *
1707 kind_name(kind)
1708 short kind;
1709 {
1710     switch (kind) {
1711     case TIMER_LEVEL:
1712         return "level";
1713     case TIMER_GLOBAL:
1714         return "global";
1715     case TIMER_OBJECT:
1716         return "object";
1717     case TIMER_MONSTER:
1718         return "monster";
1719     }
1720     return "unknown";
1721 }
1722
1723 STATIC_OVL void
1724 print_queue(win, base)
1725 winid win;
1726 timer_element *base;
1727 {
1728     timer_element *curr;
1729     char buf[BUFSZ];
1730
1731     if (!base) {
1732         putstr(win, 0, "<empty>");
1733     } else {
1734         putstr(win, 0, "timeout  id   kind   call");
1735         for (curr = base; curr; curr = curr->next) {
1736 #ifdef VERBOSE_TIMER
1737             Sprintf(buf, " %4ld   %4ld  %-6s %s(%s)", curr->timeout,
1738                     curr->tid, kind_name(curr->kind),
1739                     timeout_funcs[curr->func_index].name,
1740                     fmt_ptr((genericptr_t) curr->arg.a_void));
1741 #else
1742             Sprintf(buf, " %4ld   %4ld  %-6s #%d(%s)", curr->timeout,
1743                     curr->tid, kind_name(curr->kind), curr->func_index,
1744                     fmt_ptr((genericptr_t) curr->arg.a_void));
1745 #endif
1746             putstr(win, 0, buf);
1747         }
1748     }
1749 }
1750
1751 int
1752 wiz_timeout_queue()
1753 {
1754     winid win;
1755     char buf[BUFSZ];
1756
1757     win = create_nhwindow(NHW_MENU); /* corner text window */
1758     if (win == WIN_ERR)
1759         return 0;
1760
1761     Sprintf(buf, "Current time = %ld.", monstermoves);
1762     putstr(win, 0, buf);
1763     putstr(win, 0, "");
1764     putstr(win, 0, "Active timeout queue:");
1765     putstr(win, 0, "");
1766     print_queue(win, timer_base);
1767
1768     display_nhwindow(win, FALSE);
1769     destroy_nhwindow(win);
1770
1771     return 0;
1772 }
1773
1774 void
1775 timer_sanity_check()
1776 {
1777     timer_element *curr;
1778
1779     /* this should be much more complete */
1780     for (curr = timer_base; curr; curr = curr->next)
1781         if (curr->kind == TIMER_OBJECT) {
1782             struct obj *obj = curr->arg.a_obj;
1783             if (obj->timed == 0) {
1784                 pline("timer sanity: untimed obj %s, timer %ld",
1785                       fmt_ptr((genericptr_t) obj), curr->tid);
1786             }
1787         }
1788 }
1789
1790 /*
1791  * Pick off timeout elements from the global queue and call their functions.
1792  * Do this until their time is less than or equal to the move count.
1793  */
1794 void
1795 run_timers()
1796 {
1797     timer_element *curr;
1798
1799     /*
1800      * Always use the first element.  Elements may be added or deleted at
1801      * any time.  The list is ordered, we are done when the first element
1802      * is in the future.
1803      */
1804     while (timer_base && timer_base->timeout <= monstermoves) {
1805         curr = timer_base;
1806         timer_base = curr->next;
1807
1808         if (curr->kind == TIMER_OBJECT)
1809             (curr->arg.a_obj)->timed--;
1810         (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
1811         free((genericptr_t) curr);
1812     }
1813 }
1814
1815 /*
1816  * Start a timer.  Return TRUE if successful.
1817  */
1818 boolean
1819 start_timer(when, kind, func_index, arg)
1820 long when;
1821 short kind;
1822 short func_index;
1823 anything *arg;
1824 {
1825     timer_element *gnu;
1826
1827     if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1828         panic("start_timer");
1829
1830     gnu = (timer_element *) alloc(sizeof(timer_element));
1831     gnu->next = 0;
1832     gnu->tid = timer_id++;
1833     gnu->timeout = monstermoves + when;
1834     gnu->kind = kind;
1835     gnu->needs_fixup = 0;
1836     gnu->func_index = func_index;
1837     gnu->arg = *arg;
1838     insert_timer(gnu);
1839
1840     if (kind == TIMER_OBJECT) /* increment object's timed count */
1841         (arg->a_obj)->timed++;
1842
1843     /* should check for duplicates and fail if any */
1844     return TRUE;
1845 }
1846
1847 /*
1848  * Remove the timer from the current list and free it up.  Return the time
1849  * remaining until it would have gone off, 0 if not found.
1850  */
1851 long
1852 stop_timer(func_index, arg)
1853 short func_index;
1854 anything *arg;
1855 {
1856     timer_element *doomed;
1857     long timeout;
1858
1859     doomed = remove_timer(&timer_base, func_index, arg);
1860
1861     if (doomed) {
1862         timeout = doomed->timeout;
1863         if (doomed->kind == TIMER_OBJECT)
1864             (arg->a_obj)->timed--;
1865         if (timeout_funcs[doomed->func_index].cleanup)
1866             (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
1867         free((genericptr_t) doomed);
1868         return (timeout - monstermoves);
1869     }
1870     return 0L;
1871 }
1872
1873 /*
1874  * Find the timeout of specified timer; return 0 if none.
1875  */
1876 long
1877 peek_timer(type, arg)
1878 short type;
1879 anything *arg;
1880 {
1881     timer_element *curr;
1882
1883     for (curr = timer_base; curr; curr = curr->next) {
1884         if (curr->func_index == type && curr->arg.a_void == arg->a_void)
1885             return curr->timeout;
1886     }
1887     return 0L;
1888 }
1889
1890 /*
1891  * Move all object timers from src to dest, leaving src untimed.
1892  */
1893 void
1894 obj_move_timers(src, dest)
1895 struct obj *src, *dest;
1896 {
1897     int count;
1898     timer_element *curr;
1899
1900     for (count = 0, curr = timer_base; curr; curr = curr->next)
1901         if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1902             curr->arg.a_obj = dest;
1903             dest->timed++;
1904             count++;
1905         }
1906     if (count != src->timed)
1907         panic("obj_move_timers");
1908     src->timed = 0;
1909 }
1910
1911 /*
1912  * Find all object timers and duplicate them for the new object "dest".
1913  */
1914 void
1915 obj_split_timers(src, dest)
1916 struct obj *src, *dest;
1917 {
1918     timer_element *curr, *next_timer = 0;
1919
1920     for (curr = timer_base; curr; curr = next_timer) {
1921         next_timer = curr->next; /* things may be inserted */
1922         if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
1923             (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
1924                                curr->func_index, obj_to_any(dest));
1925         }
1926     }
1927 }
1928
1929 /*
1930  * Stop all timers attached to this object.  We can get away with this because
1931  * all object pointers are unique.
1932  */
1933 void
1934 obj_stop_timers(obj)
1935 struct obj *obj;
1936 {
1937     timer_element *curr, *prev, *next_timer = 0;
1938
1939     for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1940         next_timer = curr->next;
1941         if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
1942             if (prev)
1943                 prev->next = curr->next;
1944             else
1945                 timer_base = curr->next;
1946             if (timeout_funcs[curr->func_index].cleanup)
1947                 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1948                                                            curr->timeout);
1949             free((genericptr_t) curr);
1950         } else {
1951             prev = curr;
1952         }
1953     }
1954     obj->timed = 0;
1955 }
1956
1957 /*
1958  * Check whether object has a timer of type timer_type.
1959  */
1960 boolean
1961 obj_has_timer(object, timer_type)
1962 struct obj *object;
1963 short timer_type;
1964 {
1965     long timeout = peek_timer(timer_type, obj_to_any(object));
1966
1967     return (boolean) (timeout != 0L);
1968 }
1969
1970 /*
1971  * Stop all timers of index func_index at this spot.
1972  *
1973  */
1974 void
1975 spot_stop_timers(x, y, func_index)
1976 xchar x, y;
1977 short func_index;
1978 {
1979     timer_element *curr, *prev, *next_timer = 0;
1980     long where = (((long) x << 16) | ((long) y));
1981
1982     for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1983         next_timer = curr->next;
1984         if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
1985             && curr->arg.a_long == where) {
1986             if (prev)
1987                 prev->next = curr->next;
1988             else
1989                 timer_base = curr->next;
1990             if (timeout_funcs[curr->func_index].cleanup)
1991                 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
1992                                                            curr->timeout);
1993             free((genericptr_t) curr);
1994         } else {
1995             prev = curr;
1996         }
1997     }
1998 }
1999
2000 /*
2001  * When is the spot timer of type func_index going to expire?
2002  * Returns 0L if no such timer.
2003  */
2004 long
2005 spot_time_expires(x, y, func_index)
2006 xchar x, y;
2007 short func_index;
2008 {
2009     timer_element *curr;
2010     long where = (((long) x << 16) | ((long) y));
2011
2012     for (curr = timer_base; curr; curr = curr->next) {
2013         if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2014             && curr->arg.a_long == where)
2015             return curr->timeout;
2016     }
2017     return 0L;
2018 }
2019
2020 long
2021 spot_time_left(x, y, func_index)
2022 xchar x, y;
2023 short func_index;
2024 {
2025     long expires = spot_time_expires(x, y, func_index);
2026     return (expires > 0L) ? expires - monstermoves : 0L;
2027 }
2028
2029 /* Insert timer into the global queue */
2030 STATIC_OVL void
2031 insert_timer(gnu)
2032 timer_element *gnu;
2033 {
2034     timer_element *curr, *prev;
2035
2036     for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2037         if (curr->timeout >= gnu->timeout)
2038             break;
2039
2040     gnu->next = curr;
2041     if (prev)
2042         prev->next = gnu;
2043     else
2044         timer_base = gnu;
2045 }
2046
2047 STATIC_OVL timer_element *
2048 remove_timer(base, func_index, arg)
2049 timer_element **base;
2050 short func_index;
2051 anything *arg;
2052 {
2053     timer_element *prev, *curr;
2054
2055     for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2056         if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2057             break;
2058
2059     if (curr) {
2060         if (prev)
2061             prev->next = curr->next;
2062         else
2063             *base = curr->next;
2064     }
2065
2066     return curr;
2067 }
2068
2069 STATIC_OVL void
2070 write_timer(fd, timer)
2071 int fd;
2072 timer_element *timer;
2073 {
2074     anything arg_save;
2075
2076     arg_save = zeroany;
2077     switch (timer->kind) {
2078     case TIMER_GLOBAL:
2079     case TIMER_LEVEL:
2080         /* assume no pointers in arg */
2081         bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2082         break;
2083
2084     case TIMER_OBJECT:
2085         if (timer->needs_fixup)
2086             bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2087         else {
2088             /* replace object pointer with id */
2089             arg_save.a_obj = timer->arg.a_obj;
2090             timer->arg = zeroany;
2091             timer->arg.a_uint = (arg_save.a_obj)->o_id;
2092             timer->needs_fixup = 1;
2093             bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2094             timer->arg.a_obj = arg_save.a_obj;
2095             timer->needs_fixup = 0;
2096         }
2097         break;
2098
2099     case TIMER_MONSTER:
2100         if (timer->needs_fixup)
2101             bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2102         else {
2103             /* replace monster pointer with id */
2104             arg_save.a_monst = timer->arg.a_monst;
2105             timer->arg = zeroany;
2106             timer->arg.a_uint = (arg_save.a_monst)->m_id;
2107             timer->needs_fixup = 1;
2108             bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2109             timer->arg.a_monst = arg_save.a_monst;
2110             timer->needs_fixup = 0;
2111         }
2112         break;
2113
2114     default:
2115         panic("write_timer");
2116         break;
2117     }
2118 }
2119
2120 /*
2121  * Return TRUE if the object will stay on the level when the level is
2122  * saved.
2123  */
2124 boolean
2125 obj_is_local(obj)
2126 struct obj *obj;
2127 {
2128     switch (obj->where) {
2129     case OBJ_INVENT:
2130     case OBJ_MIGRATING:
2131         return FALSE;
2132     case OBJ_FLOOR:
2133     case OBJ_BURIED:
2134         return TRUE;
2135     case OBJ_CONTAINED:
2136         return obj_is_local(obj->ocontainer);
2137     case OBJ_MINVENT:
2138         return mon_is_local(obj->ocarry);
2139     }
2140     panic("obj_is_local");
2141     return FALSE;
2142 }
2143
2144 /*
2145  * Return TRUE if the given monster will stay on the level when the
2146  * level is saved.
2147  */
2148 STATIC_OVL boolean
2149 mon_is_local(mon)
2150 struct monst *mon;
2151 {
2152     struct monst *curr;
2153
2154     for (curr = migrating_mons; curr; curr = curr->nmon)
2155         if (curr == mon)
2156             return FALSE;
2157     /* `mydogs' is used during level changes, never saved and restored */
2158     for (curr = mydogs; curr; curr = curr->nmon)
2159         if (curr == mon)
2160             return FALSE;
2161     return TRUE;
2162 }
2163
2164 /*
2165  * Return TRUE if the timer is attached to something that will stay on the
2166  * level when the level is saved.
2167  */
2168 STATIC_OVL boolean
2169 timer_is_local(timer)
2170 timer_element *timer;
2171 {
2172     switch (timer->kind) {
2173     case TIMER_LEVEL:
2174         return TRUE;
2175     case TIMER_GLOBAL:
2176         return FALSE;
2177     case TIMER_OBJECT:
2178         return obj_is_local(timer->arg.a_obj);
2179     case TIMER_MONSTER:
2180         return mon_is_local(timer->arg.a_monst);
2181     }
2182     panic("timer_is_local");
2183     return FALSE;
2184 }
2185
2186 /*
2187  * Part of the save routine.  Count up the number of timers that would
2188  * be written.  If write_it is true, actually write the timer.
2189  */
2190 STATIC_OVL int
2191 maybe_write_timer(fd, range, write_it)
2192 int fd, range;
2193 boolean write_it;
2194 {
2195     int count = 0;
2196     timer_element *curr;
2197
2198     for (curr = timer_base; curr; curr = curr->next) {
2199         if (range == RANGE_GLOBAL) {
2200             /* global timers */
2201
2202             if (!timer_is_local(curr)) {
2203                 count++;
2204                 if (write_it)
2205                     write_timer(fd, curr);
2206             }
2207
2208         } else {
2209             /* local timers */
2210
2211             if (timer_is_local(curr)) {
2212                 count++;
2213                 if (write_it)
2214                     write_timer(fd, curr);
2215             }
2216         }
2217     }
2218
2219     return count;
2220 }
2221
2222 /*
2223  * Save part of the timer list.  The parameter 'range' specifies either
2224  * global or level timers to save.  The timer ID is saved with the global
2225  * timers.
2226  *
2227  * Global range:
2228  *      + timeouts that follow the hero (global)
2229  *      + timeouts that follow obj & monst that are migrating
2230  *
2231  * Level range:
2232  *      + timeouts that are level specific (e.g. storms)
2233  *      + timeouts that stay with the level (obj & monst)
2234  */
2235 void
2236 save_timers(fd, mode, range)
2237 int fd, mode, range;
2238 {
2239     timer_element *curr, *prev, *next_timer = 0;
2240     int count;
2241
2242     if (perform_bwrite(mode)) {
2243         if (range == RANGE_GLOBAL)
2244             bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2245
2246         count = maybe_write_timer(fd, range, FALSE);
2247         bwrite(fd, (genericptr_t) &count, sizeof count);
2248         (void) maybe_write_timer(fd, range, TRUE);
2249     }
2250
2251     if (release_data(mode)) {
2252         for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2253             next_timer = curr->next; /* in case curr is removed */
2254
2255             if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2256                 if (prev)
2257                     prev->next = curr->next;
2258                 else
2259                     timer_base = curr->next;
2260                 free((genericptr_t) curr);
2261                 /* prev stays the same */
2262             } else {
2263                 prev = curr;
2264             }
2265         }
2266     }
2267 }
2268
2269 /*
2270  * Pull in the structures from disk, but don't recalculate the object and
2271  * monster pointers.
2272  */
2273 void
2274 restore_timers(fd, range, ghostly, adjust)
2275 int fd, range;
2276 boolean ghostly; /* restoring from a ghost level */
2277 long adjust;     /* how much to adjust timeout */
2278 {
2279     int count;
2280     timer_element *curr;
2281
2282     if (range == RANGE_GLOBAL)
2283         mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2284
2285     /* restore elements */
2286     mread(fd, (genericptr_t) &count, sizeof count);
2287     while (count-- > 0) {
2288         curr = (timer_element *) alloc(sizeof(timer_element));
2289         mread(fd, (genericptr_t) curr, sizeof(timer_element));
2290         if (ghostly)
2291             curr->timeout += adjust;
2292         insert_timer(curr);
2293     }
2294 }
2295
2296 /* reset all timers that are marked for reseting */
2297 void
2298 relink_timers(ghostly)
2299 boolean ghostly;
2300 {
2301     timer_element *curr;
2302     unsigned nid;
2303
2304     for (curr = timer_base; curr; curr = curr->next) {
2305         if (curr->needs_fixup) {
2306             if (curr->kind == TIMER_OBJECT) {
2307                 if (ghostly) {
2308                     if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2309                         panic("relink_timers 1");
2310                 } else
2311                     nid = curr->arg.a_uint;
2312                 curr->arg.a_obj = find_oid(nid);
2313                 if (!curr->arg.a_obj)
2314                     panic("cant find o_id %d", nid);
2315                 curr->needs_fixup = 0;
2316             } else if (curr->kind == TIMER_MONSTER) {
2317                 panic("relink_timers: no monster timer implemented");
2318             } else
2319                 panic("relink_timers 2");
2320         }
2321     }
2322 }
2323
2324 /*timeout.c*/