1 /* NetHack 3.6 timeout.c $NHDT-Date: 1545182148 2018/12/19 01:15:48 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.89 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
9 /* JNetHack may be freely redistributed. See license for details. */
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(slip_or_trip);
21 STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *));
22 STATIC_DCL void FDECL(lantern_message, (struct obj *));
23 STATIC_DCL void FDECL(cleanup_burn, (ANY_P *, long));
25 /* used by wizard mode #timeout and #wizintrinsic; order by 'interest'
26 for timeout countdown, where most won't occur in normal play */
27 /*JP
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\82Å
\82µ
\82©
\8eg
\82í
\82ê
\82È
\82¢
\82æ
\82¤
\82È
\82Ì
\82Å
\96|
\96ó
\82µ
\82È
\82¢ */
28 const struct propname {
30 const char *prop_name;
32 { INVULNERABLE, "invulnerable" },
33 { STONED, "petrifying" },
34 { SLIMED, "becoming slime" },
35 { STRANGLED, "strangling" },
36 { SICK, "fatally sick" },
37 { STUNNED, "stunned" },
38 { CONFUSION, "confused" },
39 { HALLUC, "hallucinating" },
40 { BLINDED, "blinded" },
42 { VOMITING, "vomiting" },
43 { GLIB, "slippery fingers" },
44 { WOUNDED_LEGS, "wounded legs" },
46 { TELEPORT, "teleporting" },
47 { POLYMORPH, "polymorphing" },
48 { LEVITATION, "levitating" },
49 { FAST, "very fast" }, /* timed 'FAST' is very fast */
50 { CLAIRVOYANT, "clairvoyant" },
51 { DETECT_MONSTERS, "monster detection" },
52 { SEE_INVIS, "see invisible" },
53 { INVIS, "invisible" },
54 /* properties beyond here don't have timed values during normal play,
55 so there's not much point in trying to order them sensibly;
56 they're either on or off based on equipment, role, actions, &c */
57 { FIRE_RES, "fire resistance" },
58 { COLD_RES, "cold resistance" },
59 { SLEEP_RES, "sleep resistance" },
60 { DISINT_RES, "disintegration resistance" },
61 { SHOCK_RES, "shock resistance" },
62 { POISON_RES, "poison resistance" },
63 { ACID_RES, "acid resistance" },
64 { STONE_RES, "stoning resistance" },
65 { DRAIN_RES, "drain resistance" },
66 { SICK_RES, "sickness resistance" },
67 { ANTIMAGIC, "magic resistance" },
68 { HALLUC_RES, "hallucination resistance" },
69 { FUMBLING, "fumbling" },
70 { HUNGER, "voracious hunger" },
71 { TELEPAT, "telepathic" },
72 { WARNING, "warning" },
73 { WARN_OF_MON, "warn: monster type or class" },
74 { WARN_UNDEAD, "warn: undead" },
75 { SEARCHING, "searching" },
76 { INFRAVISION, "infravision" },
77 { ADORNED, "adorned (+/- Cha)" },
78 { DISPLACED, "displaced" },
79 { STEALTH, "stealthy" },
80 { AGGRAVATE_MONSTER, "monster aggravation" },
81 { CONFLICT, "conflict" },
82 { JUMPING, "jumping" },
83 { TELEPORT_CONTROL, "teleport control" },
85 { WWALKING, "water walking" },
86 { SWIMMING, "swimming" },
87 { MAGICAL_BREATHING, "magical breathing" },
88 { PASSES_WALLS, "pass thru walls" },
89 { SLOW_DIGESTION, "slow digestion" },
90 { HALF_SPDAM, "half spell damage" },
91 { HALF_PHDAM, "half physical damage" },
92 { REGENERATION, "HP regeneration" },
93 { ENERGY_REGENERATION, "energy regeneration" },
94 { PROTECTION, "extra protection" },
95 { PROT_FROM_SHAPE_CHANGERS, "protection from shape changers" },
96 { POLYMORPH_CONTROL, "polymorph control" },
97 { UNCHANGING, "unchanging" },
98 { REFLECTING, "reflecting" },
99 { FREE_ACTION, "free action" },
100 { FIXED_ABIL, "fixed abilites" },
101 { LIFESAVED, "life will be saved" },
105 /* He is being petrified - dialogue by inmet!tower */
106 static NEARDATA const char *const stoned_texts[] = {
108 "You are slowing down.", /* 5 */
109 "Your limbs are stiffening.", /* 4 */
110 "Your limbs have turned to stone.", /* 3 */
111 "You have turned to stone.", /* 2 */
112 "You are a statue." /* 1 */
114 "
\82 \82È
\82½
\82Í
\82Ì
\82ë
\82
\82È
\82Á
\82½
\81D", /* 5 */
115 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\8dd
\92¼
\82µ
\82½
\81D", /* 4 */
116 "
\82 \82È
\82½
\82Ì
\8eè
\91«
\82Í
\90Î
\89»
\82µ
\82½
\81D", /* 3 */
117 "
\82 \82È
\82½
\82Í
\90Î
\82É
\82È
\82Á
\82½
\81D", /* 2 */
118 "
\82 \82È
\82½
\82Í
\92¤
\91\9c\82É
\82È
\82Á
\82½
\81D" /* 1 */
125 register long i = (Stoned & TIMEOUT);
127 if (i > 0L && i <= SIZE(stoned_texts)) {
130 Strcpy(buf, stoned_texts[SIZE(stoned_texts) - i]);
132 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
133 (void) strsubst(buf, "limbs", "extremities");
135 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
136 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
141 case 5: /* slowing down */
146 case 4: /* limbs stiffening */
147 /* just one move left to save oneself so quit fiddling around;
148 don't stop attempt to eat tin--might be lizard or acidic */
154 case 3: /* limbs turned to stone */
156 nomul(-3); /* can't move anymore */
158 multi_reason = "getting stoned";
160 multi_reason = "
\90Î
\89»
\82µ
\82Â
\82Â
\82 \82é
\8e\9e\82É";
161 nomovemsg = You_can_move_again; /* not unconscious */
162 /* "your limbs have turned to stone" so terminate wounded legs */
163 if (Wounded_legs && !u.usteed)
166 case 2: /* turned to stone */
167 if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
168 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
169 /* if also vomiting or turning into slime, stop those (no messages) */
171 make_vomiting(0L, FALSE);
173 make_slimed(0L, (char *) 0);
178 exercise(A_DEX, FALSE);
181 /* hero is getting sicker and sicker prior to vomiting */
182 static NEARDATA const char *const vomiting_texts[] = {
184 "are feeling mildly nauseated.", /* 14 */
185 "feel slightly confused.", /* 11 */
186 "can't seem to think straight.", /* 8 */
187 "feel incredibly sick.", /* 5 */
188 "are about to vomit." /* 2 */
190 "
\82¿
\82å
\82Á
\82Æ
\93f
\82«
\8bC
\82ª
\82µ
\82½
\81D", /* 14 */
191 "
\8f
\82µ
\8d¬
\97\90\82µ
\82½
\81D", /* 11 */
192 "
\82Ü
\82Æ
\82à
\82É
\8ev
\8dl
\82Å
\82«
\82È
\82
\82È
\82Á
\82½
\81D", /* 8 */
193 "
\82Æ
\82Ä
\82à
\8bC
\95ª
\82ª
\88«
\82
\82È
\82Á
\82½
\81D", /* 5 */
194 "
\93Ë
\91R
\9aq
\93f
\82µ
\82½
\81D" /* 2 */
202 long v = (Vomiting & TIMEOUT);
204 /* note: nhtimeout() hasn't decremented timed properties for the
205 current turn yet, so we use Vomiting-1 here */
206 switch ((int) (v - 1L)) {
208 txt = vomiting_texts[0];
211 txt = vomiting_texts[1];
214 make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE);
215 if (!Popeye(VOMITING))
219 make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE);
224 txt = vomiting_texts[2];
227 txt = vomiting_texts[3];
230 txt = vomiting_texts[4];
231 if (cantvomit(youmonst.data))
233 txt = "gag uncontrollably.";
235 txt = "
\8bC
\95ª
\82Ì
\88«
\82³
\82ª
\97}
\82¦
\82ç
\82ê
\82È
\82
\82È
\82Á
\82½
\81D";
236 else if (Hallucination)
237 /* "hurl" is short for "hurl chunks" which is slang for
238 relatively violent vomiting... */
240 txt = "are about to hurl!";
242 txt = "
\83\8a\83o
\81[
\83X
\90¡
\91O
\82¾
\81I";
246 if (!cantvomit(youmonst.data)) {
248 /* case 2 used to be "You suddenly vomit!" but it wasn't sudden
249 since you've just been through the earlier messages of the
250 countdown, and it was still possible to move around between
251 that message and "You can move again." (from vomit()'s
252 nomul(-2)) with no intervening message; give one here to
253 have more specific point at which hero became unable to move
254 [vomit() issues its own message for the cantvomit() case
255 and for the FAINTING-or-worse case where stomach is empty] */
256 if (u.uhs < FAINTING)
258 You("%s!", !Hallucination ? "vomit" : "hurl chunks");
260 You("%s
\81I", !Hallucination ? "
\93f
\82¢
\82½" : "
\83\8a\83o
\81[
\83X
\82µ
\82½");
269 exercise(A_CON, FALSE);
272 static NEARDATA const char *const choke_texts[] = {
274 "You find it hard to breathe.",
275 "You're gasping for air.",
276 "You can no longer breathe.",
277 "You're turning %s.",
280 "
\82 \82È
\82½
\82Í
\8cÄ
\8bz
\82ª
\8d¢
\93ï
\82É
\82È
\82Á
\82½
\81D",
281 "
\82 \82È
\82½
\82Í
\8bê
\82µ
\82
\82Ä
\82 \82¦
\82¢
\82¾
\81D",
282 "
\82 \82È
\82½
\82Í
\82à
\82¤
\8cÄ
\8bz
\82ª
\82Å
\82«
\82È
\82¢
\81D",
283 "
\82 \82È
\82½
\82Í%s
\82È
\82Á
\82½
\81D",
284 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
288 static NEARDATA const char *const choke_texts2[] = {
290 "Your %s is becoming constricted.",
291 "Your blood is having trouble reaching your brain.",
292 "The pressure on your %s increases.",
293 "Your consciousness is fading.",
296 "
\82 \82È
\82½
\82Ì%s
\82Í
\8di
\82ß
\82Â
\82¯
\82ç
\82ê
\82½
\81D",
297 "
\8c\8c\89t
\82Ì
\82ß
\82®
\82è
\82ª
\88«
\82
\82È
\82Á
\82½
\81D",
298 "%s
\82Ì
\88³
\97Í
\82ª
\8d\82\82
\82È
\82Á
\82½
\81D",
299 "
\88Ó
\8e¯
\82ª
\89\93\82
\82È
\82Á
\82Ä
\82«
\82½
\81D",
300 "
\82 \82È
\82½
\82Í
\92\82\91§
\82µ
\82½
\81D"
307 register long i = (Strangled & TIMEOUT);
309 if (i > 0 && i <= SIZE(choke_texts)) {
310 if (Breathless || !rn2(50))
311 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
313 const char *str = choke_texts[SIZE(choke_texts) - i];
317 pline(str, hcolor(NH_BLUE));
319 pline(str, jconj_adj(hcolor(NH_BLUE)));
324 exercise(A_STR, FALSE);
327 static NEARDATA const char *const levi_texts[] = {
328 #if 0 /*JP*//* %s
\82Í
\8eg
\82í
\82È
\82¢ */
329 "You float slightly lower.",
330 "You wobble unsteadily %s the %s."
332 "
\82 \82È
\82½
\82Ì
\95\82\82«
\8bï
\8d\87\82Í
\8f
\82µ
\92á
\82
\82È
\82Á
\82½
\81D",
333 "
\82 \82È
\82½
\82Í
\82®
\82ç
\82®
\82ç
\97h
\82ê
\82Í
\82¶
\82ß
\82½
\81D"
338 levitation_dialogue()
340 /* -1 because the last message comes via float_down() */
341 long i = (((HLevitation & TIMEOUT) - 1L) / 2L);
346 if (!ACCESSIBLE(levl[u.ux][u.uy].typ)
347 && !is_pool_or_lava(u.ux,u.uy))
350 if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) {
351 const char *s = levi_texts[SIZE(levi_texts) - i];
353 #if 0 /*JP*//* %s
\82Í
\8eg
\82Á
\82Ä
\82¢
\82È
\82¢
\82Ì
\82Å
\92P
\8f\83\89» */
355 boolean danger = (is_pool_or_lava(u.ux, u.uy)
356 && !Is_waterlevel(&u.uz));
358 pline(s, danger ? "over" : "in",
359 danger ? surface(u.ux, u.uy) : "air");
366 static NEARDATA const char *const slime_texts[] = {
368 "You are turning a little %s.", /* 5 */
369 "Your limbs are getting oozy.", /* 4 */
370 "Your skin begins to peel away.", /* 3 */
371 "You are turning into %s.", /* 2 */
372 "You have become %s." /* 1 */
374 "
\8f
\82µ%s
\82È
\82Á
\82½
\81D", /* 5 */
375 "
\8eè
\91«
\82ª
\97n
\82¯
\82Í
\82¶
\82ß
\82½
\81D", /* 4 */
376 "
\94§
\82ª
\82Ç
\82ë
\82Ç
\82ë
\82É
\82È
\82Á
\82Ä
\82«
\82½
\81D", /* 3 */
377 "%s
\82É
\82È
\82è
\82Í
\82¶
\82ß
\82½
\81D", /* 2 */
378 "%s
\82É
\82È
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", /* 1 */
385 register long i = (Slimed & TIMEOUT) / 2L;
388 /* display as green slime during "You have become green slime."
389 but don't worry about not being able to see self; if already
390 mimicking something else at the time, implicitly be revealed */
391 youmonst.m_ap_type = M_AP_MONSTER;
392 youmonst.mappearance = PM_GREEN_SLIME;
394 if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) {
397 Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]);
399 if (nolimbs(youmonst.data) && strstri(buf, "limbs"))
400 (void) strsubst(buf, "limbs", "extremities");
402 if (nolimbs(youmonst.data) && strstri(buf, "
\8eè
\91«"))
403 (void) strsubst(buf, "
\8eè
\91«", "
\90æ
\92[");
406 if (index(buf, '%')) {
407 if (i == 4L) { /* "you are turning green" */
408 if (!Blind) /* [what if you're already green?] */
410 pline(buf, hcolor(NH_GREEN));
412 pline(buf, jconj_adj(hcolor(NH_GREEN)));
416 an(Hallucination ? rndmonnam(NULL) : "green slime"));
418 Hallucination ? rndmonnam(NULL) : "
\97Î
\83X
\83\89\83C
\83\80");
424 case 3L: /* limbs becoming oozy */
425 HFast = 0L; /* lose intrinsic speed */
431 case 2L: /* skin begins to peel */
432 if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
433 set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
435 case 1L: /* turning into slime */
436 /* if also turning to stone, stop doing that (no message) */
438 make_stoned(0L, (char *) 0, KILLED_BY_AN, (char *) 0);
441 exercise(A_DEX, FALSE);
449 make_slimed(0L, "The slime that covers you is burned away!");
451 make_slimed(0L, "
\82 \82È
\82½
\82ð
\95¢
\82Á
\82Ä
\82¢
\82½
\83X
\83\89\83C
\83\80\82Í
\8fÄ
\82¯
\97\8e\82¿
\82½
\81I");
455 /* countdown timer for turning into green slime has run out; kill our hero */
457 slimed_to_death(kptr)
462 /* redundant: polymon() cures sliming when polying into green slime */
463 if (Upolyd && youmonst.data == &mons[PM_GREEN_SLIME]) {
464 dealloc_killer(kptr);
467 /* more sure killer reason is set up */
468 if (kptr && kptr->name[0]) {
469 killer.format = kptr->format;
470 Strcpy(killer.name, kptr->name);
472 killer.format = NO_KILLER_PREFIX;
474 Strcpy(killer.name, "turned into green slime");
476 Strcpy(killer.name, "
\97Î
\83X
\83\89\83C
\83\80\82É
\82È
\82Á
\82½");
478 dealloc_killer(kptr);
481 * Polymorph into a green slime, which might destroy some worn armor
482 * (potentially affecting bones) and dismount from steed.
483 * Can't be Unchanging; wouldn't have turned into slime if we were.
484 * Despite lack of Unchanging, neither done() nor savelife() calls
485 * rehumanize() if hero dies while polymorphed.
486 * polymon() undoes the slime countdown's mimick-green-slime hack
487 * but does not perform polyself()'s light source bookkeeping.
488 * No longer need to manually increment uconduct.polyselfs to reflect
489 * [formerly implicit] change of form; polymon() takes care of that.
490 * Temporarily ungenocide if necessary.
492 if (emits_light(youmonst.data))
493 del_light_source(LS_MONSTER, monst_to_any(&youmonst));
494 save_mvflags = mvitals[PM_GREEN_SLIME].mvflags;
495 mvitals[PM_GREEN_SLIME].mvflags = save_mvflags & ~G_GENOD;
496 (void) polymon(PM_GREEN_SLIME);
497 mvitals[PM_GREEN_SLIME].mvflags = save_mvflags;
500 /* life-saved; even so, hero still has turned into green slime;
501 player may have genocided green slimes after being infected */
502 if ((mvitals[PM_GREEN_SLIME].mvflags & G_GENOD) != 0) {
503 killer.format = KILLED_BY;
505 Strcpy(killer.name, "slimicide");
507 Strcpy(killer.name, "
\83X
\83\89\83C
\83\80\8bs
\8eE");
508 /* immediately follows "OK, so you don't die." */
510 pline("Yes, you do. Green slime has been genocided...");
512 pline("
\82Í
\82¢
\81C
\82»
\82¤
\82Å
\82·
\81D
\97Î
\83X
\83\89\83C
\83\80\82Í
\8bs
\8eE
\82³
\82ê
\82Ü
\82µ
\82½
\81D
\81D
\81D");
514 /* could be life-saved again (only in explore or wizard mode)
515 but green slimes are gone; just stay in current form */
520 /* Intrinsic Passes_walls is temporary when your god is trying to fix
521 all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
522 it can't find anywhere to place you. If that happens you get a small
523 value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
524 Message given is "you feel much slimmer" as a joke hint that you can
525 move between things which are closely packed--like the substance of
527 static NEARDATA const char *const phaze_texts[] = {
529 "You start to feel bloated.",
530 "You are feeling rather flabby.",
532 "
\82 \82È
\82½
\82Í
\96c
\82ç
\82Ý
\82Í
\82¶
\82ß
\82½
\8bC
\82ª
\82·
\82é
\81D",
533 "
\82 \82È
\82½
\82Í
\8f
\82µ
\82½
\82é
\82ñ
\82¾
\8bC
\82ª
\82·
\82é
\81D",
540 long i = ((HPasses_walls & TIMEOUT) / 2L);
542 if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
545 if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
546 pline1(phaze_texts[SIZE(phaze_texts) - i]);
552 register struct prop *upp;
557 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
562 if (u.uluck != baseluck
563 && moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
564 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
565 * stop good luck from timing out; normal luckstones stop both;
566 * neither is stopped if you don't have a luckstone.
567 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
569 register int time_luck = stone_luck(FALSE);
570 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
572 if (u.uluck > baseluck && (nostone || time_luck < 0))
574 else if (u.uluck < baseluck && (nostone || time_luck > 0))
578 return; /* things past this point could kill you */
587 if (HLevitation & TIMEOUT)
588 levitation_dialogue();
589 if (HPasses_walls & TIMEOUT)
591 if (u.mtimedone && !--u.mtimedone) {
593 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
594 else if (is_were(youmonst.data))
595 you_unwere(FALSE); /* if polycontrl, asks whether to rehumanize */
602 /* Dissipate spell-based protection. */
604 if (--u.usptime == 0 && u.uspellprot) {
605 u.usptime = u.uspmtime;
610 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
611 u.uspellprot ? "becomes less dense" : "disappears");
613 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
614 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
620 if (--u.ugallop == 0L && u.usteed)
622 pline("%s stops galloping.", Monnam(u.usteed));
624 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
628 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
629 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
630 kptr = find_delayed_killer((int) (upp - u.uprops));
631 switch (upp - u.uprops) {
633 if (kptr && kptr->name[0]) {
634 killer.format = kptr->format;
636 Strcpy(killer.name, kptr->name);
638 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
642 killer.format = NO_KILLER_PREFIX;
643 Strcpy(killer.name, "killed by petrification");
645 killer.format = KILLED_BY;
646 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
649 dealloc_killer(kptr);
650 /* (unlike sliming, you aren't changing form here) */
654 slimed_to_death(kptr); /* done(TURNED_SLIME) */
657 make_vomiting(0L, TRUE);
661 You("die from your illness.");
663 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
664 if (kptr && kptr->name[0]) {
665 killer.format = kptr->format;
666 Strcpy(killer.name, kptr->name);
668 killer.format = KILLED_BY_AN;
669 killer.name[0] = 0; /* take the default */
671 dealloc_killer(kptr);
673 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
674 if (type_is_pname(&mons[m_idx])) {
675 killer.format = KILLED_BY;
676 } else if (mons[m_idx].geno & G_UNIQ) {
677 Strcpy(killer.name, the(killer.name));
678 killer.format = KILLED_BY;
687 You_feel("yourself slowing down%s.",
688 Fast ? " a bit" : "");
690 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
691 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
695 /* So make_confused works properly */
696 set_itimeout(&HConfusion, 1L);
697 make_confused(0L, TRUE);
702 set_itimeout(&HStun, 1L);
703 make_stunned(0L, TRUE);
708 set_itimeout(&Blinded, 1L);
709 make_blinded(0L, TRUE);
714 set_itimeout(&HDeaf, 1L);
722 if (!Invis && !BInvis && !Blind) {
725 ? "are no longer invisible."
726 : "can no longer see through yourself.");
729 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
730 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
736 set_mimic_blocking(); /* do special mimic handling */
737 see_monsters(); /* make invis mons appear */
738 newsym(u.ux, u.uy); /* make self appear */
748 make_totter(0L, TRUE);
753 set_itimeout(&HHallucination, 1L);
754 (void) make_hallucinated(0L, TRUE, 0L);
759 if (unconscious() || Sleep_resistance) {
760 incr_itimeout(&HSleepy, rnd(100));
765 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
767 fall_asleep(-sleeptime, TRUE);
768 incr_itimeout(&HSleepy, sleeptime + rnd(100));
772 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
775 /* timed Flying is via #wizintrinsic only */
776 if (was_flying && !Flying) {
781 You("
\92\85\92n
\82µ
\82½
\81D");
786 /* timed Warn_of_mon is via #wizintrinsic only */
788 context.warntype.speciesidx = NON_PM;
789 if (context.warntype.species) {
791 You("are no longer warned about %s.",
792 makeplural(context.warntype.species->mname));
794 You("
\82à
\82Í
\82â%s
\82ð
\8cx
\8d\90\82µ
\82È
\82
\82È
\82Á
\82½
\81D",
795 makeplural(context.warntype.species->mname));
797 context.warntype.species = (struct permonst *) 0;
805 You_feel("hemmed in again.");
807 You_feel("
\82Ü
\82½
\95Â
\82¶
\8d\9e\82ß
\82ç
\82ê
\82½
\82æ
\82¤
\82¾
\81D");
810 pline("You're back to your %s self again.",
811 !Upolyd ? "normal" : "unusual");
813 pline("
\82 \82È
\82½
\82Í
\8dÄ
\82Ñ
\92Ê
\8fí%s
\82Ì
\8fó
\91Ô
\82É
\82È
\82Á
\82½
\81D",
814 !Upolyd ? "" : "
\82Å
\82Í
\82È
\82¢");
819 killer.format = KILLED_BY;
822 (u.uburied) ? "suffocation" : "strangulation");
825 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
828 /* must be declining to die in explore|wizard mode;
829 treat like being cured of strangulation by prayer */
830 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
832 Your("amulet vanishes!");
834 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
839 /* call this only when a move took place. */
840 /* otherwise handle fumbling msgs locally. */
841 if (u.umoved && !Levitation) {
845 multi_reason = "fumbling";
847 multi_reason = "
\82Ö
\82Ü
\82ð
\82µ
\82½
\8c\84\82É";
849 /* The more you are carrying the more likely you
850 * are to make noise when you fumble. Adjustments
851 * to this number must be thoroughly play tested.
853 if ((inv_weight() > -500)) {
855 You("make a lot of noise!");
857 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
861 /* from outside means slippery ice; don't reset
862 counter if that's the only fumble reason */
863 HFumbling &= ~FROMOUTSIDE;
865 incr_itimeout(&HFumbling, rnd(20));
867 case DETECT_MONSTERS:
877 fall_asleep(how_long, wakeup_msg)
884 multi_reason = "sleeping";
886 multi_reason = "
\96°
\82è
\82Ì
\82³
\82È
\82©
\82É";
887 /* generally don't notice sounds while sleeping */
888 if (wakeup_msg && multi == how_long) {
889 /* caller can follow with a direct call to Hear_again() if
890 there's a need to override this when wakeup_msg is true */
891 incr_itimeout(&HDeaf, how_long);
893 afternmv = Hear_again; /* this won't give any messages */
895 /* early wakeup from combat won't be possible until next monster turn */
896 u.usleep = monstermoves;
898 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
900 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
903 /* Attach an egg hatch timeout to the given egg.
904 * when = Time to hatch, usually only passed if re-creating an
905 * existing hatch timer. Pass 0L for random hatch time.
908 attach_egg_hatch_timeout(egg, when)
914 /* stop previous timer, if any */
915 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
918 * Decide if and when to hatch the egg. The old hatch_it() code tried
919 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
920 * a number x, 1<=x<=age, where x>150. This yields a chance of
921 * hatching > 99.9993%. Mimic that here.
924 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
932 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
936 /* prevent an egg from ever hatching */
941 /* stop previous timer, if any */
942 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
945 /* timer callback routine: hatch the given egg */
947 hatch_egg(arg, timeout)
952 struct monst *mon, *mon2;
955 boolean yours, silent, knows_egg = FALSE;
956 boolean cansee_hatchspot = FALSE;
957 int i, mnum, hatchcount = 0;
960 /* sterilized while waiting */
961 if (egg->corpsenm == NON_PM)
964 mon = mon2 = (struct monst *) 0;
965 mnum = big_to_little(egg->corpsenm);
966 /* The identity of one's father is learned, not innate */
967 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
968 silent = (timeout != monstermoves); /* hatched while away */
970 /* only can hatch when in INVENT, FLOOR, MINVENT */
971 if (get_obj_location(egg, &x, &y, 0)) {
972 hatchcount = rnd((int) egg->quan);
973 cansee_hatchspot = cansee(x, y) && !silent;
974 if (!(mons[mnum].geno & G_UNIQ)
975 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
976 for (i = hatchcount; i > 0; i--) {
977 if (!enexto(&cc, x, y, &mons[mnum])
978 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
980 /* tame if your own egg hatches while you're on the
981 same dungeon level, or any dragon egg which hatches
982 while it's in your inventory */
983 if ((yours && !silent)
984 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
985 if (tamedog(mon, (struct obj *) 0)) {
986 if (carried(egg) && mon->data->mlet != S_DRAGON)
990 if (mvitals[mnum].mvflags & G_EXTINCT)
991 break; /* just made last one */
992 mon2 = mon; /* in case makemon() fails on 2nd egg */
997 egg->quan -= (long) hatchcount;
1001 * We could possibly hatch while migrating, but the code isn't
1004 } else if (obj->where == OBJ_MIGRATING) {
1006 * We can do several things. The first ones that come to
1008 * + Create the hatched monster then place it on the migrating
1009 * mons list. This is tough because all makemon() is made
1010 * to place the monster as well. Makemon() also doesn't lend
1011 * itself well to splitting off a "not yet placed" subroutine.
1012 * + Mark the egg as hatched, then place the monster when we
1013 * place the migrating objects.
1014 * + Or just kill any egg which gets sent to another level.
1015 * Falling is the usual reason such transportation occurs.
1017 cansee_hatchspot = FALSE;
1023 char monnambuf[BUFSZ], carriedby[BUFSZ];
1024 boolean siblings = (hatchcount > 1), redraw = FALSE;
1026 if (cansee_hatchspot) {
1027 /* [bug? m_monnam() yields accurate monster type
1028 regardless of hallucination] */
1030 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
1031 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
1033 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
1036 /* we don't learn the egg type here because learning
1037 an egg type requires either seeing the egg hatch
1038 or being familiar with the egg already,
1039 as well as being able to see the resulting
1040 monster, checked below
1043 switch (egg->where) {
1045 knows_egg = TRUE; /* true even if you are blind */
1046 if (!cansee_hatchspot)
1048 You_feel("%s %s from your pack!", something,
1049 locomotion(mon->data, "drop"));
1051 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
1052 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1056 You_see("%s %s out of your pack!", monnambuf,
1057 locomotion(mon->data, "drop"));
1059 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
1060 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1064 pline("%s cries sound like \"%s%s\"",
1065 siblings ? "Their" : "Its",
1066 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
1068 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
1069 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
1071 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
1073 verbalize("Gleep!"); /* Mything eggs :-) */
1075 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
1081 if (cansee_hatchspot) {
1084 You_see("%s hatch.", monnambuf);
1086 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
1087 redraw = TRUE; /* update egg's map location */
1092 if (cansee_hatchspot) {
1093 /* egg carrying monster might be invisible */
1096 && (!mon2->wormno || cansee(mon2->mx, mon2->my))) {
1098 Sprintf(carriedby, "%s pack",
1099 s_suffix(a_monnam(mon2)));
1101 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
1105 } else if (is_pool(mon->mx, mon->my)) {
1107 Strcpy(carriedby, "empty water");
1109 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
1112 Strcpy(carriedby, "thin air");
1114 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
1117 You_see("%s %s out of %s!", monnambuf,
1118 locomotion(mon->data, "drop"), carriedby);
1120 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
1121 locomotion(mon->data, "
\97\8e\82¿
\82é"));
1130 impossible("egg hatched where? (%d)", (int) egg->where);
1134 if (cansee_hatchspot && knows_egg)
1135 learn_egg_type(mnum);
1137 if (egg->quan > 0) {
1138 /* still some eggs left */
1139 /* Instead of ordinary egg timeout use a short one */
1140 attach_egg_hatch_timeout(egg, (long) rnd(12));
1141 } else if (carried(egg)) {
1144 /* free egg here because we use it above */
1145 obj_extract_self(egg);
1146 obfree(egg, (struct obj *) 0);
1153 /* Learn to recognize eggs of the given type. */
1155 learn_egg_type(mnum)
1158 /* baby monsters hatch from grown-up eggs */
1159 mnum = little_to_big(mnum);
1160 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
1161 /* we might have just learned about other eggs being carried */
1165 /* Attach a fig_transform timeout to the given figurine. */
1167 attach_fig_transform_timeout(figurine)
1168 struct obj *figurine;
1172 /* stop previous timer, if any */
1173 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
1176 * Decide when to transform the figurine.
1178 i = rnd(9000) + 200;
1179 /* figurine will transform */
1180 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
1181 obj_to_any(figurine));
1184 /* give a fumble message */
1188 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
1191 boolean on_foot = TRUE;
1195 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
1198 if (otmp && on_foot) { /* trip over something in particular */
1200 If there is only one item, it will have just been named
1201 during the move, so refer to by via pronoun; otherwise,
1202 if the top item has been or can be seen, refer to it by
1203 name; if not, look for rocks to trip over; trip over
1204 anonymous "something" if there aren't any rocks.
1207 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1208 ? ((otmp->quan == 1L) ? "it"
1209 : Hallucination ? "they" : "them")
1210 : (otmp->dknown || !Blind)
1212 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1214 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
1216 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1218 : (otmp->dknown || !Blind)
1220 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1224 if (Hallucination) {
1225 what = strcpy(buf, what);
1226 buf[0] = highc(buf[0]);
1228 pline("Egads! %s bite%s your %s!", what,
1229 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
1231 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
1235 You("trip over %s.", what);
1237 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
1239 if (!uarmf && otmp->otyp == CORPSE
1240 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
1242 Sprintf(killer.name, "tripping over %s corpse",
1243 an(mons[otmp->corpsenm].mname));
1245 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
1246 mons[otmp->corpsenm].mname);
1248 instapetrify(killer.name);
1250 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
1252 pline("%s %s%s on the ice.",
1253 u.usteed ? upstart(x_monnam(u.usteed,
1254 (has_mname(u.usteed)) ? ARTICLE_NONE
1256 (char *) 0, SUPPRESS_SADDLE, FALSE))
1258 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
1260 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
1261 u.usteed ? upstart(x_monnam(u.usteed,
1262 (has_mname(u.usteed)) ? ARTICLE_NONE
1264 (char *) 0, SUPPRESS_SADDLE, FALSE))
1272 You("trip over your own %s.",
1273 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
1275 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
1276 Hallucination ? "
\95I" : body_part(FOOT));
1282 Hallucination ? "on a banana peel" : "and nearly fall");
1284 You("%s
\81D", Hallucination ?
1285 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
1292 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
1298 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
1305 Your("%s slip out of the stirrups.",
1306 makeplural(body_part(FOOT)));
1308 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1313 You("let go of the reins.");
1315 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1319 You("bang into the saddle-horn.");
1321 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1325 You("slide to one side of the saddle.");
1327 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1330 dismount_steed(DISMOUNT_FELL);
1335 /* Print a lamp flicker message with tailer. */
1337 see_lamp_flicker(obj, tailer)
1341 switch (obj->where) {
1345 pline("%s flickers%s.", Yname2(obj), tailer);
1347 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1351 You_see("%s flicker%s.", an(xname(obj)), tailer);
1353 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1358 /* Print a dimming message for brass lanterns. */
1360 lantern_message(obj)
1363 /* from adventure */
1364 switch (obj->where) {
1367 Your("lantern is getting dim.");
1369 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1372 pline("Batteries have not been invented yet.");
1374 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1378 You_see("a lantern getting dim.");
1380 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1384 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1386 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1392 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1393 * See begin_burn() for meanings of obj->age and obj->spe.
1396 burn_object(arg, timeout)
1400 struct obj *obj = arg->a_obj;
1402 boolean canseeit, many, menorah, need_newsym, need_invupdate;
1404 boolean canseeit, menorah, need_newsym, need_invupdate;
1409 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1411 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1414 /* timeout while away */
1415 if (timeout != monstermoves) {
1416 long how_long = monstermoves - timeout;
1418 if (how_long >= obj->age) {
1420 end_burn(obj, FALSE);
1423 obj->spe = 0; /* no more candles */
1424 obj->owt = weight(obj);
1425 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1426 /* get rid of candles and burning oil potions;
1427 we know this object isn't carried by hero,
1428 nor is it migrating */
1429 obj_extract_self(obj);
1430 obfree(obj, (struct obj *) 0);
1431 obj = (struct obj *) 0;
1435 obj->age -= how_long;
1436 begin_burn(obj, TRUE);
1441 /* only interested in INVENT, FLOOR, and MINVENT */
1442 if (get_obj_location(obj, &x, &y, 0)) {
1443 canseeit = !Blind && cansee(x, y);
1444 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1445 (void) Shk_Your(whose, obj);
1449 need_newsym = need_invupdate = FALSE;
1451 /* obj->age is the age remaining at this point. */
1452 switch (obj->otyp) {
1454 /* this should only be called when we run out */
1456 switch (obj->where) {
1458 need_invupdate = TRUE;
1462 pline("%spotion of oil has burnt away.", whose);
1464 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1468 You_see("a burning potion of oil go out.");
1470 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1475 end_burn(obj, FALSE); /* turn off light source */
1479 /* clear migrating obj's destination code before obfree
1480 to avoid false complaint of deleting worn item */
1481 if (obj->where == OBJ_MIGRATING)
1482 obj->owornmask = 0L;
1483 obj_extract_self(obj);
1484 obfree(obj, (struct obj *) 0);
1486 obj = (struct obj *) 0;
1491 switch ((int) obj->age) {
1496 if (obj->otyp == BRASS_LANTERN)
1497 lantern_message(obj);
1499 see_lamp_flicker(obj,
1501 obj->age == 50L ? " considerably" : "");
1503 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1509 if (obj->otyp == BRASS_LANTERN)
1510 lantern_message(obj);
1512 switch (obj->where) {
1516 pline("%s seems about to go out.", Yname2(obj));
1518 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1522 You_see("%s about to go out.", an(xname(obj)));
1524 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1532 /* even if blind you'll know if holding it */
1533 if (canseeit || obj->where == OBJ_INVENT) {
1534 switch (obj->where) {
1536 need_invupdate = TRUE;
1539 if (obj->otyp == BRASS_LANTERN)
1541 pline("%slantern has run out of power.", whose);
1543 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1546 pline("%s has gone out.", Yname2(obj));
1548 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1551 if (obj->otyp == BRASS_LANTERN)
1553 You_see("a lantern run out of power.");
1555 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1558 You_see("%s go out.", an(xname(obj)));
1560 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1564 end_burn(obj, FALSE);
1569 * Someone added fuel to the lamp while it was
1570 * lit. Just fall through and let begin burn
1571 * handle the new age.
1577 begin_burn(obj, TRUE);
1581 case CANDELABRUM_OF_INVOCATION:
1587 switch (obj->where) {
1591 pline("%s%scandle%s getting short.", whose,
1592 menorah ? "candelabrum's " : "",
1593 many ? "s are" : " is");
1595 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1596 menorah ? "
\90C
\91ä
\82Ì" : "");
1601 You_see("%scandle%s getting short.",
1602 menorah ? "a candelabrum's " : many ? "some "
1606 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1607 menorah ? "
\90C
\91ä
\82Ì" : "");
1615 switch (obj->where) {
1619 pline("%s%scandle%s flame%s flicker%s low!", whose,
1620 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1621 many ? "s" : "", many ? "" : "s");
1623 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1624 menorah ? "
\90C
\91ä
\82Ì" : "");
1629 You_see("%scandle%s flame%s flicker low!",
1630 menorah ? "a candelabrum's " : many ? "some "
1632 many ? "s'" : "'s", many ? "s" : "");
1634 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1635 menorah ? "
\90C
\91ä
\82Ì" : "");
1642 /* we know even if blind and in our inventory */
1643 if (canseeit || obj->where == OBJ_INVENT) {
1645 switch (obj->where) {
1647 need_invupdate = TRUE;
1651 pline("%scandelabrum's flame%s.", whose,
1652 many ? "s die" : " dies");
1654 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1659 You_see("a candelabrum's flame%s die.",
1662 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1667 switch (obj->where) {
1669 /* no need_invupdate for update_inventory() necessary;
1670 useupall() -> freeinv() handles it */
1674 pline("%s %s consumed!", Yname2(obj),
1675 many ? "are" : "is");
1677 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1682 You see some wax candles consumed!
1683 You see a wax candle consumed!
1686 You_see("%s%s consumed!", many ? "some " : "",
1687 many ? xname(obj) : an(xname(obj)));
1689 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1698 ? (many ? "They shriek!" : "It shrieks!")
1699 : Blind ? "" : (many ? "Their flames die."
1700 : "Its flame dies."));
1702 pline(Hallucination ? "
\82»
\82ê
\82Í
\8bà
\90Ø
\82è
\90º
\82ð
\82 \82°
\82½
\81I"
1704 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1708 end_burn(obj, FALSE);
1712 obj->owt = weight(obj);
1717 /* clear migrating obj's destination code
1718 so obfree won't think this item is worn */
1719 if (obj->where == OBJ_MIGRATING)
1720 obj->owornmask = 0L;
1721 obj_extract_self(obj);
1722 obfree(obj, (struct obj *) 0);
1724 obj = (struct obj *) 0;
1726 break; /* case [age ==] 0 */
1730 * Someone added fuel (candles) to the menorah while
1731 * it was lit. Just fall through and let begin burn
1732 * handle the new age.
1737 if (obj && obj->age)
1738 begin_burn(obj, TRUE);
1739 break; /* case [otyp ==] candelabrum|tallow_candle|wax_candle */
1742 impossible("burn_object: unexpeced obj %s", xname(obj));
1752 * Start a burn timeout on the given object. If not "already lit" then
1753 * create a light source for the vision system. There had better not
1754 * be a burn already running on the object.
1756 * Magic lamps stay lit as long as there's a genie inside, so don't start
1760 * potions of oil, lamps & candles:
1761 * age = # of turns of fuel left
1765 * spe = 0 not lightable, 1 lightable forever
1767 * age = # of turns of fuel left
1768 * spe = # of candles
1770 * Once the burn begins, the age will be set to the amount of fuel
1771 * remaining _once_the_burn_finishes_. If the burn is terminated
1772 * early then fuel is added back.
1774 * This use of age differs from the use of age for corpses and eggs.
1775 * For the latter items, age is when the object was created, so we
1776 * know when it becomes "bad".
1778 * This is a "silent" routine - it should not print anything out.
1781 begin_burn(obj, already_lit)
1783 boolean already_lit;
1787 boolean do_timer = TRUE;
1789 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1792 switch (obj->otyp) {
1801 turns = (3L * turns + 2L) / 4L;
1802 radius = 1; /* very dim light */
1807 /* magic times are 150, 100, 50, 25, and 0 */
1808 if (obj->age > 150L)
1809 turns = obj->age - 150L;
1810 else if (obj->age > 100L)
1811 turns = obj->age - 100L;
1812 else if (obj->age > 50L)
1813 turns = obj->age - 50L;
1814 else if (obj->age > 25L)
1815 turns = obj->age - 25L;
1820 case CANDELABRUM_OF_INVOCATION:
1823 /* magic times are 75, 15, and 0 */
1825 turns = obj->age - 75L;
1826 else if (obj->age > 15L)
1827 turns = obj->age - 15L;
1830 radius = candle_light_range(obj);
1834 /* [ALI] Support artifact light sources */
1835 if (artifact_light(obj)) {
1838 radius = arti_light_radius(obj);
1840 impossible("begin burn: unexpected %s", xname(obj));
1847 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1850 if (carried(obj) && !already_lit)
1856 if (carried(obj) && !already_lit)
1860 if (obj->lamplit && !already_lit) {
1863 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1864 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1866 impossible("begin_burn: can't get obj position");
1871 * Stop a burn timeout on the given object if timer attached. Darken
1875 end_burn(obj, timer_attached)
1877 boolean timer_attached;
1879 if (!obj->lamplit) {
1880 impossible("end_burn: obj %s not lit", xname(obj));
1884 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1885 timer_attached = FALSE;
1887 if (!timer_attached) {
1888 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1889 del_light_source(LS_OBJECT, obj_to_any(obj));
1891 if (obj->where == OBJ_INVENT)
1893 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1894 impossible("end_burn: obj %s not timed!", xname(obj));
1898 * Cleanup a burning object if timer stopped.
1901 cleanup_burn(arg, expire_time)
1905 struct obj *obj = arg->a_obj;
1906 if (!obj->lamplit) {
1907 impossible("cleanup_burn: obj %s not lit", xname(obj));
1911 del_light_source(LS_OBJECT, obj_to_any(obj));
1913 /* restore unused time */
1914 obj->age += expire_time - monstermoves;
1918 if (obj->where == OBJ_INVENT)
1930 /* no lightning if not the air level or too often, even then */
1931 if (!Is_airlevel(&u.uz) || rn2(8))
1934 /* the number of strikes is 8-log2(nstrike) */
1935 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1940 } while (++count < 100 && levl[x][y].typ != CLOUD);
1945 if (dirx != 0 || diry != 0)
1946 buzz(-15, /* "monster" LIGHTNING spell */
1947 8, x, y, dirx, diry);
1951 if (levl[u.ux][u.uy].typ == CLOUD) {
1952 /* Inside a cloud during a thunder storm is deafening. */
1953 /* Even if already deaf, we sense the thunder's vibrations. */
1955 pline("Kaboom!!! Boom!! Boom!!");
1957 pline("
\83s
\83J
\83b
\81I
\81I
\83S
\83\8d\83S
\83\8d\83S
\83\8d\83S
\83\8d\81I
\81I
\83h
\81[
\83\93\81I");
1958 incr_itimeout(&HDeaf, rn1(20, 30));
1959 context.botl = TRUE;
1960 if (!u.uinvulnerable) {
1964 multi_reason = "hiding from thunderstorm";
1966 multi_reason = "
\97\8b\82Ì
\97\92\82ð
\94ð
\82¯
\82Ä
\82¢
\82é
\8e\9e\82É";
1971 You_hear("a rumbling noise.");
1973 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1976 /* -------------------------------------------------------------------------
1979 * Generic Timeout Functions.
1984 * boolean start_timer(long timeout,short kind,short func_index,
1986 * Start a timer of kind 'kind' that will expire at time
1987 * monstermoves+'timeout'. Call the function at 'func_index'
1988 * in the timeout table using argument 'arg'. Return TRUE if
1989 * a timer was started. This places the timer on a list ordered
1990 * "sooner" to "later". If an object, increment the object's
1993 * long stop_timer(short func_index, anything *arg)
1994 * Stop a timer specified by the (func_index, arg) pair. This
1995 * assumes that such a pair is unique. Return the time the
1996 * timer would have gone off. If no timer is found, return 0.
1997 * If an object, decrement the object's timer count.
1999 * long peek_timer(short func_index, anything *arg)
2000 * Return time specified timer will go off (0 if no such timer).
2002 * void run_timers(void)
2003 * Call timers that have timed out.
2006 * void save_timers(int fd, int mode, int range)
2007 * Save all timers of range 'range'. Range is either global
2008 * or local. Global timers follow game play, local timers
2009 * are saved with a level. Object and monster timers are
2010 * saved using their respective id's instead of pointers.
2012 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
2013 * Restore timers of range 'range'. If from a ghost pile,
2014 * adjust the timeout by 'adjust'. The object and monster
2015 * ids are not restored until later.
2017 * void relink_timers(boolean ghostly)
2018 * Relink all object and monster timers that had been saved
2019 * using their object's or monster's id number.
2022 * void obj_move_timers(struct obj *src, struct obj *dest)
2023 * Reassign all timers from src to dest.
2025 * void obj_split_timers(struct obj *src, struct obj *dest)
2026 * Duplicate all timers assigned to src and attach them to dest.
2028 * void obj_stop_timers(struct obj *obj)
2029 * Stop all timers attached to obj.
2031 * boolean obj_has_timer(struct obj *object, short timer_type)
2032 * Check whether object has a timer of type timer_type.
2035 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
2036 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
2037 STATIC_DCL void FDECL(insert_timer, (timer_element *));
2038 STATIC_DCL timer_element *FDECL(remove_timer,
2039 (timer_element **, SHORT_P, ANY_P *));
2040 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
2041 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
2042 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
2043 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
2045 /* ordered timer list */
2046 static timer_element *timer_base; /* "active" */
2047 static unsigned long timer_id = 1;
2049 /* If defined, then include names when printing out the timer queue */
2050 #define VERBOSE_TIMER
2053 timeout_proc f, cleanup;
2054 #ifdef VERBOSE_TIMER
2056 #define TTAB(a, b, c) \
2061 #define TTAB(a, b, c) \
2068 /* table of timeout functions */
2069 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
2070 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
2071 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
2072 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
2073 TTAB(burn_object, cleanup_burn, "burn_object"),
2074 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
2075 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
2076 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
2080 STATIC_OVL const char *
2098 print_queue(win, base)
2100 timer_element *base;
2102 timer_element *curr;
2106 putstr(win, 0, " <empty>");
2108 putstr(win, 0, "timeout id kind call");
2109 for (curr = base; curr; curr = curr->next) {
2110 #ifdef VERBOSE_TIMER
2111 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
2112 curr->tid, kind_name(curr->kind),
2113 timeout_funcs[curr->func_index].name,
2114 fmt_ptr((genericptr_t) curr->arg.a_void));
2116 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
2117 curr->tid, kind_name(curr->kind), curr->func_index,
2118 fmt_ptr((genericptr_t) curr->arg.a_void));
2120 putstr(win, 0, buf);
2130 const char *propname;
2132 int i, p, count, longestlen, ln, specindx = 0;
2134 win = create_nhwindow(NHW_MENU); /* corner text window */
2138 Sprintf(buf, "Current time = %ld.", monstermoves);
2139 putstr(win, 0, buf);
2141 putstr(win, 0, "Active timeout queue:");
2143 print_queue(win, timer_base);
2146 * check every one; the majority can't obtain temporary timeouts in
2147 * normal play but those can be forced via the #wizintrinsic command.
2149 count = longestlen = 0;
2150 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2151 p = propertynames[i].prop_num;
2152 intrinsic = u.uprops[p].intrinsic;
2153 if (intrinsic & TIMEOUT) {
2155 if ((ln = (int) strlen(propname)) > longestlen)
2158 if (specindx == 0 && p == FIRE_RES)
2163 putstr(win, 0, "No timed properties.");
2165 putstr(win, 0, "Timed properties:");
2167 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2168 p = propertynames[i].prop_num;
2169 intrinsic = u.uprops[p].intrinsic;
2170 if (intrinsic & TIMEOUT) {
2171 if (specindx > 0 && i >= specindx) {
2172 putstr(win, 0, " -- settable via #wizinstrinc only --");
2175 /* timeout value can be up to 16777215 (0x00ffffff) but
2176 width of 4 digits should result in values lining up
2177 almost all the time (if/when they don't, it won't
2178 look nice but the information will still be accurate) */
2179 Sprintf(buf, " %*s %4ld", -longestlen, propname,
2180 (intrinsic & TIMEOUT));
2181 putstr(win, 0, buf);
2185 display_nhwindow(win, FALSE);
2186 destroy_nhwindow(win);
2192 timer_sanity_check()
2194 timer_element *curr;
2196 /* this should be much more complete */
2197 for (curr = timer_base; curr; curr = curr->next)
2198 if (curr->kind == TIMER_OBJECT) {
2199 struct obj *obj = curr->arg.a_obj;
2201 if (obj->timed == 0) {
2202 impossible("timer sanity: untimed obj %s, timer %ld",
2203 fmt_ptr((genericptr_t) obj), curr->tid);
2209 * Pick off timeout elements from the global queue and call their functions.
2210 * Do this until their time is less than or equal to the move count.
2215 timer_element *curr;
2218 * Always use the first element. Elements may be added or deleted at
2219 * any time. The list is ordered, we are done when the first element
2222 while (timer_base && timer_base->timeout <= monstermoves) {
2224 timer_base = curr->next;
2226 if (curr->kind == TIMER_OBJECT)
2227 (curr->arg.a_obj)->timed--;
2228 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
2229 free((genericptr_t) curr);
2234 * Start a timer. Return TRUE if successful.
2237 start_timer(when, kind, func_index, arg)
2245 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
2246 panic("start_timer");
2248 gnu = (timer_element *) alloc(sizeof(timer_element));
2249 (void) memset((genericptr_t)gnu, 0, sizeof(timer_element));
2251 gnu->tid = timer_id++;
2252 gnu->timeout = monstermoves + when;
2254 gnu->needs_fixup = 0;
2255 gnu->func_index = func_index;
2259 if (kind == TIMER_OBJECT) /* increment object's timed count */
2260 (arg->a_obj)->timed++;
2262 /* should check for duplicates and fail if any */
2267 * Remove the timer from the current list and free it up. Return the time
2268 * remaining until it would have gone off, 0 if not found.
2271 stop_timer(func_index, arg)
2275 timer_element *doomed;
2278 doomed = remove_timer(&timer_base, func_index, arg);
2281 timeout = doomed->timeout;
2282 if (doomed->kind == TIMER_OBJECT)
2283 (arg->a_obj)->timed--;
2284 if (timeout_funcs[doomed->func_index].cleanup)
2285 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
2286 free((genericptr_t) doomed);
2287 return (timeout - monstermoves);
2293 * Find the timeout of specified timer; return 0 if none.
2296 peek_timer(type, arg)
2300 timer_element *curr;
2302 for (curr = timer_base; curr; curr = curr->next) {
2303 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
2304 return curr->timeout;
2310 * Move all object timers from src to dest, leaving src untimed.
2313 obj_move_timers(src, dest)
2314 struct obj *src, *dest;
2317 timer_element *curr;
2319 for (count = 0, curr = timer_base; curr; curr = curr->next)
2320 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2321 curr->arg.a_obj = dest;
2325 if (count != src->timed)
2326 panic("obj_move_timers");
2331 * Find all object timers and duplicate them for the new object "dest".
2334 obj_split_timers(src, dest)
2335 struct obj *src, *dest;
2337 timer_element *curr, *next_timer = 0;
2339 for (curr = timer_base; curr; curr = next_timer) {
2340 next_timer = curr->next; /* things may be inserted */
2341 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2342 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
2343 curr->func_index, obj_to_any(dest));
2349 * Stop all timers attached to this object. We can get away with this because
2350 * all object pointers are unique.
2353 obj_stop_timers(obj)
2356 timer_element *curr, *prev, *next_timer = 0;
2358 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2359 next_timer = curr->next;
2360 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
2362 prev->next = curr->next;
2364 timer_base = curr->next;
2365 if (timeout_funcs[curr->func_index].cleanup)
2366 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2368 free((genericptr_t) curr);
2377 * Check whether object has a timer of type timer_type.
2380 obj_has_timer(object, timer_type)
2384 long timeout = peek_timer(timer_type, obj_to_any(object));
2386 return (boolean) (timeout != 0L);
2390 * Stop all timers of index func_index at this spot.
2394 spot_stop_timers(x, y, func_index)
2398 timer_element *curr, *prev, *next_timer = 0;
2399 long where = (((long) x << 16) | ((long) y));
2401 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2402 next_timer = curr->next;
2403 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2404 && curr->arg.a_long == where) {
2406 prev->next = curr->next;
2408 timer_base = curr->next;
2409 if (timeout_funcs[curr->func_index].cleanup)
2410 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2412 free((genericptr_t) curr);
2420 * When is the spot timer of type func_index going to expire?
2421 * Returns 0L if no such timer.
2424 spot_time_expires(x, y, func_index)
2428 timer_element *curr;
2429 long where = (((long) x << 16) | ((long) y));
2431 for (curr = timer_base; curr; curr = curr->next) {
2432 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2433 && curr->arg.a_long == where)
2434 return curr->timeout;
2440 spot_time_left(x, y, func_index)
2444 long expires = spot_time_expires(x, y, func_index);
2445 return (expires > 0L) ? expires - monstermoves : 0L;
2448 /* Insert timer into the global queue */
2453 timer_element *curr, *prev;
2455 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2456 if (curr->timeout >= gnu->timeout)
2466 STATIC_OVL timer_element *
2467 remove_timer(base, func_index, arg)
2468 timer_element **base;
2472 timer_element *prev, *curr;
2474 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2475 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2480 prev->next = curr->next;
2489 write_timer(fd, timer)
2491 timer_element *timer;
2496 switch (timer->kind) {
2499 /* assume no pointers in arg */
2500 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2504 if (timer->needs_fixup)
2505 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2507 /* replace object pointer with id */
2508 arg_save.a_obj = timer->arg.a_obj;
2509 timer->arg = zeroany;
2510 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2511 timer->needs_fixup = 1;
2512 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2513 timer->arg.a_obj = arg_save.a_obj;
2514 timer->needs_fixup = 0;
2519 if (timer->needs_fixup)
2520 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2522 /* replace monster pointer with id */
2523 arg_save.a_monst = timer->arg.a_monst;
2524 timer->arg = zeroany;
2525 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2526 timer->needs_fixup = 1;
2527 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2528 timer->arg.a_monst = arg_save.a_monst;
2529 timer->needs_fixup = 0;
2534 panic("write_timer");
2540 * Return TRUE if the object will stay on the level when the level is
2547 switch (obj->where) {
2555 return obj_is_local(obj->ocontainer);
2557 return mon_is_local(obj->ocarry);
2559 panic("obj_is_local");
2564 * Return TRUE if the given monster will stay on the level when the
2573 for (curr = migrating_mons; curr; curr = curr->nmon)
2576 /* `mydogs' is used during level changes, never saved and restored */
2577 for (curr = mydogs; curr; curr = curr->nmon)
2584 * Return TRUE if the timer is attached to something that will stay on the
2585 * level when the level is saved.
2588 timer_is_local(timer)
2589 timer_element *timer;
2591 switch (timer->kind) {
2597 return obj_is_local(timer->arg.a_obj);
2599 return mon_is_local(timer->arg.a_monst);
2601 panic("timer_is_local");
2606 * Part of the save routine. Count up the number of timers that would
2607 * be written. If write_it is true, actually write the timer.
2610 maybe_write_timer(fd, range, write_it)
2615 timer_element *curr;
2617 for (curr = timer_base; curr; curr = curr->next) {
2618 if (range == RANGE_GLOBAL) {
2621 if (!timer_is_local(curr)) {
2624 write_timer(fd, curr);
2630 if (timer_is_local(curr)) {
2633 write_timer(fd, curr);
2642 * Save part of the timer list. The parameter 'range' specifies either
2643 * global or level timers to save. The timer ID is saved with the global
2647 * + timeouts that follow the hero (global)
2648 * + timeouts that follow obj & monst that are migrating
2651 * + timeouts that are level specific (e.g. storms)
2652 * + timeouts that stay with the level (obj & monst)
2655 save_timers(fd, mode, range)
2656 int fd, mode, range;
2658 timer_element *curr, *prev, *next_timer = 0;
2661 if (perform_bwrite(mode)) {
2662 if (range == RANGE_GLOBAL)
2663 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2665 count = maybe_write_timer(fd, range, FALSE);
2666 bwrite(fd, (genericptr_t) &count, sizeof count);
2667 (void) maybe_write_timer(fd, range, TRUE);
2670 if (release_data(mode)) {
2671 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2672 next_timer = curr->next; /* in case curr is removed */
2674 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2676 prev->next = curr->next;
2678 timer_base = curr->next;
2679 free((genericptr_t) curr);
2680 /* prev stays the same */
2689 * Pull in the structures from disk, but don't recalculate the object and
2693 restore_timers(fd, range, ghostly, adjust)
2695 boolean ghostly; /* restoring from a ghost level */
2696 long adjust; /* how much to adjust timeout */
2699 timer_element *curr;
2701 if (range == RANGE_GLOBAL)
2702 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2704 /* restore elements */
2705 mread(fd, (genericptr_t) &count, sizeof count);
2706 while (count-- > 0) {
2707 curr = (timer_element *) alloc(sizeof(timer_element));
2708 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2710 curr->timeout += adjust;
2715 /* to support '#stats' wizard-mode command */
2717 timer_stats(hdrfmt, hdrbuf, count, size)
2724 Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
2725 *count = *size = 0L;
2726 for (te = timer_base; te; te = te->next) {
2728 *size += (long) sizeof *te;
2732 /* reset all timers that are marked for reseting */
2734 relink_timers(ghostly)
2737 timer_element *curr;
2740 for (curr = timer_base; curr; curr = curr->next) {
2741 if (curr->needs_fixup) {
2742 if (curr->kind == TIMER_OBJECT) {
2744 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2745 panic("relink_timers 1");
2747 nid = curr->arg.a_uint;
2748 curr->arg.a_obj = find_oid(nid);
2749 if (!curr->arg.a_obj)
2750 panic("cant find o_id %d", nid);
2751 curr->needs_fixup = 0;
2752 } else if (curr->kind == TIMER_MONSTER) {
2753 panic("relink_timers: no monster timer implemented");
2755 panic("relink_timers 2");