OSDN Git Service

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