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
));
1537 gnu
->tid
= timer_id
++;
1538 gnu
->timeout
= monstermoves
+ when
;
1540 gnu
->needs_fixup
= 0;
1541 gnu
->func_index
= func_index
;
1545 if (kind
== TIMER_OBJECT
) /* increment object's timed count */
1546 (arg
->a_obj
)->timed
++;
1548 /* should check for duplicates and fail if any */
1553 * Remove the timer from the current list and free it up. Return the time
1554 * remaining until it would have gone off, 0 if not found.
1557 stop_timer(func_index
, arg
)
1561 timer_element
*doomed
;
1564 doomed
= remove_timer(&timer_base
, func_index
, arg
);
1567 timeout
= doomed
->timeout
;
1568 if (doomed
->kind
== TIMER_OBJECT
)
1569 (arg
->a_obj
)->timed
--;
1570 if (timeout_funcs
[doomed
->func_index
].cleanup
)
1571 (*timeout_funcs
[doomed
->func_index
].cleanup
)(arg
, timeout
);
1572 free((genericptr_t
) doomed
);
1573 return (timeout
- monstermoves
);
1579 * Find the timeout of specified timer; return 0 if none.
1582 peek_timer(type
, arg
)
1586 timer_element
*curr
;
1588 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1589 if (curr
->func_index
== type
&& curr
->arg
.a_void
== arg
->a_void
)
1590 return curr
->timeout
;
1596 * Move all object timers from src to dest, leaving src untimed.
1599 obj_move_timers(src
, dest
)
1600 struct obj
*src
, *dest
;
1603 timer_element
*curr
;
1605 for (count
= 0, curr
= timer_base
; curr
; curr
= curr
->next
)
1606 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1607 curr
->arg
.a_obj
= dest
;
1611 if (count
!= src
->timed
)
1612 panic("obj_move_timers");
1617 * Find all object timers and duplicate them for the new object "dest".
1620 obj_split_timers(src
, dest
)
1621 struct obj
*src
, *dest
;
1623 timer_element
*curr
, *next_timer
= 0;
1625 for (curr
= timer_base
; curr
; curr
= next_timer
) {
1626 next_timer
= curr
->next
; /* things may be inserted */
1627 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1628 (void) start_timer(curr
->timeout
- monstermoves
, TIMER_OBJECT
,
1629 curr
->func_index
, obj_to_any(dest
));
1635 * Stop all timers attached to this object. We can get away with this because
1636 * all object pointers are unique.
1639 obj_stop_timers(obj
)
1642 timer_element
*curr
, *prev
, *next_timer
= 0;
1644 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1645 next_timer
= curr
->next
;
1646 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== obj
) {
1648 prev
->next
= curr
->next
;
1650 timer_base
= curr
->next
;
1651 if (timeout_funcs
[curr
->func_index
].cleanup
)
1652 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1654 free((genericptr_t
) curr
);
1663 * Check whether object has a timer of type timer_type.
1666 obj_has_timer(object
, timer_type
)
1670 long timeout
= peek_timer(timer_type
, obj_to_any(object
));
1672 return (boolean
) (timeout
!= 0L);
1676 * Stop all timers of index func_index at this spot.
1680 spot_stop_timers(x
, y
, func_index
)
1684 timer_element
*curr
, *prev
, *next_timer
= 0;
1685 long where
= (((long) x
<< 16) | ((long) y
));
1687 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1688 next_timer
= curr
->next
;
1689 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1690 && curr
->arg
.a_long
== where
) {
1692 prev
->next
= curr
->next
;
1694 timer_base
= curr
->next
;
1695 if (timeout_funcs
[curr
->func_index
].cleanup
)
1696 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1698 free((genericptr_t
) curr
);
1706 * When is the spot timer of type func_index going to expire?
1707 * Returns 0L if no such timer.
1710 spot_time_expires(x
, y
, func_index
)
1714 timer_element
*curr
;
1715 long where
= (((long) x
<< 16) | ((long) y
));
1717 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1718 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1719 && curr
->arg
.a_long
== where
)
1720 return curr
->timeout
;
1726 spot_time_left(x
, y
, func_index
)
1730 long expires
= spot_time_expires(x
, y
, func_index
);
1731 return (expires
> 0L) ? expires
- monstermoves
: 0L;
1734 /* Insert timer into the global queue */
1739 timer_element
*curr
, *prev
;
1741 for (prev
= 0, curr
= timer_base
; curr
; prev
= curr
, curr
= curr
->next
)
1742 if (curr
->timeout
>= gnu
->timeout
)
1752 STATIC_OVL timer_element
*
1753 remove_timer(base
, func_index
, arg
)
1754 timer_element
**base
;
1758 timer_element
*prev
, *curr
;
1760 for (prev
= 0, curr
= *base
; curr
; prev
= curr
, curr
= curr
->next
)
1761 if (curr
->func_index
== func_index
&& curr
->arg
.a_void
== arg
->a_void
)
1766 prev
->next
= curr
->next
;
1775 write_timer(fd
, timer
)
1777 timer_element
*timer
;
1782 switch (timer
->kind
) {
1785 /* assume no pointers in arg */
1786 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1790 if (timer
->needs_fixup
)
1791 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1793 /* replace object pointer with id */
1794 arg_save
.a_obj
= timer
->arg
.a_obj
;
1795 timer
->arg
= zeroany
;
1796 timer
->arg
.a_uint
= (arg_save
.a_obj
)->o_id
;
1797 timer
->needs_fixup
= 1;
1798 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1799 timer
->arg
.a_obj
= arg_save
.a_obj
;
1800 timer
->needs_fixup
= 0;
1805 if (timer
->needs_fixup
)
1806 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1808 /* replace monster pointer with id */
1809 arg_save
.a_monst
= timer
->arg
.a_monst
;
1810 timer
->arg
= zeroany
;
1811 timer
->arg
.a_uint
= (arg_save
.a_monst
)->m_id
;
1812 timer
->needs_fixup
= 1;
1813 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1814 timer
->arg
.a_monst
= arg_save
.a_monst
;
1815 timer
->needs_fixup
= 0;
1820 panic("write_timer");
1826 * Return TRUE if the object will stay on the level when the level is
1833 switch (obj
->where
) {
1841 return obj_is_local(obj
->ocontainer
);
1843 return mon_is_local(obj
->ocarry
);
1845 panic("obj_is_local");
1850 * Return TRUE if the given monster will stay on the level when the
1859 for (curr
= migrating_mons
; curr
; curr
= curr
->nmon
)
1862 /* `mydogs' is used during level changes, never saved and restored */
1863 for (curr
= mydogs
; curr
; curr
= curr
->nmon
)
1870 * Return TRUE if the timer is attached to something that will stay on the
1871 * level when the level is saved.
1874 timer_is_local(timer
)
1875 timer_element
*timer
;
1877 switch (timer
->kind
) {
1883 return obj_is_local(timer
->arg
.a_obj
);
1885 return mon_is_local(timer
->arg
.a_monst
);
1887 panic("timer_is_local");
1892 * Part of the save routine. Count up the number of timers that would
1893 * be written. If write_it is true, actually write the timer.
1896 maybe_write_timer(fd
, range
, write_it
)
1901 timer_element
*curr
;
1903 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1904 if (range
== RANGE_GLOBAL
) {
1907 if (!timer_is_local(curr
)) {
1910 write_timer(fd
, curr
);
1916 if (timer_is_local(curr
)) {
1919 write_timer(fd
, curr
);
1928 * Save part of the timer list. The parameter 'range' specifies either
1929 * global or level timers to save. The timer ID is saved with the global
1933 * + timeouts that follow the hero (global)
1934 * + timeouts that follow obj & monst that are migrating
1937 * + timeouts that are level specific (e.g. storms)
1938 * + timeouts that stay with the level (obj & monst)
1941 save_timers(fd
, mode
, range
)
1942 int fd
, mode
, range
;
1944 timer_element
*curr
, *prev
, *next_timer
= 0;
1947 if (perform_bwrite(mode
)) {
1948 if (range
== RANGE_GLOBAL
)
1949 bwrite(fd
, (genericptr_t
) &timer_id
, sizeof(timer_id
));
1951 count
= maybe_write_timer(fd
, range
, FALSE
);
1952 bwrite(fd
, (genericptr_t
) &count
, sizeof count
);
1953 (void) maybe_write_timer(fd
, range
, TRUE
);
1956 if (release_data(mode
)) {
1957 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1958 next_timer
= curr
->next
; /* in case curr is removed */
1960 if (!(!!(range
== RANGE_LEVEL
) ^ !!timer_is_local(curr
))) {
1962 prev
->next
= curr
->next
;
1964 timer_base
= curr
->next
;
1965 free((genericptr_t
) curr
);
1966 /* prev stays the same */
1975 * Pull in the structures from disk, but don't recalculate the object and
1979 restore_timers(fd
, range
, ghostly
, adjust
)
1981 boolean ghostly
; /* restoring from a ghost level */
1982 long adjust
; /* how much to adjust timeout */
1985 timer_element
*curr
;
1987 if (range
== RANGE_GLOBAL
)
1988 mread(fd
, (genericptr_t
) &timer_id
, sizeof timer_id
);
1990 /* restore elements */
1991 mread(fd
, (genericptr_t
) &count
, sizeof count
);
1992 while (count
-- > 0) {
1993 curr
= (timer_element
*) alloc(sizeof(timer_element
));
1994 mread(fd
, (genericptr_t
) curr
, sizeof(timer_element
));
1996 curr
->timeout
+= adjust
;
2001 /* to support '#stats' wizard-mode command */
2003 timer_stats(hdrfmt
, hdrbuf
, count
, size
)
2010 Sprintf(hdrbuf
, hdrfmt
, (long) sizeof (timer_element
));
2011 *count
= *size
= 0L;
2012 for (te
= timer_base
; te
; te
= te
->next
) {
2014 *size
+= (long) sizeof *te
;
2018 /* reset all timers that are marked for reseting */
2020 relink_timers(ghostly
)
2023 timer_element
*curr
;
2026 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
2027 if (curr
->needs_fixup
) {
2028 if (curr
->kind
== TIMER_OBJECT
) {
2030 if (!lookup_id_mapping(curr
->arg
.a_uint
, &nid
))
2031 panic("relink_timers 1");
2033 nid
= curr
->arg
.a_uint
;
2034 curr
->arg
.a_obj
= find_oid(nid
);
2035 if (!curr
->arg
.a_obj
)
2036 panic("cant find o_id %d", nid
);
2037 curr
->needs_fixup
= 0;
2038 } else if (curr
->kind
== TIMER_MONSTER
) {
2039 panic("relink_timers: no monster timer implemented");
2041 panic("relink_timers 2");