OSDN Git Service

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