1 /* NetHack 3.6 timeout.c $NHDT-Date: 1456526165 2016/02/26 22:36:05 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.65 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 #include "lev.h" /* for checking save modes */
8 STATIC_DCL
void NDECL(stoned_dialogue
);
9 STATIC_DCL
void NDECL(vomiting_dialogue
);
10 STATIC_DCL
void NDECL(choke_dialogue
);
11 STATIC_DCL
void NDECL(slime_dialogue
);
12 STATIC_DCL
void NDECL(slip_or_trip
);
13 STATIC_DCL
void FDECL(see_lamp_flicker
, (struct obj
*, const char *));
14 STATIC_DCL
void FDECL(lantern_message
, (struct obj
*));
15 STATIC_DCL
void FDECL(cleanup_burn
, (ANY_P
*, long));
17 /* He is being petrified - dialogue by inmet!tower */
18 static NEARDATA
const char *const stoned_texts
[] = {
19 "You are slowing down.", /* 5 */
20 "Your limbs are stiffening.", /* 4 */
21 "Your limbs have turned to stone.", /* 3 */
22 "You have turned to stone.", /* 2 */
23 "You are a statue." /* 1 */
29 register long i
= (Stoned
& TIMEOUT
);
31 if (i
> 0L && i
<= SIZE(stoned_texts
)) {
34 Strcpy(buf
, stoned_texts
[SIZE(stoned_texts
) - i
]);
35 if (nolimbs(youmonst
.data
) && strstri(buf
, "limbs"))
36 (void) strsubst(buf
, "limbs", "extremities");
40 case 5: /* slowing down */
45 case 4: /* limbs stiffening */
46 /* just one move left to save oneself so quit fiddling around;
47 don't stop attempt to eat tin--might be lizard or acidic */
53 case 3: /* limbs turned to stone */
55 nomul(-3); /* can't move anymore */
56 multi_reason
= "getting stoned";
57 nomovemsg
= You_can_move_again
; /* not unconscious */
62 exercise(A_DEX
, FALSE
);
65 /* He is getting sicker and sicker prior to vomiting */
66 static NEARDATA
const char *const vomiting_texts
[] = {
67 "are feeling mildly nauseated.", /* 14 */
68 "feel slightly confused.", /* 11 */
69 "can't seem to think straight.", /* 8 */
70 "feel incredibly sick.", /* 5 */
71 "suddenly vomit!" /* 2 */
78 long v
= (Vomiting
& TIMEOUT
);
80 /* note: nhtimeout() hasn't decremented timed properties for the
81 current turn yet, so we use Vomiting-1 here */
82 switch ((int) (v
- 1L)) {
84 txt
= vomiting_texts
[0];
87 txt
= vomiting_texts
[1];
90 make_stunned((HStun
& TIMEOUT
) + (long) d(2, 4), FALSE
);
91 if (!Popeye(VOMITING
))
95 make_confused((HConfusion
& TIMEOUT
) + (long) d(2, 4), FALSE
);
100 txt
= vomiting_texts
[2];
103 txt
= vomiting_texts
[3];
106 txt
= vomiting_texts
[4];
107 if (cantvomit(youmonst
.data
))
108 txt
= "gag uncontrolably.";
112 if (!cantvomit(youmonst
.data
))
121 exercise(A_CON
, FALSE
);
124 static NEARDATA
const char *const choke_texts
[] = {
125 "You find it hard to breathe.", "You're gasping for air.",
126 "You can no longer breathe.", "You're turning %s.", "You suffocate."
129 static NEARDATA
const char *const choke_texts2
[] = {
130 "Your %s is becoming constricted.",
131 "Your blood is having trouble reaching your brain.",
132 "The pressure on your %s increases.", "Your consciousness is fading.",
139 register long i
= (Strangled
& TIMEOUT
);
141 if (i
> 0 && i
<= SIZE(choke_texts
)) {
142 if (Breathless
|| !rn2(50))
143 pline(choke_texts2
[SIZE(choke_texts2
) - i
], body_part(NECK
));
145 const char *str
= choke_texts
[SIZE(choke_texts
) - i
];
148 pline(str
, hcolor(NH_BLUE
));
153 exercise(A_STR
, FALSE
);
156 static NEARDATA
const char *const slime_texts
[] = {
157 "You are turning a little %s.", /* 5 */
158 "Your limbs are getting oozy.", /* 4 */
159 "Your skin begins to peel away.", /* 3 */
160 "You are turning into %s.", /* 2 */
161 "You have become %s." /* 1 */
167 register long i
= (Slimed
& TIMEOUT
) / 2L;
169 if (((Slimed
& TIMEOUT
) % 2L) && i
>= 0L && i
< SIZE(slime_texts
)) {
172 Strcpy(buf
, slime_texts
[SIZE(slime_texts
) - i
- 1L]);
173 if (nolimbs(youmonst
.data
) && strstri(buf
, "limbs"))
174 (void) strsubst(buf
, "limbs", "extremities");
176 if (index(buf
, '%')) {
177 if (i
== 4L) { /* "you are turning green" */
178 if (!Blind
) /* [what if you're already green?] */
179 pline(buf
, hcolor(NH_GREEN
));
182 an(Hallucination
? rndmonnam(NULL
) : "green slime"));
186 if (i
== 3L) { /* limbs becoming oozy */
187 HFast
= 0L; /* lose intrinsic speed */
193 exercise(A_DEX
, FALSE
);
200 make_slimed(0L, "The slime that covers you is burned away!");
207 register struct prop
*upp
;
211 int baseluck
= (flags
.moonphase
== FULL_MOON
) ? 1 : 0;
216 if (u
.uluck
!= baseluck
217 && moves
% (u
.uhave
.amulet
|| u
.ugangr
? 300 : 600) == 0) {
218 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
219 * stop good luck from timing out; normal luckstones stop both;
220 * neither is stopped if you don't have a luckstone.
221 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
223 register int time_luck
= stone_luck(FALSE
);
224 boolean nostone
= !carrying(LUCKSTONE
) && !stone_luck(TRUE
);
226 if (u
.uluck
> baseluck
&& (nostone
|| time_luck
< 0))
228 else if (u
.uluck
< baseluck
&& (nostone
|| time_luck
> 0))
232 return; /* things past this point could kill you */
241 if (u
.mtimedone
&& !--u
.mtimedone
) {
243 u
.mtimedone
= rnd(100 * youmonst
.data
->mlevel
+ 1);
250 /* Dissipate spell-based protection. */
252 if (--u
.usptime
== 0 && u
.uspellprot
) {
253 u
.usptime
= u
.uspmtime
;
257 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN
),
258 u
.uspellprot
? "becomes less dense" : "disappears");
263 if (--u
.ugallop
== 0L && u
.usteed
)
264 pline("%s stops galloping.", Monnam(u
.usteed
));
267 for (upp
= u
.uprops
; upp
< u
.uprops
+ SIZE(u
.uprops
); upp
++)
268 if ((upp
->intrinsic
& TIMEOUT
) && !(--upp
->intrinsic
& TIMEOUT
)) {
269 kptr
= find_delayed_killer((int) (upp
- u
.uprops
));
270 switch (upp
- u
.uprops
) {
272 if (kptr
&& kptr
->name
[0]) {
273 killer
.format
= kptr
->format
;
274 Strcpy(killer
.name
, kptr
->name
);
276 killer
.format
= NO_KILLER_PREFIX
;
277 Strcpy(killer
.name
, "killed by petrification");
279 dealloc_killer(kptr
);
280 /* (unlike sliming, you aren't changing form here) */
284 if (kptr
&& kptr
->name
[0]) {
285 killer
.format
= kptr
->format
;
286 Strcpy(killer
.name
, kptr
->name
);
288 killer
.format
= NO_KILLER_PREFIX
;
289 Strcpy(killer
.name
, "turned into green slime");
291 dealloc_killer(kptr
);
292 /* involuntarily break "never changed form" conduct */
293 u
.uconduct
.polyselfs
++;
297 make_vomiting(0L, TRUE
);
300 You("die from your illness.");
301 if (kptr
&& kptr
->name
[0]) {
302 killer
.format
= kptr
->format
;
303 Strcpy(killer
.name
, kptr
->name
);
305 killer
.format
= KILLED_BY_AN
;
306 killer
.name
[0] = 0; /* take the default */
308 dealloc_killer(kptr
);
310 if ((m_idx
= name_to_mon(killer
.name
)) >= LOW_PM
) {
311 if (type_is_pname(&mons
[m_idx
])) {
312 killer
.format
= KILLED_BY
;
313 } else if (mons
[m_idx
].geno
& G_UNIQ
) {
314 Strcpy(killer
.name
, the(killer
.name
));
315 killer
.format
= KILLED_BY
;
323 You_feel("yourself slowing down%s.",
324 Fast
? " a bit" : "");
327 /* So make_confused works properly */
328 set_itimeout(&HConfusion
, 1L);
329 make_confused(0L, TRUE
);
334 set_itimeout(&HStun
, 1L);
335 make_stunned(0L, TRUE
);
340 set_itimeout(&Blinded
, 1L);
341 make_blinded(0L, TRUE
);
346 set_itimeout(&HDeaf
, 1L);
354 if (!Invis
&& !BInvis
&& !Blind
) {
356 ? "are no longer invisible."
357 : "can no longer see through yourself.");
362 set_mimic_blocking(); /* do special mimic handling */
363 see_monsters(); /* make invis mons appear */
364 newsym(u
.ux
, u
.uy
); /* make self appear */
372 set_itimeout(&HHallucination
, 1L);
373 (void) make_hallucinated(0L, TRUE
, 0L);
378 if (unconscious() || Sleep_resistance
) {
379 incr_itimeout(&HSleepy
, rnd(100));
383 fall_asleep(-sleeptime
, TRUE
);
384 incr_itimeout(&HSleepy
, sleeptime
+ rnd(100));
388 (void) float_down(I_SPECIAL
| TIMEOUT
, 0L);
391 killer
.format
= KILLED_BY
;
393 (u
.uburied
) ? "suffocation" : "strangulation");
395 /* must be declining to die in explore|wizard mode;
396 treat like being cured of strangulation by prayer */
397 if (uamul
&& uamul
->otyp
== AMULET_OF_STRANGULATION
) {
398 Your("amulet vanishes!");
403 /* call this only when a move took place. */
404 /* otherwise handle fumbling msgs locally. */
405 if (u
.umoved
&& !Levitation
) {
408 multi_reason
= "fumbling";
410 /* The more you are carrying the more likely you
411 * are to make noise when you fumble. Adjustments
412 * to this number must be thoroughly play tested.
414 if ((inv_weight() > -500)) {
415 You("make a lot of noise!");
419 /* from outside means slippery ice; don't reset
420 counter if that's the only fumble reason */
421 HFumbling
&= ~FROMOUTSIDE
;
423 incr_itimeout(&HFumbling
, rnd(20));
425 case DETECT_MONSTERS
:
435 fall_asleep(how_long
, wakeup_msg
)
441 multi_reason
= "sleeping";
442 /* generally don't notice sounds while sleeping */
443 if (wakeup_msg
&& multi
== how_long
) {
444 /* caller can follow with a direct call to Hear_again() if
445 there's a need to override this when wakeup_msg is true */
446 incr_itimeout(&HDeaf
, how_long
);
448 afternmv
= Hear_again
; /* this won't give any messages */
450 /* early wakeup from combat won't be possible until next monster turn */
451 u
.usleep
= monstermoves
;
452 nomovemsg
= wakeup_msg
? "You wake up." : You_can_move_again
;
455 /* Attach an egg hatch timeout to the given egg.
456 * when = Time to hatch, usually only passed if re-creating an
457 * existing hatch timer. Pass 0L for random hatch time.
460 attach_egg_hatch_timeout(egg
, when
)
466 /* stop previous timer, if any */
467 (void) stop_timer(HATCH_EGG
, obj_to_any(egg
));
470 * Decide if and when to hatch the egg. The old hatch_it() code tried
471 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
472 * a number x, 1<=x<=age, where x>150. This yields a chance of
473 * hatching > 99.9993%. Mimic that here.
476 for (i
= (MAX_EGG_HATCH_TIME
- 50) + 1; i
<= MAX_EGG_HATCH_TIME
; i
++)
484 (void) start_timer(when
, TIMER_OBJECT
, HATCH_EGG
, obj_to_any(egg
));
488 /* prevent an egg from ever hatching */
493 /* stop previous timer, if any */
494 (void) stop_timer(HATCH_EGG
, obj_to_any(egg
));
497 /* timer callback routine: hatch the given egg */
499 hatch_egg(arg
, timeout
)
504 struct monst
*mon
, *mon2
;
507 boolean yours
, silent
, knows_egg
= FALSE
;
508 boolean cansee_hatchspot
= FALSE
;
509 int i
, mnum
, hatchcount
= 0;
512 /* sterilized while waiting */
513 if (egg
->corpsenm
== NON_PM
)
516 mon
= mon2
= (struct monst
*) 0;
517 mnum
= big_to_little(egg
->corpsenm
);
518 /* The identity of one's father is learned, not innate */
519 yours
= (egg
->spe
|| (!flags
.female
&& carried(egg
) && !rn2(2)));
520 silent
= (timeout
!= monstermoves
); /* hatched while away */
522 /* only can hatch when in INVENT, FLOOR, MINVENT */
523 if (get_obj_location(egg
, &x
, &y
, 0)) {
524 hatchcount
= rnd((int) egg
->quan
);
525 cansee_hatchspot
= cansee(x
, y
) && !silent
;
526 if (!(mons
[mnum
].geno
& G_UNIQ
)
527 && !(mvitals
[mnum
].mvflags
& (G_GENOD
| G_EXTINCT
))) {
528 for (i
= hatchcount
; i
> 0; i
--) {
529 if (!enexto(&cc
, x
, y
, &mons
[mnum
])
530 || !(mon
= makemon(&mons
[mnum
], cc
.x
, cc
.y
, NO_MINVENT
)))
532 /* tame if your own egg hatches while you're on the
533 same dungeon level, or any dragon egg which hatches
534 while it's in your inventory */
535 if ((yours
&& !silent
)
536 || (carried(egg
) && mon
->data
->mlet
== S_DRAGON
)) {
537 if (tamedog(mon
, (struct obj
*) 0)) {
538 if (carried(egg
) && mon
->data
->mlet
!= S_DRAGON
)
542 if (mvitals
[mnum
].mvflags
& G_EXTINCT
)
543 break; /* just made last one */
544 mon2
= mon
; /* in case makemon() fails on 2nd egg */
549 egg
->quan
-= (long) hatchcount
;
553 * We could possibly hatch while migrating, but the code isn't
556 } else if (obj
->where
== OBJ_MIGRATING
) {
558 * We can do several things. The first ones that come to
560 * + Create the hatched monster then place it on the migrating
561 * mons list. This is tough because all makemon() is made
562 * to place the monster as well. Makemon() also doesn't lend
563 * itself well to splitting off a "not yet placed" subroutine.
564 * + Mark the egg as hatched, then place the monster when we
565 * place the migrating objects.
566 * + Or just kill any egg which gets sent to another level.
567 * Falling is the usual reason such transportation occurs.
569 cansee_hatchspot
= FALSE
;
575 char monnambuf
[BUFSZ
], carriedby
[BUFSZ
];
576 boolean siblings
= (hatchcount
> 1), redraw
= FALSE
;
578 if (cansee_hatchspot
) {
579 Sprintf(monnambuf
, "%s%s", siblings
? "some " : "",
580 siblings
? makeplural(m_monnam(mon
)) : an(m_monnam(mon
)));
581 /* we don't learn the egg type here because learning
582 an egg type requires either seeing the egg hatch
583 or being familiar with the egg already,
584 as well as being able to see the resulting
585 monster, checked below
588 switch (egg
->where
) {
590 knows_egg
= TRUE
; /* true even if you are blind */
591 if (!cansee_hatchspot
)
592 You_feel("%s %s from your pack!", something
,
593 locomotion(mon
->data
, "drop"));
595 You_see("%s %s out of your pack!", monnambuf
,
596 locomotion(mon
->data
, "drop"));
598 pline("%s cries sound like \"%s%s\"",
599 siblings
? "Their" : "Its",
600 flags
.female
? "mommy" : "daddy", egg
->spe
? "." : "?");
601 } else if (mon
->data
->mlet
== S_DRAGON
&& !Deaf
) {
602 verbalize("Gleep!"); /* Mything eggs :-) */
607 if (cansee_hatchspot
) {
609 You_see("%s hatch.", monnambuf
);
610 redraw
= TRUE
; /* update egg's map location */
615 if (cansee_hatchspot
) {
616 /* egg carrying monster might be invisible */
619 && (!mon2
->wormno
|| cansee(mon2
->mx
, mon2
->my
))) {
620 Sprintf(carriedby
, "%s pack",
621 s_suffix(a_monnam(mon2
)));
623 } else if (is_pool(mon
->mx
, mon
->my
)) {
624 Strcpy(carriedby
, "empty water");
626 Strcpy(carriedby
, "thin air");
628 You_see("%s %s out of %s!", monnambuf
,
629 locomotion(mon
->data
, "drop"), carriedby
);
637 impossible("egg hatched where? (%d)", (int) egg
->where
);
641 if (cansee_hatchspot
&& knows_egg
)
642 learn_egg_type(mnum
);
645 /* still some eggs left */
646 /* Instead of ordinary egg timeout use a short one */
647 attach_egg_hatch_timeout(egg
, (long) rnd(12));
648 } else if (carried(egg
)) {
651 /* free egg here because we use it above */
652 obj_extract_self(egg
);
653 obfree(egg
, (struct obj
*) 0);
660 /* Learn to recognize eggs of the given type. */
665 /* baby monsters hatch from grown-up eggs */
666 mnum
= little_to_big(mnum
);
667 mvitals
[mnum
].mvflags
|= MV_KNOWS_EGG
;
668 /* we might have just learned about other eggs being carried */
672 /* Attach a fig_transform timeout to the given figurine. */
674 attach_fig_transform_timeout(figurine
)
675 struct obj
*figurine
;
679 /* stop previous timer, if any */
680 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(figurine
));
683 * Decide when to transform the figurine.
686 /* figurine will transform */
687 (void) start_timer((long) i
, TIMER_OBJECT
, FIG_TRANSFORM
,
688 obj_to_any(figurine
));
691 /* give a fumble message */
695 struct obj
*otmp
= vobj_at(u
.ux
, u
.uy
), *otmp2
;
698 boolean on_foot
= TRUE
;
702 if (otmp
&& on_foot
&& !u
.uinwater
&& is_pool(u
.ux
, u
.uy
))
705 if (otmp
&& on_foot
) { /* trip over something in particular */
707 If there is only one item, it will have just been named
708 during the move, so refer to by via pronoun; otherwise,
709 if the top item has been or can be seen, refer to it by
710 name; if not, look for rocks to trip over; trip over
711 anonymous "something" if there aren't any rocks.
713 what
= (iflags
.last_msg
== PLNMSG_ONE_ITEM_HERE
)
714 ? ((otmp
->quan
== 1L) ? "it"
715 : Hallucination
? "they" : "them")
716 : (otmp
->dknown
|| !Blind
)
718 : ((otmp2
= sobj_at(ROCK
, u
.ux
, u
.uy
)) == 0
720 : (otmp2
->quan
== 1L ? "a rock" : "some rocks"));
722 what
= strcpy(buf
, what
);
723 buf
[0] = highc(buf
[0]);
724 pline("Egads! %s bite%s your %s!", what
,
725 (!otmp
|| otmp
->quan
== 1L) ? "s" : "", body_part(FOOT
));
727 You("trip over %s.", what
);
729 if (!uarmf
&& otmp
->otyp
== CORPSE
730 && touch_petrifies(&mons
[otmp
->corpsenm
]) && !Stone_resistance
) {
731 Sprintf(killer
.name
, "tripping over %s corpse",
732 an(mons
[otmp
->corpsenm
].mname
));
733 instapetrify(killer
.name
);
735 } else if (rn2(3) && is_ice(u
.ux
, u
.uy
)) {
736 pline("%s %s%s on the ice.",
737 u
.usteed
? upstart(x_monnam(u
.usteed
,
738 (has_mname(u
.usteed
)) ? ARTICLE_NONE
740 (char *) 0, SUPPRESS_SADDLE
, FALSE
))
742 rn2(2) ? "slip" : "slide", on_foot
? "" : "s");
747 You("trip over your own %s.",
748 Hallucination
? "elbow" : makeplural(body_part(FOOT
)));
752 Hallucination
? "on a banana peel" : "and nearly fall");
764 Your("%s slip out of the stirrups.",
765 makeplural(body_part(FOOT
)));
768 You("let go of the reins.");
771 You("bang into the saddle-horn.");
774 You("slide to one side of the saddle.");
777 dismount_steed(DISMOUNT_FELL
);
782 /* Print a lamp flicker message with tailer. */
784 see_lamp_flicker(obj
, tailer
)
788 switch (obj
->where
) {
791 pline("%s flickers%s.", Yname2(obj
), tailer
);
794 You_see("%s flicker%s.", an(xname(obj
)), tailer
);
799 /* Print a dimming message for brass lanterns. */
805 switch (obj
->where
) {
807 Your("lantern is getting dim.");
809 pline("Batteries have not been invented yet.");
812 You_see("a lantern getting dim.");
815 pline("%s lantern is getting dim.", s_suffix(Monnam(obj
->ocarry
)));
821 * Timeout callback for for objects that are burning. E.g. lamps, candles.
822 * See begin_burn() for meanings of obj->age and obj->spe.
825 burn_object(arg
, timeout
)
829 struct obj
*obj
= arg
->a_obj
;
830 boolean canseeit
, many
, menorah
, need_newsym
;
834 menorah
= obj
->otyp
== CANDELABRUM_OF_INVOCATION
;
835 many
= menorah
? obj
->spe
> 1 : obj
->quan
> 1L;
837 /* timeout while away */
838 if (timeout
!= monstermoves
) {
839 long how_long
= monstermoves
- timeout
;
841 if (how_long
>= obj
->age
) {
843 end_burn(obj
, FALSE
);
846 obj
->spe
= 0; /* no more candles */
847 } else if (Is_candle(obj
) || obj
->otyp
== POT_OIL
) {
848 /* get rid of candles and burning oil potions;
849 we know this object isn't carried by hero,
850 nor is it migrating */
851 obj_extract_self(obj
);
852 obfree(obj
, (struct obj
*) 0);
853 obj
= (struct obj
*) 0;
857 obj
->age
-= how_long
;
858 begin_burn(obj
, TRUE
);
863 /* only interested in INVENT, FLOOR, and MINVENT */
864 if (get_obj_location(obj
, &x
, &y
, 0)) {
865 canseeit
= !Blind
&& cansee(x
, y
);
866 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
867 (void) Shk_Your(whose
, obj
);
873 /* obj->age is the age remaining at this point. */
876 /* this should only be called when we run out */
878 switch (obj
->where
) {
881 pline("%spotion of oil has burnt away.", whose
);
884 You_see("a burning potion of oil go out.");
889 end_burn(obj
, FALSE
); /* turn off light source */
893 /* clear migrating obj's destination code before obfree
894 to avoid false complaint of deleting worn item */
895 if (obj
->where
== OBJ_MIGRATING
)
897 obj_extract_self(obj
);
898 obfree(obj
, (struct obj
*) 0);
900 obj
= (struct obj
*) 0;
905 switch ((int) obj
->age
) {
910 if (obj
->otyp
== BRASS_LANTERN
)
911 lantern_message(obj
);
913 see_lamp_flicker(obj
,
914 obj
->age
== 50L ? " considerably" : "");
920 if (obj
->otyp
== BRASS_LANTERN
)
921 lantern_message(obj
);
923 switch (obj
->where
) {
926 pline("%s seems about to go out.", Yname2(obj
));
929 You_see("%s about to go out.", an(xname(obj
)));
937 /* even if blind you'll know if holding it */
938 if (canseeit
|| obj
->where
== OBJ_INVENT
) {
939 switch (obj
->where
) {
942 if (obj
->otyp
== BRASS_LANTERN
)
943 pline("%slantern has run out of power.", whose
);
945 pline("%s has gone out.", Yname2(obj
));
948 if (obj
->otyp
== BRASS_LANTERN
)
949 You_see("a lantern run out of power.");
951 You_see("%s go out.", an(xname(obj
)));
955 end_burn(obj
, FALSE
);
960 * Someone added fuel to the lamp while it was
961 * lit. Just fall through and let begin burn
962 * handle the new age.
968 begin_burn(obj
, TRUE
);
972 case CANDELABRUM_OF_INVOCATION
:
978 switch (obj
->where
) {
981 pline("%s%scandle%s getting short.", whose
,
982 menorah
? "candelabrum's " : "",
983 many
? "s are" : " is");
986 You_see("%scandle%s getting short.",
987 menorah
? "a candelabrum's " : many
? "some "
996 switch (obj
->where
) {
999 pline("%s%scandle%s flame%s flicker%s low!", whose
,
1000 menorah
? "candelabrum's " : "", many
? "s'" : "'s",
1001 many
? "s" : "", many
? "" : "s");
1004 You_see("%scandle%s flame%s flicker low!",
1005 menorah
? "a candelabrum's " : many
? "some "
1007 many
? "s'" : "'s", many
? "s" : "");
1013 /* we know even if blind and in our inventory */
1014 if (canseeit
|| obj
->where
== OBJ_INVENT
) {
1016 switch (obj
->where
) {
1019 pline("%scandelabrum's flame%s.", whose
,
1020 many
? "s die" : " dies");
1023 You_see("a candelabrum's flame%s die.",
1028 switch (obj
->where
) {
1031 pline("%s %s consumed!", Yname2(obj
),
1032 many
? "are" : "is");
1036 You see some wax candles consumed!
1037 You see a wax candle consumed!
1039 You_see("%s%s consumed!", many
? "some " : "",
1040 many
? xname(obj
) : an(xname(obj
)));
1047 ? (many
? "They shriek!" : "It shrieks!")
1048 : Blind
? "" : (many
? "Their flames die."
1049 : "Its flame dies."));
1052 end_burn(obj
, FALSE
);
1060 /* clear migrating obj's destination code
1061 so obfree won't think this item is worn */
1062 if (obj
->where
== OBJ_MIGRATING
)
1063 obj
->owornmask
= 0L;
1064 obj_extract_self(obj
);
1065 obfree(obj
, (struct obj
*) 0);
1067 obj
= (struct obj
*) 0;
1073 * Someone added fuel (candles) to the menorah while
1074 * it was lit. Just fall through and let begin burn
1075 * handle the new age.
1080 if (obj
&& obj
->age
)
1081 begin_burn(obj
, TRUE
);
1086 impossible("burn_object: unexpeced obj %s", xname(obj
));
1094 * Start a burn timeout on the given object. If not "already lit" then
1095 * create a light source for the vision system. There had better not
1096 * be a burn already running on the object.
1098 * Magic lamps stay lit as long as there's a genie inside, so don't start
1102 * potions of oil, lamps & candles:
1103 * age = # of turns of fuel left
1107 * spe = 0 not lightable, 1 lightable forever
1109 * age = # of turns of fuel left
1110 * spe = # of candles
1112 * Once the burn begins, the age will be set to the amount of fuel
1113 * remaining _once_the_burn_finishes_. If the burn is terminated
1114 * early then fuel is added back.
1116 * This use of age differs from the use of age for corpses and eggs.
1117 * For the latter items, age is when the object was created, so we
1118 * know when it becomes "bad".
1120 * This is a "silent" routine - it should not print anything out.
1123 begin_burn(obj
, already_lit
)
1125 boolean already_lit
;
1129 boolean do_timer
= TRUE
;
1131 if (obj
->age
== 0 && obj
->otyp
!= MAGIC_LAMP
&& !artifact_light(obj
))
1134 switch (obj
->otyp
) {
1142 radius
= 1; /* very dim light */
1147 /* magic times are 150, 100, 50, 25, and 0 */
1148 if (obj
->age
> 150L)
1149 turns
= obj
->age
- 150L;
1150 else if (obj
->age
> 100L)
1151 turns
= obj
->age
- 100L;
1152 else if (obj
->age
> 50L)
1153 turns
= obj
->age
- 50L;
1154 else if (obj
->age
> 25L)
1155 turns
= obj
->age
- 25L;
1160 case CANDELABRUM_OF_INVOCATION
:
1163 /* magic times are 75, 15, and 0 */
1165 turns
= obj
->age
- 75L;
1166 else if (obj
->age
> 15L)
1167 turns
= obj
->age
- 15L;
1170 radius
= candle_light_range(obj
);
1174 /* [ALI] Support artifact light sources */
1175 if (artifact_light(obj
)) {
1178 radius
= arti_light_radius(obj
);
1180 impossible("begin burn: unexpected %s", xname(obj
));
1187 if (start_timer(turns
, TIMER_OBJECT
, BURN_OBJECT
, obj_to_any(obj
))) {
1190 if (carried(obj
) && !already_lit
)
1196 if (carried(obj
) && !already_lit
)
1200 if (obj
->lamplit
&& !already_lit
) {
1203 if (get_obj_location(obj
, &x
, &y
, CONTAINED_TOO
| BURIED_TOO
))
1204 new_light_source(x
, y
, radius
, LS_OBJECT
, obj_to_any(obj
));
1206 impossible("begin_burn: can't get obj position");
1211 * Stop a burn timeout on the given object if timer attached. Darken
1215 end_burn(obj
, timer_attached
)
1217 boolean timer_attached
;
1219 if (!obj
->lamplit
) {
1220 impossible("end_burn: obj %s not lit", xname(obj
));
1224 if (obj
->otyp
== MAGIC_LAMP
|| artifact_light(obj
))
1225 timer_attached
= FALSE
;
1227 if (!timer_attached
) {
1228 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1229 del_light_source(LS_OBJECT
, obj_to_any(obj
));
1231 if (obj
->where
== OBJ_INVENT
)
1233 } else if (!stop_timer(BURN_OBJECT
, obj_to_any(obj
)))
1234 impossible("end_burn: obj %s not timed!", xname(obj
));
1238 * Cleanup a burning object if timer stopped.
1241 cleanup_burn(arg
, expire_time
)
1245 struct obj
*obj
= arg
->a_obj
;
1246 if (!obj
->lamplit
) {
1247 impossible("cleanup_burn: obj %s not lit", xname(obj
));
1251 del_light_source(LS_OBJECT
, obj_to_any(obj
));
1253 /* restore unused time */
1254 obj
->age
+= expire_time
- monstermoves
;
1258 if (obj
->where
== OBJ_INVENT
)
1270 /* no lightning if not the air level or too often, even then */
1271 if (!Is_airlevel(&u
.uz
) || rn2(8))
1274 /* the number of strikes is 8-log2(nstrike) */
1275 for (nstrike
= rnd(64); nstrike
<= 64; nstrike
*= 2) {
1280 } while (++count
< 100 && levl
[x
][y
].typ
!= CLOUD
);
1285 if (dirx
!= 0 || diry
!= 0)
1286 buzz(-15, /* "monster" LIGHTNING spell */
1287 8, x
, y
, dirx
, diry
);
1291 if (levl
[u
.ux
][u
.uy
].typ
== CLOUD
) {
1292 /* Inside a cloud during a thunder storm is deafening. */
1293 /* Even if already deaf, we sense the thunder's vibrations. */
1294 pline("Kaboom!!! Boom!! Boom!!");
1295 incr_itimeout(&HDeaf
, rn1(20, 30));
1296 context
.botl
= TRUE
;
1297 if (!u
.uinvulnerable
) {
1300 multi_reason
= "hiding from thunderstorm";
1304 You_hear("a rumbling noise.");
1307 /* -------------------------------------------------------------------------
1310 * Generic Timeout Functions.
1315 * boolean start_timer(long timeout,short kind,short func_index,
1317 * Start a timer of kind 'kind' that will expire at time
1318 * monstermoves+'timeout'. Call the function at 'func_index'
1319 * in the timeout table using argument 'arg'. Return TRUE if
1320 * a timer was started. This places the timer on a list ordered
1321 * "sooner" to "later". If an object, increment the object's
1324 * long stop_timer(short func_index, anything *arg)
1325 * Stop a timer specified by the (func_index, arg) pair. This
1326 * assumes that such a pair is unique. Return the time the
1327 * timer would have gone off. If no timer is found, return 0.
1328 * If an object, decrement the object's timer count.
1330 * long peek_timer(short func_index, anything *arg)
1331 * Return time specified timer will go off (0 if no such timer).
1333 * void run_timers(void)
1334 * Call timers that have timed out.
1337 * void save_timers(int fd, int mode, int range)
1338 * Save all timers of range 'range'. Range is either global
1339 * or local. Global timers follow game play, local timers
1340 * are saved with a level. Object and monster timers are
1341 * saved using their respective id's instead of pointers.
1343 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1344 * Restore timers of range 'range'. If from a ghost pile,
1345 * adjust the timeout by 'adjust'. The object and monster
1346 * ids are not restored until later.
1348 * void relink_timers(boolean ghostly)
1349 * Relink all object and monster timers that had been saved
1350 * using their object's or monster's id number.
1353 * void obj_move_timers(struct obj *src, struct obj *dest)
1354 * Reassign all timers from src to dest.
1356 * void obj_split_timers(struct obj *src, struct obj *dest)
1357 * Duplicate all timers assigned to src and attach them to dest.
1359 * void obj_stop_timers(struct obj *obj)
1360 * Stop all timers attached to obj.
1362 * boolean obj_has_timer(struct obj *object, short timer_type)
1363 * Check whether object has a timer of type timer_type.
1366 STATIC_DCL
const char *FDECL(kind_name
, (SHORT_P
));
1367 STATIC_DCL
void FDECL(print_queue
, (winid
, timer_element
*));
1368 STATIC_DCL
void FDECL(insert_timer
, (timer_element
*));
1369 STATIC_DCL timer_element
*FDECL(remove_timer
,
1370 (timer_element
**, SHORT_P
, ANY_P
*));
1371 STATIC_DCL
void FDECL(write_timer
, (int, timer_element
*));
1372 STATIC_DCL boolean
FDECL(mon_is_local
, (struct monst
*));
1373 STATIC_DCL boolean
FDECL(timer_is_local
, (timer_element
*));
1374 STATIC_DCL
int FDECL(maybe_write_timer
, (int, int, BOOLEAN_P
));
1376 /* ordered timer list */
1377 static timer_element
*timer_base
; /* "active" */
1378 static unsigned long timer_id
= 1;
1380 /* If defined, then include names when printing out the timer queue */
1381 #define VERBOSE_TIMER
1384 timeout_proc f
, cleanup
;
1385 #ifdef VERBOSE_TIMER
1387 #define TTAB(a, b, c) \
1392 #define TTAB(a, b, c) \
1399 /* table of timeout functions */
1400 static const ttable timeout_funcs
[NUM_TIME_FUNCS
] = {
1401 TTAB(rot_organic
, (timeout_proc
) 0, "rot_organic"),
1402 TTAB(rot_corpse
, (timeout_proc
) 0, "rot_corpse"),
1403 TTAB(revive_mon
, (timeout_proc
) 0, "revive_mon"),
1404 TTAB(burn_object
, cleanup_burn
, "burn_object"),
1405 TTAB(hatch_egg
, (timeout_proc
) 0, "hatch_egg"),
1406 TTAB(fig_transform
, (timeout_proc
) 0, "fig_transform"),
1407 TTAB(melt_ice_away
, (timeout_proc
) 0, "melt_ice_away")
1411 STATIC_OVL
const char *
1429 print_queue(win
, base
)
1431 timer_element
*base
;
1433 timer_element
*curr
;
1437 putstr(win
, 0, "<empty>");
1439 putstr(win
, 0, "timeout id kind call");
1440 for (curr
= base
; curr
; curr
= curr
->next
) {
1441 #ifdef VERBOSE_TIMER
1442 Sprintf(buf
, " %4ld %4ld %-6s %s(%s)", curr
->timeout
,
1443 curr
->tid
, kind_name(curr
->kind
),
1444 timeout_funcs
[curr
->func_index
].name
,
1445 fmt_ptr((genericptr_t
) curr
->arg
.a_void
));
1447 Sprintf(buf
, " %4ld %4ld %-6s #%d(%s)", curr
->timeout
,
1448 curr
->tid
, kind_name(curr
->kind
), curr
->func_index
,
1449 fmt_ptr((genericptr_t
) curr
->arg
.a_void
));
1451 putstr(win
, 0, buf
);
1462 win
= create_nhwindow(NHW_MENU
); /* corner text window */
1466 Sprintf(buf
, "Current time = %ld.", monstermoves
);
1467 putstr(win
, 0, buf
);
1469 putstr(win
, 0, "Active timeout queue:");
1471 print_queue(win
, timer_base
);
1473 display_nhwindow(win
, FALSE
);
1474 destroy_nhwindow(win
);
1480 timer_sanity_check()
1482 timer_element
*curr
;
1484 /* this should be much more complete */
1485 for (curr
= timer_base
; curr
; curr
= curr
->next
)
1486 if (curr
->kind
== TIMER_OBJECT
) {
1487 struct obj
*obj
= curr
->arg
.a_obj
;
1488 if (obj
->timed
== 0) {
1489 pline("timer sanity: untimed obj %s, timer %ld",
1490 fmt_ptr((genericptr_t
) obj
), curr
->tid
);
1496 * Pick off timeout elements from the global queue and call their functions.
1497 * Do this until their time is less than or equal to the move count.
1502 timer_element
*curr
;
1505 * Always use the first element. Elements may be added or deleted at
1506 * any time. The list is ordered, we are done when the first element
1509 while (timer_base
&& timer_base
->timeout
<= monstermoves
) {
1511 timer_base
= curr
->next
;
1513 if (curr
->kind
== TIMER_OBJECT
)
1514 (curr
->arg
.a_obj
)->timed
--;
1515 (*timeout_funcs
[curr
->func_index
].f
)(&curr
->arg
, curr
->timeout
);
1516 free((genericptr_t
) curr
);
1521 * Start a timer. Return TRUE if successful.
1524 start_timer(when
, kind
, func_index
, arg
)
1532 if (func_index
< 0 || func_index
>= NUM_TIME_FUNCS
)
1533 panic("start_timer");
1535 gnu
= (timer_element
*) alloc(sizeof(timer_element
));
1536 (void) memset((genericptr_t
)gnu
, 0, sizeof(timer_element
));
1538 gnu
->tid
= timer_id
++;
1539 gnu
->timeout
= monstermoves
+ when
;
1541 gnu
->needs_fixup
= 0;
1542 gnu
->func_index
= func_index
;
1546 if (kind
== TIMER_OBJECT
) /* increment object's timed count */
1547 (arg
->a_obj
)->timed
++;
1549 /* should check for duplicates and fail if any */
1554 * Remove the timer from the current list and free it up. Return the time
1555 * remaining until it would have gone off, 0 if not found.
1558 stop_timer(func_index
, arg
)
1562 timer_element
*doomed
;
1565 doomed
= remove_timer(&timer_base
, func_index
, arg
);
1568 timeout
= doomed
->timeout
;
1569 if (doomed
->kind
== TIMER_OBJECT
)
1570 (arg
->a_obj
)->timed
--;
1571 if (timeout_funcs
[doomed
->func_index
].cleanup
)
1572 (*timeout_funcs
[doomed
->func_index
].cleanup
)(arg
, timeout
);
1573 free((genericptr_t
) doomed
);
1574 return (timeout
- monstermoves
);
1580 * Find the timeout of specified timer; return 0 if none.
1583 peek_timer(type
, arg
)
1587 timer_element
*curr
;
1589 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1590 if (curr
->func_index
== type
&& curr
->arg
.a_void
== arg
->a_void
)
1591 return curr
->timeout
;
1597 * Move all object timers from src to dest, leaving src untimed.
1600 obj_move_timers(src
, dest
)
1601 struct obj
*src
, *dest
;
1604 timer_element
*curr
;
1606 for (count
= 0, curr
= timer_base
; curr
; curr
= curr
->next
)
1607 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1608 curr
->arg
.a_obj
= dest
;
1612 if (count
!= src
->timed
)
1613 panic("obj_move_timers");
1618 * Find all object timers and duplicate them for the new object "dest".
1621 obj_split_timers(src
, dest
)
1622 struct obj
*src
, *dest
;
1624 timer_element
*curr
, *next_timer
= 0;
1626 for (curr
= timer_base
; curr
; curr
= next_timer
) {
1627 next_timer
= curr
->next
; /* things may be inserted */
1628 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1629 (void) start_timer(curr
->timeout
- monstermoves
, TIMER_OBJECT
,
1630 curr
->func_index
, obj_to_any(dest
));
1636 * Stop all timers attached to this object. We can get away with this because
1637 * all object pointers are unique.
1640 obj_stop_timers(obj
)
1643 timer_element
*curr
, *prev
, *next_timer
= 0;
1645 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1646 next_timer
= curr
->next
;
1647 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== obj
) {
1649 prev
->next
= curr
->next
;
1651 timer_base
= curr
->next
;
1652 if (timeout_funcs
[curr
->func_index
].cleanup
)
1653 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1655 free((genericptr_t
) curr
);
1664 * Check whether object has a timer of type timer_type.
1667 obj_has_timer(object
, timer_type
)
1671 long timeout
= peek_timer(timer_type
, obj_to_any(object
));
1673 return (boolean
) (timeout
!= 0L);
1677 * Stop all timers of index func_index at this spot.
1681 spot_stop_timers(x
, y
, func_index
)
1685 timer_element
*curr
, *prev
, *next_timer
= 0;
1686 long where
= (((long) x
<< 16) | ((long) y
));
1688 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1689 next_timer
= curr
->next
;
1690 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1691 && curr
->arg
.a_long
== where
) {
1693 prev
->next
= curr
->next
;
1695 timer_base
= curr
->next
;
1696 if (timeout_funcs
[curr
->func_index
].cleanup
)
1697 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1699 free((genericptr_t
) curr
);
1707 * When is the spot timer of type func_index going to expire?
1708 * Returns 0L if no such timer.
1711 spot_time_expires(x
, y
, func_index
)
1715 timer_element
*curr
;
1716 long where
= (((long) x
<< 16) | ((long) y
));
1718 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1719 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1720 && curr
->arg
.a_long
== where
)
1721 return curr
->timeout
;
1727 spot_time_left(x
, y
, func_index
)
1731 long expires
= spot_time_expires(x
, y
, func_index
);
1732 return (expires
> 0L) ? expires
- monstermoves
: 0L;
1735 /* Insert timer into the global queue */
1740 timer_element
*curr
, *prev
;
1742 for (prev
= 0, curr
= timer_base
; curr
; prev
= curr
, curr
= curr
->next
)
1743 if (curr
->timeout
>= gnu
->timeout
)
1753 STATIC_OVL timer_element
*
1754 remove_timer(base
, func_index
, arg
)
1755 timer_element
**base
;
1759 timer_element
*prev
, *curr
;
1761 for (prev
= 0, curr
= *base
; curr
; prev
= curr
, curr
= curr
->next
)
1762 if (curr
->func_index
== func_index
&& curr
->arg
.a_void
== arg
->a_void
)
1767 prev
->next
= curr
->next
;
1776 write_timer(fd
, timer
)
1778 timer_element
*timer
;
1783 switch (timer
->kind
) {
1786 /* assume no pointers in arg */
1787 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1791 if (timer
->needs_fixup
)
1792 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1794 /* replace object pointer with id */
1795 arg_save
.a_obj
= timer
->arg
.a_obj
;
1796 timer
->arg
= zeroany
;
1797 timer
->arg
.a_uint
= (arg_save
.a_obj
)->o_id
;
1798 timer
->needs_fixup
= 1;
1799 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1800 timer
->arg
.a_obj
= arg_save
.a_obj
;
1801 timer
->needs_fixup
= 0;
1806 if (timer
->needs_fixup
)
1807 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1809 /* replace monster pointer with id */
1810 arg_save
.a_monst
= timer
->arg
.a_monst
;
1811 timer
->arg
= zeroany
;
1812 timer
->arg
.a_uint
= (arg_save
.a_monst
)->m_id
;
1813 timer
->needs_fixup
= 1;
1814 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1815 timer
->arg
.a_monst
= arg_save
.a_monst
;
1816 timer
->needs_fixup
= 0;
1821 panic("write_timer");
1827 * Return TRUE if the object will stay on the level when the level is
1834 switch (obj
->where
) {
1842 return obj_is_local(obj
->ocontainer
);
1844 return mon_is_local(obj
->ocarry
);
1846 panic("obj_is_local");
1851 * Return TRUE if the given monster will stay on the level when the
1860 for (curr
= migrating_mons
; curr
; curr
= curr
->nmon
)
1863 /* `mydogs' is used during level changes, never saved and restored */
1864 for (curr
= mydogs
; curr
; curr
= curr
->nmon
)
1871 * Return TRUE if the timer is attached to something that will stay on the
1872 * level when the level is saved.
1875 timer_is_local(timer
)
1876 timer_element
*timer
;
1878 switch (timer
->kind
) {
1884 return obj_is_local(timer
->arg
.a_obj
);
1886 return mon_is_local(timer
->arg
.a_monst
);
1888 panic("timer_is_local");
1893 * Part of the save routine. Count up the number of timers that would
1894 * be written. If write_it is true, actually write the timer.
1897 maybe_write_timer(fd
, range
, write_it
)
1902 timer_element
*curr
;
1904 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1905 if (range
== RANGE_GLOBAL
) {
1908 if (!timer_is_local(curr
)) {
1911 write_timer(fd
, curr
);
1917 if (timer_is_local(curr
)) {
1920 write_timer(fd
, curr
);
1929 * Save part of the timer list. The parameter 'range' specifies either
1930 * global or level timers to save. The timer ID is saved with the global
1934 * + timeouts that follow the hero (global)
1935 * + timeouts that follow obj & monst that are migrating
1938 * + timeouts that are level specific (e.g. storms)
1939 * + timeouts that stay with the level (obj & monst)
1942 save_timers(fd
, mode
, range
)
1943 int fd
, mode
, range
;
1945 timer_element
*curr
, *prev
, *next_timer
= 0;
1948 if (perform_bwrite(mode
)) {
1949 if (range
== RANGE_GLOBAL
)
1950 bwrite(fd
, (genericptr_t
) &timer_id
, sizeof(timer_id
));
1952 count
= maybe_write_timer(fd
, range
, FALSE
);
1953 bwrite(fd
, (genericptr_t
) &count
, sizeof count
);
1954 (void) maybe_write_timer(fd
, range
, TRUE
);
1957 if (release_data(mode
)) {
1958 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1959 next_timer
= curr
->next
; /* in case curr is removed */
1961 if (!(!!(range
== RANGE_LEVEL
) ^ !!timer_is_local(curr
))) {
1963 prev
->next
= curr
->next
;
1965 timer_base
= curr
->next
;
1966 free((genericptr_t
) curr
);
1967 /* prev stays the same */
1976 * Pull in the structures from disk, but don't recalculate the object and
1980 restore_timers(fd
, range
, ghostly
, adjust
)
1982 boolean ghostly
; /* restoring from a ghost level */
1983 long adjust
; /* how much to adjust timeout */
1986 timer_element
*curr
;
1988 if (range
== RANGE_GLOBAL
)
1989 mread(fd
, (genericptr_t
) &timer_id
, sizeof timer_id
);
1991 /* restore elements */
1992 mread(fd
, (genericptr_t
) &count
, sizeof count
);
1993 while (count
-- > 0) {
1994 curr
= (timer_element
*) alloc(sizeof(timer_element
));
1995 mread(fd
, (genericptr_t
) curr
, sizeof(timer_element
));
1997 curr
->timeout
+= adjust
;
2002 /* to support '#stats' wizard-mode command */
2004 timer_stats(hdrfmt
, hdrbuf
, count
, size
)
2011 Sprintf(hdrbuf
, hdrfmt
, (long) sizeof (timer_element
));
2012 *count
= *size
= 0L;
2013 for (te
= timer_base
; te
; te
= te
->next
) {
2015 *size
+= (long) sizeof *te
;
2019 /* reset all timers that are marked for reseting */
2021 relink_timers(ghostly
)
2024 timer_element
*curr
;
2027 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
2028 if (curr
->needs_fixup
) {
2029 if (curr
->kind
== TIMER_OBJECT
) {
2031 if (!lookup_id_mapping(curr
->arg
.a_uint
, &nid
))
2032 panic("relink_timers 1");
2034 nid
= curr
->arg
.a_uint
;
2035 curr
->arg
.a_obj
= find_oid(nid
);
2036 if (!curr
->arg
.a_obj
)
2037 panic("cant find o_id %d", nid
);
2038 curr
->needs_fixup
= 0;
2039 } else if (curr
->kind
== TIMER_MONSTER
) {
2040 panic("relink_timers: no monster timer implemented");
2042 panic("relink_timers 2");