OSDN Git Service

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