OSDN Git Service

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