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