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;
504 Strcpy(killer.name, "slimicide");
505 /* immediately follows "OK, so you don't die." */
506 pline("Yes, you do. Green slime has been genocided...");
508 /* could be life-saved again (only in explore or wizard mode)
509 but green slimes are gone; just stay in current form */
514 /* Intrinsic Passes_walls is temporary when your god is trying to fix
515 all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but
516 it can't find anywhere to place you. If that happens you get a small
517 value for (HPasses_walls & TIMEOUT) to move somewhere yourself.
518 Message given is "you feel much slimmer" as a joke hint that you can
519 move between things which are closely packed--like the substance of
521 static NEARDATA const char *const phaze_texts[] = {
523 "You start to feel bloated.",
524 "You are feeling rather flabby.",
526 "
\82 \82È
\82½
\82Í
\96c
\82ç
\82Ý
\82Í
\82¶
\82ß
\82½
\8bC
\82ª
\82·
\82é
\81D",
527 "
\82 \82È
\82½
\82Í
\8f
\82µ
\82½
\82é
\82ñ
\82¾
\8bC
\82ª
\82·
\82é
\81D",
534 long i = ((HPasses_walls & TIMEOUT) / 2L);
536 if (EPasses_walls || (HPasses_walls & ~TIMEOUT))
539 if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts))
540 pline1(phaze_texts[SIZE(phaze_texts) - i]);
546 register struct prop *upp;
551 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
556 if (u.uluck != baseluck
557 && moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
558 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
559 * stop good luck from timing out; normal luckstones stop both;
560 * neither is stopped if you don't have a luckstone.
561 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
563 register int time_luck = stone_luck(FALSE);
564 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
566 if (u.uluck > baseluck && (nostone || time_luck < 0))
568 else if (u.uluck < baseluck && (nostone || time_luck > 0))
572 return; /* things past this point could kill you */
581 if (HLevitation & TIMEOUT)
582 levitation_dialogue();
583 if (HPasses_walls & TIMEOUT)
585 if (u.mtimedone && !--u.mtimedone) {
587 u.mtimedone = rnd(100 * youmonst.data->mlevel + 1);
588 else if (is_were(youmonst.data))
589 you_unwere(FALSE); /* if polycontrl, asks whether to rehumanize */
596 /* Dissipate spell-based protection. */
598 if (--u.usptime == 0 && u.uspellprot) {
599 u.usptime = u.uspmtime;
604 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
605 u.uspellprot ? "becomes less dense" : "disappears");
607 Norep("
\82 \82È
\82½
\82Ì
\89ñ
\82è
\82Ì%s
\96¶
\82Í%s
\81D", hcolor(NH_GOLDEN),
608 u.uspellprot ? "
\8fÁ
\82¦
\82Í
\82¶
\82ß
\82½" : "
\8fÁ
\82¦
\82½");
614 if (--u.ugallop == 0L && u.usteed)
616 pline("%s stops galloping.", Monnam(u.usteed));
618 pline("%s
\82Í
\91¬
\8bì
\82¯
\82ð
\82â
\82ß
\82½
\81D", Monnam(u.usteed));
622 for (upp = u.uprops; upp < u.uprops + SIZE(u.uprops); upp++)
623 if ((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
624 kptr = find_delayed_killer((int) (upp - u.uprops));
625 switch (upp - u.uprops) {
627 if (kptr && kptr->name[0]) {
628 killer.format = kptr->format;
630 Strcpy(killer.name, kptr->name);
632 Sprintf(killer.name, "%s
\82Ì
\8dU
\8c\82\82Å", kptr->name);
636 killer.format = NO_KILLER_PREFIX;
637 Strcpy(killer.name, "killed by petrification");
639 killer.format = KILLED_BY;
640 Strcpy(killer.name, "
\90Î
\89»
\8dU
\8c\82\82Å");
643 dealloc_killer(kptr);
644 /* (unlike sliming, you aren't changing form here) */
648 slimed_to_death(kptr); /* done(TURNED_SLIME) */
651 make_vomiting(0L, TRUE);
655 You("die from your illness.");
657 You("
\95a
\8bC
\82Å
\8e\80\82ñ
\82¾
\81D");
658 if (kptr && kptr->name[0]) {
659 killer.format = kptr->format;
660 Strcpy(killer.name, kptr->name);
662 killer.format = KILLED_BY_AN;
663 killer.name[0] = 0; /* take the default */
665 dealloc_killer(kptr);
667 if ((m_idx = name_to_mon(killer.name)) >= LOW_PM) {
668 if (type_is_pname(&mons[m_idx])) {
669 killer.format = KILLED_BY;
670 } else if (mons[m_idx].geno & G_UNIQ) {
671 Strcpy(killer.name, the(killer.name));
672 killer.format = KILLED_BY;
681 You_feel("yourself slowing down%s.",
682 Fast ? " a bit" : "");
684 You("%s
\92x
\82
\82È
\82Á
\82½
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
685 Fast ? "
\82¿
\82å
\82Á
\82Æ" : "");
689 /* So make_confused works properly */
690 set_itimeout(&HConfusion, 1L);
691 make_confused(0L, TRUE);
696 set_itimeout(&HStun, 1L);
697 make_stunned(0L, TRUE);
702 set_itimeout(&Blinded, 1L);
703 make_blinded(0L, TRUE);
708 set_itimeout(&HDeaf, 1L);
716 if (!Invis && !BInvis && !Blind) {
719 ? "are no longer invisible."
720 : "can no longer see through yourself.");
723 ? "
\82à
\82¤
\93§
\96¾
\82Å
\82Í
\82È
\82¢
\81D"
724 : "
\93§
\82«
\82Æ
\82¨
\82Á
\82Ä
\82¢
\82È
\82¢
\81D");
730 set_mimic_blocking(); /* do special mimic handling */
731 see_monsters(); /* make invis mons appear */
732 newsym(u.ux, u.uy); /* make self appear */
742 make_totter(0L, TRUE);
747 set_itimeout(&HHallucination, 1L);
748 (void) make_hallucinated(0L, TRUE, 0L);
753 if (unconscious() || Sleep_resistance) {
754 incr_itimeout(&HSleepy, rnd(100));
759 You("
\96°
\82è
\82É
\97\8e\82¿
\82½
\81D");
761 fall_asleep(-sleeptime, TRUE);
762 incr_itimeout(&HSleepy, sleeptime + rnd(100));
766 (void) float_down(I_SPECIAL | TIMEOUT, 0L);
769 /* timed Flying is via #wizintrinsic only */
770 if (was_flying && !Flying) {
777 /* timed Warn_of_mon is via #wizintrinsic only */
779 context.warntype.speciesidx = NON_PM;
780 if (context.warntype.species) {
781 You("are no longer warned about %s.",
782 makeplural(context.warntype.species->mname));
783 context.warntype.species = (struct permonst *) 0;
791 You_feel("hemmed in again.");
793 You_feel("
\82Ü
\82½
\95Â
\82¶
\8d\9e\82ß
\82ç
\82ê
\82½
\82æ
\82¤
\82¾
\81D");
796 pline("You're back to your %s self again.",
797 !Upolyd ? "normal" : "unusual");
799 pline("
\82 \82È
\82½
\82Í
\8dÄ
\82Ñ
\92Ê
\8fí%s
\82Ì
\8fó
\91Ô
\82É
\82È
\82Á
\82½
\81D",
800 !Upolyd ? "" : "
\82Å
\82Í
\82È
\82¢");
805 killer.format = KILLED_BY;
808 (u.uburied) ? "suffocation" : "strangulation");
811 (u.uburied) ? "
\92\82\91§
\82µ
\82Ä" : "
\8eñ
\82ð
\8di
\82ß
\82ç
\82ê
\82Ä");
814 /* must be declining to die in explore|wizard mode;
815 treat like being cured of strangulation by prayer */
816 if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) {
818 Your("amulet vanishes!");
820 Your("
\96\82\8f\9c\82¯
\82Í
\8fÁ
\82¦
\82½
\81I");
825 /* call this only when a move took place. */
826 /* otherwise handle fumbling msgs locally. */
827 if (u.umoved && !Levitation) {
831 multi_reason = "fumbling";
833 multi_reason = "
\82Ö
\82Ü
\82ð
\82µ
\82½
\8c\84\82É";
835 /* The more you are carrying the more likely you
836 * are to make noise when you fumble. Adjustments
837 * to this number must be thoroughly play tested.
839 if ((inv_weight() > -500)) {
841 You("make a lot of noise!");
843 You("
\91å
\82«
\82È
\89¹
\82ð
\82½
\82Ä
\82½
\81I");
847 /* from outside means slippery ice; don't reset
848 counter if that's the only fumble reason */
849 HFumbling &= ~FROMOUTSIDE;
851 incr_itimeout(&HFumbling, rnd(20));
853 case DETECT_MONSTERS:
863 fall_asleep(how_long, wakeup_msg)
870 multi_reason = "sleeping";
872 multi_reason = "
\96°
\82è
\82Ì
\82³
\82È
\82©
\82É";
873 /* generally don't notice sounds while sleeping */
874 if (wakeup_msg && multi == how_long) {
875 /* caller can follow with a direct call to Hear_again() if
876 there's a need to override this when wakeup_msg is true */
877 incr_itimeout(&HDeaf, how_long);
879 afternmv = Hear_again; /* this won't give any messages */
881 /* early wakeup from combat won't be possible until next monster turn */
882 u.usleep = monstermoves;
884 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
886 nomovemsg = wakeup_msg ? "
\96Ú
\82ð
\8ao
\82Ü
\82µ
\82½
\81D" : You_can_move_again;
889 /* Attach an egg hatch timeout to the given egg.
890 * when = Time to hatch, usually only passed if re-creating an
891 * existing hatch timer. Pass 0L for random hatch time.
894 attach_egg_hatch_timeout(egg, when)
900 /* stop previous timer, if any */
901 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
904 * Decide if and when to hatch the egg. The old hatch_it() code tried
905 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
906 * a number x, 1<=x<=age, where x>150. This yields a chance of
907 * hatching > 99.9993%. Mimic that here.
910 for (i = (MAX_EGG_HATCH_TIME - 50) + 1; i <= MAX_EGG_HATCH_TIME; i++)
918 (void) start_timer(when, TIMER_OBJECT, HATCH_EGG, obj_to_any(egg));
922 /* prevent an egg from ever hatching */
927 /* stop previous timer, if any */
928 (void) stop_timer(HATCH_EGG, obj_to_any(egg));
931 /* timer callback routine: hatch the given egg */
933 hatch_egg(arg, timeout)
938 struct monst *mon, *mon2;
941 boolean yours, silent, knows_egg = FALSE;
942 boolean cansee_hatchspot = FALSE;
943 int i, mnum, hatchcount = 0;
946 /* sterilized while waiting */
947 if (egg->corpsenm == NON_PM)
950 mon = mon2 = (struct monst *) 0;
951 mnum = big_to_little(egg->corpsenm);
952 /* The identity of one's father is learned, not innate */
953 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
954 silent = (timeout != monstermoves); /* hatched while away */
956 /* only can hatch when in INVENT, FLOOR, MINVENT */
957 if (get_obj_location(egg, &x, &y, 0)) {
958 hatchcount = rnd((int) egg->quan);
959 cansee_hatchspot = cansee(x, y) && !silent;
960 if (!(mons[mnum].geno & G_UNIQ)
961 && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
962 for (i = hatchcount; i > 0; i--) {
963 if (!enexto(&cc, x, y, &mons[mnum])
964 || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
966 /* tame if your own egg hatches while you're on the
967 same dungeon level, or any dragon egg which hatches
968 while it's in your inventory */
969 if ((yours && !silent)
970 || (carried(egg) && mon->data->mlet == S_DRAGON)) {
971 if (tamedog(mon, (struct obj *) 0)) {
972 if (carried(egg) && mon->data->mlet != S_DRAGON)
976 if (mvitals[mnum].mvflags & G_EXTINCT)
977 break; /* just made last one */
978 mon2 = mon; /* in case makemon() fails on 2nd egg */
983 egg->quan -= (long) hatchcount;
987 * We could possibly hatch while migrating, but the code isn't
990 } else if (obj->where == OBJ_MIGRATING) {
992 * We can do several things. The first ones that come to
994 * + Create the hatched monster then place it on the migrating
995 * mons list. This is tough because all makemon() is made
996 * to place the monster as well. Makemon() also doesn't lend
997 * itself well to splitting off a "not yet placed" subroutine.
998 * + Mark the egg as hatched, then place the monster when we
999 * place the migrating objects.
1000 * + Or just kill any egg which gets sent to another level.
1001 * Falling is the usual reason such transportation occurs.
1003 cansee_hatchspot = FALSE;
1009 char monnambuf[BUFSZ], carriedby[BUFSZ];
1010 boolean siblings = (hatchcount > 1), redraw = FALSE;
1012 if (cansee_hatchspot) {
1013 /* [bug? m_monnam() yields accurate monster type
1014 regardless of hallucination] */
1016 Sprintf(monnambuf, "%s%s", siblings ? "some " : "",
1017 siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon)));
1019 Sprintf(monnambuf, "%s%s", siblings ? "
\82¢
\82
\82Â
\82©
\82Ì" : "",
1022 /* we don't learn the egg type here because learning
1023 an egg type requires either seeing the egg hatch
1024 or being familiar with the egg already,
1025 as well as being able to see the resulting
1026 monster, checked below
1029 switch (egg->where) {
1031 knows_egg = TRUE; /* true even if you are blind */
1032 if (!cansee_hatchspot)
1034 You_feel("%s %s from your pack!", something,
1035 locomotion(mon->data, "drop"));
1037 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82æ
\82¤
\82È
\8bC
\82ª
\82µ
\82½
\81D",
1038 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1042 You_see("%s %s out of your pack!", monnambuf,
1043 locomotion(mon->data, "drop"));
1045 You("%s
\82ª
\82 \82È
\82½
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf,
1046 jpast(locomotion(mon->data, "
\97\8e\82¿
\82é")));
1050 pline("%s cries sound like \"%s%s\"",
1051 siblings ? "Their" : "Its",
1052 flags.female ? "mommy" : "daddy", egg->spe ? "." : "?");
1054 pline("
\82»
\82ê
\82Í
\81w%s%s
\81x
\82Æ
\96Â
\82¢
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D",
1055 flags.female ? "
\83}
\83}" : "
\83p
\83p", egg->spe ? "" : "
\81H");
1057 } else if (mon->data->mlet == S_DRAGON && !Deaf) {
1059 verbalize("Gleep!"); /* Mything eggs :-) */
1061 verbalize("
\83u
\83H
\81[
\81I"); /* Mything eggs :-) */
1067 if (cansee_hatchspot) {
1070 You_see("%s hatch.", monnambuf);
1072 You("%s
\82ª
\97\91\82©
\82ç
\82©
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf);
1073 redraw = TRUE; /* update egg's map location */
1078 if (cansee_hatchspot) {
1079 /* egg carrying monster might be invisible */
1082 && (!mon2->wormno || cansee(mon2->mx, mon2->my))) {
1084 Sprintf(carriedby, "%s pack",
1085 s_suffix(a_monnam(mon2)));
1087 Sprintf(carriedby, "%s
\82Ì
\94w
\95\89\82¢
\91Ü
\82©
\82ç",
1091 } else if (is_pool(mon->mx, mon->my)) {
1093 Strcpy(carriedby, "empty water");
1095 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\90\85\92\86\82©
\82ç");
1098 Strcpy(carriedby, "thin air");
1100 Strcpy(carriedby, "
\89½
\82à
\82È
\82¢
\8bó
\8aÔ
\82©
\82ç");
1103 You_see("%s %s out of %s!", monnambuf,
1104 locomotion(mon->data, "drop"), carriedby);
1106 You("%s
\82ª%s%s
\82Ì
\82ð
\8c©
\82½
\81D", monnambuf, carriedby,
1107 locomotion(mon->data, "
\97\8e\82¿
\82é"));
1116 impossible("egg hatched where? (%d)", (int) egg->where);
1120 if (cansee_hatchspot && knows_egg)
1121 learn_egg_type(mnum);
1123 if (egg->quan > 0) {
1124 /* still some eggs left */
1125 /* Instead of ordinary egg timeout use a short one */
1126 attach_egg_hatch_timeout(egg, (long) rnd(12));
1127 } else if (carried(egg)) {
1130 /* free egg here because we use it above */
1131 obj_extract_self(egg);
1132 obfree(egg, (struct obj *) 0);
1139 /* Learn to recognize eggs of the given type. */
1141 learn_egg_type(mnum)
1144 /* baby monsters hatch from grown-up eggs */
1145 mnum = little_to_big(mnum);
1146 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
1147 /* we might have just learned about other eggs being carried */
1151 /* Attach a fig_transform timeout to the given figurine. */
1153 attach_fig_transform_timeout(figurine)
1154 struct obj *figurine;
1158 /* stop previous timer, if any */
1159 (void) stop_timer(FIG_TRANSFORM, obj_to_any(figurine));
1162 * Decide when to transform the figurine.
1164 i = rnd(9000) + 200;
1165 /* figurine will transform */
1166 (void) start_timer((long) i, TIMER_OBJECT, FIG_TRANSFORM,
1167 obj_to_any(figurine));
1170 /* give a fumble message */
1174 struct obj *otmp = vobj_at(u.ux, u.uy), *otmp2;
1177 boolean on_foot = TRUE;
1181 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy))
1184 if (otmp && on_foot) { /* trip over something in particular */
1186 If there is only one item, it will have just been named
1187 during the move, so refer to by via pronoun; otherwise,
1188 if the top item has been or can be seen, refer to it by
1189 name; if not, look for rocks to trip over; trip over
1190 anonymous "something" if there aren't any rocks.
1193 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1194 ? ((otmp->quan == 1L) ? "it"
1195 : Hallucination ? "they" : "them")
1196 : (otmp->dknown || !Blind)
1198 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1200 : (otmp2->quan == 1L ? "a rock" : "some rocks"));
1202 what = (iflags.last_msg == PLNMSG_ONE_ITEM_HERE)
1204 : (otmp->dknown || !Blind)
1206 : ((otmp2 = sobj_at(ROCK, u.ux, u.uy)) == 0
1210 if (Hallucination) {
1211 what = strcpy(buf, what);
1212 buf[0] = highc(buf[0]);
1214 pline("Egads! %s bite%s your %s!", what,
1215 (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT));
1217 pline("
\82®
\82í
\82\9f\81I%s
\82ª%s
\82É
\8a\9a\82Ý
\82Â
\82¢
\82½
\81I", what, body_part(FOOT));
1221 You("trip over %s.", what);
1223 You("%s
\82É
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D", what);
1225 if (!uarmf && otmp->otyp == CORPSE
1226 && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) {
1228 Sprintf(killer.name, "tripping over %s corpse",
1229 an(mons[otmp->corpsenm].mname));
1231 Sprintf(killer.name, "%s
\82Ì
\8e\80\91Ì
\82É
\82Â
\82Ü
\82Ã
\82¢
\82Ä",
1232 mons[otmp->corpsenm].mname);
1234 instapetrify(killer.name);
1236 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
1238 pline("%s %s%s on the ice.",
1239 u.usteed ? upstart(x_monnam(u.usteed,
1240 (has_mname(u.usteed)) ? ARTICLE_NONE
1242 (char *) 0, SUPPRESS_SADDLE, FALSE))
1244 rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
1246 pline("%s
\82Í
\95X
\82Ì
\8fã
\82Å
\8a\8a\82Á
\82½
\81D",
1247 u.usteed ? upstart(x_monnam(u.usteed,
1248 (has_mname(u.usteed)) ? ARTICLE_NONE
1250 (char *) 0, SUPPRESS_SADDLE, FALSE))
1258 You("trip over your own %s.",
1259 Hallucination ? "elbow" : makeplural(body_part(FOOT)));
1261 You("
\8e©
\95ª
\82Ì%s
\82ð
\93¥
\82ñ
\82Å
\82Â
\82Ü
\82Ã
\82¢
\82½
\81D",
1262 Hallucination ? "
\95I" : body_part(FOOT));
1268 Hallucination ? "on a banana peel" : "and nearly fall");
1270 You("%s
\81D", Hallucination ?
1271 "
\83o
\83i
\83i
\82Ì
\94ç
\82Å
\8a\8a\82Á
\82½" : "
\8a\8a\82Á
\82Ä
\93]
\82Ñ
\82»
\82¤
\82É
\82È
\82Á
\82½");
1278 You("
\82¶
\82½
\82Î
\82½
\82µ
\82½
\81D");
1284 You("
\82æ
\82ë
\82ß
\82¢
\82½
\81D");
1291 Your("%s slip out of the stirrups.",
1292 makeplural(body_part(FOOT)));
1294 You("
\82 \82Ô
\82Ý
\82ð
\93¥
\82Ý
\8aO
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1299 You("let go of the reins.");
1301 You("
\8eè
\8dj
\82ð
\95ú
\82µ
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1305 You("bang into the saddle-horn.");
1307 You("
\83T
\83h
\83\8b\83z
\81[
\83\93\82É
\82Ô
\82Â
\82©
\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1311 You("slide to one side of the saddle.");
1313 You("
\82·
\82×
\82Á
\82Ä
\88Æ
\82Ì
\95Ð
\91¤
\82É
\82¸
\82ê
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D");
1316 dismount_steed(DISMOUNT_FELL);
1321 /* Print a lamp flicker message with tailer. */
1323 see_lamp_flicker(obj, tailer)
1327 switch (obj->where) {
1331 pline("%s flickers%s.", Yname2(obj), tailer);
1333 pline("%s
\82Í%s
\93_
\96Å
\82µ
\82½
\81D", Yname2(obj), tailer);
1337 You_see("%s flicker%s.", an(xname(obj)), tailer);
1339 You("%s
\82ª%s
\93_
\96Å
\82·
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)), tailer);
1344 /* Print a dimming message for brass lanterns. */
1346 lantern_message(obj)
1349 /* from adventure */
1350 switch (obj->where) {
1353 Your("lantern is getting dim.");
1355 Your("
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D");
1358 pline("Batteries have not been invented yet.");
1360 pline("
\93d
\92r
\82Í
\82Ü
\82¾
\94
\96¾
\82³
\82ê
\82Ä
\82È
\82¢
\82ñ
\82¾
\82Á
\82¯
\81D");
1364 You_see("a lantern getting dim.");
1366 pline("
\83\89\83\93\83^
\83\93\82ª
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\82Ì
\82ª
\8c©
\82¦
\82½
\81D");
1370 pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry)));
1372 pline("%s
\82Ì
\83\89\83\93\83^
\83\93\82Í
\88Ã
\82
\82È
\82Á
\82Ä
\82«
\82½
\81D", Monnam(obj->ocarry));
1378 * Timeout callback for for objects that are burning. E.g. lamps, candles.
1379 * See begin_burn() for meanings of obj->age and obj->spe.
1382 burn_object(arg, timeout)
1386 struct obj *obj = arg->a_obj;
1388 boolean canseeit, many, menorah, need_newsym, need_invupdate;
1390 boolean canseeit, menorah, need_newsym, need_invupdate;
1395 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
1397 many = menorah ? obj->spe > 1 : obj->quan > 1L;
1400 /* timeout while away */
1401 if (timeout != monstermoves) {
1402 long how_long = monstermoves - timeout;
1404 if (how_long >= obj->age) {
1406 end_burn(obj, FALSE);
1409 obj->spe = 0; /* no more candles */
1410 obj->owt = weight(obj);
1411 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
1412 /* get rid of candles and burning oil potions;
1413 we know this object isn't carried by hero,
1414 nor is it migrating */
1415 obj_extract_self(obj);
1416 obfree(obj, (struct obj *) 0);
1417 obj = (struct obj *) 0;
1421 obj->age -= how_long;
1422 begin_burn(obj, TRUE);
1427 /* only interested in INVENT, FLOOR, and MINVENT */
1428 if (get_obj_location(obj, &x, &y, 0)) {
1429 canseeit = !Blind && cansee(x, y);
1430 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
1431 (void) Shk_Your(whose, obj);
1435 need_newsym = need_invupdate = FALSE;
1437 /* obj->age is the age remaining at this point. */
1438 switch (obj->otyp) {
1440 /* this should only be called when we run out */
1442 switch (obj->where) {
1444 need_invupdate = TRUE;
1448 pline("%spotion of oil has burnt away.", whose);
1450 pline("%s
\83I
\83C
\83\8b\82Í
\94R
\82¦
\82Â
\82«
\82½
\81D", whose);
1454 You_see("a burning potion of oil go out.");
1456 You("
\83I
\83C
\83\8b\82Ì
\89Î
\82ª
\8fÁ
\82¦
\82½
\82Ì
\82ð
\8c©
\82½
\81D");
1461 end_burn(obj, FALSE); /* turn off light source */
1465 /* clear migrating obj's destination code before obfree
1466 to avoid false complaint of deleting worn item */
1467 if (obj->where == OBJ_MIGRATING)
1468 obj->owornmask = 0L;
1469 obj_extract_self(obj);
1470 obfree(obj, (struct obj *) 0);
1472 obj = (struct obj *) 0;
1477 switch ((int) obj->age) {
1482 if (obj->otyp == BRASS_LANTERN)
1483 lantern_message(obj);
1485 see_lamp_flicker(obj,
1487 obj->age == 50L ? " considerably" : "");
1489 obj->age == 50L ? "
\8c\83\82µ
\82" : "");
1495 if (obj->otyp == BRASS_LANTERN)
1496 lantern_message(obj);
1498 switch (obj->where) {
1502 pline("%s seems about to go out.", Yname2(obj));
1504 pline("%s
\82Í
\8d¡
\82É
\82à
\8fÁ
\82¦
\82»
\82¤
\82¾
\81D", Yname2(obj));
1508 You_see("%s about to go out.", an(xname(obj)));
1510 pline("%s
\82ª
\8fÁ
\82¦
\82©
\82¯
\82Ä
\82¢
\82é
\82Ì
\82ª
\8c©
\82¦
\82½
\81D", an(xname(obj)));
1518 /* even if blind you'll know if holding it */
1519 if (canseeit || obj->where == OBJ_INVENT) {
1520 switch (obj->where) {
1522 need_invupdate = TRUE;
1525 if (obj->otyp == BRASS_LANTERN)
1527 pline("%slantern has run out of power.", whose);
1529 pline("%s
\83\89\83\93\83^
\83\93\82Ì
\97Í
\82ð
\8eg
\82¢
\90Ø
\82Á
\82½
\81D", whose);
1532 pline("%s has gone out.", Yname2(obj));
1534 pline("%s
\82Í
\8fÁ
\82¦
\82½
\81D", Yname2(obj));
1537 if (obj->otyp == BRASS_LANTERN)
1539 You_see("a lantern run out of power.");
1541 You("
\83\89\83\93\83^
\83\93\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1544 You_see("%s go out.", an(xname(obj)));
1546 You("%s
\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D", an(xname(obj)));
1550 end_burn(obj, FALSE);
1555 * Someone added fuel to the lamp while it was
1556 * lit. Just fall through and let begin burn
1557 * handle the new age.
1563 begin_burn(obj, TRUE);
1567 case CANDELABRUM_OF_INVOCATION:
1573 switch (obj->where) {
1577 pline("%s%scandle%s getting short.", whose,
1578 menorah ? "candelabrum's " : "",
1579 many ? "s are" : " is");
1581 pline("%s%s
\82ë
\82¤
\82»
\82
\82Í
\92Z
\82
\82È
\82Á
\82½
\81D", whose,
1582 menorah ? "
\90C
\91ä
\82Ì" : "");
1587 You_see("%scandle%s getting short.",
1588 menorah ? "a candelabrum's " : many ? "some "
1592 You("%s
\82ë
\82¤
\82»
\82
\82ª
\92Z
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81D",
1593 menorah ? "
\90C
\91ä
\82Ì" : "");
1601 switch (obj->where) {
1605 pline("%s%scandle%s flame%s flicker%s low!", whose,
1606 menorah ? "candelabrum's " : "", many ? "s'" : "'s",
1607 many ? "s" : "", many ? "" : "s");
1609 pline("%s%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82Í
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82Á
\82½
\81I", whose,
1610 menorah ? "
\90C
\91ä
\82Ì" : "");
1615 You_see("%scandle%s flame%s flicker low!",
1616 menorah ? "a candelabrum's " : many ? "some "
1618 many ? "s'" : "'s", many ? "s" : "");
1620 You("%s
\82ë
\82¤
\82»
\82
\82Ì
\89\8a\82ª
\93_
\96Å
\82µ
\81C
\88Ã
\82
\82È
\82é
\82Ì
\82ð
\8c©
\82½
\81I",
1621 menorah ? "
\90C
\91ä
\82Ì" : "");
1628 /* we know even if blind and in our inventory */
1629 if (canseeit || obj->where == OBJ_INVENT) {
1631 switch (obj->where) {
1633 need_invupdate = TRUE;
1637 pline("%scandelabrum's flame%s.", whose,
1638 many ? "s die" : " dies");
1640 pline("%s
\90C
\91ä
\82Ì
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D", whose);
1645 You_see("a candelabrum's flame%s die.",
1648 You("
\90C
\91ä
\82Ì
\89\8a\82ª
\8fÁ
\82¦
\82é
\82Ì
\82ð
\8c©
\82½
\81D");
1653 switch (obj->where) {
1655 /* no need_invupdate for update_inventory() necessary;
1656 useupall() -> freeinv() handles it */
1660 pline("%s %s consumed!", Yname2(obj),
1661 many ? "are" : "is");
1663 pline("%s
\82Í
\94R
\82¦
\82Â
\82«
\82½
\81I", Yname2(obj));
1668 You see some wax candles consumed!
1669 You see a wax candle consumed!
1672 You_see("%s%s consumed!", many ? "some " : "",
1673 many ? xname(obj) : an(xname(obj)));
1675 You("%s
\82ª
\94R
\82¦
\82Â
\82«
\82é
\82Ì
\82ð
\8c©
\82½
\81I", xname(obj));
1684 ? (many ? "They shriek!" : "It shrieks!")
1685 : Blind ? "" : (many ? "Their flames die."
1686 : "Its flame dies."));
1688 pline(Hallucination ? "
\82»
\82ê
\82Í
\8bà
\90Ø
\82è
\90º
\82ð
\82 \82°
\82½
\81I"
1690 : "
\89\8a\82Í
\8fÁ
\82¦
\82½
\81D");
1694 end_burn(obj, FALSE);
1698 obj->owt = weight(obj);
1703 /* clear migrating obj's destination code
1704 so obfree won't think this item is worn */
1705 if (obj->where == OBJ_MIGRATING)
1706 obj->owornmask = 0L;
1707 obj_extract_self(obj);
1708 obfree(obj, (struct obj *) 0);
1710 obj = (struct obj *) 0;
1712 break; /* case [age ==] 0 */
1716 * Someone added fuel (candles) to the menorah while
1717 * it was lit. Just fall through and let begin burn
1718 * handle the new age.
1723 if (obj && obj->age)
1724 begin_burn(obj, TRUE);
1725 break; /* case [otyp ==] candelabrum|tallow_candle|wax_candle */
1728 impossible("burn_object: unexpeced obj %s", xname(obj));
1738 * Start a burn timeout on the given object. If not "already lit" then
1739 * create a light source for the vision system. There had better not
1740 * be a burn already running on the object.
1742 * Magic lamps stay lit as long as there's a genie inside, so don't start
1746 * potions of oil, lamps & candles:
1747 * age = # of turns of fuel left
1751 * spe = 0 not lightable, 1 lightable forever
1753 * age = # of turns of fuel left
1754 * spe = # of candles
1756 * Once the burn begins, the age will be set to the amount of fuel
1757 * remaining _once_the_burn_finishes_. If the burn is terminated
1758 * early then fuel is added back.
1760 * This use of age differs from the use of age for corpses and eggs.
1761 * For the latter items, age is when the object was created, so we
1762 * know when it becomes "bad".
1764 * This is a "silent" routine - it should not print anything out.
1767 begin_burn(obj, already_lit)
1769 boolean already_lit;
1773 boolean do_timer = TRUE;
1775 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1778 switch (obj->otyp) {
1787 turns = (3L * turns + 2L) / 4L;
1788 radius = 1; /* very dim light */
1793 /* magic times are 150, 100, 50, 25, and 0 */
1794 if (obj->age > 150L)
1795 turns = obj->age - 150L;
1796 else if (obj->age > 100L)
1797 turns = obj->age - 100L;
1798 else if (obj->age > 50L)
1799 turns = obj->age - 50L;
1800 else if (obj->age > 25L)
1801 turns = obj->age - 25L;
1806 case CANDELABRUM_OF_INVOCATION:
1809 /* magic times are 75, 15, and 0 */
1811 turns = obj->age - 75L;
1812 else if (obj->age > 15L)
1813 turns = obj->age - 15L;
1816 radius = candle_light_range(obj);
1820 /* [ALI] Support artifact light sources */
1821 if (artifact_light(obj)) {
1824 radius = arti_light_radius(obj);
1826 impossible("begin burn: unexpected %s", xname(obj));
1833 if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, obj_to_any(obj))) {
1836 if (carried(obj) && !already_lit)
1842 if (carried(obj) && !already_lit)
1846 if (obj->lamplit && !already_lit) {
1849 if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
1850 new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
1852 impossible("begin_burn: can't get obj position");
1857 * Stop a burn timeout on the given object if timer attached. Darken
1861 end_burn(obj, timer_attached)
1863 boolean timer_attached;
1865 if (!obj->lamplit) {
1866 impossible("end_burn: obj %s not lit", xname(obj));
1870 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1871 timer_attached = FALSE;
1873 if (!timer_attached) {
1874 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1875 del_light_source(LS_OBJECT, obj_to_any(obj));
1877 if (obj->where == OBJ_INVENT)
1879 } else if (!stop_timer(BURN_OBJECT, obj_to_any(obj)))
1880 impossible("end_burn: obj %s not timed!", xname(obj));
1884 * Cleanup a burning object if timer stopped.
1887 cleanup_burn(arg, expire_time)
1891 struct obj *obj = arg->a_obj;
1892 if (!obj->lamplit) {
1893 impossible("cleanup_burn: obj %s not lit", xname(obj));
1897 del_light_source(LS_OBJECT, obj_to_any(obj));
1899 /* restore unused time */
1900 obj->age += expire_time - monstermoves;
1904 if (obj->where == OBJ_INVENT)
1916 /* no lightning if not the air level or too often, even then */
1917 if (!Is_airlevel(&u.uz) || rn2(8))
1920 /* the number of strikes is 8-log2(nstrike) */
1921 for (nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1926 } while (++count < 100 && levl[x][y].typ != CLOUD);
1931 if (dirx != 0 || diry != 0)
1932 buzz(-15, /* "monster" LIGHTNING spell */
1933 8, x, y, dirx, diry);
1937 if (levl[u.ux][u.uy].typ == CLOUD) {
1938 /* Inside a cloud during a thunder storm is deafening. */
1939 /* Even if already deaf, we sense the thunder's vibrations. */
1941 pline("Kaboom!!! Boom!! Boom!!");
1943 pline("
\83s
\83J
\83b
\81I
\81I
\83S
\83\8d\83S
\83\8d\83S
\83\8d\83S
\83\8d\81I
\81I
\83h
\81[
\83\93\81I");
1944 incr_itimeout(&HDeaf, rn1(20, 30));
1945 context.botl = TRUE;
1946 if (!u.uinvulnerable) {
1950 multi_reason = "hiding from thunderstorm";
1952 multi_reason = "
\97\8b\82Ì
\97\92\82ð
\94ð
\82¯
\82Ä
\82¢
\82é
\8e\9e\82É";
1957 You_hear("a rumbling noise.");
1959 You_hear("
\97\8b\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
1962 /* -------------------------------------------------------------------------
1965 * Generic Timeout Functions.
1970 * boolean start_timer(long timeout,short kind,short func_index,
1972 * Start a timer of kind 'kind' that will expire at time
1973 * monstermoves+'timeout'. Call the function at 'func_index'
1974 * in the timeout table using argument 'arg'. Return TRUE if
1975 * a timer was started. This places the timer on a list ordered
1976 * "sooner" to "later". If an object, increment the object's
1979 * long stop_timer(short func_index, anything *arg)
1980 * Stop a timer specified by the (func_index, arg) pair. This
1981 * assumes that such a pair is unique. Return the time the
1982 * timer would have gone off. If no timer is found, return 0.
1983 * If an object, decrement the object's timer count.
1985 * long peek_timer(short func_index, anything *arg)
1986 * Return time specified timer will go off (0 if no such timer).
1988 * void run_timers(void)
1989 * Call timers that have timed out.
1992 * void save_timers(int fd, int mode, int range)
1993 * Save all timers of range 'range'. Range is either global
1994 * or local. Global timers follow game play, local timers
1995 * are saved with a level. Object and monster timers are
1996 * saved using their respective id's instead of pointers.
1998 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1999 * Restore timers of range 'range'. If from a ghost pile,
2000 * adjust the timeout by 'adjust'. The object and monster
2001 * ids are not restored until later.
2003 * void relink_timers(boolean ghostly)
2004 * Relink all object and monster timers that had been saved
2005 * using their object's or monster's id number.
2008 * void obj_move_timers(struct obj *src, struct obj *dest)
2009 * Reassign all timers from src to dest.
2011 * void obj_split_timers(struct obj *src, struct obj *dest)
2012 * Duplicate all timers assigned to src and attach them to dest.
2014 * void obj_stop_timers(struct obj *obj)
2015 * Stop all timers attached to obj.
2017 * boolean obj_has_timer(struct obj *object, short timer_type)
2018 * Check whether object has a timer of type timer_type.
2021 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
2022 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
2023 STATIC_DCL void FDECL(insert_timer, (timer_element *));
2024 STATIC_DCL timer_element *FDECL(remove_timer,
2025 (timer_element **, SHORT_P, ANY_P *));
2026 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
2027 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
2028 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
2029 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
2031 /* ordered timer list */
2032 static timer_element *timer_base; /* "active" */
2033 static unsigned long timer_id = 1;
2035 /* If defined, then include names when printing out the timer queue */
2036 #define VERBOSE_TIMER
2039 timeout_proc f, cleanup;
2040 #ifdef VERBOSE_TIMER
2042 #define TTAB(a, b, c) \
2047 #define TTAB(a, b, c) \
2054 /* table of timeout functions */
2055 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
2056 TTAB(rot_organic, (timeout_proc) 0, "rot_organic"),
2057 TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"),
2058 TTAB(revive_mon, (timeout_proc) 0, "revive_mon"),
2059 TTAB(burn_object, cleanup_burn, "burn_object"),
2060 TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"),
2061 TTAB(fig_transform, (timeout_proc) 0, "fig_transform"),
2062 TTAB(melt_ice_away, (timeout_proc) 0, "melt_ice_away")
2066 STATIC_OVL const char *
2084 print_queue(win, base)
2086 timer_element *base;
2088 timer_element *curr;
2092 putstr(win, 0, " <empty>");
2094 putstr(win, 0, "timeout id kind call");
2095 for (curr = base; curr; curr = curr->next) {
2096 #ifdef VERBOSE_TIMER
2097 Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout,
2098 curr->tid, kind_name(curr->kind),
2099 timeout_funcs[curr->func_index].name,
2100 fmt_ptr((genericptr_t) curr->arg.a_void));
2102 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout,
2103 curr->tid, kind_name(curr->kind), curr->func_index,
2104 fmt_ptr((genericptr_t) curr->arg.a_void));
2106 putstr(win, 0, buf);
2116 const char *propname;
2118 int i, p, count, longestlen, ln, specindx = 0;
2120 win = create_nhwindow(NHW_MENU); /* corner text window */
2124 Sprintf(buf, "Current time = %ld.", monstermoves);
2125 putstr(win, 0, buf);
2127 putstr(win, 0, "Active timeout queue:");
2129 print_queue(win, timer_base);
2132 * check every one; the majority can't obtain temporary timeouts in
2133 * normal play but those can be forced via the #wizintrinsic command.
2135 count = longestlen = 0;
2136 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2137 p = propertynames[i].prop_num;
2138 intrinsic = u.uprops[p].intrinsic;
2139 if (intrinsic & TIMEOUT) {
2141 if ((ln = (int) strlen(propname)) > longestlen)
2144 if (specindx == 0 && p == FIRE_RES)
2149 putstr(win, 0, "No timed properties.");
2151 putstr(win, 0, "Timed properties:");
2153 for (i = 0; (propname = propertynames[i].prop_name) != 0; ++i) {
2154 p = propertynames[i].prop_num;
2155 intrinsic = u.uprops[p].intrinsic;
2156 if (intrinsic & TIMEOUT) {
2157 if (specindx > 0 && i >= specindx) {
2158 putstr(win, 0, " -- settable via #wizinstrinc only --");
2161 /* timeout value can be up to 16777215 (0x00ffffff) but
2162 width of 4 digits should result in values lining up
2163 almost all the time (if/when they don't, it won't
2164 look nice but the information will still be accurate) */
2165 Sprintf(buf, " %*s %4ld", -longestlen, propname,
2166 (intrinsic & TIMEOUT));
2167 putstr(win, 0, buf);
2171 display_nhwindow(win, FALSE);
2172 destroy_nhwindow(win);
2178 timer_sanity_check()
2180 timer_element *curr;
2182 /* this should be much more complete */
2183 for (curr = timer_base; curr; curr = curr->next)
2184 if (curr->kind == TIMER_OBJECT) {
2185 struct obj *obj = curr->arg.a_obj;
2187 if (obj->timed == 0) {
2188 impossible("timer sanity: untimed obj %s, timer %ld",
2189 fmt_ptr((genericptr_t) obj), curr->tid);
2195 * Pick off timeout elements from the global queue and call their functions.
2196 * Do this until their time is less than or equal to the move count.
2201 timer_element *curr;
2204 * Always use the first element. Elements may be added or deleted at
2205 * any time. The list is ordered, we are done when the first element
2208 while (timer_base && timer_base->timeout <= monstermoves) {
2210 timer_base = curr->next;
2212 if (curr->kind == TIMER_OBJECT)
2213 (curr->arg.a_obj)->timed--;
2214 (*timeout_funcs[curr->func_index].f)(&curr->arg, curr->timeout);
2215 free((genericptr_t) curr);
2220 * Start a timer. Return TRUE if successful.
2223 start_timer(when, kind, func_index, arg)
2231 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
2232 panic("start_timer");
2234 gnu = (timer_element *) alloc(sizeof(timer_element));
2235 (void) memset((genericptr_t)gnu, 0, sizeof(timer_element));
2237 gnu->tid = timer_id++;
2238 gnu->timeout = monstermoves + when;
2240 gnu->needs_fixup = 0;
2241 gnu->func_index = func_index;
2245 if (kind == TIMER_OBJECT) /* increment object's timed count */
2246 (arg->a_obj)->timed++;
2248 /* should check for duplicates and fail if any */
2253 * Remove the timer from the current list and free it up. Return the time
2254 * remaining until it would have gone off, 0 if not found.
2257 stop_timer(func_index, arg)
2261 timer_element *doomed;
2264 doomed = remove_timer(&timer_base, func_index, arg);
2267 timeout = doomed->timeout;
2268 if (doomed->kind == TIMER_OBJECT)
2269 (arg->a_obj)->timed--;
2270 if (timeout_funcs[doomed->func_index].cleanup)
2271 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
2272 free((genericptr_t) doomed);
2273 return (timeout - monstermoves);
2279 * Find the timeout of specified timer; return 0 if none.
2282 peek_timer(type, arg)
2286 timer_element *curr;
2288 for (curr = timer_base; curr; curr = curr->next) {
2289 if (curr->func_index == type && curr->arg.a_void == arg->a_void)
2290 return curr->timeout;
2296 * Move all object timers from src to dest, leaving src untimed.
2299 obj_move_timers(src, dest)
2300 struct obj *src, *dest;
2303 timer_element *curr;
2305 for (count = 0, curr = timer_base; curr; curr = curr->next)
2306 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2307 curr->arg.a_obj = dest;
2311 if (count != src->timed)
2312 panic("obj_move_timers");
2317 * Find all object timers and duplicate them for the new object "dest".
2320 obj_split_timers(src, dest)
2321 struct obj *src, *dest;
2323 timer_element *curr, *next_timer = 0;
2325 for (curr = timer_base; curr; curr = next_timer) {
2326 next_timer = curr->next; /* things may be inserted */
2327 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == src) {
2328 (void) start_timer(curr->timeout - monstermoves, TIMER_OBJECT,
2329 curr->func_index, obj_to_any(dest));
2335 * Stop all timers attached to this object. We can get away with this because
2336 * all object pointers are unique.
2339 obj_stop_timers(obj)
2342 timer_element *curr, *prev, *next_timer = 0;
2344 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2345 next_timer = curr->next;
2346 if (curr->kind == TIMER_OBJECT && curr->arg.a_obj == obj) {
2348 prev->next = curr->next;
2350 timer_base = curr->next;
2351 if (timeout_funcs[curr->func_index].cleanup)
2352 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2354 free((genericptr_t) curr);
2363 * Check whether object has a timer of type timer_type.
2366 obj_has_timer(object, timer_type)
2370 long timeout = peek_timer(timer_type, obj_to_any(object));
2372 return (boolean) (timeout != 0L);
2376 * Stop all timers of index func_index at this spot.
2380 spot_stop_timers(x, y, func_index)
2384 timer_element *curr, *prev, *next_timer = 0;
2385 long where = (((long) x << 16) | ((long) y));
2387 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2388 next_timer = curr->next;
2389 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2390 && curr->arg.a_long == where) {
2392 prev->next = curr->next;
2394 timer_base = curr->next;
2395 if (timeout_funcs[curr->func_index].cleanup)
2396 (*timeout_funcs[curr->func_index].cleanup)(&curr->arg,
2398 free((genericptr_t) curr);
2406 * When is the spot timer of type func_index going to expire?
2407 * Returns 0L if no such timer.
2410 spot_time_expires(x, y, func_index)
2414 timer_element *curr;
2415 long where = (((long) x << 16) | ((long) y));
2417 for (curr = timer_base; curr; curr = curr->next) {
2418 if (curr->kind == TIMER_LEVEL && curr->func_index == func_index
2419 && curr->arg.a_long == where)
2420 return curr->timeout;
2426 spot_time_left(x, y, func_index)
2430 long expires = spot_time_expires(x, y, func_index);
2431 return (expires > 0L) ? expires - monstermoves : 0L;
2434 /* Insert timer into the global queue */
2439 timer_element *curr, *prev;
2441 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
2442 if (curr->timeout >= gnu->timeout)
2452 STATIC_OVL timer_element *
2453 remove_timer(base, func_index, arg)
2454 timer_element **base;
2458 timer_element *prev, *curr;
2460 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
2461 if (curr->func_index == func_index && curr->arg.a_void == arg->a_void)
2466 prev->next = curr->next;
2475 write_timer(fd, timer)
2477 timer_element *timer;
2482 switch (timer->kind) {
2485 /* assume no pointers in arg */
2486 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2490 if (timer->needs_fixup)
2491 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2493 /* replace object pointer with id */
2494 arg_save.a_obj = timer->arg.a_obj;
2495 timer->arg = zeroany;
2496 timer->arg.a_uint = (arg_save.a_obj)->o_id;
2497 timer->needs_fixup = 1;
2498 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2499 timer->arg.a_obj = arg_save.a_obj;
2500 timer->needs_fixup = 0;
2505 if (timer->needs_fixup)
2506 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2508 /* replace monster pointer with id */
2509 arg_save.a_monst = timer->arg.a_monst;
2510 timer->arg = zeroany;
2511 timer->arg.a_uint = (arg_save.a_monst)->m_id;
2512 timer->needs_fixup = 1;
2513 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
2514 timer->arg.a_monst = arg_save.a_monst;
2515 timer->needs_fixup = 0;
2520 panic("write_timer");
2526 * Return TRUE if the object will stay on the level when the level is
2533 switch (obj->where) {
2541 return obj_is_local(obj->ocontainer);
2543 return mon_is_local(obj->ocarry);
2545 panic("obj_is_local");
2550 * Return TRUE if the given monster will stay on the level when the
2559 for (curr = migrating_mons; curr; curr = curr->nmon)
2562 /* `mydogs' is used during level changes, never saved and restored */
2563 for (curr = mydogs; curr; curr = curr->nmon)
2570 * Return TRUE if the timer is attached to something that will stay on the
2571 * level when the level is saved.
2574 timer_is_local(timer)
2575 timer_element *timer;
2577 switch (timer->kind) {
2583 return obj_is_local(timer->arg.a_obj);
2585 return mon_is_local(timer->arg.a_monst);
2587 panic("timer_is_local");
2592 * Part of the save routine. Count up the number of timers that would
2593 * be written. If write_it is true, actually write the timer.
2596 maybe_write_timer(fd, range, write_it)
2601 timer_element *curr;
2603 for (curr = timer_base; curr; curr = curr->next) {
2604 if (range == RANGE_GLOBAL) {
2607 if (!timer_is_local(curr)) {
2610 write_timer(fd, curr);
2616 if (timer_is_local(curr)) {
2619 write_timer(fd, curr);
2628 * Save part of the timer list. The parameter 'range' specifies either
2629 * global or level timers to save. The timer ID is saved with the global
2633 * + timeouts that follow the hero (global)
2634 * + timeouts that follow obj & monst that are migrating
2637 * + timeouts that are level specific (e.g. storms)
2638 * + timeouts that stay with the level (obj & monst)
2641 save_timers(fd, mode, range)
2642 int fd, mode, range;
2644 timer_element *curr, *prev, *next_timer = 0;
2647 if (perform_bwrite(mode)) {
2648 if (range == RANGE_GLOBAL)
2649 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
2651 count = maybe_write_timer(fd, range, FALSE);
2652 bwrite(fd, (genericptr_t) &count, sizeof count);
2653 (void) maybe_write_timer(fd, range, TRUE);
2656 if (release_data(mode)) {
2657 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
2658 next_timer = curr->next; /* in case curr is removed */
2660 if (!(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr))) {
2662 prev->next = curr->next;
2664 timer_base = curr->next;
2665 free((genericptr_t) curr);
2666 /* prev stays the same */
2675 * Pull in the structures from disk, but don't recalculate the object and
2679 restore_timers(fd, range, ghostly, adjust)
2681 boolean ghostly; /* restoring from a ghost level */
2682 long adjust; /* how much to adjust timeout */
2685 timer_element *curr;
2687 if (range == RANGE_GLOBAL)
2688 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
2690 /* restore elements */
2691 mread(fd, (genericptr_t) &count, sizeof count);
2692 while (count-- > 0) {
2693 curr = (timer_element *) alloc(sizeof(timer_element));
2694 mread(fd, (genericptr_t) curr, sizeof(timer_element));
2696 curr->timeout += adjust;
2701 /* to support '#stats' wizard-mode command */
2703 timer_stats(hdrfmt, hdrbuf, count, size)
2710 Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
2711 *count = *size = 0L;
2712 for (te = timer_base; te; te = te->next) {
2714 *size += (long) sizeof *te;
2718 /* reset all timers that are marked for reseting */
2720 relink_timers(ghostly)
2723 timer_element *curr;
2726 for (curr = timer_base; curr; curr = curr->next) {
2727 if (curr->needs_fixup) {
2728 if (curr->kind == TIMER_OBJECT) {
2730 if (!lookup_id_mapping(curr->arg.a_uint, &nid))
2731 panic("relink_timers 1");
2733 nid = curr->arg.a_uint;
2734 curr->arg.a_obj = find_oid(nid);
2735 if (!curr->arg.a_obj)
2736 panic("cant find o_id %d", nid);
2737 curr->needs_fixup = 0;
2738 } else if (curr->kind == TIMER_MONSTER) {
2739 panic("relink_timers: no monster timer implemented");
2741 panic("relink_timers 2");