1 /* NetHack 3.6 timeout.c $NHDT-Date: 1573290422 2019/11/09 09:07:02 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.93 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
9 /* JNetHack may be freely redistributed. See license for details. */
12 #include "lev.h" /* for checking save modes */
14 STATIC_DCL void NDECL(stoned_dialogue);
15 STATIC_DCL void NDECL(vomiting_dialogue);
16 STATIC_DCL void NDECL(choke_dialogue);
17 STATIC_DCL void NDECL(levitation_dialogue);
18 STATIC_DCL void NDECL(slime_dialogue);
19 STATIC_DCL void FDECL(slimed_to_death, (struct kinfo *));
20 STATIC_DCL void NDECL(phaze_dialogue);
21 STATIC_DCL void FDECL(done_timeout, (int, int));
22 STATIC_DCL void NDECL(slip_or_trip);
23 STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
24 STATIC_DCL void FDECL(lantern_message, (struct obj *));
25 STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long));
27 /* used by wizard mode #timeout and #wizintrinsic; order by 'interest'
28 for timeout countdown, where most won't occur in normal play */
29 /*JP
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Å
\82µ
\82©
\8eg
\82í
\82ê
\82È
\82¢
\82æ
\82¤
\82È
\82Ì
\82Å
\96|
\96ó
\82µ
\82È
\82¢ */
30 const struct propname {
32 const char *prop_name;
34 { INVULNERABLE, "invulnerable" },
35 { STONED, "petrifying" },
36 { SLIMED, "becoming slime" },
37 { STRANGLED, "strangling" },
38 { SICK, "fatally sick" },
39 { STUNNED, "stunned" },
40 { CONFUSION, "confused" },
41 { HALLUC, "hallucinating" },
42 { BLINDED, "blinded" },
44 { VOMITING, "vomiting" },
45 { GLIB, "slippery fingers" },
46 { WOUNDED_LEGS, "wounded legs" },
48 { TELEPORT, "teleporting" },
49 { POLYMORPH, "polymorphing" },
50 { LEVITATION, "levitating" },
51 { FAST, "very fast" }, /* timed 'FAST' is very fast */
52 { CLAIRVOYANT, "clairvoyant" },
53 { DETECT_MONSTERS, "monster detection" },
54 { SEE_INVIS, "see invisible" },
55 { INVIS, "invisible" },
56 /* properties beyond here don't have timed values during normal play,
57 so there's not much point in trying to order them sensibly;
58 they're either on or off based on equipment, role, actions, &c */
59 { FIRE_RES, "fire resistance" },
60 { COLD_RES, "cold resistance" },
61 { SLEEP_RES, "sleep resistance" },
62 { DISINT_RES, "disintegration resistance" },
63 { SHOCK_RES, "shock resistance" },
64 { POISON_RES, "poison resistance" },
65 { ACID_RES, "acid resistance" },
66 { STONE_RES, "stoning resistance" },
67 { DRAIN_RES, "drain resistance" },
68 { SICK_RES, "sickness resistance" },
69 { ANTIMAGIC, "magic resistance" },
70 { HALLUC_RES, "hallucination resistance" },
71 { FUMBLING, "fumbling" },
72 { HUNGER, "voracious hunger" },
73 { TELEPAT, "telepathic" },
74 { WARNING, "warning" },
75 { WARN_OF_MON, "warn: monster type or class" },
76 { WARN_UNDEAD, "warn: undead" },
77 { SEARCHING, "searching" },
78 { INFRAVISION, "infravision" },
79 { ADORNED, "adorned (+/- Cha)" },
80 { DISPLACED, "displaced" },
81 { STEALTH, "stealthy" },
82 { AGGRAVATE_MONSTER, "monster aggravation" },
83 { CONFLICT, "conflict" },
84 { JUMPING, "jumping" },
85 { TELEPORT_CONTROL, "teleport control" },
87 { WWALKING, "water walking" },
88 { SWIMMING, "swimming" },
89 { MAGICAL_BREATHING, "magical breathing" },
90 { PASSES_WALLS, "pass thru walls" },
91 { SLOW_DIGESTION, "slow digestion" },
92 { HALF_SPDAM, "half spell damage" },
93 { HALF_PHDAM, "half physical damage" },
94 { REGENERATION, "HP regeneration" },
95 { ENERGY_REGENERATION, "energy regeneration" },
96 { PROTECTION, "extra protection" },
97 { PROT_FROM_SHAPE_CHANGERS, "protection from shape changers" },
98 { POLYMORPH_CONTROL, "polymorph control" },
99 { UNCHANGING, "unchanging" },
100 { REFLECTING, "reflecting" },
101 { FREE_ACTION, "free action" },
102 { FIXED_ABIL, "fixed abilities" },
103 { LIFESAVED, "life will be saved" },
107 /* He is being petrified - dialogue by inmet!tower */
108 static NEARDATA const char *const stoned_texts[] = {
110 "You are slowing down.", /* 5 */
111 "Your limbs are stiffening.", /* 4 */
112 "Your limbs have turned to stone.", /* 3 */
113 "You have turned to stone.", /* 2 */
114 "You are a statue." /* 1 */
116 "
\82 \82È
\82½
\82Í
\82Ì
\82ë
\82
\82È
\82Á
\82½
\81D", /* 5 */
117 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\8dd
\92¼
\82µ
\82½
\81D", /* 4 */
118 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\90Î
\89»
\82µ
\82½
\81D", /* 3 */
119 "
\82 \82È
\82½
\82Í
\90Î
\82É
\82È
\82Á
\82½
\81D", /* 2 */
120 "
\82 \82È
\82½
\82Í
\92¤
\91\9c\82É
\82È
\82Á
\82½
\81D" /* 1 */
127 register long i = (Stoned & TIMEOUT);
129 if (i > 0L && i <= SIZE(stoned_texts)) {
132 Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
134 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
135 (void) strsubst(buf, "limbs", "extremities");
137 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
138 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
143 case 5: /* slowing down */
148 case 4: /* limbs stiffening */
149 /* just one move left to save oneself so quit fiddling around;
150 don't stop attempt to eat tin--might be lizard or acidic */
156 case 3: /* limbs turned to stone */
158 nomul(-3); /* can't move anymore */
160 multi_reason = "getting stoned";
162 multi_reason = "
\90Î
\89»
\82µ
\82Â
\82Â
\82 \82é
\8e\9e\82É";
163 nomovemsg = You_can_move_again; /* not unconscious */
164 /* "your limbs have turned to stone" so terminate wounded legs */
165 if (Wounded_legs && !u.usteed)
168 case 2: /* turned to stone */
169 if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
170 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
171 /* if also vomiting or turning into slime, stop those (no messages) */
173 make_vomiting(0L, FALSE);
175 make_slimed(0L, (char *) 0);
180 exercise(A_DEX, FALSE);
183 /* hero is getting sicker and sicker prior to vomiting */
184 static NEARDATA const char *const vomiting_texts[] = {
186 "are feeling mildly nauseated.", /* 14 */
187 "feel slightly confused.", /* 11 */
188 "can't seem to think straight.", /* 8 */
189 "feel incredibly sick.", /* 5 */
190 "are about to vomit." /* 2 */
192 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
193 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
194 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
195 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
196 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81D" /* 2 */
204 long v = (Vomiting & TIMEOUT);
206 /* note: nhtimeout() hasn't decremented timed properties for the
207 current turn yet, so we use Vomiting-1 here */
208 switch ((int) (v - 1L)) {
210 txt = vomiting_texts[0];
213 txt = vomiting_texts[1];
216 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
217 if (!Popeye(VOMITING))
221 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
226 txt = vomiting_texts[2];
229 txt = vomiting_texts[3];
232 txt = vomiting_texts[4];
233 if (cantvomit(youmonst.data))
235 txt = "gag uncontrollably.";
237 txt = "
\8bC
\95ª
\82Ì
\88«
\82³
\82ª
\97}
\82¦
\82ç
\82ê
\82È
\82
\82È
\82Á
\82½
\81D";
238 else if (Hallucination)
239 /* "hurl" is short for "hurl chunks" which is slang for
240 relatively violent vomiting... */
242 txt = "are about to hurl!";
244 txt = "
\83\8a\83o
\81[
\83X
\90¡
\91O
\82¾
\81I";
248 if (!cantvomit(youmonst.data)) {
250 /* case 2 used to be "You suddenly vomit!" but it wasn't sudden
251 since you've just been through the earlier messages of the
252 countdown, and it was still possible to move around between
253 that message and "You can move again." (from vomit()'s
254 nomul(-2)) with no intervening message; give one here to
255 have more specific point at which hero became unable to move
256 [vomit() issues its own message for the cantvomit() case
257 and for the FAINTING-or-worse case where stomach is empty] */
258 if (u.uhs < FAINTING)
260 You("%s!", !Hallucination ? "vomit" : "hurl chunks");
262 You("%s
\81I", !Hallucination ? "
\93f
\82¢
\82½" : "
\83\8a\83o
\81[
\83X
\82µ
\82½");
271 exercise(A_CON, FALSE);
274 static NEARDATA const char *const choke_texts[] = {
276 "You find it hard to breathe.",
277 "You're gasping for air.",
278 "You can no longer breathe.",
279 "You're turning %s.",
282 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
283 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
284 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
285 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
286 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
290 static NEARDATA const char *const choke_texts2[] = {
292 "Your %s is becoming constricted.",
293 "Your blood is having trouble reaching your brain.",
294 "The pressure on your %s increases.",
295 "Your consciousness is fading.",
298 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
299 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
300 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
301 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
302 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
309 register long i = (Strangled & TIMEOUT);
311 if (i > 0 && i <= SIZE(choke_texts)) {
312 if (Breathless || !rn2(50))
313 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
315 const char *str = choke_texts[SIZE(choke_texts) - i];
319 pline(str, hcolor(NH_BLUE));
321 pline(str, jconj_adj(hcolor(NH_BLUE)));
326 exercise(A_STR, FALSE);
329 static NEARDATA const char *const levi_texts[] = {
330 #if 0 /*JP*//* %s
\82Í
\8eg
\82í
\82È
\82¢ */
331 "You float slightly lower.",
332 "You wobble unsteadily %s the %s."
334 "
\82 \82È
\82½
\82Ì
\95\82\82«
\8bï
\8d\87\82Í
\8f
\82µ
\92á
\82
\82È
\82Á
\82½
\81D",
335 "
\82 \82È
\82½
\82Í
\82®
\82ç
\82®
\82ç
\97h
\82ê
\82Í
\82¶
\82ß
\82½
\81D"
340 levitation_dialogue()
342 /* -1 because the last message comes via float_down() */
343 long i = (((HLevitation & TIMEOUT) - 1L) / 2L);
348 if (!ACCESSIBLE(levl[u.ux][u.uy].typ)
349 && !is_pool_or_lava(u.ux,u.uy))
352 if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) {
353 const char *s = levi_texts[SIZE(levi_texts) - i];
355 #if 0 /*JP*//* %s
\82Í
\8eg
\82Á
\82Ä
\82¢
\82È
\82¢
\82Ì
\82Å
\92P
\8f\83\89» */
357 boolean danger = (is_pool_or_lava(u.ux, u.uy)
358 && !Is_waterlevel(&u.uz));
360 pline(s, danger ? "over" : "in",
361 danger ? surface(u.ux, u.uy) : "air");
368 static NEARDATA const char *const slime_texts[] = {
370 "You are turning a little %s.", /* 5 */
371 "Your limbs are getting oozy.", /* 4 */
372 "Your skin begins to peel away.", /* 3 */
373 "You are turning into %s.", /* 2 */
374 "You have become %s." /* 1 */
376 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
377 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
378 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
379 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
380 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
387 register long i = (Slimed & TIMEOUT) / 2L;
390 /* display as green slime during "You have become green slime."
391 but don't worry about not being able to see self; if already
392 mimicking something else at the time, implicitly be revealed */
393 youmonst.m_ap_type = M_AP_MONSTER;
394 youmonst.mappearance = PM_GREEN_SLIME;
396 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
399 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
401 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
402 (void) strsubst(buf, "limbs", "extremities");
404 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
405 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
408 if (index(buf, '%')) {
409 if (i == 4L) { /* "you are turning green" */
410 if (!Blind) /* [what if you're already green?] */
412 pline(buf, hcolor(NH_GREEN));
414 pline(buf, jconj_adj(hcolor(NH_GREEN)));
418 an(Hallucination ? rndmonnam(NULL) : "green slime"));
420 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
426 case 3L: /* limbs becoming oozy */
427 HFast = 0L; /* lose intrinsic speed */
433 case 2L: /* skin begins to peel */
434 if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
435 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
437 case 1L: /* turning into slime */
438 /* if also turning to stone, stop doing that (no message) */
440 make_stoned(0L, (char *) 0, KILLED_BY_AN, (char *) 0);
443 exercise(A_DEX, FALSE);
451 make_slimed(0L, "The slime that covers you is burned away!");
453 make_slimed(0L, "
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
457 /* countdown timer for turning into green slime has run out; kill our hero */
459 slimed_to_death(kptr)
464 /* redundant: polymon() cures sliming when polying into green slime */
465 if (Upolyd && youmonst.data == &mons[PM_GREEN_SLIME]) {
466 dealloc_killer(kptr);
469 /* more sure killer reason is set up */
470 if (kptr && kptr->name[0]) {
471 killer.format = kptr->format;
472 Strcpy(killer.name, kptr->name);
474 killer.format = NO_KILLER_PREFIX;
476 Strcpy(killer.name, "turned into green slime");
478 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
480 dealloc_killer(kptr);
483 * Polymorph into a green slime, which might destroy some worn armor
484 * (potentially affecting bones) and dismount from steed.
485 * Can't be Unchanging; wouldn't have turned into slime if we were.
486 * Despite lack of Unchanging, neither done() nor savelife() calls
487 * rehumanize() if hero dies while polymorphed.
488 * polymon() undoes the slime countdown's mimick-green-slime hack
489 * but does not perform polyself()'s light source bookkeeping.
490 * No longer need to manually increment uconduct.polyselfs to reflect
491 * [formerly implicit] change of form; polymon() takes care of that.
492 * Temporarily ungenocide if necessary.
494 if (emits_light(youmonst.data))
495 del_light_source(LS_MONSTER, monst_to_any(&youmonst));
496 save_mvflags = mvitals[PM_GREEN_SLIME].mvflags;
497 mvitals[PM_GREEN_SLIME].mvflags = save_mvflags & ~G_GENOD;
498 /* become a green slime; also resets youmonst.m_ap_type+.mappearance */
499 (void) polymon(PM_GREEN_SLIME);
500 mvitals[PM_GREEN_SLIME].mvflags = save_mvflags;
501 done_timeout(TURNED_SLIME, SLIMED);
503 /* life-saved; even so, hero still has turned into green slime;
504 player may have genocided green slimes after being infected */
505 if ((mvitals[PM_GREEN_SLIME].mvflags & G_GENOD) != 0) {
506 char slimebuf[BUFSZ];
508 killer.format = KILLED_BY;
510 Strcpy(killer.name, "slimicide");
512 Strcpy(killer.name, "
\83X
\83\89\83C
\83\80\8bs
\8eE");
513 /* vary the message depending upon whether life-save was due to
514 amulet or due to declining to die in explore or wizard mode */
516 Strcpy(slimebuf, "green slime has been genocided...");
518 Strcpy(slimebuf, "
\97Î
\83X
\83\89\83C
\83\80\82Í
\8bs
\8eE
\82³
\82ê
\82Ü
\82µ
\82½
\81D
\81D
\81D");
519 if (iflags.last_msg == PLNMSG_OK_DONT_DIE)
520 /* follows "OK, so you don't die." and arg is second sentence */
522 pline("Yes, you do. %s", upstart(slimebuf));
524 pline("
\82Í
\82¢
\81C
\82»
\82¤
\82Å
\82·
\81D%s", upstart(slimebuf));
526 /* follows "The medallion crumbles to dust." */
528 pline("Unfortunately, %s", slimebuf);
530 pline("
\82´
\82ñ
\82Ë
\82ñ
\82Å
\82·
\82ª%s", slimebuf);
531 /* die again; no possibility of amulet this time */
532 done(GENOCIDED); /* [should it be done_timeout(GENOCIDED, SLIMED)?] */
533 /* could be life-saved again (only in explore or wizard mode)
534 but green slimes are gone; just stay in current form */
539 /* Intrinsic Passes_walls is temporary when your god is trying to fix
540 all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
541 it can't find anywhere to place you. If that happens you get a small
542 value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
543 Message given is "you feel much slimmer" as a joke hint that you can
544 move between things which are closely packed--like the substance of
546 static NEARDATA const char *const phaze_texts[] = {
548 "You start to feel bloated.",
549 "You are feeling rather flabby.",
551 "
\82 \82È
\82½
\82Í
\96c
\82ç
\82Ý
\82Í
\82¶
\82ß
\82½
\8bC
\82ª
\82·
\82é
\81D",
552 "
\82 \82È
\82½
\82Í
\8f
\82µ
\82½
\82é
\82ñ
\82¾
\8bC
\82ª
\82·
\82é
\81D",
559 long i = ((HPasses_walls & TIMEOUT) / 2L);
561 if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
564 if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
565 pline1(phaze_texts[SIZE(phaze_texts) - i]);
568 /* when a status timeout is fatal, keep the status line indicator shown
569 during end of game rundown (and potential dumplog);
570 timeout has already counted down to 0 by the time we get here */
572 done_timeout(how, which)
575 long *intrinsic_p = &u.uprops[which].intrinsic;
577 *intrinsic_p |= I_SPECIAL; /* affects final disclosure */
581 *intrinsic_p &= ~I_SPECIAL;
588 register struct prop *upp;
593 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
598 if (u.uluck != baseluck
599 && moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
600 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
601 * stop good luck from timing out; normal luckstones stop both;
602 * neither is stopped if you don't have a luckstone.
603 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
605 register int time_luck = stone_luck(FALSE);
606 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
608 if (u.uluck > baseluck && (nostone || time_luck < 0))
610 else if (u.uluck < baseluck && (nostone || time_luck > 0))
614 return; /* things past this point could kill you */
623 if (HLevitation & TIMEOUT)
624 levitation_dialogue();
625 if (HPasses_walls & TIMEOUT)
627 if (u.mtimedone && !--u.mtimedone) {
629 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
630 else if (is_were(youmonst.data))
631 you_unwere(FALSE); /* if polycontrl, asks whether to rehumanize */
638 /* Dissipate spell-based protection. */
640 if (--u.usptime == 0 && u.uspellprot) {
641 u.usptime = u.uspmtime;
646 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
647 u.uspellprot ? "becomes less dense" : "disappears");
649 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
650 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
656 if (--u.ugallop == 0L && u.usteed)
658 pline("%s stops galloping.", Monnam(u.usteed));
660 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
664 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
665 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
666 kptr = find_delayed_killer((int) (upp - u.uprops));
667 switch (upp - u.uprops) {
669 if (kptr && kptr->name[0]) {
670 killer.format = kptr->format;
672 Strcpy(killer.name, kptr->name);
674 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
678 killer.format = NO_KILLER_PREFIX;
679 Strcpy(killer.name, "killed by petrification");
681 killer.format = KILLED_BY;
682 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
685 dealloc_killer(kptr);
686 /* (unlike sliming, you aren't changing form here) */
687 done_timeout(STONING, STONED);
690 slimed_to_death(kptr); /* done_timeout(TURNED_SLIME,SLIMED) */
693 make_vomiting(0L, TRUE);
697 You("die from your illness.");
699 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
700 if (kptr && kptr->name[0]) {
701 killer.format = kptr->format;
702 Strcpy(killer.name, kptr->name);
704 killer.format = KILLED_BY_AN;
705 killer.name[0] = 0; /* take the default */
707 dealloc_killer(kptr);
709 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
710 if (type_is_pname(&mons[m_idx])) {
711 killer.format = KILLED_BY;
712 } else if (mons[m_idx].geno & G_UNIQ) {
713 Strcpy(killer.name, the(killer.name));
714 killer.format = KILLED_BY;
717 done_timeout(POISONING, SICK);
723 You_feel("yourself slowing down%s.",
724 Fast ? " a bit" : "");
726 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
727 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
731 /* So make_confused works properly */
732 set_itimeout(&HConfusion, 1L);
733 make_confused(0L, TRUE);
738 set_itimeout(&HStun, 1L);
739 make_stunned(0L, TRUE);
744 set_itimeout(&Blinded, 1L);
745 make_blinded(0L, TRUE);
750 set_itimeout(&HDeaf, 1L);
758 if (!Invis && !BInvis && !Blind) {
761 ? "are no longer invisible."
762 : "can no longer see through yourself.");
765 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
766 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
772 set_mimic_blocking(); /* do special mimic handling */
773 see_monsters(); /* make invis mons appear */
774 newsym(u.ux, u.uy); /* make self appear */
784 make_totter(0L, TRUE);
789 set_itimeout(&HHallucination, 1L);
790 (void) make_hallucinated(0L, TRUE, 0L);
795 if (unconscious() || Sleep_resistance) {
796 incr_itimeout(&HSleepy, rnd(100));
801 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
803 fall_asleep(-sleeptime, TRUE);
804 incr_itimeout(&HSleepy, sleeptime + rnd(100));
808 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
811 /* timed Flying is via #wizintrinsic only */
812 if (was_flying && !Flying) {
817 You("
\92\85\92n
\82µ
\82½
\81D");
822 /* timed Warn_of_mon is via #wizintrinsic only */
824 context.warntype.speciesidx = NON_PM;
825 if (context.warntype.species) {
827 You("are no longer warned about %s.",
828 makeplural(context.warntype.species->mname));
830 You("
\82à
\82Í
\82â%s
\82ð
\8cx
\8d\90\82µ
\82È
\82
\82È
\82Á
\82½
\81D",
831 makeplural(context.warntype.species->mname));
833 context.warntype.species = (struct permonst *) 0;
841 You_feel("hemmed in again.");
843 You_feel("
\82Ü
\82½
\95Â
\82¶
\8d\9e\82ß
\82ç
\82ê
\82½
\82æ
\82¤
\82¾
\81D");
846 pline("You're back to your %s self again.",
847 !Upolyd ? "normal" : "unusual");
849 pline("
\82 \82È
\82½
\82Í
\8dÄ
\82Ñ
\92Ê
\8fí%s
\82Ì
\8fó
\91Ô
\82É
\82È
\82Á
\82½
\81D",
850 !Upolyd ? "" : "
\82Å
\82Í
\82È
\82¢");
855 killer.format = KILLED_BY;
858 (u.uburied) ? "suffocation" : "strangulation");
861 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
863 done_timeout(DIED, STRANGLED);
864 /* must be declining to die in explore|wizard mode;
865 treat like being cured of strangulation by prayer */
866 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
868 Your("amulet vanishes!");
870 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
875 /* call this only when a move took place. */
876 /* otherwise handle fumbling msgs locally. */
877 if (u.umoved && !Levitation) {
881 multi_reason = "fumbling";
883 multi_reason = "
\82Ö
\82Ü
\82ð
\82µ
\82½
\8c\84\82É";
885 /* The more you are carrying the more likely you
886 * are to make noise when you fumble. Adjustments
887 * to this number must be thoroughly play tested.
889 if ((inv_weight() > -500)) {
891 You("make a lot of noise!");
893 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
897 /* from outside means slippery ice; don't reset
898 counter if that's the only fumble reason */
899 HFumbling &= ~FROMOUTSIDE;
901 incr_itimeout(&HFumbling, rnd(20));
903 case DETECT_MONSTERS:
907 make_glib(0); /* might update persistent inventory */
916 fall_asleep(how_long, wakeup_msg)
923 multi_reason = "sleeping";
925 multi_reason = "
\96°
\82è
\82Ì
\82³
\82È
\82©
\82É";
926 /* generally don't notice sounds while sleeping */
927 if (wakeup_msg && multi == how_long) {
928 /* caller can follow with a direct call to Hear_again() if
929 there's a need to override this when wakeup_msg is true */
930 incr_itimeout(&HDeaf, how_long);
932 afternmv = Hear_again; /* this won't give any messages */
934 /* early wakeup from combat won't be possible until next monster turn */
935 u.usleep = monstermoves;
937 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
939 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
942 /* Attach an egg hatch timeout to the given egg.
943 * when = Time to hatch, usually only passed if re-creating an
944 * existing hatch timer. Pass 0L for random hatch time.
947 attach_egg_hatch_timeout(egg, when)
953 /* stop previous timer, if any */
954 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
957 * Decide if and when to hatch the egg. The old hatch_it() code tried
958 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
959 * a number x, 1<=x<=age, where x>150. This yields a chance of
960 * hatching > 99.9993%. Mimic that here.
963 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
971 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
975 /* prevent an egg from ever hatching */
980 /* stop previous timer, if any */
981 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
984 /* timer callback routine: hatch the given egg */
986 hatch_egg(arg, timeout)
991 struct monst *mon, *mon2;
994 boolean yours, silent, knows_egg = FALSE;
995 boolean cansee_hatchspot = FALSE;
996 int i, mnum, hatchcount = 0;
999 /* sterilized while waiting */
1000 if (egg->corpsenm == NON_PM)
1003 mon = mon2 = (struct monst *) 0;
1004 mnum = big_to_little(egg->corpsenm);
1005 /* The identity of one's father is learned, not innate */
1006 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
1007 silent = (timeout != monstermoves); /* hatched while away */
1009 /* only can hatch when in INVENT, FLOOR, MINVENT */
1010 if (get_obj_location(egg, &x, &y, 0)) {
1011 hatchcount = rnd((int) egg->quan);
1012 cansee_hatchspot = cansee(x, y) && !silent;
1013 if (!(mons[mnum].geno & G_UNIQ)
1014 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
1015 for (i = hatchcount; i > 0; i--) {
1016 if (!enexto(&cc, x, y, &mons[mnum])
1017 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
1019 /* tame if your own egg hatches while you're on the
1020 same dungeon level, or any dragon egg which hatches
1021 while it's in your inventory */
1022 if ((yours && !silent)
1023 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
1024 if (tamedog(mon, (struct obj *) 0)) {
1025 if (carried(egg) && mon->data->mlet != S_DRAGON)
1029 if (mvitals[mnum].mvflags & G_EXTINCT)
1030 break; /* just made last one */
1031 mon2 = mon; /* in case makemon() fails on 2nd egg */
1036 egg->quan -= (long) hatchcount;
1040 * We could possibly hatch while migrating, but the code isn't
1043 } else if (obj->where == OBJ_MIGRATING) {
1045 * We can do several things. The first ones that come to
1047 * + Create the hatched monster then place it on the migrating
1048 * mons list. This is tough because all makemon() is made
1049 * to place the monster as well. Makemon() also doesn't lend
1050 * itself well to splitting off a "not yet placed" subroutine.
1051 * + Mark the egg as hatched, then place the monster when we
1052 * place the migrating objects.
1053 * + Or just kill any egg which gets sent to another level.
1054 * Falling is the usual reason such transportation occurs.
1056 cansee_hatchspot = FALSE;
1062 char monnambuf[BUFSZ], carriedby[BUFSZ];
1063 boolean siblings = (hatchcount > 1), redraw = FALSE;
1065 if (cansee_hatchspot) {
1066 /* [bug? m_monnam() yields accurate monster type
1067 regardless of hallucination] */
1069 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
1070 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
1072 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
1075 /* we don't learn the egg type here because learning
1076 an egg type requires either seeing the egg hatch
1077 or being familiar with the egg already,
1078 as well as being able to see the resulting
1079 monster, checked below
1082 switch (egg->where) {
1084 knows_egg = TRUE; /* true even if you are blind */
1085 if (!cansee_hatchspot)
1087 You_feel("%s %s from your pack!", something,
1088 locomotion(mon->data, "drop"));
1090 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
1091 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1095 You_see("%s %s out of your pack!", monnambuf,
1096 locomotion(mon->data, "drop"));
1098 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
1099 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1103 pline("%s cries sound like \"%s%s\"",
1104 siblings ? "Their" : "Its",
1105 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
1107 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
1108 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
1110 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
1112 verbalize("Gleep!"); /* Mything eggs :-) */
1114 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
1120 if (cansee_hatchspot) {
1123 You_see("%s hatch.", monnambuf);
1125 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
1126 redraw = TRUE; /* update egg's map location */
1131 if (cansee_hatchspot) {
1132 /* egg carrying monster might be invisible */
1135 && (!mon2->wormno || cansee(mon2->mx, mon2->my))) {
1137 Sprintf(carriedby, "%s pack",
1138 s_suffix(a_monnam(mon2)));
1140 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
1144 } else if (is_pool(mon->mx, mon->my)) {
1146 Strcpy(carriedby, "empty water");
1148 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
1151 Strcpy(carriedby, "thin air");
1153 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
1156 You_see("%s %s out of %s!", monnambuf,
1157 locomotion(mon->data, "drop"), carriedby);
1159 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
1160 locomotion(mon->data, "
\97\8e\82¿
\82é"));
1169 impossible("egg hatched where? (%d)", (int) egg->where);
1173 if (cansee_hatchspot && knows_egg)
1174 learn_egg_type(mnum);
1176 if (egg->quan > 0) {
1177 /* still some eggs left */
1178 /* Instead of ordinary egg timeout use a short one */
1179 attach_egg_hatch_timeout(egg, (long) rnd(12));
1180 } else if (carried(egg)) {
1183 /* free egg here because we use it above */
1184 obj_extract_self(egg);
1185 obfree(egg, (struct obj *) 0);
1192 /* Learn to recognize eggs of the given type. */
1194 learn_egg_type(mnum)
1197 /* baby monsters hatch from grown-up eggs */
1198 mnum = little_to_big(mnum);
1199 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
1200 /* we might have just learned about other eggs being carried */
1204 /* Attach a fig_transform timeout to the given figurine. */
1206 attach_fig_transform_timeout(figurine)
1207 struct obj *figurine;
1211 /* stop previous timer, if any */
1212 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
1215 * Decide when to transform the figurine.
1217 i = rnd(9000) + 200;
1218 /* figurine will transform */
1219 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
1220 obj_to_any(figurine));
1223 /* give a fumble message */
1227 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
1230 boolean on_foot = TRUE;
1234 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
1237 if (otmp && on_foot) { /* trip over something in particular */
1239 If there is only one item, it will have just been named
1240 during the move, so refer to by via pronoun; otherwise,
1241 if the top item has been or can be seen, refer to it by
1242 name; if not, look for rocks to trip over; trip over
1243 anonymous "something" if there aren't any rocks.
1246 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1247 ? ((otmp->quan == 1L) ? "it"
1248 : Hallucination ? "they" : "them")
1249 : (otmp->dknown || !Blind)
1251 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1253 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
1255 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1257 : (otmp->dknown || !Blind)
1259 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1263 if (Hallucination) {
1264 what = strcpy(buf, what);
1265 buf[0] = highc(buf[0]);
1267 pline("Egads! %s bite%s your %s!", what,
1268 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
1270 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
1274 You("trip over %s.", what);
1276 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
1278 if (!uarmf && otmp->otyp == CORPSE
1279 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
1281 Sprintf(killer.name, "tripping over %s corpse",
1282 an(mons[otmp->corpsenm].mname));
1284 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
1285 mons[otmp->corpsenm].mname);
1287 instapetrify(killer.name);
1289 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
1291 pline("%s %s%s on the ice.",
1292 u.usteed ? upstart(x_monnam(u.usteed,
1293 (has_mname(u.usteed)) ? ARTICLE_NONE
1295 (char *) 0, SUPPRESS_SADDLE, FALSE))
1297 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
1299 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
1300 u.usteed ? upstart(x_monnam(u.usteed,
1301 (has_mname(u.usteed)) ? ARTICLE_NONE
1303 (char *) 0, SUPPRESS_SADDLE, FALSE))
1311 You("trip over your own %s.",
1312 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
1314 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
1315 Hallucination ? "
\95I" : body_part(FOOT));
1321 Hallucination ? "on a banana peel" : "and nearly fall");
1323 You("%s
\81D", Hallucination ?
1324 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
1331 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
1337 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
1344 Your("%s slip out of the stirrups.",
1345 makeplural(body_part(FOOT)));
1347 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1352 You("let go of the reins.");
1354 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1358 You("bang into the saddle-horn.");
1360 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1364 You("slide to one side of the saddle.");
1366 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1369 dismount_steed(DISMOUNT_FELL);
1374 /* Print a lamp flicker message with tailer. */
1376 see_lamp_flicker(obj, tailer)
1380 switch (obj->where) {
1384 pline("%s flickers%s.", Yname2(obj), tailer);
1386 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1390 You_see("%s flicker%s.", an(xname(obj)), tailer);
1392 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1397 /* Print a dimming message for brass lanterns. */
1399 lantern_message(obj)
1402 /* from adventure */
1403 switch (obj->where) {
1406 Your("lantern is getting dim.");
1408 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1411 pline("Batteries have not been invented yet.");
1413 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1417 You_see("a lantern getting dim.");
1419 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1423 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1425 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1431 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1432 * See begin_burn() for meanings of obj->age and obj->spe.
1435 burn_object(arg, timeout)
1439 struct obj *obj = arg->a_obj;
1441 boolean canseeit, many, menorah, need_newsym, need_invupdate;
1443 boolean canseeit, menorah, need_newsym, need_invupdate;
1448 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1450 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1453 /* timeout while away */
1454 if (timeout != monstermoves) {
1455 long how_long = monstermoves - timeout;
1457 if (how_long >= obj->age) {
1459 end_burn(obj, FALSE);
1462 obj->spe = 0; /* no more candles */
1463 obj->owt = weight(obj);
1464 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1465 /* get rid of candles and burning oil potions;
1466 we know this object isn't carried by hero,
1467 nor is it migrating */
1468 obj_extract_self(obj);
1469 obfree(obj, (struct obj *) 0);
1470 obj = (struct obj *) 0;
1474 obj->age -= how_long;
1475 begin_burn(obj, TRUE);
1480 /* only interested in INVENT, FLOOR, and MINVENT */
1481 if (get_obj_location(obj, &x, &y, 0)) {
1482 canseeit = !Blind && cansee(x, y);
1483 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1484 (void) Shk_Your(whose, obj);
1488 need_newsym = need_invupdate = FALSE;
1490 /* obj->age is the age remaining at this point. */
1491 switch (obj->otyp) {
1493 /* this should only be called when we run out */
1495 switch (obj->where) {
1497 need_invupdate = TRUE;
1501 pline("%spotion of oil has burnt away.", whose);
1503 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1507 You_see("a burning potion of oil go out.");
1509 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1514 end_burn(obj, FALSE); /* turn off light source */
1518 /* clear migrating obj's destination code before obfree
1519 to avoid false complaint of deleting worn item */
1520 if (obj->where == OBJ_MIGRATING)
1521 obj->owornmask = 0L;
1522 obj_extract_self(obj);
1523 obfree(obj, (struct obj *) 0);
1525 obj = (struct obj *) 0;
1530 switch ((int) obj->age) {
1535 if (obj->otyp == BRASS_LANTERN)
1536 lantern_message(obj);
1538 see_lamp_flicker(obj,
1540 obj->age == 50L ? " considerably" : "");
1542 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1548 if (obj->otyp == BRASS_LANTERN)
1549 lantern_message(obj);
1551 switch (obj->where) {
1555 pline("%s seems about to go out.", Yname2(obj));
1557 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1561 You_see("%s about to go out.", an(xname(obj)));
1563 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1571 /* even if blind you'll know if holding it */
1572 if (canseeit || obj->where == OBJ_INVENT) {
1573 switch (obj->where) {
1575 need_invupdate = TRUE;
1578 if (obj->otyp == BRASS_LANTERN)
1580 pline("%slantern has run out of power.", whose);
1582 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1585 pline("%s has gone out.", Yname2(obj));
1587 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1590 if (obj->otyp == BRASS_LANTERN)
1592 You_see("a lantern run out of power.");
1594 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1597 You_see("%s go out.", an(xname(obj)));
1599 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1603 end_burn(obj, FALSE);
1608 * Someone added fuel to the lamp while it was
1609 * lit. Just fall through and let begin burn
1610 * handle the new age.
1616 begin_burn(obj, TRUE);
1620 case CANDELABRUM_OF_INVOCATION:
1626 switch (obj->where) {
1630 pline("%s%scandle%s getting short.", whose,
1631 menorah ? "candelabrum's " : "",
1632 many ? "s are" : " is");
1634 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1635 menorah ? "
\90C
\91ä
\82Ì" : "");
1640 You_see("%scandle%s getting short.",
1641 menorah ? "a candelabrum's " : many ? "some "
1645 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1646 menorah ? "
\90C
\91ä
\82Ì" : "");
1654 switch (obj->where) {
1658 pline("%s%scandle%s flame%s flicker%s low!", whose,
1659 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1660 many ? "s" : "", many ? "" : "s");
1662 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1663 menorah ? "
\90C
\91ä
\82Ì" : "");
1668 You_see("%scandle%s flame%s flicker low!",
1669 menorah ? "a candelabrum's " : many ? "some "
1671 many ? "s'" : "'s", many ? "s" : "");
1673 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1674 menorah ? "
\90C
\91ä
\82Ì" : "");
1681 /* we know even if blind and in our inventory */
1682 if (canseeit || obj->where == OBJ_INVENT) {
1684 switch (obj->where) {
1686 need_invupdate = TRUE;
1690 pline("%scandelabrum's flame%s.", whose,
1691 many ? "s die" : " dies");
1693 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1698 You_see("a candelabrum's flame%s die.",
1701 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1706 switch (obj->where) {
1708 /* no need_invupdate for update_inventory() necessary;
1709 useupall() -> freeinv() handles it */
1713 pline("%s %s consumed!", Yname2(obj),
1714 many ? "are" : "is");
1716 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1721 You see some wax candles consumed!
1722 You see a wax candle consumed!
1725 You_see("%s%s consumed!", many ? "some " : "",
1726 many ? xname(obj) : an(xname(obj)));
1728 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1737 ? (many ? "They shriek!" : "It shrieks!")
1738 : Blind ? "" : (many ? "Their flames die."
1739 : "Its flame dies."));
1741 pline(Hallucination ? "
\82»
\82ê
\82Í
\8bà
\90Ø
\82è
\90º
\82ð
\82 \82°
\82½
\81I"
1743 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1747 end_burn(obj, FALSE);
1751 obj->owt = weight(obj);
1756 /* clear migrating obj's destination code
1757 so obfree won't think this item is worn */
1758 if (obj->where == OBJ_MIGRATING)
1759 obj->owornmask = 0L;
1760 obj_extract_self(obj);
1761 obfree(obj, (struct obj *) 0);
1763 obj = (struct obj *) 0;
1765 break; /* case [age ==] 0 */
1769 * Someone added fuel (candles) to the menorah while
1770 * it was lit. Just fall through and let begin burn
1771 * handle the new age.
1776 if (obj && obj->age)
1777 begin_burn(obj, TRUE);
1778 break; /* case [otyp ==] candelabrum|tallow_candle|wax_candle */
1781 impossible("burn_object: unexpected obj %s", xname(obj));
1791 * Start a burn timeout on the given object. If not "already lit" then
1792 * create a light source for the vision system. There had better not
1793 * be a burn already running on the object.
1795 * Magic lamps stay lit as long as there's a genie inside, so don't start
1799 * potions of oil, lamps & candles:
1800 * age = # of turns of fuel left
1804 * spe = 0 not lightable, 1 lightable forever
1806 * age = # of turns of fuel left
1807 * spe = # of candles
1809 * Once the burn begins, the age will be set to the amount of fuel
1810 * remaining _once_the_burn_finishes_. If the burn is terminated
1811 * early then fuel is added back.
1813 * This use of age differs from the use of age for corpses and eggs.
1814 * For the latter items, age is when the object was created, so we
1815 * know when it becomes "bad".
1817 * This is a "silent" routine - it should not print anything out.
1820 begin_burn(obj, already_lit)
1822 boolean already_lit;
1826 boolean do_timer = TRUE;
1828 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1831 switch (obj->otyp) {
1840 turns = (3L * turns + 2L) / 4L;
1841 radius = 1; /* very dim light */
1846 /* magic times are 150, 100, 50, 25, and 0 */
1847 if (obj->age > 150L)
1848 turns = obj->age - 150L;
1849 else if (obj->age > 100L)
1850 turns = obj->age - 100L;
1851 else if (obj->age > 50L)
1852 turns = obj->age - 50L;
1853 else if (obj->age > 25L)
1854 turns = obj->age - 25L;
1859 case CANDELABRUM_OF_INVOCATION:
1862 /* magic times are 75, 15, and 0 */
1864 turns = obj->age - 75L;
1865 else if (obj->age > 15L)
1866 turns = obj->age - 15L;
1869 radius = candle_light_range(obj);
1873 /* [ALI] Support artifact light sources */
1874 if (artifact_light(obj)) {
1877 radius = arti_light_radius(obj);
1879 impossible("begin burn: unexpected %s", xname(obj));
1886 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1889 if (carried(obj) && !already_lit)
1895 if (carried(obj) && !already_lit)
1899 if (obj->lamplit && !already_lit) {
1902 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1903 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1905 impossible("begin_burn: can't get obj position");
1910 * Stop a burn timeout on the given object if timer attached. Darken
1914 end_burn(obj, timer_attached)
1916 boolean timer_attached;
1918 if (!obj->lamplit) {
1919 impossible("end_burn: obj %s not lit", xname(obj));
1923 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1924 timer_attached = FALSE;
1926 if (!timer_attached) {
1927 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1928 del_light_source(LS_OBJECT, obj_to_any(obj));
1930 if (obj->where == OBJ_INVENT)
1932 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1933 impossible("end_burn: obj %s not timed!", xname(obj));
1937 * Cleanup a burning object if timer stopped.
1940 cleanup_burn(arg, expire_time)
1944 struct obj *obj = arg->a_obj;
1945 if (!obj->lamplit) {
1946 impossible("cleanup_burn: obj %s not lit", xname(obj));
1950 del_light_source(LS_OBJECT, obj_to_any(obj));
1952 /* restore unused time */
1953 obj->age += expire_time - monstermoves;
1957 if (obj->where == OBJ_INVENT)
1969 /* no lightning if not the air level or too often, even then */
1970 if (!Is_airlevel(&u.uz) || rn2(8))
1973 /* the number of strikes is 8-log2(nstrike) */
1974 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1979 } while (++count < 100 && levl[x][y].typ != CLOUD);
1984 if (dirx != 0 || diry != 0)
1985 buzz(-15, /* "monster" LIGHTNING spell */
1986 8, x, y, dirx, diry);
1990 if (levl[u.ux][u.uy].typ == CLOUD) {
1991 /* Inside a cloud during a thunder storm is deafening. */
1992 /* Even if already deaf, we sense the thunder's vibrations. */
1994 pline("Kaboom!!! Boom!! Boom!!");
1996 pline("
\83s
\83J
\83b
\81I
\81I
\83S
\83\8d\83S
\83\8d\83S
\83\8d\83S
\83\8d\81I
\81I
\83h
\81[
\83\93\81I");
1997 incr_itimeout(&HDeaf, rn1(20, 30));
1998 context.botl = TRUE;
1999 if (!u.uinvulnerable) {
2003 multi_reason = "hiding from thunderstorm";
2005 multi_reason = "
\97\8b\82Ì
\97\92\82ð
\94ð
\82¯
\82Ä
\82¢
\82é
\8e\9e\82É";
2010 You_hear("a rumbling noise.");
2012 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
2015 /* -------------------------------------------------------------------------
2018 * Generic Timeout Functions.
2023 * boolean start_timer(long timeout,short kind,short func_index,
2025 * Start a timer of kind 'kind' that will expire at time
2026 * monstermoves+'timeout'. Call the function at 'func_index'
2027 * in the timeout table using argument 'arg'. Return TRUE if
2028 * a timer was started. This places the timer on a list ordered
2029 * "sooner" to "later". If an object, increment the object's
2032 * long stop_timer(short func_index, anything *arg)
2033 * Stop a timer specified by the (func_index, arg) pair. This
2034 * assumes that such a pair is unique. Return the time the
2035 * timer would have gone off. If no timer is found, return 0.
2036 * If an object, decrement the object's timer count.
2038 * long peek_timer(short func_index, anything *arg)
2039 * Return time specified timer will go off (0 if no such timer).
2041 * void run_timers(void)
2042 * Call timers that have timed out.
2045 * void save_timers(int fd, int mode, int range)
2046 * Save all timers of range 'range'. Range is either global
2047 * or local. Global timers follow game play, local timers
2048 * are saved with a level. Object and monster timers are
2049 * saved using their respective id's instead of pointers.
2051 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
2052 * Restore timers of range 'range'. If from a ghost pile,
2053 * adjust the timeout by 'adjust'. The object and monster
2054 * ids are not restored until later.
2056 * void relink_timers(boolean ghostly)
2057 * Relink all object and monster timers that had been saved
2058 * using their object's or monster's id number.
2061 * void obj_move_timers(struct obj *src, struct obj *dest)
2062 * Reassign all timers from src to dest.
2064 * void obj_split_timers(struct obj *src, struct obj *dest)
2065 * Duplicate all timers assigned to src and attach them to dest.
2067 * void obj_stop_timers(struct obj *obj)
2068 * Stop all timers attached to obj.
2070 * boolean obj_has_timer(struct obj *object, short timer_type)
2071 * Check whether object has a timer of type timer_type.
2074 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
2075 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
2076 STATIC_DCL void FDECL(insert_timer, (timer_element *));
2077 STATIC_DCL timer_element *FDECL(remove_timer,
2078 (timer_element **, SHORT_P, ANY_P *));
2079 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
2080 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
2081 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
2082 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
2084 /* ordered timer list */
2085 static timer_element *timer_base; /* "active" */
2086 static unsigned long timer_id = 1;
2088 /* If defined, then include names when printing out the timer queue */
2089 #define VERBOSE_TIMER
2092 timeout_proc f, cleanup;
2093 #ifdef VERBOSE_TIMER
2095 #define TTAB(a, b, c) \
2100 #define TTAB(a, b, c) \
2107 /* table of timeout functions */
2108 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
2109 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
2110 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
2111 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
2112 TTAB(burn_object, cleanup_burn, "burn_object"),
2113 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
2114 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
2115 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
2119 STATIC_OVL const char *
2137 print_queue(win, base)
2139 timer_element *base;
2141 timer_element *curr;
2145 putstr(win, 0, " <empty>");
2147 putstr(win, 0, "timeout id kind call");
2148 for (curr = base; curr; curr = curr->next) {
2149 #ifdef VERBOSE_TIMER
2150 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
2151 curr->tid, kind_name(curr->kind),
2152 timeout_funcs[curr->func_index].name,
2153 fmt_ptr((genericptr_t) curr->arg.a_void));
2155 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
2156 curr->tid, kind_name(curr->kind), curr->func_index,
2157 fmt_ptr((genericptr_t) curr->arg.a_void));
2159 putstr(win, 0, buf);
2169 const char *propname;
2171 int i, p, count, longestlen, ln, specindx = 0;
2173 win = create_nhwindow(NHW_MENU); /* corner text window */
2177 Sprintf(buf, "Current time = %ld.", monstermoves);
2178 putstr(win, 0, buf);
2180 putstr(win, 0, "Active timeout queue:");
2182 print_queue(win, timer_base);
2185 * check every one; the majority can't obtain temporary timeouts in
2186 * normal play but those can be forced via the #wizintrinsic command.
2188 count = longestlen = 0;
2189 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2190 p = propertynames[i].prop_num;
2191 intrinsic = u.uprops[p].intrinsic;
2192 if (intrinsic & TIMEOUT) {
2194 if ((ln = (int) strlen(propname)) > longestlen)
2197 if (specindx == 0 && p == FIRE_RES)
2202 putstr(win, 0, "No timed properties.");
2204 putstr(win, 0, "Timed properties:");
2206 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2207 p = propertynames[i].prop_num;
2208 intrinsic = u.uprops[p].intrinsic;
2209 if (intrinsic & TIMEOUT) {
2210 if (specindx > 0 && i >= specindx) {
2211 putstr(win, 0, " -- settable via #wizinstrinc only --");
2214 /* timeout value can be up to 16777215 (0x00ffffff) but
2215 width of 4 digits should result in values lining up
2216 almost all the time (if/when they don't, it won't
2217 look nice but the information will still be accurate) */
2218 Sprintf(buf, " %*s %4ld", -longestlen, propname,
2219 (intrinsic & TIMEOUT));
2220 putstr(win, 0, buf);
2224 display_nhwindow(win, FALSE);
2225 destroy_nhwindow(win);
2231 timer_sanity_check()
2233 timer_element *curr;
2235 /* this should be much more complete */
2236 for (curr = timer_base; curr; curr = curr->next)
2237 if (curr->kind == TIMER_OBJECT) {
2238 struct obj *obj = curr->arg.a_obj;
2240 if (obj->timed == 0) {
2241 impossible("timer sanity: untimed obj %s, timer %ld",
2242 fmt_ptr((genericptr_t) obj), curr->tid);
2248 * Pick off timeout elements from the global queue and call their functions.
2249 * Do this until their time is less than or equal to the move count.
2254 timer_element *curr;
2257 * Always use the first element. Elements may be added or deleted at
2258 * any time. The list is ordered, we are done when the first element
2261 while (timer_base && timer_base->timeout <= monstermoves) {
2263 timer_base = curr->next;
2265 if (curr->kind == TIMER_OBJECT)
2266 (curr->arg.a_obj)->timed--;
2267 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
2268 free((genericptr_t) curr);
2273 * Start a timer. Return TRUE if successful.
2276 start_timer(when, kind, func_index, arg)
2282 timer_element *gnu, *dup;
2284 if (kind < 0 || kind >= NUM_TIMER_KINDS
2285 || func_index < 0 || func_index >= NUM_TIME_FUNCS)
2286 panic("start_timer (%s: %d)", kind_name(kind), (int) func_index);
2288 /* fail if <arg> already has a <func_index> timer running */
2289 for (dup = timer_base; dup; dup = dup->next)
2290 if (dup->kind == kind
2291 && dup->func_index == func_index
2292 && dup->arg.a_void == arg->a_void)
2297 #ifdef VERBOSE_TIMER
2298 Sprintf(idbuf, "%s timer", timeout_funcs[func_index].name);
2300 Sprintf(idbuf, "%s timer (%d)", kind_name(kind), (int) func_index);
2302 impossible("Attempted to start duplicate %s, aborted.", idbuf);
2306 gnu = (timer_element *) alloc(sizeof *gnu);
2307 (void) memset((genericptr_t) gnu, 0, sizeof *gnu);
2309 gnu->tid = timer_id++;
2310 gnu->timeout = monstermoves + when;
2312 gnu->needs_fixup = 0;
2313 gnu->func_index = func_index;
2317 if (kind == TIMER_OBJECT) /* increment object's timed count */
2318 (arg->a_obj)->timed++;
2324 * Remove the timer from the current list and free it up. Return the time
2325 * remaining until it would have gone off, 0 if not found.
2328 stop_timer(func_index, arg)
2332 timer_element *doomed;
2335 doomed = remove_timer(&timer_base, func_index, arg);
2338 timeout = doomed->timeout;
2339 if (doomed->kind == TIMER_OBJECT)
2340 (arg->a_obj)->timed--;
2341 if (timeout_funcs[doomed->func_index].cleanup)
2342 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
2343 free((genericptr_t) doomed);
2344 return (timeout - monstermoves);
2350 * Find the timeout of specified timer; return 0 if none.
2353 peek_timer(type, arg)
2357 timer_element *curr;
2359 for (curr = timer_base; curr; curr = curr->next) {
2360 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
2361 return curr->timeout;
2367 * Move all object timers from src to dest, leaving src untimed.
2370 obj_move_timers(src, dest)
2371 struct obj *src, *dest;
2374 timer_element *curr;
2376 for (count = 0, curr = timer_base; curr; curr = curr->next)
2377 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2378 curr->arg.a_obj = dest;
2382 if (count != src->timed)
2383 panic("obj_move_timers");
2388 * Find all object timers and duplicate them for the new object "dest".
2391 obj_split_timers(src, dest)
2392 struct obj *src, *dest;
2394 timer_element *curr, *next_timer = 0;
2396 for (curr = timer_base; curr; curr = next_timer) {
2397 next_timer = curr->next; /* things may be inserted */
2398 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2399 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
2400 curr->func_index, obj_to_any(dest));
2406 * Stop all timers attached to this object. We can get away with this because
2407 * all object pointers are unique.
2410 obj_stop_timers(obj)
2413 timer_element *curr, *prev, *next_timer = 0;
2415 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2416 next_timer = curr->next;
2417 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
2419 prev->next = curr->next;
2421 timer_base = curr->next;
2422 if (timeout_funcs[curr->func_index].cleanup)
2423 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2425 free((genericptr_t) curr);
2434 * Check whether object has a timer of type timer_type.
2437 obj_has_timer(object, timer_type)
2441 long timeout = peek_timer(timer_type, obj_to_any(object));
2443 return (boolean) (timeout != 0L);
2447 * Stop all timers of index func_index at this spot.
2451 spot_stop_timers(x, y, func_index)
2455 timer_element *curr, *prev, *next_timer = 0;
2456 long where = (((long) x << 16) | ((long) y));
2458 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2459 next_timer = curr->next;
2460 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2461 && curr->arg.a_long == where) {
2463 prev->next = curr->next;
2465 timer_base = curr->next;
2466 if (timeout_funcs[curr->func_index].cleanup)
2467 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2469 free((genericptr_t) curr);
2477 * When is the spot timer of type func_index going to expire?
2478 * Returns 0L if no such timer.
2481 spot_time_expires(x, y, func_index)
2485 timer_element *curr;
2486 long where = (((long) x << 16) | ((long) y));
2488 for (curr = timer_base; curr; curr = curr->next) {
2489 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2490 && curr->arg.a_long == where)
2491 return curr->timeout;
2497 spot_time_left(x, y, func_index)
2501 long expires = spot_time_expires(x, y, func_index);
2502 return (expires > 0L) ? expires - monstermoves : 0L;
2505 /* Insert timer into the global queue */
2510 timer_element *curr, *prev;
2512 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2513 if (curr->timeout >= gnu->timeout)
2523 STATIC_OVL timer_element *
2524 remove_timer(base, func_index, arg)
2525 timer_element **base;
2529 timer_element *prev, *curr;
2531 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2532 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2537 prev->next = curr->next;
2546 write_timer(fd, timer)
2548 timer_element *timer;
2553 switch (timer->kind) {
2556 /* assume no pointers in arg */
2557 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2561 if (timer->needs_fixup)
2562 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2564 /* replace object pointer with id */
2565 arg_save.a_obj = timer->arg.a_obj;
2566 timer->arg = zeroany;
2567 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2568 timer->needs_fixup = 1;
2569 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2570 timer->arg.a_obj = arg_save.a_obj;
2571 timer->needs_fixup = 0;
2576 if (timer->needs_fixup)
2577 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2579 /* replace monster pointer with id */
2580 arg_save.a_monst = timer->arg.a_monst;
2581 timer->arg = zeroany;
2582 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2583 timer->needs_fixup = 1;
2584 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2585 timer->arg.a_monst = arg_save.a_monst;
2586 timer->needs_fixup = 0;
2591 panic("write_timer");
2597 * Return TRUE if the object will stay on the level when the level is
2604 switch (obj->where) {
2612 return obj_is_local(obj->ocontainer);
2614 return mon_is_local(obj->ocarry);
2616 panic("obj_is_local");
2621 * Return TRUE if the given monster will stay on the level when the
2630 for (curr = migrating_mons; curr; curr = curr->nmon)
2633 /* `mydogs' is used during level changes, never saved and restored */
2634 for (curr = mydogs; curr; curr = curr->nmon)
2641 * Return TRUE if the timer is attached to something that will stay on the
2642 * level when the level is saved.
2645 timer_is_local(timer)
2646 timer_element *timer;
2648 switch (timer->kind) {
2654 return obj_is_local(timer->arg.a_obj);
2656 return mon_is_local(timer->arg.a_monst);
2658 panic("timer_is_local");
2663 * Part of the save routine. Count up the number of timers that would
2664 * be written. If write_it is true, actually write the timer.
2667 maybe_write_timer(fd, range, write_it)
2672 timer_element *curr;
2674 for (curr = timer_base; curr; curr = curr->next) {
2675 if (range == RANGE_GLOBAL) {
2678 if (!timer_is_local(curr)) {
2681 write_timer(fd, curr);
2687 if (timer_is_local(curr)) {
2690 write_timer(fd, curr);
2699 * Save part of the timer list. The parameter 'range' specifies either
2700 * global or level timers to save. The timer ID is saved with the global
2704 * + timeouts that follow the hero (global)
2705 * + timeouts that follow obj & monst that are migrating
2708 * + timeouts that are level specific (e.g. storms)
2709 * + timeouts that stay with the level (obj & monst)
2712 save_timers(fd, mode, range)
2713 int fd, mode, range;
2715 timer_element *curr, *prev, *next_timer = 0;
2718 if (perform_bwrite(mode)) {
2719 if (range == RANGE_GLOBAL)
2720 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2722 count = maybe_write_timer(fd, range, FALSE);
2723 bwrite(fd, (genericptr_t) &count, sizeof count);
2724 (void) maybe_write_timer(fd, range, TRUE);
2727 if (release_data(mode)) {
2728 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2729 next_timer = curr->next; /* in case curr is removed */
2731 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2733 prev->next = curr->next;
2735 timer_base = curr->next;
2736 free((genericptr_t) curr);
2737 /* prev stays the same */
2746 * Pull in the structures from disk, but don't recalculate the object and
2750 restore_timers(fd, range, ghostly, adjust)
2752 boolean ghostly; /* restoring from a ghost level */
2753 long adjust; /* how much to adjust timeout */
2756 timer_element *curr;
2758 if (range == RANGE_GLOBAL)
2759 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2761 /* restore elements */
2762 mread(fd, (genericptr_t) &count, sizeof count);
2763 while (count-- > 0) {
2764 curr = (timer_element *) alloc(sizeof(timer_element));
2765 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2767 curr->timeout += adjust;
2772 /* to support '#stats' wizard-mode command */
2774 timer_stats(hdrfmt, hdrbuf, count, size)
2781 Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
2782 *count = *size = 0L;
2783 for (te = timer_base; te; te = te->next) {
2785 *size += (long) sizeof *te;
2789 /* reset all timers that are marked for reseting */
2791 relink_timers(ghostly)
2794 timer_element *curr;
2797 for (curr = timer_base; curr; curr = curr->next) {
2798 if (curr->needs_fixup) {
2799 if (curr->kind == TIMER_OBJECT) {
2801 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2802 panic("relink_timers 1");
2804 nid = curr->arg.a_uint;
2805 curr->arg.a_obj = find_oid(nid);
2806 if (!curr->arg.a_obj)
2807 panic("cant find o_id %d", nid);
2808 curr->needs_fixup = 0;
2809 } else if (curr->kind == TIMER_MONSTER) {
2810 panic("relink_timers: no monster timer implemented");
2812 panic("relink_timers 2");