OSDN Git Service

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