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(levitation_dialogue
);
12 STATIC_DCL
void NDECL(slime_dialogue
);
13 STATIC_DCL
void NDECL(slip_or_trip
);
14 STATIC_DCL
void FDECL(see_lamp_flicker
, (struct obj
*, const char *));
15 STATIC_DCL
void FDECL(lantern_message
, (struct obj
*));
16 STATIC_DCL
void FDECL(cleanup_burn
, (ANY_P
*, long));
18 /* He is being petrified - dialogue by inmet!tower */
19 static NEARDATA
const char *const stoned_texts
[] = {
20 "You are slowing down.", /* 5 */
21 "Your limbs are stiffening.", /* 4 */
22 "Your limbs have turned to stone.", /* 3 */
23 "You have turned to stone.", /* 2 */
24 "You are a statue." /* 1 */
30 register long i
= (Stoned
& TIMEOUT
);
32 if (i
> 0L && i
<= SIZE(stoned_texts
)) {
35 Strcpy(buf
, stoned_texts
[SIZE(stoned_texts
) - i
]);
36 if (nolimbs(youmonst
.data
) && strstri(buf
, "limbs"))
37 (void) strsubst(buf
, "limbs", "extremities");
41 case 5: /* slowing down */
46 case 4: /* limbs stiffening */
47 /* just one move left to save oneself so quit fiddling around;
48 don't stop attempt to eat tin--might be lizard or acidic */
54 case 3: /* limbs turned to stone */
56 nomul(-3); /* can't move anymore */
57 multi_reason
= "getting stoned";
58 nomovemsg
= You_can_move_again
; /* not unconscious */
63 exercise(A_DEX
, FALSE
);
66 /* He is getting sicker and sicker prior to vomiting */
67 static NEARDATA
const char *const vomiting_texts
[] = {
68 "are feeling mildly nauseated.", /* 14 */
69 "feel slightly confused.", /* 11 */
70 "can't seem to think straight.", /* 8 */
71 "feel incredibly sick.", /* 5 */
72 "suddenly vomit!" /* 2 */
79 long v
= (Vomiting
& TIMEOUT
);
81 /* note: nhtimeout() hasn't decremented timed properties for the
82 current turn yet, so we use Vomiting-1 here */
83 switch ((int) (v
- 1L)) {
85 txt
= vomiting_texts
[0];
88 txt
= vomiting_texts
[1];
91 make_stunned((HStun
& TIMEOUT
) + (long) d(2, 4), FALSE
);
92 if (!Popeye(VOMITING
))
96 make_confused((HConfusion
& TIMEOUT
) + (long) d(2, 4), FALSE
);
101 txt
= vomiting_texts
[2];
104 txt
= vomiting_texts
[3];
107 txt
= vomiting_texts
[4];
108 if (cantvomit(youmonst
.data
))
109 txt
= "gag uncontrolably.";
113 if (!cantvomit(youmonst
.data
))
122 exercise(A_CON
, FALSE
);
125 static NEARDATA
const char *const choke_texts
[] = {
126 "You find it hard to breathe.", "You're gasping for air.",
127 "You can no longer breathe.", "You're turning %s.", "You suffocate."
130 static NEARDATA
const char *const choke_texts2
[] = {
131 "Your %s is becoming constricted.",
132 "Your blood is having trouble reaching your brain.",
133 "The pressure on your %s increases.", "Your consciousness is fading.",
140 register long i
= (Strangled
& TIMEOUT
);
142 if (i
> 0 && i
<= SIZE(choke_texts
)) {
143 if (Breathless
|| !rn2(50))
144 pline(choke_texts2
[SIZE(choke_texts2
) - i
], body_part(NECK
));
146 const char *str
= choke_texts
[SIZE(choke_texts
) - i
];
149 pline(str
, hcolor(NH_BLUE
));
154 exercise(A_STR
, FALSE
);
157 static NEARDATA
const char *const levi_texts
[] = {
158 "You float slightly lower.",
159 "You wobble unsteadily %s the %s.",
164 levitation_dialogue()
166 long i
= (HLevitation
& TIMEOUT
) / 2L;
171 if (!ACCESSIBLE(levl
[u
.ux
][u
.uy
].typ
)
172 && !is_pool_or_lava(u
.ux
,u
.uy
))
175 if (((HLevitation
& TIMEOUT
) % 2L) && i
>= 0L && i
< SIZE(levi_texts
)) {
176 const char *s
= levi_texts
[SIZE(levi_texts
) - i
- 1L];
179 boolean danger
= is_pool_or_lava(u
.ux
, u
.uy
)
180 && !Is_waterlevel(&u
.uz
);
181 pline(s
, danger
? "over" : "in",
182 danger
? surface(u
.ux
, u
.uy
) : "air");
189 static NEARDATA
const char *const slime_texts
[] = {
190 "You are turning a little %s.", /* 5 */
191 "Your limbs are getting oozy.", /* 4 */
192 "Your skin begins to peel away.", /* 3 */
193 "You are turning into %s.", /* 2 */
194 "You have become %s." /* 1 */
200 register long i
= (Slimed
& TIMEOUT
) / 2L;
202 if (((Slimed
& TIMEOUT
) % 2L) && i
>= 0L && i
< SIZE(slime_texts
)) {
205 Strcpy(buf
, slime_texts
[SIZE(slime_texts
) - i
- 1L]);
206 if (nolimbs(youmonst
.data
) && strstri(buf
, "limbs"))
207 (void) strsubst(buf
, "limbs", "extremities");
209 if (index(buf
, '%')) {
210 if (i
== 4L) { /* "you are turning green" */
211 if (!Blind
) /* [what if you're already green?] */
212 pline(buf
, hcolor(NH_GREEN
));
215 an(Hallucination
? rndmonnam(NULL
) : "green slime"));
219 if (i
== 3L) { /* limbs becoming oozy */
220 HFast
= 0L; /* lose intrinsic speed */
226 exercise(A_DEX
, FALSE
);
233 make_slimed(0L, "The slime that covers you is burned away!");
240 register struct prop
*upp
;
244 int baseluck
= (flags
.moonphase
== FULL_MOON
) ? 1 : 0;
249 if (u
.uluck
!= baseluck
250 && moves
% (u
.uhave
.amulet
|| u
.ugangr
? 300 : 600) == 0) {
251 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
252 * stop good luck from timing out; normal luckstones stop both;
253 * neither is stopped if you don't have a luckstone.
254 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
256 register int time_luck
= stone_luck(FALSE
);
257 boolean nostone
= !carrying(LUCKSTONE
) && !stone_luck(TRUE
);
259 if (u
.uluck
> baseluck
&& (nostone
|| time_luck
< 0))
261 else if (u
.uluck
< baseluck
&& (nostone
|| time_luck
> 0))
265 return; /* things past this point could kill you */
275 levitation_dialogue();
276 if (u
.mtimedone
&& !--u
.mtimedone
) {
278 u
.mtimedone
= rnd(100 * youmonst
.data
->mlevel
+ 1);
285 /* Dissipate spell-based protection. */
287 if (--u
.usptime
== 0 && u
.uspellprot
) {
288 u
.usptime
= u
.uspmtime
;
292 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN
),
293 u
.uspellprot
? "becomes less dense" : "disappears");
298 if (--u
.ugallop
== 0L && u
.usteed
)
299 pline("%s stops galloping.", Monnam(u
.usteed
));
302 for (upp
= u
.uprops
; upp
< u
.uprops
+ SIZE(u
.uprops
); upp
++)
303 if ((upp
->intrinsic
& TIMEOUT
) && !(--upp
->intrinsic
& TIMEOUT
)) {
304 kptr
= find_delayed_killer((int) (upp
- u
.uprops
));
305 switch (upp
- u
.uprops
) {
307 if (kptr
&& kptr
->name
[0]) {
308 killer
.format
= kptr
->format
;
309 Strcpy(killer
.name
, kptr
->name
);
311 killer
.format
= NO_KILLER_PREFIX
;
312 Strcpy(killer
.name
, "killed by petrification");
314 dealloc_killer(kptr
);
315 /* (unlike sliming, you aren't changing form here) */
319 if (kptr
&& kptr
->name
[0]) {
320 killer
.format
= kptr
->format
;
321 Strcpy(killer
.name
, kptr
->name
);
323 killer
.format
= NO_KILLER_PREFIX
;
324 Strcpy(killer
.name
, "turned into green slime");
326 dealloc_killer(kptr
);
327 /* involuntarily break "never changed form" conduct */
328 u
.uconduct
.polyselfs
++;
332 make_vomiting(0L, TRUE
);
335 You("die from your illness.");
336 if (kptr
&& kptr
->name
[0]) {
337 killer
.format
= kptr
->format
;
338 Strcpy(killer
.name
, kptr
->name
);
340 killer
.format
= KILLED_BY_AN
;
341 killer
.name
[0] = 0; /* take the default */
343 dealloc_killer(kptr
);
345 if ((m_idx
= name_to_mon(killer
.name
)) >= LOW_PM
) {
346 if (type_is_pname(&mons
[m_idx
])) {
347 killer
.format
= KILLED_BY
;
348 } else if (mons
[m_idx
].geno
& G_UNIQ
) {
349 Strcpy(killer
.name
, the(killer
.name
));
350 killer
.format
= KILLED_BY
;
358 You_feel("yourself slowing down%s.",
359 Fast
? " a bit" : "");
362 /* So make_confused works properly */
363 set_itimeout(&HConfusion
, 1L);
364 make_confused(0L, TRUE
);
369 set_itimeout(&HStun
, 1L);
370 make_stunned(0L, TRUE
);
375 set_itimeout(&Blinded
, 1L);
376 make_blinded(0L, TRUE
);
381 set_itimeout(&HDeaf
, 1L);
389 if (!Invis
&& !BInvis
&& !Blind
) {
391 ? "are no longer invisible."
392 : "can no longer see through yourself.");
397 set_mimic_blocking(); /* do special mimic handling */
398 see_monsters(); /* make invis mons appear */
399 newsym(u
.ux
, u
.uy
); /* make self appear */
407 set_itimeout(&HHallucination
, 1L);
408 (void) make_hallucinated(0L, TRUE
, 0L);
413 if (unconscious() || Sleep_resistance
) {
414 incr_itimeout(&HSleepy
, rnd(100));
418 fall_asleep(-sleeptime
, TRUE
);
419 incr_itimeout(&HSleepy
, sleeptime
+ rnd(100));
423 (void) float_down(I_SPECIAL
| TIMEOUT
, 0L);
426 killer
.format
= KILLED_BY
;
428 (u
.uburied
) ? "suffocation" : "strangulation");
430 /* must be declining to die in explore|wizard mode;
431 treat like being cured of strangulation by prayer */
432 if (uamul
&& uamul
->otyp
== AMULET_OF_STRANGULATION
) {
433 Your("amulet vanishes!");
438 /* call this only when a move took place. */
439 /* otherwise handle fumbling msgs locally. */
440 if (u
.umoved
&& !Levitation
) {
443 multi_reason
= "fumbling";
445 /* The more you are carrying the more likely you
446 * are to make noise when you fumble. Adjustments
447 * to this number must be thoroughly play tested.
449 if ((inv_weight() > -500)) {
450 You("make a lot of noise!");
454 /* from outside means slippery ice; don't reset
455 counter if that's the only fumble reason */
456 HFumbling
&= ~FROMOUTSIDE
;
458 incr_itimeout(&HFumbling
, rnd(20));
460 case DETECT_MONSTERS
:
470 fall_asleep(how_long
, wakeup_msg
)
476 multi_reason
= "sleeping";
477 /* generally don't notice sounds while sleeping */
478 if (wakeup_msg
&& multi
== how_long
) {
479 /* caller can follow with a direct call to Hear_again() if
480 there's a need to override this when wakeup_msg is true */
481 incr_itimeout(&HDeaf
, how_long
);
483 afternmv
= Hear_again
; /* this won't give any messages */
485 /* early wakeup from combat won't be possible until next monster turn */
486 u
.usleep
= monstermoves
;
487 nomovemsg
= wakeup_msg
? "You wake up." : You_can_move_again
;
490 /* Attach an egg hatch timeout to the given egg.
491 * when = Time to hatch, usually only passed if re-creating an
492 * existing hatch timer. Pass 0L for random hatch time.
495 attach_egg_hatch_timeout(egg
, when
)
501 /* stop previous timer, if any */
502 (void) stop_timer(HATCH_EGG
, obj_to_any(egg
));
505 * Decide if and when to hatch the egg. The old hatch_it() code tried
506 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
507 * a number x, 1<=x<=age, where x>150. This yields a chance of
508 * hatching > 99.9993%. Mimic that here.
511 for (i
= (MAX_EGG_HATCH_TIME
- 50) + 1; i
<= MAX_EGG_HATCH_TIME
; i
++)
519 (void) start_timer(when
, TIMER_OBJECT
, HATCH_EGG
, obj_to_any(egg
));
523 /* prevent an egg from ever hatching */
528 /* stop previous timer, if any */
529 (void) stop_timer(HATCH_EGG
, obj_to_any(egg
));
532 /* timer callback routine: hatch the given egg */
534 hatch_egg(arg
, timeout
)
539 struct monst
*mon
, *mon2
;
542 boolean yours
, silent
, knows_egg
= FALSE
;
543 boolean cansee_hatchspot
= FALSE
;
544 int i
, mnum
, hatchcount
= 0;
547 /* sterilized while waiting */
548 if (egg
->corpsenm
== NON_PM
)
551 mon
= mon2
= (struct monst
*) 0;
552 mnum
= big_to_little(egg
->corpsenm
);
553 /* The identity of one's father is learned, not innate */
554 yours
= (egg
->spe
|| (!flags
.female
&& carried(egg
) && !rn2(2)));
555 silent
= (timeout
!= monstermoves
); /* hatched while away */
557 /* only can hatch when in INVENT, FLOOR, MINVENT */
558 if (get_obj_location(egg
, &x
, &y
, 0)) {
559 hatchcount
= rnd((int) egg
->quan
);
560 cansee_hatchspot
= cansee(x
, y
) && !silent
;
561 if (!(mons
[mnum
].geno
& G_UNIQ
)
562 && !(mvitals
[mnum
].mvflags
& (G_GENOD
| G_EXTINCT
))) {
563 for (i
= hatchcount
; i
> 0; i
--) {
564 if (!enexto(&cc
, x
, y
, &mons
[mnum
])
565 || !(mon
= makemon(&mons
[mnum
], cc
.x
, cc
.y
, NO_MINVENT
)))
567 /* tame if your own egg hatches while you're on the
568 same dungeon level, or any dragon egg which hatches
569 while it's in your inventory */
570 if ((yours
&& !silent
)
571 || (carried(egg
) && mon
->data
->mlet
== S_DRAGON
)) {
572 if (tamedog(mon
, (struct obj
*) 0)) {
573 if (carried(egg
) && mon
->data
->mlet
!= S_DRAGON
)
577 if (mvitals
[mnum
].mvflags
& G_EXTINCT
)
578 break; /* just made last one */
579 mon2
= mon
; /* in case makemon() fails on 2nd egg */
584 egg
->quan
-= (long) hatchcount
;
588 * We could possibly hatch while migrating, but the code isn't
591 } else if (obj
->where
== OBJ_MIGRATING
) {
593 * We can do several things. The first ones that come to
595 * + Create the hatched monster then place it on the migrating
596 * mons list. This is tough because all makemon() is made
597 * to place the monster as well. Makemon() also doesn't lend
598 * itself well to splitting off a "not yet placed" subroutine.
599 * + Mark the egg as hatched, then place the monster when we
600 * place the migrating objects.
601 * + Or just kill any egg which gets sent to another level.
602 * Falling is the usual reason such transportation occurs.
604 cansee_hatchspot
= FALSE
;
610 char monnambuf
[BUFSZ
], carriedby
[BUFSZ
];
611 boolean siblings
= (hatchcount
> 1), redraw
= FALSE
;
613 if (cansee_hatchspot
) {
614 Sprintf(monnambuf
, "%s%s", siblings
? "some " : "",
615 siblings
? makeplural(m_monnam(mon
)) : an(m_monnam(mon
)));
616 /* we don't learn the egg type here because learning
617 an egg type requires either seeing the egg hatch
618 or being familiar with the egg already,
619 as well as being able to see the resulting
620 monster, checked below
623 switch (egg
->where
) {
625 knows_egg
= TRUE
; /* true even if you are blind */
626 if (!cansee_hatchspot
)
627 You_feel("%s %s from your pack!", something
,
628 locomotion(mon
->data
, "drop"));
630 You_see("%s %s out of your pack!", monnambuf
,
631 locomotion(mon
->data
, "drop"));
633 pline("%s cries sound like \"%s%s\"",
634 siblings
? "Their" : "Its",
635 flags
.female
? "mommy" : "daddy", egg
->spe
? "." : "?");
636 } else if (mon
->data
->mlet
== S_DRAGON
&& !Deaf
) {
637 verbalize("Gleep!"); /* Mything eggs :-) */
642 if (cansee_hatchspot
) {
644 You_see("%s hatch.", monnambuf
);
645 redraw
= TRUE
; /* update egg's map location */
650 if (cansee_hatchspot
) {
651 /* egg carrying monster might be invisible */
654 && (!mon2
->wormno
|| cansee(mon2
->mx
, mon2
->my
))) {
655 Sprintf(carriedby
, "%s pack",
656 s_suffix(a_monnam(mon2
)));
658 } else if (is_pool(mon
->mx
, mon
->my
)) {
659 Strcpy(carriedby
, "empty water");
661 Strcpy(carriedby
, "thin air");
663 You_see("%s %s out of %s!", monnambuf
,
664 locomotion(mon
->data
, "drop"), carriedby
);
672 impossible("egg hatched where? (%d)", (int) egg
->where
);
676 if (cansee_hatchspot
&& knows_egg
)
677 learn_egg_type(mnum
);
680 /* still some eggs left */
681 /* Instead of ordinary egg timeout use a short one */
682 attach_egg_hatch_timeout(egg
, (long) rnd(12));
683 } else if (carried(egg
)) {
686 /* free egg here because we use it above */
687 obj_extract_self(egg
);
688 obfree(egg
, (struct obj
*) 0);
695 /* Learn to recognize eggs of the given type. */
700 /* baby monsters hatch from grown-up eggs */
701 mnum
= little_to_big(mnum
);
702 mvitals
[mnum
].mvflags
|= MV_KNOWS_EGG
;
703 /* we might have just learned about other eggs being carried */
707 /* Attach a fig_transform timeout to the given figurine. */
709 attach_fig_transform_timeout(figurine
)
710 struct obj
*figurine
;
714 /* stop previous timer, if any */
715 (void) stop_timer(FIG_TRANSFORM
, obj_to_any(figurine
));
718 * Decide when to transform the figurine.
721 /* figurine will transform */
722 (void) start_timer((long) i
, TIMER_OBJECT
, FIG_TRANSFORM
,
723 obj_to_any(figurine
));
726 /* give a fumble message */
730 struct obj
*otmp
= vobj_at(u
.ux
, u
.uy
), *otmp2
;
733 boolean on_foot
= TRUE
;
737 if (otmp
&& on_foot
&& !u
.uinwater
&& is_pool(u
.ux
, u
.uy
))
740 if (otmp
&& on_foot
) { /* trip over something in particular */
742 If there is only one item, it will have just been named
743 during the move, so refer to by via pronoun; otherwise,
744 if the top item has been or can be seen, refer to it by
745 name; if not, look for rocks to trip over; trip over
746 anonymous "something" if there aren't any rocks.
748 what
= (iflags
.last_msg
== PLNMSG_ONE_ITEM_HERE
)
749 ? ((otmp
->quan
== 1L) ? "it"
750 : Hallucination
? "they" : "them")
751 : (otmp
->dknown
|| !Blind
)
753 : ((otmp2
= sobj_at(ROCK
, u
.ux
, u
.uy
)) == 0
755 : (otmp2
->quan
== 1L ? "a rock" : "some rocks"));
757 what
= strcpy(buf
, what
);
758 buf
[0] = highc(buf
[0]);
759 pline("Egads! %s bite%s your %s!", what
,
760 (!otmp
|| otmp
->quan
== 1L) ? "s" : "", body_part(FOOT
));
762 You("trip over %s.", what
);
764 if (!uarmf
&& otmp
->otyp
== CORPSE
765 && touch_petrifies(&mons
[otmp
->corpsenm
]) && !Stone_resistance
) {
766 Sprintf(killer
.name
, "tripping over %s corpse",
767 an(mons
[otmp
->corpsenm
].mname
));
768 instapetrify(killer
.name
);
770 } else if (rn2(3) && is_ice(u
.ux
, u
.uy
)) {
771 pline("%s %s%s on the ice.",
772 u
.usteed
? upstart(x_monnam(u
.usteed
,
773 (has_mname(u
.usteed
)) ? ARTICLE_NONE
775 (char *) 0, SUPPRESS_SADDLE
, FALSE
))
777 rn2(2) ? "slip" : "slide", on_foot
? "" : "s");
782 You("trip over your own %s.",
783 Hallucination
? "elbow" : makeplural(body_part(FOOT
)));
787 Hallucination
? "on a banana peel" : "and nearly fall");
799 Your("%s slip out of the stirrups.",
800 makeplural(body_part(FOOT
)));
803 You("let go of the reins.");
806 You("bang into the saddle-horn.");
809 You("slide to one side of the saddle.");
812 dismount_steed(DISMOUNT_FELL
);
817 /* Print a lamp flicker message with tailer. */
819 see_lamp_flicker(obj
, tailer
)
823 switch (obj
->where
) {
826 pline("%s flickers%s.", Yname2(obj
), tailer
);
829 You_see("%s flicker%s.", an(xname(obj
)), tailer
);
834 /* Print a dimming message for brass lanterns. */
840 switch (obj
->where
) {
842 Your("lantern is getting dim.");
844 pline("Batteries have not been invented yet.");
847 You_see("a lantern getting dim.");
850 pline("%s lantern is getting dim.", s_suffix(Monnam(obj
->ocarry
)));
856 * Timeout callback for for objects that are burning. E.g. lamps, candles.
857 * See begin_burn() for meanings of obj->age and obj->spe.
860 burn_object(arg
, timeout
)
864 struct obj
*obj
= arg
->a_obj
;
865 boolean canseeit
, many
, menorah
, need_newsym
;
869 menorah
= obj
->otyp
== CANDELABRUM_OF_INVOCATION
;
870 many
= menorah
? obj
->spe
> 1 : obj
->quan
> 1L;
872 /* timeout while away */
873 if (timeout
!= monstermoves
) {
874 long how_long
= monstermoves
- timeout
;
876 if (how_long
>= obj
->age
) {
878 end_burn(obj
, FALSE
);
881 obj
->spe
= 0; /* no more candles */
882 } else if (Is_candle(obj
) || obj
->otyp
== POT_OIL
) {
883 /* get rid of candles and burning oil potions;
884 we know this object isn't carried by hero,
885 nor is it migrating */
886 obj_extract_self(obj
);
887 obfree(obj
, (struct obj
*) 0);
888 obj
= (struct obj
*) 0;
892 obj
->age
-= how_long
;
893 begin_burn(obj
, TRUE
);
898 /* only interested in INVENT, FLOOR, and MINVENT */
899 if (get_obj_location(obj
, &x
, &y
, 0)) {
900 canseeit
= !Blind
&& cansee(x
, y
);
901 /* set `whose[]' to be "Your " or "Fred's " or "The goblin's " */
902 (void) Shk_Your(whose
, obj
);
908 /* obj->age is the age remaining at this point. */
911 /* this should only be called when we run out */
913 switch (obj
->where
) {
916 pline("%spotion of oil has burnt away.", whose
);
919 You_see("a burning potion of oil go out.");
924 end_burn(obj
, FALSE
); /* turn off light source */
928 /* clear migrating obj's destination code before obfree
929 to avoid false complaint of deleting worn item */
930 if (obj
->where
== OBJ_MIGRATING
)
932 obj_extract_self(obj
);
933 obfree(obj
, (struct obj
*) 0);
935 obj
= (struct obj
*) 0;
940 switch ((int) obj
->age
) {
945 if (obj
->otyp
== BRASS_LANTERN
)
946 lantern_message(obj
);
948 see_lamp_flicker(obj
,
949 obj
->age
== 50L ? " considerably" : "");
955 if (obj
->otyp
== BRASS_LANTERN
)
956 lantern_message(obj
);
958 switch (obj
->where
) {
961 pline("%s seems about to go out.", Yname2(obj
));
964 You_see("%s about to go out.", an(xname(obj
)));
972 /* even if blind you'll know if holding it */
973 if (canseeit
|| obj
->where
== OBJ_INVENT
) {
974 switch (obj
->where
) {
977 if (obj
->otyp
== BRASS_LANTERN
)
978 pline("%slantern has run out of power.", whose
);
980 pline("%s has gone out.", Yname2(obj
));
983 if (obj
->otyp
== BRASS_LANTERN
)
984 You_see("a lantern run out of power.");
986 You_see("%s go out.", an(xname(obj
)));
990 end_burn(obj
, FALSE
);
995 * Someone added fuel to the lamp while it was
996 * lit. Just fall through and let begin burn
997 * handle the new age.
1003 begin_burn(obj
, TRUE
);
1007 case CANDELABRUM_OF_INVOCATION
:
1013 switch (obj
->where
) {
1016 pline("%s%scandle%s getting short.", whose
,
1017 menorah
? "candelabrum's " : "",
1018 many
? "s are" : " is");
1021 You_see("%scandle%s getting short.",
1022 menorah
? "a candelabrum's " : many
? "some "
1031 switch (obj
->where
) {
1034 pline("%s%scandle%s flame%s flicker%s low!", whose
,
1035 menorah
? "candelabrum's " : "", many
? "s'" : "'s",
1036 many
? "s" : "", many
? "" : "s");
1039 You_see("%scandle%s flame%s flicker low!",
1040 menorah
? "a candelabrum's " : many
? "some "
1042 many
? "s'" : "'s", many
? "s" : "");
1048 /* we know even if blind and in our inventory */
1049 if (canseeit
|| obj
->where
== OBJ_INVENT
) {
1051 switch (obj
->where
) {
1054 pline("%scandelabrum's flame%s.", whose
,
1055 many
? "s die" : " dies");
1058 You_see("a candelabrum's flame%s die.",
1063 switch (obj
->where
) {
1066 pline("%s %s consumed!", Yname2(obj
),
1067 many
? "are" : "is");
1071 You see some wax candles consumed!
1072 You see a wax candle consumed!
1074 You_see("%s%s consumed!", many
? "some " : "",
1075 many
? xname(obj
) : an(xname(obj
)));
1082 ? (many
? "They shriek!" : "It shrieks!")
1083 : Blind
? "" : (many
? "Their flames die."
1084 : "Its flame dies."));
1087 end_burn(obj
, FALSE
);
1095 /* clear migrating obj's destination code
1096 so obfree won't think this item is worn */
1097 if (obj
->where
== OBJ_MIGRATING
)
1098 obj
->owornmask
= 0L;
1099 obj_extract_self(obj
);
1100 obfree(obj
, (struct obj
*) 0);
1102 obj
= (struct obj
*) 0;
1108 * Someone added fuel (candles) to the menorah while
1109 * it was lit. Just fall through and let begin burn
1110 * handle the new age.
1115 if (obj
&& obj
->age
)
1116 begin_burn(obj
, TRUE
);
1121 impossible("burn_object: unexpeced obj %s", xname(obj
));
1129 * Start a burn timeout on the given object. If not "already lit" then
1130 * create a light source for the vision system. There had better not
1131 * be a burn already running on the object.
1133 * Magic lamps stay lit as long as there's a genie inside, so don't start
1137 * potions of oil, lamps & candles:
1138 * age = # of turns of fuel left
1142 * spe = 0 not lightable, 1 lightable forever
1144 * age = # of turns of fuel left
1145 * spe = # of candles
1147 * Once the burn begins, the age will be set to the amount of fuel
1148 * remaining _once_the_burn_finishes_. If the burn is terminated
1149 * early then fuel is added back.
1151 * This use of age differs from the use of age for corpses and eggs.
1152 * For the latter items, age is when the object was created, so we
1153 * know when it becomes "bad".
1155 * This is a "silent" routine - it should not print anything out.
1158 begin_burn(obj
, already_lit
)
1160 boolean already_lit
;
1164 boolean do_timer
= TRUE
;
1166 if (obj
->age
== 0 && obj
->otyp
!= MAGIC_LAMP
&& !artifact_light(obj
))
1169 switch (obj
->otyp
) {
1177 radius
= 1; /* very dim light */
1182 /* magic times are 150, 100, 50, 25, and 0 */
1183 if (obj
->age
> 150L)
1184 turns
= obj
->age
- 150L;
1185 else if (obj
->age
> 100L)
1186 turns
= obj
->age
- 100L;
1187 else if (obj
->age
> 50L)
1188 turns
= obj
->age
- 50L;
1189 else if (obj
->age
> 25L)
1190 turns
= obj
->age
- 25L;
1195 case CANDELABRUM_OF_INVOCATION
:
1198 /* magic times are 75, 15, and 0 */
1200 turns
= obj
->age
- 75L;
1201 else if (obj
->age
> 15L)
1202 turns
= obj
->age
- 15L;
1205 radius
= candle_light_range(obj
);
1209 /* [ALI] Support artifact light sources */
1210 if (artifact_light(obj
)) {
1213 radius
= arti_light_radius(obj
);
1215 impossible("begin burn: unexpected %s", xname(obj
));
1222 if (start_timer(turns
, TIMER_OBJECT
, BURN_OBJECT
, obj_to_any(obj
))) {
1225 if (carried(obj
) && !already_lit
)
1231 if (carried(obj
) && !already_lit
)
1235 if (obj
->lamplit
&& !already_lit
) {
1238 if (get_obj_location(obj
, &x
, &y
, CONTAINED_TOO
| BURIED_TOO
))
1239 new_light_source(x
, y
, radius
, LS_OBJECT
, obj_to_any(obj
));
1241 impossible("begin_burn: can't get obj position");
1246 * Stop a burn timeout on the given object if timer attached. Darken
1250 end_burn(obj
, timer_attached
)
1252 boolean timer_attached
;
1254 if (!obj
->lamplit
) {
1255 impossible("end_burn: obj %s not lit", xname(obj
));
1259 if (obj
->otyp
== MAGIC_LAMP
|| artifact_light(obj
))
1260 timer_attached
= FALSE
;
1262 if (!timer_attached
) {
1263 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1264 del_light_source(LS_OBJECT
, obj_to_any(obj
));
1266 if (obj
->where
== OBJ_INVENT
)
1268 } else if (!stop_timer(BURN_OBJECT
, obj_to_any(obj
)))
1269 impossible("end_burn: obj %s not timed!", xname(obj
));
1273 * Cleanup a burning object if timer stopped.
1276 cleanup_burn(arg
, expire_time
)
1280 struct obj
*obj
= arg
->a_obj
;
1281 if (!obj
->lamplit
) {
1282 impossible("cleanup_burn: obj %s not lit", xname(obj
));
1286 del_light_source(LS_OBJECT
, obj_to_any(obj
));
1288 /* restore unused time */
1289 obj
->age
+= expire_time
- monstermoves
;
1293 if (obj
->where
== OBJ_INVENT
)
1305 /* no lightning if not the air level or too often, even then */
1306 if (!Is_airlevel(&u
.uz
) || rn2(8))
1309 /* the number of strikes is 8-log2(nstrike) */
1310 for (nstrike
= rnd(64); nstrike
<= 64; nstrike
*= 2) {
1315 } while (++count
< 100 && levl
[x
][y
].typ
!= CLOUD
);
1320 if (dirx
!= 0 || diry
!= 0)
1321 buzz(-15, /* "monster" LIGHTNING spell */
1322 8, x
, y
, dirx
, diry
);
1326 if (levl
[u
.ux
][u
.uy
].typ
== CLOUD
) {
1327 /* Inside a cloud during a thunder storm is deafening. */
1328 /* Even if already deaf, we sense the thunder's vibrations. */
1329 pline("Kaboom!!! Boom!! Boom!!");
1330 incr_itimeout(&HDeaf
, rn1(20, 30));
1331 context
.botl
= TRUE
;
1332 if (!u
.uinvulnerable
) {
1335 multi_reason
= "hiding from thunderstorm";
1339 You_hear("a rumbling noise.");
1342 /* -------------------------------------------------------------------------
1345 * Generic Timeout Functions.
1350 * boolean start_timer(long timeout,short kind,short func_index,
1352 * Start a timer of kind 'kind' that will expire at time
1353 * monstermoves+'timeout'. Call the function at 'func_index'
1354 * in the timeout table using argument 'arg'. Return TRUE if
1355 * a timer was started. This places the timer on a list ordered
1356 * "sooner" to "later". If an object, increment the object's
1359 * long stop_timer(short func_index, anything *arg)
1360 * Stop a timer specified by the (func_index, arg) pair. This
1361 * assumes that such a pair is unique. Return the time the
1362 * timer would have gone off. If no timer is found, return 0.
1363 * If an object, decrement the object's timer count.
1365 * long peek_timer(short func_index, anything *arg)
1366 * Return time specified timer will go off (0 if no such timer).
1368 * void run_timers(void)
1369 * Call timers that have timed out.
1372 * void save_timers(int fd, int mode, int range)
1373 * Save all timers of range 'range'. Range is either global
1374 * or local. Global timers follow game play, local timers
1375 * are saved with a level. Object and monster timers are
1376 * saved using their respective id's instead of pointers.
1378 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1379 * Restore timers of range 'range'. If from a ghost pile,
1380 * adjust the timeout by 'adjust'. The object and monster
1381 * ids are not restored until later.
1383 * void relink_timers(boolean ghostly)
1384 * Relink all object and monster timers that had been saved
1385 * using their object's or monster's id number.
1388 * void obj_move_timers(struct obj *src, struct obj *dest)
1389 * Reassign all timers from src to dest.
1391 * void obj_split_timers(struct obj *src, struct obj *dest)
1392 * Duplicate all timers assigned to src and attach them to dest.
1394 * void obj_stop_timers(struct obj *obj)
1395 * Stop all timers attached to obj.
1397 * boolean obj_has_timer(struct obj *object, short timer_type)
1398 * Check whether object has a timer of type timer_type.
1401 STATIC_DCL
const char *FDECL(kind_name
, (SHORT_P
));
1402 STATIC_DCL
void FDECL(print_queue
, (winid
, timer_element
*));
1403 STATIC_DCL
void FDECL(insert_timer
, (timer_element
*));
1404 STATIC_DCL timer_element
*FDECL(remove_timer
,
1405 (timer_element
**, SHORT_P
, ANY_P
*));
1406 STATIC_DCL
void FDECL(write_timer
, (int, timer_element
*));
1407 STATIC_DCL boolean
FDECL(mon_is_local
, (struct monst
*));
1408 STATIC_DCL boolean
FDECL(timer_is_local
, (timer_element
*));
1409 STATIC_DCL
int FDECL(maybe_write_timer
, (int, int, BOOLEAN_P
));
1411 /* ordered timer list */
1412 static timer_element
*timer_base
; /* "active" */
1413 static unsigned long timer_id
= 1;
1415 /* If defined, then include names when printing out the timer queue */
1416 #define VERBOSE_TIMER
1419 timeout_proc f
, cleanup
;
1420 #ifdef VERBOSE_TIMER
1422 #define TTAB(a, b, c) \
1427 #define TTAB(a, b, c) \
1434 /* table of timeout functions */
1435 static const ttable timeout_funcs
[NUM_TIME_FUNCS
] = {
1436 TTAB(rot_organic
, (timeout_proc
) 0, "rot_organic"),
1437 TTAB(rot_corpse
, (timeout_proc
) 0, "rot_corpse"),
1438 TTAB(revive_mon
, (timeout_proc
) 0, "revive_mon"),
1439 TTAB(burn_object
, cleanup_burn
, "burn_object"),
1440 TTAB(hatch_egg
, (timeout_proc
) 0, "hatch_egg"),
1441 TTAB(fig_transform
, (timeout_proc
) 0, "fig_transform"),
1442 TTAB(melt_ice_away
, (timeout_proc
) 0, "melt_ice_away")
1446 STATIC_OVL
const char *
1464 print_queue(win
, base
)
1466 timer_element
*base
;
1468 timer_element
*curr
;
1472 putstr(win
, 0, "<empty>");
1474 putstr(win
, 0, "timeout id kind call");
1475 for (curr
= base
; curr
; curr
= curr
->next
) {
1476 #ifdef VERBOSE_TIMER
1477 Sprintf(buf
, " %4ld %4ld %-6s %s(%s)", curr
->timeout
,
1478 curr
->tid
, kind_name(curr
->kind
),
1479 timeout_funcs
[curr
->func_index
].name
,
1480 fmt_ptr((genericptr_t
) curr
->arg
.a_void
));
1482 Sprintf(buf
, " %4ld %4ld %-6s #%d(%s)", curr
->timeout
,
1483 curr
->tid
, kind_name(curr
->kind
), curr
->func_index
,
1484 fmt_ptr((genericptr_t
) curr
->arg
.a_void
));
1486 putstr(win
, 0, buf
);
1497 win
= create_nhwindow(NHW_MENU
); /* corner text window */
1501 Sprintf(buf
, "Current time = %ld.", monstermoves
);
1502 putstr(win
, 0, buf
);
1504 putstr(win
, 0, "Active timeout queue:");
1506 print_queue(win
, timer_base
);
1508 display_nhwindow(win
, FALSE
);
1509 destroy_nhwindow(win
);
1515 timer_sanity_check()
1517 timer_element
*curr
;
1519 /* this should be much more complete */
1520 for (curr
= timer_base
; curr
; curr
= curr
->next
)
1521 if (curr
->kind
== TIMER_OBJECT
) {
1522 struct obj
*obj
= curr
->arg
.a_obj
;
1523 if (obj
->timed
== 0) {
1524 pline("timer sanity: untimed obj %s, timer %ld",
1525 fmt_ptr((genericptr_t
) obj
), curr
->tid
);
1531 * Pick off timeout elements from the global queue and call their functions.
1532 * Do this until their time is less than or equal to the move count.
1537 timer_element
*curr
;
1540 * Always use the first element. Elements may be added or deleted at
1541 * any time. The list is ordered, we are done when the first element
1544 while (timer_base
&& timer_base
->timeout
<= monstermoves
) {
1546 timer_base
= curr
->next
;
1548 if (curr
->kind
== TIMER_OBJECT
)
1549 (curr
->arg
.a_obj
)->timed
--;
1550 (*timeout_funcs
[curr
->func_index
].f
)(&curr
->arg
, curr
->timeout
);
1551 free((genericptr_t
) curr
);
1556 * Start a timer. Return TRUE if successful.
1559 start_timer(when
, kind
, func_index
, arg
)
1567 if (func_index
< 0 || func_index
>= NUM_TIME_FUNCS
)
1568 panic("start_timer");
1570 gnu
= (timer_element
*) alloc(sizeof(timer_element
));
1571 (void) memset((genericptr_t
)gnu
, 0, sizeof(timer_element
));
1573 gnu
->tid
= timer_id
++;
1574 gnu
->timeout
= monstermoves
+ when
;
1576 gnu
->needs_fixup
= 0;
1577 gnu
->func_index
= func_index
;
1581 if (kind
== TIMER_OBJECT
) /* increment object's timed count */
1582 (arg
->a_obj
)->timed
++;
1584 /* should check for duplicates and fail if any */
1589 * Remove the timer from the current list and free it up. Return the time
1590 * remaining until it would have gone off, 0 if not found.
1593 stop_timer(func_index
, arg
)
1597 timer_element
*doomed
;
1600 doomed
= remove_timer(&timer_base
, func_index
, arg
);
1603 timeout
= doomed
->timeout
;
1604 if (doomed
->kind
== TIMER_OBJECT
)
1605 (arg
->a_obj
)->timed
--;
1606 if (timeout_funcs
[doomed
->func_index
].cleanup
)
1607 (*timeout_funcs
[doomed
->func_index
].cleanup
)(arg
, timeout
);
1608 free((genericptr_t
) doomed
);
1609 return (timeout
- monstermoves
);
1615 * Find the timeout of specified timer; return 0 if none.
1618 peek_timer(type
, arg
)
1622 timer_element
*curr
;
1624 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1625 if (curr
->func_index
== type
&& curr
->arg
.a_void
== arg
->a_void
)
1626 return curr
->timeout
;
1632 * Move all object timers from src to dest, leaving src untimed.
1635 obj_move_timers(src
, dest
)
1636 struct obj
*src
, *dest
;
1639 timer_element
*curr
;
1641 for (count
= 0, curr
= timer_base
; curr
; curr
= curr
->next
)
1642 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1643 curr
->arg
.a_obj
= dest
;
1647 if (count
!= src
->timed
)
1648 panic("obj_move_timers");
1653 * Find all object timers and duplicate them for the new object "dest".
1656 obj_split_timers(src
, dest
)
1657 struct obj
*src
, *dest
;
1659 timer_element
*curr
, *next_timer
= 0;
1661 for (curr
= timer_base
; curr
; curr
= next_timer
) {
1662 next_timer
= curr
->next
; /* things may be inserted */
1663 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== src
) {
1664 (void) start_timer(curr
->timeout
- monstermoves
, TIMER_OBJECT
,
1665 curr
->func_index
, obj_to_any(dest
));
1671 * Stop all timers attached to this object. We can get away with this because
1672 * all object pointers are unique.
1675 obj_stop_timers(obj
)
1678 timer_element
*curr
, *prev
, *next_timer
= 0;
1680 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1681 next_timer
= curr
->next
;
1682 if (curr
->kind
== TIMER_OBJECT
&& curr
->arg
.a_obj
== obj
) {
1684 prev
->next
= curr
->next
;
1686 timer_base
= curr
->next
;
1687 if (timeout_funcs
[curr
->func_index
].cleanup
)
1688 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1690 free((genericptr_t
) curr
);
1699 * Check whether object has a timer of type timer_type.
1702 obj_has_timer(object
, timer_type
)
1706 long timeout
= peek_timer(timer_type
, obj_to_any(object
));
1708 return (boolean
) (timeout
!= 0L);
1712 * Stop all timers of index func_index at this spot.
1716 spot_stop_timers(x
, y
, func_index
)
1720 timer_element
*curr
, *prev
, *next_timer
= 0;
1721 long where
= (((long) x
<< 16) | ((long) y
));
1723 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1724 next_timer
= curr
->next
;
1725 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1726 && curr
->arg
.a_long
== where
) {
1728 prev
->next
= curr
->next
;
1730 timer_base
= curr
->next
;
1731 if (timeout_funcs
[curr
->func_index
].cleanup
)
1732 (*timeout_funcs
[curr
->func_index
].cleanup
)(&curr
->arg
,
1734 free((genericptr_t
) curr
);
1742 * When is the spot timer of type func_index going to expire?
1743 * Returns 0L if no such timer.
1746 spot_time_expires(x
, y
, func_index
)
1750 timer_element
*curr
;
1751 long where
= (((long) x
<< 16) | ((long) y
));
1753 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1754 if (curr
->kind
== TIMER_LEVEL
&& curr
->func_index
== func_index
1755 && curr
->arg
.a_long
== where
)
1756 return curr
->timeout
;
1762 spot_time_left(x
, y
, func_index
)
1766 long expires
= spot_time_expires(x
, y
, func_index
);
1767 return (expires
> 0L) ? expires
- monstermoves
: 0L;
1770 /* Insert timer into the global queue */
1775 timer_element
*curr
, *prev
;
1777 for (prev
= 0, curr
= timer_base
; curr
; prev
= curr
, curr
= curr
->next
)
1778 if (curr
->timeout
>= gnu
->timeout
)
1788 STATIC_OVL timer_element
*
1789 remove_timer(base
, func_index
, arg
)
1790 timer_element
**base
;
1794 timer_element
*prev
, *curr
;
1796 for (prev
= 0, curr
= *base
; curr
; prev
= curr
, curr
= curr
->next
)
1797 if (curr
->func_index
== func_index
&& curr
->arg
.a_void
== arg
->a_void
)
1802 prev
->next
= curr
->next
;
1811 write_timer(fd
, timer
)
1813 timer_element
*timer
;
1818 switch (timer
->kind
) {
1821 /* assume no pointers in arg */
1822 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1826 if (timer
->needs_fixup
)
1827 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1829 /* replace object pointer with id */
1830 arg_save
.a_obj
= timer
->arg
.a_obj
;
1831 timer
->arg
= zeroany
;
1832 timer
->arg
.a_uint
= (arg_save
.a_obj
)->o_id
;
1833 timer
->needs_fixup
= 1;
1834 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1835 timer
->arg
.a_obj
= arg_save
.a_obj
;
1836 timer
->needs_fixup
= 0;
1841 if (timer
->needs_fixup
)
1842 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1844 /* replace monster pointer with id */
1845 arg_save
.a_monst
= timer
->arg
.a_monst
;
1846 timer
->arg
= zeroany
;
1847 timer
->arg
.a_uint
= (arg_save
.a_monst
)->m_id
;
1848 timer
->needs_fixup
= 1;
1849 bwrite(fd
, (genericptr_t
) timer
, sizeof(timer_element
));
1850 timer
->arg
.a_monst
= arg_save
.a_monst
;
1851 timer
->needs_fixup
= 0;
1856 panic("write_timer");
1862 * Return TRUE if the object will stay on the level when the level is
1869 switch (obj
->where
) {
1877 return obj_is_local(obj
->ocontainer
);
1879 return mon_is_local(obj
->ocarry
);
1881 panic("obj_is_local");
1886 * Return TRUE if the given monster will stay on the level when the
1895 for (curr
= migrating_mons
; curr
; curr
= curr
->nmon
)
1898 /* `mydogs' is used during level changes, never saved and restored */
1899 for (curr
= mydogs
; curr
; curr
= curr
->nmon
)
1906 * Return TRUE if the timer is attached to something that will stay on the
1907 * level when the level is saved.
1910 timer_is_local(timer
)
1911 timer_element
*timer
;
1913 switch (timer
->kind
) {
1919 return obj_is_local(timer
->arg
.a_obj
);
1921 return mon_is_local(timer
->arg
.a_monst
);
1923 panic("timer_is_local");
1928 * Part of the save routine. Count up the number of timers that would
1929 * be written. If write_it is true, actually write the timer.
1932 maybe_write_timer(fd
, range
, write_it
)
1937 timer_element
*curr
;
1939 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
1940 if (range
== RANGE_GLOBAL
) {
1943 if (!timer_is_local(curr
)) {
1946 write_timer(fd
, curr
);
1952 if (timer_is_local(curr
)) {
1955 write_timer(fd
, curr
);
1964 * Save part of the timer list. The parameter 'range' specifies either
1965 * global or level timers to save. The timer ID is saved with the global
1969 * + timeouts that follow the hero (global)
1970 * + timeouts that follow obj & monst that are migrating
1973 * + timeouts that are level specific (e.g. storms)
1974 * + timeouts that stay with the level (obj & monst)
1977 save_timers(fd
, mode
, range
)
1978 int fd
, mode
, range
;
1980 timer_element
*curr
, *prev
, *next_timer
= 0;
1983 if (perform_bwrite(mode
)) {
1984 if (range
== RANGE_GLOBAL
)
1985 bwrite(fd
, (genericptr_t
) &timer_id
, sizeof(timer_id
));
1987 count
= maybe_write_timer(fd
, range
, FALSE
);
1988 bwrite(fd
, (genericptr_t
) &count
, sizeof count
);
1989 (void) maybe_write_timer(fd
, range
, TRUE
);
1992 if (release_data(mode
)) {
1993 for (prev
= 0, curr
= timer_base
; curr
; curr
= next_timer
) {
1994 next_timer
= curr
->next
; /* in case curr is removed */
1996 if (!(!!(range
== RANGE_LEVEL
) ^ !!timer_is_local(curr
))) {
1998 prev
->next
= curr
->next
;
2000 timer_base
= curr
->next
;
2001 free((genericptr_t
) curr
);
2002 /* prev stays the same */
2011 * Pull in the structures from disk, but don't recalculate the object and
2015 restore_timers(fd
, range
, ghostly
, adjust
)
2017 boolean ghostly
; /* restoring from a ghost level */
2018 long adjust
; /* how much to adjust timeout */
2021 timer_element
*curr
;
2023 if (range
== RANGE_GLOBAL
)
2024 mread(fd
, (genericptr_t
) &timer_id
, sizeof timer_id
);
2026 /* restore elements */
2027 mread(fd
, (genericptr_t
) &count
, sizeof count
);
2028 while (count
-- > 0) {
2029 curr
= (timer_element
*) alloc(sizeof(timer_element
));
2030 mread(fd
, (genericptr_t
) curr
, sizeof(timer_element
));
2032 curr
->timeout
+= adjust
;
2037 /* to support '#stats' wizard-mode command */
2039 timer_stats(hdrfmt
, hdrbuf
, count
, size
)
2046 Sprintf(hdrbuf
, hdrfmt
, (long) sizeof (timer_element
));
2047 *count
= *size
= 0L;
2048 for (te
= timer_base
; te
; te
= te
->next
) {
2050 *size
+= (long) sizeof *te
;
2054 /* reset all timers that are marked for reseting */
2056 relink_timers(ghostly
)
2059 timer_element
*curr
;
2062 for (curr
= timer_base
; curr
; curr
= curr
->next
) {
2063 if (curr
->needs_fixup
) {
2064 if (curr
->kind
== TIMER_OBJECT
) {
2066 if (!lookup_id_mapping(curr
->arg
.a_uint
, &nid
))
2067 panic("relink_timers 1");
2069 nid
= curr
->arg
.a_uint
;
2070 curr
->arg
.a_obj
= find_oid(nid
);
2071 if (!curr
->arg
.a_obj
)
2072 panic("cant find o_id %d", nid
);
2073 curr
->needs_fixup
= 0;
2074 } else if (curr
->kind
== TIMER_MONSTER
) {
2075 panic("relink_timers: no monster timer implemented");
2077 panic("relink_timers 2");