1 /* SCCS Id: @(#)timeout.c 3.4 2002/12/17 */
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, (genericptr_t,long));
19 /* He is being petrified - dialogue by inmet!tower */
20 static NEARDATA const char * const stoned_texts[] = {
21 "You are slowing down.", /* 5 */
22 "Your limbs are stiffening.", /* 4 */
23 "Your limbs have turned to stone.", /* 3 */
24 "You have turned to stone.", /* 2 */
25 "You are a statue." /* 1 */
31 register long i = (Stoned & TIMEOUT);
33 if (i > 0L && i <= SIZE(stoned_texts))
34 pline(stoned_texts[SIZE(stoned_texts) - i]);
39 exercise(A_DEX, FALSE);
42 /* He is getting sicker and sicker prior to vomiting */
43 static NEARDATA const char * const vomiting_texts[] = {
44 "are feeling mildly nauseated.", /* 14 */
45 "feel slightly confused.", /* 11 */
46 "can't seem to think straight.", /* 8 */
47 "feel incredibly sick.", /* 5 */
48 "suddenly vomit!" /* 2 */
54 register long i = (Vomiting & TIMEOUT) / 3L;
56 if ((((Vomiting & TIMEOUT) % 3L) == 2) && (i >= 0)
57 && (i < SIZE(vomiting_texts)))
58 You(vomiting_texts[SIZE(vomiting_texts) - i - 1]);
66 make_stunned(HStun + d(2,4), FALSE);
69 make_confused(HConfusion + d(2,4), FALSE);
72 exercise(A_CON, FALSE);
75 static NEARDATA const char * const choke_texts[] = {
76 "You find it hard to breathe.",
77 "You're gasping for air.",
78 "You can no longer breathe.",
83 static NEARDATA const char * const choke_texts2[] = {
84 "Your %s is becoming constricted.",
85 "Your blood is having trouble reaching your brain.",
86 "The pressure on your %s increases.",
87 "Your consciousness is fading.",
94 register long i = (Strangled & TIMEOUT);
96 if(i > 0 && i <= SIZE(choke_texts)) {
97 if (Breathless || !rn2(50))
98 pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
100 const char *str = choke_texts[SIZE(choke_texts)-i];
103 pline(str, hcolor(NH_BLUE));
108 exercise(A_STR, FALSE);
111 static NEARDATA const char * const slime_texts[] = {
112 "You are turning a little %s.", /* 5 */
113 "Your limbs are getting oozy.", /* 4 */
114 "Your skin begins to peel away.", /* 3 */
115 "You are turning into %s.", /* 2 */
116 "You have become %s." /* 1 */
122 register long i = (Slimed & TIMEOUT) / 2L;
124 if (((Slimed & TIMEOUT) % 2L) && i >= 0L
125 && i < SIZE(slime_texts)) {
126 const char *str = slime_texts[SIZE(slime_texts) - i - 1L];
128 if (index(str, '%')) {
129 if (i == 4L) { /* "you are turning green" */
130 if (!Blind) /* [what if you're already green?] */
131 pline(str, hcolor(NH_GREEN));
133 pline(str, an(Hallucination ? rndmonnam() : "green slime"));
137 if (i == 3L) { /* limbs becoming oozy */
138 HFast = 0L; /* lose intrinsic speed */
140 if (multi > 0) nomul(0);
142 exercise(A_DEX, FALSE);
149 pline_The("slime that covers you is burned away!");
163 register struct prop *upp;
166 int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
168 if (flags.friday13) baseluck -= 1;
170 if (u.uluck != baseluck &&
171 moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) {
172 /* Cursed luckstones stop bad luck from timing out; blessed luckstones
173 * stop good luck from timing out; normal luckstones stop both;
174 * neither is stopped if you don't have a luckstone.
175 * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th
177 register int time_luck = stone_luck(FALSE);
178 boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
180 if(u.uluck > baseluck && (nostone || time_luck < 0))
182 else if(u.uluck < baseluck && (nostone || time_luck > 0))
185 if(u.uinvulnerable) return; /* things past this point could kill you */
186 if(Stoned) stoned_dialogue();
187 if(Slimed) slime_dialogue();
188 if(Vomiting) vomiting_dialogue();
189 if(Strangled) choke_dialogue();
190 if(u.mtimedone && !--u.mtimedone) {
192 u.mtimedone = rnd(100*youmonst.data->mlevel + 1);
196 if(u.ucreamed) u.ucreamed--;
198 /* Dissipate spell-based protection. */
200 if (--u.usptime == 0 && u.uspellprot) {
201 u.usptime = u.uspmtime;
205 Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
206 u.uspellprot ? "becomes less dense" : "disappears");
212 if (--u.ugallop == 0L && u.usteed)
213 pline("%s stops galloping.", Monnam(u.usteed));
217 for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
218 if((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) {
219 switch(upp - u.uprops){
221 if (delayed_killer && !killer) {
222 killer = delayed_killer;
226 /* leaving killer_format would make it
227 "petrified by petrification" */
228 killer_format = NO_KILLER_PREFIX;
229 killer = "killed by petrification";
234 if (delayed_killer && !killer) {
235 killer = delayed_killer;
239 killer_format = NO_KILLER_PREFIX;
240 killer = "turned into green slime";
245 make_vomiting(0L, TRUE);
248 You("die from your illness.");
249 killer_format = KILLED_BY_AN;
250 killer = u.usick_cause;
251 if ((m_idx = name_to_mon(killer)) >= LOW_PM) {
252 if (type_is_pname(&mons[m_idx])) {
253 killer_format = KILLED_BY;
254 } else if (mons[m_idx].geno & G_UNIQ) {
255 killer = the(killer);
256 Strcpy(u.usick_cause, killer);
257 killer_format = KILLED_BY;
265 You_feel("yourself slowing down%s.",
266 Fast ? " a bit" : "");
269 HConfusion = 1; /* So make_confused works properly */
270 make_confused(0L, TRUE);
275 make_stunned(0L, TRUE);
280 make_blinded(0L, TRUE);
285 if (!Invis && !BInvis && !Blind) {
287 "are no longer invisible." :
288 "can no longer see through yourself.");
293 set_mimic_blocking(); /* do special mimic handling */
294 see_monsters(); /* make invis mons appear */
295 newsym(u.ux,u.uy); /* make self appear */
304 (void) make_hallucinated(0L, TRUE, 0L);
308 if (unconscious() || Sleep_resistance)
309 HSleeping += rnd(100);
313 fall_asleep(-sleeptime, TRUE);
314 HSleeping += sleeptime + rnd(100);
318 (void) float_down(I_SPECIAL|TIMEOUT, 0L);
321 killer_format = KILLED_BY;
322 killer = (u.uburied) ? "suffocation" : "strangulation";
326 /* call this only when a move took place. */
327 /* otherwise handle fumbling msgs locally. */
328 if (u.umoved && !Levitation) {
332 /* The more you are carrying the more likely you
333 * are to make noise when you fumble. Adjustments
334 * to this number must be thoroughly play tested.
336 if ((inv_weight() > -500)) {
337 You("make a lot of noise!");
341 /* from outside means slippery ice; don't reset
342 counter if that's the only fumble reason */
343 HFumbling &= ~FROMOUTSIDE;
345 HFumbling += rnd(20);
347 case DETECT_MONSTERS:
360 fall_asleep(how_long, wakeup_msg)
366 /* generally don't notice sounds while sleeping */
367 if (wakeup_msg && multi == how_long) {
368 /* caller can follow with a direct call to Hear_again() if
369 there's a need to override this when wakeup_msg is true */
371 afternmv = Hear_again; /* this won't give any messages */
373 /* early wakeup from combat won't be possible until next monster turn */
374 u.usleep = monstermoves;
375 nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again;
378 /* Attach an egg hatch timeout to the given egg. */
380 attach_egg_hatch_timeout(egg)
385 /* stop previous timer, if any */
386 (void) stop_timer(HATCH_EGG, (genericptr_t) egg);
389 * Decide if and when to hatch the egg. The old hatch_it() code tried
390 * once a turn from age 151 to 200 (inclusive), hatching if it rolled
391 * a number x, 1<=x<=age, where x>150. This yields a chance of
392 * hatching > 99.9993%. Mimic that here.
394 for (i = (MAX_EGG_HATCH_TIME-50)+1; i <= MAX_EGG_HATCH_TIME; i++)
397 (void) start_timer((long)i, TIMER_OBJECT,
398 HATCH_EGG, (genericptr_t)egg);
403 /* prevent an egg from ever hatching */
408 /* stop previous timer, if any */
409 (void) stop_timer(HATCH_EGG, (genericptr_t) egg);
412 /* timer callback routine: hatch the given egg */
414 hatch_egg(arg, timeout)
419 struct monst *mon, *mon2;
422 boolean yours, silent, knows_egg = FALSE;
423 boolean cansee_hatchspot = FALSE;
424 int i, mnum, hatchcount = 0;
426 egg = (struct obj *) arg;
427 /* sterilized while waiting */
428 if (egg->corpsenm == NON_PM) return;
430 mon = mon2 = (struct monst *)0;
431 mnum = big_to_little(egg->corpsenm);
432 /* The identity of one's father is learned, not innate */
433 yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2)));
434 silent = (timeout != monstermoves); /* hatched while away */
436 /* only can hatch when in INVENT, FLOOR, MINVENT */
437 if (get_obj_location(egg, &x, &y, 0)) {
438 hatchcount = rnd((int)egg->quan);
439 cansee_hatchspot = cansee(x, y) && !silent;
440 if (!(mons[mnum].geno & G_UNIQ) &&
441 !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) {
442 for (i = hatchcount; i > 0; i--) {
443 if (!enexto(&cc, x, y, &mons[mnum]) ||
444 !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT)))
446 /* tame if your own egg hatches while you're on the
447 same dungeon level, or any dragon egg which hatches
448 while it's in your inventory */
449 if ((yours && !silent) ||
450 (carried(egg) && mon->data->mlet == S_DRAGON)) {
451 if ((mon2 = tamedog(mon, (struct obj *)0)) != 0) {
453 if (carried(egg) && mon->data->mlet != S_DRAGON)
457 if (mvitals[mnum].mvflags & G_EXTINCT)
458 break; /* just made last one */
459 mon2 = mon; /* in case makemon() fails on 2nd egg */
461 if (!mon) mon = mon2;
463 egg->quan -= (long)hatchcount;
468 * We could possibly hatch while migrating, but the code isn't
471 else if (obj->where == OBJ_MIGRATING) {
473 We can do several things. The first ones that come to
476 + Create the hatched monster then place it on the migrating
477 mons list. This is tough because all makemon() is made
478 to place the monster as well. Makemon() also doesn't
479 lend itself well to splitting off a "not yet placed"
482 + Mark the egg as hatched, then place the monster when we
483 place the migrating objects.
485 + Or just kill any egg which gets sent to another level.
486 Falling is the usual reason such transportation occurs.
488 cansee_hatchspot = FALSE;
494 char monnambuf[BUFSZ], carriedby[BUFSZ];
495 boolean siblings = (hatchcount > 1), redraw = FALSE;
497 if (cansee_hatchspot) {
498 Sprintf(monnambuf, "%s%s",
499 siblings ? "some " : "",
501 makeplural(m_monnam(mon)) : an(m_monnam(mon)));
502 /* we don't learn the egg type here because learning
503 an egg type requires either seeing the egg hatch
504 or being familiar with the egg already,
505 as well as being able to see the resulting
506 monster, checked below
509 switch (egg->where) {
511 knows_egg = TRUE; /* true even if you are blind */
512 if (!cansee_hatchspot)
513 You_feel("%s %s from your pack!", something,
514 locomotion(mon->data, "drop"));
516 You("see %s %s out of your pack!",
517 monnambuf, locomotion(mon->data, "drop"));
519 pline("%s cries sound like \"%s%s\"",
520 siblings ? "Their" : "Its",
521 flags.female ? "mommy" : "daddy",
522 egg->spe ? "." : "?");
523 } else if (mon->data->mlet == S_DRAGON) {
524 verbalize("Gleep!"); /* Mything eggs :-) */
529 if (cansee_hatchspot) {
531 You("see %s hatch.", monnambuf);
532 redraw = TRUE; /* update egg's map location */
537 if (cansee_hatchspot) {
538 /* egg carring monster might be invisible */
539 if (canseemon(egg->ocarry)) {
540 Sprintf(carriedby, "%s pack",
541 s_suffix(a_monnam(egg->ocarry)));
544 else if (is_pool(mon->mx, mon->my))
545 Strcpy(carriedby, "empty water");
547 Strcpy(carriedby, "thin air");
548 You("see %s %s out of %s!", monnambuf,
549 locomotion(mon->data, "drop"), carriedby);
557 impossible("egg hatched where? (%d)", (int)egg->where);
561 if (cansee_hatchspot && knows_egg)
562 learn_egg_type(mnum);
565 /* still some eggs left */
566 attach_egg_hatch_timeout(egg);
568 /* replace ordinary egg timeout with a short one */
569 (void) stop_timer(HATCH_EGG, (genericptr_t)egg);
570 (void) start_timer((long)rnd(12), TIMER_OBJECT,
571 HATCH_EGG, (genericptr_t)egg);
573 } else if (carried(egg)) {
576 /* free egg here because we use it above */
577 obj_extract_self(egg);
578 obfree(egg, (struct obj *)0);
580 if (redraw) newsym(x, y);
584 /* Learn to recognize eggs of the given type. */
589 /* baby monsters hatch from grown-up eggs */
590 mnum = little_to_big(mnum);
591 mvitals[mnum].mvflags |= MV_KNOWS_EGG;
592 /* we might have just learned about other eggs being carried */
596 /* Attach a fig_transform timeout to the given figurine. */
598 attach_fig_transform_timeout(figurine)
599 struct obj *figurine;
603 /* stop previous timer, if any */
604 (void) stop_timer(FIG_TRANSFORM, (genericptr_t) figurine);
607 * Decide when to transform the figurine.
610 /* figurine will transform */
611 (void) start_timer((long)i, TIMER_OBJECT,
612 FIG_TRANSFORM, (genericptr_t)figurine);
615 /* give a fumble message */
619 struct obj *otmp = vobj_at(u.ux, u.uy);
620 const char *what, *pronoun;
622 boolean on_foot = TRUE;
624 if (u.usteed) on_foot = FALSE;
627 if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0;
629 if (otmp && on_foot) { /* trip over something in particular */
631 If there is only one item, it will have just been named
632 during the move, so refer to by via pronoun; otherwise,
633 if the top item has been or can be seen, refer to it by
634 name; if not, look for rocks to trip over; trip over
635 anonymous "something" if there aren't any rocks.
637 pronoun = otmp->quan == 1L ? "it" : Hallucination ? "they" : "them";
638 what = !otmp->nexthere ? pronoun :
639 (otmp->dknown || !Blind) ? doname(otmp) :
640 ((otmp = sobj_at(ROCK, u.ux, u.uy)) == 0 ? something :
641 (otmp->quan == 1L ? "a rock" : "some rocks"));
643 what = strcpy(buf, what);
644 buf[0] = highc(buf[0]);
645 pline("Egads! %s bite%s your %s!",
646 what, (!otmp || otmp->quan == 1L) ? "s" : "",
649 You("trip over %s.", what);
651 } else if (rn2(3) && is_ice(u.ux, u.uy)) {
652 pline("%s %s%s on the ice.",
654 u.usteed ? upstart(x_monnam(u.usteed,
655 u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
656 (char *)0, SUPPRESS_SADDLE, FALSE)) :
658 "You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
663 You("trip over your own %s.", Hallucination ?
664 "elbow" : makeplural(body_part(FOOT)));
667 You("slip %s.", Hallucination ?
668 "on a banana peel" : "and nearly fall");
682 Your("%s slip out of the stirrups.", makeplural(body_part(FOOT)));
685 You("let go of the reins.");
688 You("bang into the saddle-horn.");
691 You("slide to one side of the saddle.");
694 dismount_steed(DISMOUNT_FELL);
700 /* Print a lamp flicker message with tailer. */
702 see_lamp_flicker(obj, tailer)
706 switch (obj->where) {
709 pline("%s flickers%s.", Yname2(obj), tailer);
712 You("see %s flicker%s.", an(xname(obj)), tailer);
717 /* Print a dimming message for brass lanterns. */
723 switch (obj->where) {
725 Your("lantern is getting dim.");
727 pline("Batteries have not been invented yet.");
730 You("see a lantern getting dim.");
733 pline("%s lantern is getting dim.",
734 s_suffix(Monnam(obj->ocarry)));
740 * Timeout callback for for objects that are burning. E.g. lamps, candles.
741 * See begin_burn() for meanings of obj->age and obj->spe.
744 burn_object(arg, timeout)
748 struct obj *obj = (struct obj *) arg;
749 boolean canseeit, many, menorah, need_newsym;
753 menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
754 many = menorah ? obj->spe > 1 : obj->quan > 1L;
756 /* timeout while away */
757 if (timeout != monstermoves) {
758 long how_long = monstermoves - timeout;
760 if (how_long >= obj->age) {
762 end_burn(obj, FALSE);
765 obj->spe = 0; /* no more candles */
766 } else if (Is_candle(obj) || obj->otyp == POT_OIL) {
767 /* get rid of candles and burning oil potions */
768 obj_extract_self(obj);
769 obfree(obj, (struct obj *)0);
770 obj = (struct obj *) 0;
774 obj->age -= how_long;
775 begin_burn(obj, TRUE);
780 /* only interested in INVENT, FLOOR, and MINVENT */
781 if (get_obj_location(obj, &x, &y, 0)) {
782 canseeit = !Blind && cansee(x, y);
783 /* set up `whose[]' to be "Your" or "Fred's" or "The goblin's" */
784 (void) Shk_Your(whose, obj);
790 /* obj->age is the age remaining at this point. */
793 /* this should only be called when we run out */
795 switch (obj->where) {
798 pline("%s potion of oil has burnt away.",
802 You("see a burning potion of oil go out.");
807 end_burn(obj, FALSE); /* turn off light source */
808 obj_extract_self(obj);
809 obfree(obj, (struct obj *)0);
810 obj = (struct obj *) 0;
815 switch((int)obj->age) {
820 if (obj->otyp == BRASS_LANTERN)
821 lantern_message(obj);
823 see_lamp_flicker(obj,
824 obj->age == 50L ? " considerably" : "");
830 if (obj->otyp == BRASS_LANTERN)
831 lantern_message(obj);
833 switch (obj->where) {
836 pline("%s %s seems about to go out.",
840 You("see %s about to go out.",
849 /* even if blind you'll know if holding it */
850 if (canseeit || obj->where == OBJ_INVENT) {
851 switch (obj->where) {
854 if (obj->otyp == BRASS_LANTERN)
855 pline("%s lantern has run out of power.",
858 pline("%s %s has gone out.",
862 if (obj->otyp == BRASS_LANTERN)
863 You("see a lantern run out of power.");
865 You("see %s go out.",
870 end_burn(obj, FALSE);
875 * Someone added fuel to the lamp while it was
876 * lit. Just fall through and let begin burn
877 * handle the new age.
883 begin_burn(obj, TRUE);
887 case CANDELABRUM_OF_INVOCATION:
893 switch (obj->where) {
896 pline("%s %scandle%s getting short.",
898 menorah ? "candelabrum's " : "",
899 many ? "s are" : " is");
902 You("see %scandle%s getting short.",
903 menorah ? "a candelabrum's " :
904 many ? "some " : "a ",
912 switch (obj->where) {
916 "%s %scandle%s flame%s flicker%s low!",
918 menorah ? "candelabrum's " : "",
924 You("see %scandle%s flame%s flicker low!",
925 menorah ? "a candelabrum's " :
926 many ? "some " : "a ",
934 /* we know even if blind and in our inventory */
935 if (canseeit || obj->where == OBJ_INVENT) {
937 switch (obj->where) {
940 pline("%s candelabrum's flame%s.",
942 many ? "s die" : " dies");
945 You("see a candelabrum's flame%s die.",
950 switch (obj->where) {
953 pline("%s %s %s consumed!",
956 many ? "are" : "is");
960 You see some wax candles consumed!
961 You see a wax candle consumed!
963 You("see %s%s consumed!",
965 many ? xname(obj):an(xname(obj)));
971 pline(Hallucination ?
972 (many ? "They shriek!" :
975 (many ? "Their flames die." :
979 end_burn(obj, FALSE);
984 obj_extract_self(obj);
985 obfree(obj, (struct obj *)0);
986 obj = (struct obj *) 0;
992 * Someone added fuel (candles) to the menorah while
993 * it was lit. Just fall through and let begin burn
994 * handle the new age.
1000 begin_burn(obj, TRUE);
1005 impossible("burn_object: unexpeced obj %s", xname(obj));
1008 if (need_newsym) newsym(x, y);
1012 * Start a burn timeout on the given object. If not "already lit" then
1013 * create a light source for the vision system. There had better not
1014 * be a burn already running on the object.
1016 * Magic lamps stay lit as long as there's a genie inside, so don't start
1020 * potions of oil, lamps & candles:
1021 * age = # of turns of fuel left
1026 * spe = 0 not lightable, 1 lightable forever
1029 * age = # of turns of fuel left
1030 * spe = # of candles
1032 * Once the burn begins, the age will be set to the amount of fuel
1033 * remaining _once_the_burn_finishes_. If the burn is terminated
1034 * early then fuel is added back.
1036 * This use of age differs from the use of age for corpses and eggs.
1037 * For the latter items, age is when the object was created, so we
1038 * know when it becomes "bad".
1040 * This is a "silent" routine - it should not print anything out.
1043 begin_burn(obj, already_lit)
1045 boolean already_lit;
1049 boolean do_timer = TRUE;
1051 if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1054 switch (obj->otyp) {
1062 radius = 1; /* very dim light */
1067 /* magic times are 150, 100, 50, 25, and 0 */
1068 if (obj->age > 150L)
1069 turns = obj->age - 150L;
1070 else if (obj->age > 100L)
1071 turns = obj->age - 100L;
1072 else if (obj->age > 50L)
1073 turns = obj->age - 50L;
1074 else if (obj->age > 25L)
1075 turns = obj->age - 25L;
1080 case CANDELABRUM_OF_INVOCATION:
1083 /* magic times are 75, 15, and 0 */
1085 turns = obj->age - 75L;
1086 else if (obj->age > 15L)
1087 turns = obj->age - 15L;
1090 radius = candle_light_range(obj);
1094 /* [ALI] Support artifact light sources */
1095 if (artifact_light(obj)) {
1100 impossible("begin burn: unexpected %s", xname(obj));
1107 if (start_timer(turns, TIMER_OBJECT,
1108 BURN_OBJECT, (genericptr_t)obj)) {
1111 if (carried(obj) && !already_lit)
1117 if (carried(obj) && !already_lit)
1121 if (obj->lamplit && !already_lit) {
1124 if (get_obj_location(obj, &x, &y, CONTAINED_TOO|BURIED_TOO))
1125 new_light_source(x, y, radius, LS_OBJECT, (genericptr_t) obj);
1127 impossible("begin_burn: can't get obj position");
1132 * Stop a burn timeout on the given object if timer attached. Darken
1136 end_burn(obj, timer_attached)
1138 boolean timer_attached;
1140 if (!obj->lamplit) {
1141 impossible("end_burn: obj %s not lit", xname(obj));
1145 if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1146 timer_attached = FALSE;
1148 if (!timer_attached) {
1149 /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1150 del_light_source(LS_OBJECT, (genericptr_t)obj);
1152 if (obj->where == OBJ_INVENT)
1154 } else if (!stop_timer(BURN_OBJECT, (genericptr_t) obj))
1155 impossible("end_burn: obj %s not timed!", xname(obj));
1162 * Cleanup a burning object if timer stopped.
1165 cleanup_burn(arg, expire_time)
1169 struct obj *obj = (struct obj *)arg;
1170 if (!obj->lamplit) {
1171 impossible("cleanup_burn: obj %s not lit", xname(obj));
1175 del_light_source(LS_OBJECT, arg);
1177 /* restore unused time */
1178 obj->age += expire_time - monstermoves;
1182 if (obj->where == OBJ_INVENT)
1197 /* no lightning if not the air level or too often, even then */
1198 if(!Is_airlevel(&u.uz) || rn2(8))
1201 /* the number of strikes is 8-log2(nstrike) */
1202 for(nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1207 } while (++count < 100 && levl[x][y].typ != CLOUD);
1212 if(dirx != 0 || diry != 0)
1213 buzz(-15, /* "monster" LIGHTNING spell */
1214 8, x, y, dirx, diry);
1218 if(levl[u.ux][u.uy].typ == CLOUD) {
1219 /* inside a cloud during a thunder storm is deafening */
1220 pline("Kaboom!!! Boom!! Boom!!");
1221 if(!u.uinvulnerable) {
1226 You_hear("a rumbling noise.");
1232 /* ------------------------------------------------------------------------- */
1234 * Generic Timeout Functions.
1239 * boolean start_timer(long timeout,short kind,short func_index,
1241 * Start a timer of kind 'kind' that will expire at time
1242 * monstermoves+'timeout'. Call the function at 'func_index'
1243 * in the timeout table using argument 'arg'. Return TRUE if
1244 * a timer was started. This places the timer on a list ordered
1245 * "sooner" to "later". If an object, increment the object's
1248 * long stop_timer(short func_index, genericptr_t arg)
1249 * Stop a timer specified by the (func_index, arg) pair. This
1250 * assumes that such a pair is unique. Return the time the
1251 * timer would have gone off. If no timer is found, return 0.
1252 * If an object, decrement the object's timer count.
1254 * void run_timers(void)
1255 * Call timers that have timed out.
1259 * void save_timers(int fd, int mode, int range)
1260 * Save all timers of range 'range'. Range is either global
1261 * or local. Global timers follow game play, local timers
1262 * are saved with a level. Object and monster timers are
1263 * saved using their respective id's instead of pointers.
1265 * void restore_timers(int fd, int range, boolean ghostly, long adjust)
1266 * Restore timers of range 'range'. If from a ghost pile,
1267 * adjust the timeout by 'adjust'. The object and monster
1268 * ids are not restored until later.
1270 * void relink_timers(boolean ghostly)
1271 * Relink all object and monster timers that had been saved
1272 * using their object's or monster's id number.
1275 * void obj_move_timers(struct obj *src, struct obj *dest)
1276 * Reassign all timers from src to dest.
1278 * void obj_split_timers(struct obj *src, struct obj *dest)
1279 * Duplicate all timers assigned to src and attach them to dest.
1281 * void obj_stop_timers(struct obj *obj)
1282 * Stop all timers attached to obj.
1286 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1287 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1289 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1290 STATIC_DCL timer_element *FDECL(remove_timer, (timer_element **, SHORT_P,
1292 STATIC_DCL void FDECL(write_timer, (int, timer_element *));
1293 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
1294 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
1295 STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
1297 /* ordered timer list */
1298 static timer_element *timer_base; /* "active" */
1299 static unsigned long timer_id = 1;
1301 /* If defined, then include names when printing out the timer queue */
1302 #define VERBOSE_TIMER
1305 timeout_proc f, cleanup;
1306 #ifdef VERBOSE_TIMER
1308 # define TTAB(a, b, c) {a,b,c}
1310 # define TTAB(a, b, c) {a,b}
1314 /* table of timeout functions */
1315 static const ttable timeout_funcs[NUM_TIME_FUNCS] = {
1316 TTAB(rot_organic, (timeout_proc)0, "rot_organic"),
1317 TTAB(rot_corpse, (timeout_proc)0, "rot_corpse"),
1318 TTAB(revive_mon, (timeout_proc)0, "revive_mon"),
1319 TTAB(burn_object, cleanup_burn, "burn_object"),
1320 TTAB(hatch_egg, (timeout_proc)0, "hatch_egg"),
1321 TTAB(fig_transform, (timeout_proc)0, "fig_transform")
1328 STATIC_OVL const char *
1333 case TIMER_LEVEL: return "level";
1334 case TIMER_GLOBAL: return "global";
1335 case TIMER_OBJECT: return "object";
1336 case TIMER_MONSTER: return "monster";
1342 print_queue(win, base)
1344 timer_element *base;
1346 timer_element *curr;
1347 char buf[BUFSZ], arg_address[20];
1350 putstr(win, 0, "<empty>");
1352 putstr(win, 0, "timeout id kind call");
1353 for (curr = base; curr; curr = curr->next) {
1354 #ifdef VERBOSE_TIMER
1355 Sprintf(buf, " %4ld %4ld %-6s %s(%s)",
1356 curr->timeout, curr->tid, kind_name(curr->kind),
1357 timeout_funcs[curr->func_index].name,
1358 fmt_ptr((genericptr_t)curr->arg, arg_address));
1360 Sprintf(buf, " %4ld %4ld %-6s #%d(%s)",
1361 curr->timeout, curr->tid, kind_name(curr->kind),
1363 fmt_ptr((genericptr_t)curr->arg, arg_address));
1365 putstr(win, 0, buf);
1376 win = create_nhwindow(NHW_MENU); /* corner text window */
1377 if (win == WIN_ERR) return 0;
1379 Sprintf(buf, "Current time = %ld.", monstermoves);
1380 putstr(win, 0, buf);
1382 putstr(win, 0, "Active timeout queue:");
1384 print_queue(win, timer_base);
1386 display_nhwindow(win, FALSE);
1387 destroy_nhwindow(win);
1393 timer_sanity_check()
1395 timer_element *curr;
1396 char obj_address[20];
1398 /* this should be much more complete */
1399 for (curr = timer_base; curr; curr = curr->next)
1400 if (curr->kind == TIMER_OBJECT) {
1401 struct obj *obj = (struct obj *) curr->arg;
1402 if (obj->timed == 0) {
1403 pline("timer sanity: untimed obj %s, timer %ld",
1404 fmt_ptr((genericptr_t)obj, obj_address), curr->tid);
1413 * Pick off timeout elements from the global queue and call their functions.
1414 * Do this until their time is less than or equal to the move count.
1419 timer_element *curr;
1422 * Always use the first element. Elements may be added or deleted at
1423 * any time. The list is ordered, we are done when the first element
1426 while (timer_base && timer_base->timeout <= monstermoves) {
1428 timer_base = curr->next;
1430 if (curr->kind == TIMER_OBJECT) ((struct obj *)(curr->arg))->timed--;
1431 (*timeout_funcs[curr->func_index].f)(curr->arg, curr->timeout);
1432 free((genericptr_t) curr);
1438 * Start a timer. Return TRUE if successful.
1441 start_timer(when, kind, func_index, arg)
1449 if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1450 panic("start_timer");
1452 gnu = (timer_element *) alloc(sizeof(timer_element));
1454 gnu->tid = timer_id++;
1455 gnu->timeout = monstermoves + when;
1457 gnu->needs_fixup = 0;
1458 gnu->func_index = func_index;
1462 if (kind == TIMER_OBJECT) /* increment object's timed count */
1463 ((struct obj *)arg)->timed++;
1465 /* should check for duplicates and fail if any */
1471 * Remove the timer from the current list and free it up. Return the time
1472 * it would have gone off, 0 if not found.
1475 stop_timer(func_index, arg)
1479 timer_element *doomed;
1482 doomed = remove_timer(&timer_base, func_index, arg);
1485 timeout = doomed->timeout;
1486 if (doomed->kind == TIMER_OBJECT)
1487 ((struct obj *)arg)->timed--;
1488 if (timeout_funcs[doomed->func_index].cleanup)
1489 (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout);
1490 free((genericptr_t) doomed);
1498 * Move all object timers from src to dest, leaving src untimed.
1501 obj_move_timers(src, dest)
1502 struct obj *src, *dest;
1505 timer_element *curr;
1507 for (count = 0, curr = timer_base; curr; curr = curr->next)
1508 if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) {
1509 curr->arg = (genericptr_t) dest;
1513 if (count != src->timed)
1514 panic("obj_move_timers");
1520 * Find all object timers and duplicate them for the new object "dest".
1523 obj_split_timers(src, dest)
1524 struct obj *src, *dest;
1526 timer_element *curr, *next_timer=0;
1528 for (curr = timer_base; curr; curr = next_timer) {
1529 next_timer = curr->next; /* things may be inserted */
1530 if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) {
1531 (void) start_timer(curr->timeout-monstermoves, TIMER_OBJECT,
1532 curr->func_index, (genericptr_t)dest);
1539 * Stop all timers attached to this object. We can get away with this because
1540 * all object pointers are unique.
1543 obj_stop_timers(obj)
1546 timer_element *curr, *prev, *next_timer=0;
1548 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1549 next_timer = curr->next;
1550 if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)obj) {
1552 prev->next = curr->next;
1554 timer_base = curr->next;
1555 if (timeout_funcs[curr->func_index].cleanup)
1556 (*timeout_funcs[curr->func_index].cleanup)(curr->arg,
1558 free((genericptr_t) curr);
1567 /* Insert timer into the global queue */
1572 timer_element *curr, *prev;
1574 for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
1575 if (curr->timeout >= gnu->timeout) break;
1585 STATIC_OVL timer_element *
1586 remove_timer(base, func_index, arg)
1587 timer_element **base;
1591 timer_element *prev, *curr;
1593 for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
1594 if (curr->func_index == func_index && curr->arg == arg) break;
1598 prev->next = curr->next;
1608 write_timer(fd, timer)
1610 timer_element *timer;
1612 genericptr_t arg_save;
1614 switch (timer->kind) {
1617 /* assume no pointers in arg */
1618 bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
1622 if (timer->needs_fixup)
1623 bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1625 /* replace object pointer with id */
1626 arg_save = timer->arg;
1627 timer->arg = (genericptr_t)((struct obj *)timer->arg)->o_id;
1628 timer->needs_fixup = 1;
1629 bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1630 timer->arg = arg_save;
1631 timer->needs_fixup = 0;
1636 if (timer->needs_fixup)
1637 bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1639 /* replace monster pointer with id */
1640 arg_save = timer->arg;
1641 timer->arg = (genericptr_t)((struct monst *)timer->arg)->m_id;
1642 timer->needs_fixup = 1;
1643 bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1644 timer->arg = arg_save;
1645 timer->needs_fixup = 0;
1650 panic("write_timer");
1657 * Return TRUE if the object will stay on the level when the level is
1664 switch (obj->where) {
1666 case OBJ_MIGRATING: return FALSE;
1668 case OBJ_BURIED: return TRUE;
1669 case OBJ_CONTAINED: return obj_is_local(obj->ocontainer);
1670 case OBJ_MINVENT: return mon_is_local(obj->ocarry);
1672 panic("obj_is_local");
1678 * Return TRUE if the given monster will stay on the level when the
1687 for (curr = migrating_mons; curr; curr = curr->nmon)
1688 if (curr == mon) return FALSE;
1689 /* `mydogs' is used during level changes, never saved and restored */
1690 for (curr = mydogs; curr; curr = curr->nmon)
1691 if (curr == mon) return FALSE;
1697 * Return TRUE if the timer is attached to something that will stay on the
1698 * level when the level is saved.
1701 timer_is_local(timer)
1702 timer_element *timer;
1704 switch (timer->kind) {
1705 case TIMER_LEVEL: return TRUE;
1706 case TIMER_GLOBAL: return FALSE;
1707 case TIMER_OBJECT: return obj_is_local((struct obj *)timer->arg);
1708 case TIMER_MONSTER: return mon_is_local((struct monst *)timer->arg);
1710 panic("timer_is_local");
1716 * Part of the save routine. Count up the number of timers that would
1717 * be written. If write_it is true, actually write the timer.
1720 maybe_write_timer(fd, range, write_it)
1725 timer_element *curr;
1727 for (curr = timer_base; curr; curr = curr->next) {
1728 if (range == RANGE_GLOBAL) {
1731 if (!timer_is_local(curr)) {
1733 if (write_it) write_timer(fd, curr);
1739 if (timer_is_local(curr)) {
1741 if (write_it) write_timer(fd, curr);
1752 * Save part of the timer list. The parameter 'range' specifies either
1753 * global or level timers to save. The timer ID is saved with the global
1757 * + timeouts that follow the hero (global)
1758 * + timeouts that follow obj & monst that are migrating
1761 * + timeouts that are level specific (e.g. storms)
1762 * + timeouts that stay with the level (obj & monst)
1765 save_timers(fd, mode, range)
1766 int fd, mode, range;
1768 timer_element *curr, *prev, *next_timer=0;
1771 if (perform_bwrite(mode)) {
1772 if (range == RANGE_GLOBAL)
1773 bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
1775 count = maybe_write_timer(fd, range, FALSE);
1776 bwrite(fd, (genericptr_t) &count, sizeof count);
1777 (void) maybe_write_timer(fd, range, TRUE);
1780 if (release_data(mode)) {
1781 for (prev = 0, curr = timer_base; curr; curr = next_timer) {
1782 next_timer = curr->next; /* in case curr is removed */
1784 if ( !(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr)) ) {
1786 prev->next = curr->next;
1788 timer_base = curr->next;
1789 free((genericptr_t) curr);
1790 /* prev stays the same */
1800 * Pull in the structures from disk, but don't recalculate the object and
1804 restore_timers(fd, range, ghostly, adjust)
1806 boolean ghostly; /* restoring from a ghost level */
1807 long adjust; /* how much to adjust timeout */
1810 timer_element *curr;
1812 if (range == RANGE_GLOBAL)
1813 mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
1815 /* restore elements */
1816 mread(fd, (genericptr_t) &count, sizeof count);
1817 while (count-- > 0) {
1818 curr = (timer_element *) alloc(sizeof(timer_element));
1819 mread(fd, (genericptr_t) curr, sizeof(timer_element));
1821 curr->timeout += adjust;
1827 /* reset all timers that are marked for reseting */
1829 relink_timers(ghostly)
1832 timer_element *curr;
1835 for (curr = timer_base; curr; curr = curr->next) {
1836 if (curr->needs_fixup) {
1837 if (curr->kind == TIMER_OBJECT) {
1839 if (!lookup_id_mapping((unsigned)curr->arg, &nid))
1840 panic("relink_timers 1");
1842 nid = (unsigned) curr->arg;
1843 curr->arg = (genericptr_t) find_oid(nid);
1844 if (!curr->arg) panic("cant find o_id %d", nid);
1845 curr->needs_fixup = 0;
1846 } else if (curr->kind == TIMER_MONSTER) {
1847 panic("relink_timers: no monster timer implemented");
1849 panic("relink_timers 2");