OSDN Git Service

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