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. */
4 
5 #include "hack.h"
6 #include "lev.h"	/* for checking save modes */
7 
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));
16 
17 #ifdef OVLB
18 
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 */
26 };
27 
28 STATIC_OVL void
stoned_dialogue()29 stoned_dialogue()
30 {
31 	register long i = (Stoned & TIMEOUT);
32 
33 	if (i > 0L && i <= SIZE(stoned_texts))
34 		pline(stoned_texts[SIZE(stoned_texts) - i]);
35 	if (i == 5L)
36 		HFast = 0L;
37 	if (i == 3L)
38 		nomul(-3);
39 	exercise(A_DEX, FALSE);
40 }
41 
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 */
49 };
50 
51 STATIC_OVL void
vomiting_dialogue()52 vomiting_dialogue()
53 {
54 	register long i = (Vomiting & TIMEOUT) / 3L;
55 
56 	if ((((Vomiting & TIMEOUT) % 3L) == 2) && (i >= 0)
57 	    && (i < SIZE(vomiting_texts)))
58 		You(vomiting_texts[SIZE(vomiting_texts) - i - 1]);
59 
60 	switch ((int) i) {
61 	case 0:
62 		vomit();
63 		morehungry(20);
64 		break;
65 	case 2:
66 		make_stunned(HStun + d(2,4), FALSE);
67 		/* fall through */
68 	case 3:
69 		make_confused(HConfusion + d(2,4), FALSE);
70 		break;
71 	}
72 	exercise(A_CON, FALSE);
73 }
74 
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.",
79 	"You're turning %s.",
80 	"You suffocate."
81 };
82 
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.",
88 	"You suffocate."
89 };
90 
91 STATIC_OVL void
choke_dialogue()92 choke_dialogue()
93 {
94 	register long i = (Strangled & TIMEOUT);
95 
96 	if(i > 0 && i <= SIZE(choke_texts)) {
97 	    if (Breathless || !rn2(50))
98 		pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK));
99 	    else {
100 		const char *str = choke_texts[SIZE(choke_texts)-i];
101 
102 		if (index(str, '%'))
103 		    pline(str, hcolor(NH_BLUE));
104 		else
105 		    pline(str);
106 	    }
107 	}
108 	exercise(A_STR, FALSE);
109 }
110 
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 */
117 };
118 
119 STATIC_OVL void
slime_dialogue()120 slime_dialogue()
121 {
122 	register long i = (Slimed & TIMEOUT) / 2L;
123 
124 	if (((Slimed & TIMEOUT) % 2L) && i >= 0L
125 		&& i < SIZE(slime_texts)) {
126 	    const char *str = slime_texts[SIZE(slime_texts) - i - 1L];
127 
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));
132 		} else
133 		    pline(str, an(Hallucination ? rndmonnam() : "green slime"));
134 	    } else
135 		pline(str);
136 	}
137 	if (i == 3L) {	/* limbs becoming oozy */
138 	    HFast = 0L;	/* lose intrinsic speed */
139 	    stop_occupation();
140 	    if (multi > 0) nomul(0);
141 	}
142 	exercise(A_DEX, FALSE);
143 }
144 
145 void
burn_away_slime()146 burn_away_slime()
147 {
148 	if (Slimed) {
149 	    pline_The("slime that covers you is burned away!");
150 	    Slimed = 0L;
151 	    flags.botl = 1;
152 	}
153 	return;
154 }
155 
156 
157 #endif /* OVLB */
158 #ifdef OVL0
159 
160 void
nh_timeout()161 nh_timeout()
162 {
163 	register struct prop *upp;
164 	int sleeptime;
165 	int m_idx;
166 	int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0;
167 
168 	if (flags.friday13) baseluck -= 1;
169 
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
176 	 */
177 	    register int time_luck = stone_luck(FALSE);
178 	    boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE);
179 
180 	    if(u.uluck > baseluck && (nostone || time_luck < 0))
181 		u.uluck--;
182 	    else if(u.uluck < baseluck && (nostone || time_luck > 0))
183 		u.uluck++;
184 	}
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) {
191 		if (Unchanging)
192 			u.mtimedone = rnd(100*youmonst.data->mlevel + 1);
193 		else
194 			rehumanize();
195 	}
196 	if(u.ucreamed) u.ucreamed--;
197 
198 	/* Dissipate spell-based protection. */
199 	if (u.usptime) {
200 	    if (--u.usptime == 0 && u.uspellprot) {
201 		u.usptime = u.uspmtime;
202 		u.uspellprot--;
203 		find_ac();
204 		if (!Blind)
205 		    Norep("The %s haze around you %s.", hcolor(NH_GOLDEN),
206 			  u.uspellprot ? "becomes less dense" : "disappears");
207 	    }
208 	}
209 
210 #ifdef STEED
211 	if (u.ugallop) {
212 	    if (--u.ugallop == 0L && u.usteed)
213 	    	pline("%s stops galloping.", Monnam(u.usteed));
214 	}
215 #endif
216 
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){
220 		case STONED:
221 			if (delayed_killer && !killer) {
222 				killer = delayed_killer;
223 				delayed_killer = 0;
224 			}
225 			if (!killer) {
226 				/* leaving killer_format would make it
227 				   "petrified by petrification" */
228 				killer_format = NO_KILLER_PREFIX;
229 				killer = "killed by petrification";
230 			}
231 			done(STONING);
232 			break;
233 		case SLIMED:
234 			if (delayed_killer && !killer) {
235 				killer = delayed_killer;
236 				delayed_killer = 0;
237 			}
238 			if (!killer) {
239 				killer_format = NO_KILLER_PREFIX;
240 				killer = "turned into green slime";
241 			}
242 			done(TURNED_SLIME);
243 			break;
244 		case VOMITING:
245 			make_vomiting(0L, TRUE);
246 			break;
247 		case SICK:
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;
258 			    }
259 			}
260 			u.usick_type = 0;
261 			done(POISONING);
262 			break;
263 		case FAST:
264 			if (!Very_fast)
265 				You_feel("yourself slowing down%s.",
266 							Fast ? " a bit" : "");
267 			break;
268 		case CONFUSION:
269 			HConfusion = 1; /* So make_confused works properly */
270 			make_confused(0L, TRUE);
271 			stop_occupation();
272 			break;
273 		case STUNNED:
274 			HStun = 1;
275 			make_stunned(0L, TRUE);
276 			stop_occupation();
277 			break;
278 		case BLINDED:
279 			Blinded = 1;
280 			make_blinded(0L, TRUE);
281 			stop_occupation();
282 			break;
283 		case INVIS:
284 			newsym(u.ux,u.uy);
285 			if (!Invis && !BInvis && !Blind) {
286 			    You(!See_invisible ?
287 				    "are no longer invisible." :
288 				    "can no longer see through yourself.");
289 			    stop_occupation();
290 			}
291 			break;
292 		case SEE_INVIS:
293 			set_mimic_blocking(); /* do special mimic handling */
294 			see_monsters();		/* make invis mons appear */
295 			newsym(u.ux,u.uy);	/* make self appear */
296 			stop_occupation();
297 			break;
298 		case WOUNDED_LEGS:
299 			heal_legs();
300 			stop_occupation();
301 			break;
302 		case HALLUC:
303 			HHallucination = 1;
304 			(void) make_hallucinated(0L, TRUE, 0L);
305 			stop_occupation();
306 			break;
307 		case SLEEPING:
308 			if (unconscious() || Sleep_resistance)
309 				HSleeping += rnd(100);
310 			else if (Sleeping) {
311 				You("fall asleep.");
312 				sleeptime = rnd(20);
313 				fall_asleep(-sleeptime, TRUE);
314 				HSleeping += sleeptime + rnd(100);
315 			}
316 			break;
317 		case LEVITATION:
318 			(void) float_down(I_SPECIAL|TIMEOUT, 0L);
319 			break;
320 		case STRANGLED:
321 			killer_format = KILLED_BY;
322 			killer = (u.uburied) ? "suffocation" : "strangulation";
323 			done(DIED);
324 			break;
325 		case FUMBLING:
326 			/* call this only when a move took place.  */
327 			/* otherwise handle fumbling msgs locally. */
328 			if (u.umoved && !Levitation) {
329 			    slip_or_trip();
330 			    nomul(-2);
331 			    nomovemsg = "";
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.
335 			     */
336 			    if ((inv_weight() > -500)) {
337 				You("make a lot of noise!");
338 				wake_nearby();
339 			    }
340 			}
341 			/* from outside means slippery ice; don't reset
342 			   counter if that's the only fumble reason */
343 			HFumbling &= ~FROMOUTSIDE;
344 			if (Fumbling)
345 			    HFumbling += rnd(20);
346 			break;
347 		case DETECT_MONSTERS:
348 			see_monsters();
349 			break;
350 		}
351 	}
352 
353 	run_timers();
354 }
355 
356 #endif /* OVL0 */
357 #ifdef OVL1
358 
359 void
fall_asleep(how_long,wakeup_msg)360 fall_asleep(how_long, wakeup_msg)
361 int how_long;
362 boolean wakeup_msg;
363 {
364 	stop_occupation();
365 	nomul(how_long);
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 */
370 	    flags.soundok = 0;
371 	    afternmv = Hear_again;	/* this won't give any messages */
372 	}
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;
376 }
377 
378 /* Attach an egg hatch timeout to the given egg. */
379 void
attach_egg_hatch_timeout(egg)380 attach_egg_hatch_timeout(egg)
381 struct obj *egg;
382 {
383 	int i;
384 
385 	/* stop previous timer, if any */
386 	(void) stop_timer(HATCH_EGG, (genericptr_t) egg);
387 
388 	/*
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.
393 	 */
394 	for (i = (MAX_EGG_HATCH_TIME-50)+1; i <= MAX_EGG_HATCH_TIME; i++)
395 	    if (rnd(i) > 150) {
396 		/* egg will hatch */
397 		(void) start_timer((long)i, TIMER_OBJECT,
398 						HATCH_EGG, (genericptr_t)egg);
399 		break;
400 	    }
401 }
402 
403 /* prevent an egg from ever hatching */
404 void
kill_egg(egg)405 kill_egg(egg)
406 struct obj *egg;
407 {
408 	/* stop previous timer, if any */
409 	(void) stop_timer(HATCH_EGG, (genericptr_t) egg);
410 }
411 
412 /* timer callback routine: hatch the given egg */
413 void
hatch_egg(arg,timeout)414 hatch_egg(arg, timeout)
415 genericptr_t arg;
416 long timeout;
417 {
418 	struct obj *egg;
419 	struct monst *mon, *mon2;
420 	coord cc;
421 	xchar x, y;
422 	boolean yours, silent, knows_egg = FALSE;
423 	boolean cansee_hatchspot = FALSE;
424 	int i, mnum, hatchcount = 0;
425 
426 	egg = (struct obj *) arg;
427 	/* sterilized while waiting */
428 	if (egg->corpsenm == NON_PM) return;
429 
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 */
435 
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)))
445 			break;
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) {
452 			    mon = mon2;
453 			    if (carried(egg) && mon->data->mlet != S_DRAGON)
454 				mon->mtame = 20;
455 			}
456 		    }
457 		    if (mvitals[mnum].mvflags & G_EXTINCT)
458 			break;	/* just made last one */
459 		    mon2 = mon;	/* in case makemon() fails on 2nd egg */
460 		}
461 		if (!mon) mon = mon2;
462 		hatchcount -= i;
463 		egg->quan -= (long)hatchcount;
464 	    }
465 	}
466 #if 0
467 	/*
468 	 * We could possibly hatch while migrating, but the code isn't
469 	 * set up for it...
470 	 */
471 	else if (obj->where == OBJ_MIGRATING) {
472 	    /*
473 	    We can do several things.  The first ones that come to
474 	    mind are:
475 
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"
480 	      subroutine.
481 
482 	    + Mark the egg as hatched, then place the monster when we
483 	      place the migrating objects.
484 
485 	    + Or just kill any egg which gets sent to another level.
486 	      Falling is the usual reason such transportation occurs.
487 	    */
488 	    cansee_hatchspot = FALSE;
489 	    mon = ???
490 	    }
491 #endif
492 
493 	if (mon) {
494 	    char monnambuf[BUFSZ], carriedby[BUFSZ];
495 	    boolean siblings = (hatchcount > 1), redraw = FALSE;
496 
497 	    if (cansee_hatchspot) {
498 		Sprintf(monnambuf, "%s%s",
499 			siblings ? "some " : "",
500 			siblings ?
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
507 		*/
508 	    }
509 	    switch (egg->where) {
510 		case OBJ_INVENT:
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"));
515 		    else
516 			You("see %s %s out of your pack!",
517 			    monnambuf, locomotion(mon->data, "drop"));
518 		    if (yours) {
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 :-) */
525 		    }
526 		    break;
527 
528 		case OBJ_FLOOR:
529 		    if (cansee_hatchspot) {
530 			knows_egg = TRUE;
531 			You("see %s hatch.", monnambuf);
532 			redraw = TRUE;	/* update egg's map location */
533 		    }
534 		    break;
535 
536 		case OBJ_MINVENT:
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)));
542 			    knows_egg = TRUE;
543 			}
544 			else if (is_pool(mon->mx, mon->my))
545 			    Strcpy(carriedby, "empty water");
546 			else
547 			    Strcpy(carriedby, "thin air");
548 			You("see %s %s out of %s!", monnambuf,
549 			    locomotion(mon->data, "drop"), carriedby);
550 		    }
551 		    break;
552 #if 0
553 		case OBJ_MIGRATING:
554 		    break;
555 #endif
556 		default:
557 		    impossible("egg hatched where? (%d)", (int)egg->where);
558 		    break;
559 	    }
560 
561 	    if (cansee_hatchspot && knows_egg)
562 		learn_egg_type(mnum);
563 
564 	    if (egg->quan > 0) {
565 		/* still some eggs left */
566 		attach_egg_hatch_timeout(egg);
567 		if (egg->timed) {
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);
572 		}
573 	    } else if (carried(egg)) {
574 		useup(egg);
575 	    } else {
576 		/* free egg here because we use it above */
577 		obj_extract_self(egg);
578 		obfree(egg, (struct obj *)0);
579 	    }
580 	    if (redraw) newsym(x, y);
581 	}
582 }
583 
584 /* Learn to recognize eggs of the given type. */
585 void
learn_egg_type(mnum)586 learn_egg_type(mnum)
587 int mnum;
588 {
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 */
593 	update_inventory();
594 }
595 
596 /* Attach a fig_transform timeout to the given figurine. */
597 void
attach_fig_transform_timeout(figurine)598 attach_fig_transform_timeout(figurine)
599 struct obj *figurine;
600 {
601 	int i;
602 
603 	/* stop previous timer, if any */
604 	(void) stop_timer(FIG_TRANSFORM, (genericptr_t) figurine);
605 
606 	/*
607 	 * Decide when to transform the figurine.
608 	 */
609 	i = rnd(9000) + 200;
610 	/* figurine will transform */
611 	(void) start_timer((long)i, TIMER_OBJECT,
612 				FIG_TRANSFORM, (genericptr_t)figurine);
613 }
614 
615 /* give a fumble message */
616 STATIC_OVL void
slip_or_trip()617 slip_or_trip()
618 {
619 	struct obj *otmp = vobj_at(u.ux, u.uy);
620 	const char *what, *pronoun;
621 	char buf[BUFSZ];
622 	boolean on_foot = TRUE;
623 #ifdef STEED
624 	if (u.usteed) on_foot = FALSE;
625 #endif
626 
627 	if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0;
628 
629 	if (otmp && on_foot) {		/* trip over something in particular */
630 	    /*
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.
636 	     */
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"));
642 	    if (Hallucination) {
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" : "",
647 			body_part(FOOT));
648 	    } else {
649 		You("trip over %s.", what);
650 	    }
651 	} else if (rn2(3) && is_ice(u.ux, u.uy)) {
652 	    pline("%s %s%s on the ice.",
653 #ifdef STEED
654 		u.usteed ? upstart(x_monnam(u.usteed,
655 				u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE,
656 				(char *)0, SUPPRESS_SADDLE, FALSE)) :
657 #endif
658 		"You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s");
659 	} else {
660 	    if (on_foot) {
661 		switch (rn2(4)) {
662 		  case 1:
663 			You("trip over your own %s.", Hallucination ?
664 				"elbow" : makeplural(body_part(FOOT)));
665 			break;
666 		  case 2:
667 			You("slip %s.", Hallucination ?
668 				"on a banana peel" : "and nearly fall");
669 			break;
670 		  case 3:
671 			You("flounder.");
672 			break;
673 		  default:
674 			You("stumble.");
675 			break;
676 		}
677 	    }
678 #ifdef STEED
679 	    else {
680 		switch (rn2(4)) {
681 		  case 1:
682 			Your("%s slip out of the stirrups.", makeplural(body_part(FOOT)));
683 			break;
684 		  case 2:
685 			You("let go of the reins.");
686 			break;
687 		  case 3:
688 			You("bang into the saddle-horn.");
689 			break;
690 		  default:
691 			You("slide to one side of the saddle.");
692 			break;
693 		}
694 		dismount_steed(DISMOUNT_FELL);
695 	    }
696 #endif
697 	}
698 }
699 
700 /* Print a lamp flicker message with tailer. */
701 STATIC_OVL void
see_lamp_flicker(obj,tailer)702 see_lamp_flicker(obj, tailer)
703 struct obj *obj;
704 const char *tailer;
705 {
706 	switch (obj->where) {
707 	    case OBJ_INVENT:
708 	    case OBJ_MINVENT:
709 		pline("%s flickers%s.", Yname2(obj), tailer);
710 		break;
711 	    case OBJ_FLOOR:
712 		You("see %s flicker%s.", an(xname(obj)), tailer);
713 		break;
714 	}
715 }
716 
717 /* Print a dimming message for brass lanterns. */
718 STATIC_OVL void
lantern_message(obj)719 lantern_message(obj)
720 struct obj *obj;
721 {
722 	/* from adventure */
723 	switch (obj->where) {
724 	    case OBJ_INVENT:
725 		Your("lantern is getting dim.");
726 		if (Hallucination)
727 		    pline("Batteries have not been invented yet.");
728 		break;
729 	    case OBJ_FLOOR:
730 		You("see a lantern getting dim.");
731 		break;
732 	    case OBJ_MINVENT:
733 		pline("%s lantern is getting dim.",
734 		    s_suffix(Monnam(obj->ocarry)));
735 		break;
736 	}
737 }
738 
739 /*
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.
742  */
743 void
burn_object(arg,timeout)744 burn_object(arg, timeout)
745 genericptr_t arg;
746 long timeout;
747 {
748 	struct obj *obj = (struct obj *) arg;
749 	boolean canseeit, many, menorah, need_newsym;
750 	xchar x, y;
751 	char whose[BUFSZ];
752 
753 	menorah = obj->otyp == CANDELABRUM_OF_INVOCATION;
754 	many = menorah ? obj->spe > 1 : obj->quan > 1L;
755 
756 	/* timeout while away */
757 	if (timeout != monstermoves) {
758 	    long how_long = monstermoves - timeout;
759 
760 	    if (how_long >= obj->age) {
761 		obj->age = 0;
762 		end_burn(obj, FALSE);
763 
764 		if (menorah) {
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;
771 		}
772 
773 	    } else {
774 		obj->age -= how_long;
775 		begin_burn(obj, TRUE);
776 	    }
777 	    return;
778 	}
779 
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);
785 	} else {
786 	    canseeit = FALSE;
787 	}
788 	need_newsym = FALSE;
789 
790 	/* obj->age is the age remaining at this point.  */
791 	switch (obj->otyp) {
792 	    case POT_OIL:
793 		    /* this should only be called when we run out */
794 		    if (canseeit) {
795 			switch (obj->where) {
796 			    case OBJ_INVENT:
797 			    case OBJ_MINVENT:
798 				pline("%s potion of oil has burnt away.",
799 				    whose);
800 				break;
801 			    case OBJ_FLOOR:
802 				You("see a burning potion of oil go out.");
803 				need_newsym = TRUE;
804 				break;
805 			}
806 		    }
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;
811 		    break;
812 
813 	    case BRASS_LANTERN:
814 	    case OIL_LAMP:
815 		switch((int)obj->age) {
816 		    case 150:
817 		    case 100:
818 		    case 50:
819 			if (canseeit) {
820 			    if (obj->otyp == BRASS_LANTERN)
821 				lantern_message(obj);
822 			    else
823 				see_lamp_flicker(obj,
824 				    obj->age == 50L ? " considerably" : "");
825 			}
826 			break;
827 
828 		    case 25:
829 			if (canseeit) {
830 			    if (obj->otyp == BRASS_LANTERN)
831 				lantern_message(obj);
832 			    else {
833 				switch (obj->where) {
834 				    case OBJ_INVENT:
835 				    case OBJ_MINVENT:
836 					pline("%s %s seems about to go out.",
837 					    whose, xname(obj));
838 					break;
839 				    case OBJ_FLOOR:
840 					You("see %s about to go out.",
841 					    an(xname(obj)));
842 					break;
843 				}
844 			    }
845 			}
846 			break;
847 
848 		    case 0:
849 			/* even if blind you'll know if holding it */
850 			if (canseeit || obj->where == OBJ_INVENT) {
851 			    switch (obj->where) {
852 				case OBJ_INVENT:
853 				case OBJ_MINVENT:
854 				    if (obj->otyp == BRASS_LANTERN)
855 					pline("%s lantern has run out of power.",
856 					    whose);
857 				    else
858 					pline("%s %s has gone out.",
859 					    whose, xname(obj));
860 				    break;
861 				case OBJ_FLOOR:
862 				    if (obj->otyp == BRASS_LANTERN)
863 					You("see a lantern run out of power.");
864 				    else
865 					You("see %s go out.",
866 					    an(xname(obj)));
867 				    break;
868 			    }
869 			}
870 			end_burn(obj, FALSE);
871 			break;
872 
873 		    default:
874 			/*
875 			 * Someone added fuel to the lamp while it was
876 			 * lit.  Just fall through and let begin burn
877 			 * handle the new age.
878 			 */
879 			break;
880 		}
881 
882 		if (obj->age)
883 		    begin_burn(obj, TRUE);
884 
885 		break;
886 
887 	    case CANDELABRUM_OF_INVOCATION:
888 	    case TALLOW_CANDLE:
889 	    case WAX_CANDLE:
890 		switch (obj->age) {
891 		    case 75:
892 			if (canseeit)
893 			    switch (obj->where) {
894 				case OBJ_INVENT:
895 				case OBJ_MINVENT:
896 				    pline("%s %scandle%s getting short.",
897 					whose,
898 					menorah ? "candelabrum's " : "",
899 					many ? "s are" : " is");
900 				    break;
901 				case OBJ_FLOOR:
902 				    You("see %scandle%s getting short.",
903 					    menorah ? "a candelabrum's " :
904 						many ? "some " : "a ",
905 					    many ? "s" : "");
906 				    break;
907 			    }
908 			break;
909 
910 		    case 15:
911 			if (canseeit)
912 			    switch (obj->where) {
913 				case OBJ_INVENT:
914 				case OBJ_MINVENT:
915 				    pline(
916 					"%s %scandle%s flame%s flicker%s low!",
917 					    whose,
918 					    menorah ? "candelabrum's " : "",
919 					    many ? "s'" : "'s",
920 					    many ? "s" : "",
921 					    many ? "" : "s");
922 				    break;
923 				case OBJ_FLOOR:
924 				    You("see %scandle%s flame%s flicker low!",
925 					    menorah ? "a candelabrum's " :
926 						many ? "some " : "a ",
927 					    many ? "s'" : "'s",
928 					    many ? "s" : "");
929 				    break;
930 			    }
931 			break;
932 
933 		    case 0:
934 			/* we know even if blind and in our inventory */
935 			if (canseeit || obj->where == OBJ_INVENT) {
936 			    if (menorah) {
937 				switch (obj->where) {
938 				    case OBJ_INVENT:
939 				    case OBJ_MINVENT:
940 					pline("%s candelabrum's flame%s.",
941 					    whose,
942 					    many ? "s die" : " dies");
943 					break;
944 				    case OBJ_FLOOR:
945 					You("see a candelabrum's flame%s die.",
946 						many ? "s" : "");
947 					break;
948 				}
949 			    } else {
950 				switch (obj->where) {
951 				    case OBJ_INVENT:
952 				    case OBJ_MINVENT:
953 					pline("%s %s %s consumed!",
954 					    whose,
955 					    xname(obj),
956 					    many ? "are" : "is");
957 					break;
958 				    case OBJ_FLOOR:
959 					/*
960 					You see some wax candles consumed!
961 					You see a wax candle consumed!
962 					*/
963 					You("see %s%s consumed!",
964 					    many ? "some " : "",
965 					    many ? xname(obj):an(xname(obj)));
966 					need_newsym = TRUE;
967 					break;
968 				}
969 
970 				/* post message */
971 				pline(Hallucination ?
972 					(many ? "They shriek!" :
973 						"It shrieks!") :
974 					Blind ? "" :
975 					    (many ? "Their flames die." :
976 						    "Its flame dies."));
977 			    }
978 			}
979 			end_burn(obj, FALSE);
980 
981 			if (menorah) {
982 			    obj->spe = 0;
983 			} else {
984 			    obj_extract_self(obj);
985 			    obfree(obj, (struct obj *)0);
986 			    obj = (struct obj *) 0;
987 			}
988 			break;
989 
990 		    default:
991 			/*
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.
995 			 */
996 			break;
997 		}
998 
999 		if (obj && obj->age)
1000 		    begin_burn(obj, TRUE);
1001 
1002 		break;
1003 
1004 	    default:
1005 		impossible("burn_object: unexpeced obj %s", xname(obj));
1006 		break;
1007 	}
1008 	if (need_newsym) newsym(x, y);
1009 }
1010 
1011 /*
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.
1015  *
1016  * Magic lamps stay lit as long as there's a genie inside, so don't start
1017  * a timer.
1018  *
1019  * Burn rules:
1020  *	potions of oil, lamps & candles:
1021  *		age = # of turns of fuel left
1022  *		spe = <unused>
1023  *
1024  *	magic lamps:
1025  *		age = <unused>
1026  *		spe = 0 not lightable, 1 lightable forever
1027  *
1028  *	candelabrum:
1029  *		age = # of turns of fuel left
1030  *		spe = # of candles
1031  *
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.
1035  *
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".
1039  *
1040  * This is a "silent" routine - it should not print anything out.
1041  */
1042 void
begin_burn(obj,already_lit)1043 begin_burn(obj, already_lit)
1044 	struct obj *obj;
1045 	boolean already_lit;
1046 {
1047 	int radius = 3;
1048 	long turns = 0;
1049 	boolean do_timer = TRUE;
1050 
1051 	if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
1052 	    return;
1053 
1054 	switch (obj->otyp) {
1055 	    case MAGIC_LAMP:
1056 		obj->lamplit = 1;
1057 		do_timer = FALSE;
1058 		break;
1059 
1060 	    case POT_OIL:
1061 		turns = obj->age;
1062 		radius = 1;	/* very dim light */
1063 		break;
1064 
1065 	    case BRASS_LANTERN:
1066 	    case OIL_LAMP:
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;
1076 		else
1077 		    turns = obj->age;
1078 		break;
1079 
1080 	    case CANDELABRUM_OF_INVOCATION:
1081 	    case TALLOW_CANDLE:
1082 	    case WAX_CANDLE:
1083 		/* magic times are 75, 15, and 0 */
1084 		if (obj->age > 75L)
1085 		    turns = obj->age - 75L;
1086 		else if (obj->age > 15L)
1087 		    turns = obj->age - 15L;
1088 		else
1089 		    turns = obj->age;
1090 		radius = candle_light_range(obj);
1091 		break;
1092 
1093 	    default:
1094                 /* [ALI] Support artifact light sources */
1095                 if (artifact_light(obj)) {
1096 		    obj->lamplit = 1;
1097 		    do_timer = FALSE;
1098 		    radius = 2;
1099 		} else {
1100 		    impossible("begin burn: unexpected %s", xname(obj));
1101 		    turns = obj->age;
1102 		}
1103 		break;
1104 	}
1105 
1106 	if (do_timer) {
1107 	    if (start_timer(turns, TIMER_OBJECT,
1108 					BURN_OBJECT, (genericptr_t)obj)) {
1109 		obj->lamplit = 1;
1110 		obj->age -= turns;
1111 		if (carried(obj) && !already_lit)
1112 		    update_inventory();
1113 	    } else {
1114 		obj->lamplit = 0;
1115 	    }
1116 	} else {
1117 	    if (carried(obj) && !already_lit)
1118 		update_inventory();
1119 	}
1120 
1121 	if (obj->lamplit && !already_lit) {
1122 	    xchar x, y;
1123 
1124 	    if (get_obj_location(obj, &x, &y, CONTAINED_TOO|BURIED_TOO))
1125 		new_light_source(x, y, radius, LS_OBJECT, (genericptr_t) obj);
1126 	    else
1127 		impossible("begin_burn: can't get obj position");
1128 	}
1129 }
1130 
1131 /*
1132  * Stop a burn timeout on the given object if timer attached.  Darken
1133  * light source.
1134  */
1135 void
end_burn(obj,timer_attached)1136 end_burn(obj, timer_attached)
1137 	struct obj *obj;
1138 	boolean timer_attached;
1139 {
1140 	if (!obj->lamplit) {
1141 	    impossible("end_burn: obj %s not lit", xname(obj));
1142 	    return;
1143 	}
1144 
1145 	if (obj->otyp == MAGIC_LAMP || artifact_light(obj))
1146 	    timer_attached = FALSE;
1147 
1148 	if (!timer_attached) {
1149 	    /* [DS] Cleanup explicitly, since timer cleanup won't happen */
1150 	    del_light_source(LS_OBJECT, (genericptr_t)obj);
1151 	    obj->lamplit = 0;
1152 	    if (obj->where == OBJ_INVENT)
1153 		update_inventory();
1154 	} else if (!stop_timer(BURN_OBJECT, (genericptr_t) obj))
1155 	    impossible("end_burn: obj %s not timed!", xname(obj));
1156 }
1157 
1158 #endif /* OVL1 */
1159 #ifdef OVL0
1160 
1161 /*
1162  * Cleanup a burning object if timer stopped.
1163  */
1164 static void
cleanup_burn(arg,expire_time)1165 cleanup_burn(arg, expire_time)
1166     genericptr_t arg;
1167     long expire_time;
1168 {
1169     struct obj *obj = (struct obj *)arg;
1170     if (!obj->lamplit) {
1171 	impossible("cleanup_burn: obj %s not lit", xname(obj));
1172 	return;
1173     }
1174 
1175     del_light_source(LS_OBJECT, arg);
1176 
1177     /* restore unused time */
1178     obj->age += expire_time - monstermoves;
1179 
1180     obj->lamplit = 0;
1181 
1182     if (obj->where == OBJ_INVENT)
1183 	update_inventory();
1184 }
1185 
1186 #endif /* OVL0 */
1187 #ifdef OVL1
1188 
1189 void
do_storms()1190 do_storms()
1191 {
1192     int nstrike;
1193     register int x, y;
1194     int dirx, diry;
1195     int count;
1196 
1197     /* no lightning if not the air level or too often, even then */
1198     if(!Is_airlevel(&u.uz) || rn2(8))
1199 	return;
1200 
1201     /* the number of strikes is 8-log2(nstrike) */
1202     for(nstrike = rnd(64); nstrike <= 64; nstrike *= 2) {
1203 	count = 0;
1204 	do {
1205 	    x = rnd(COLNO-1);
1206 	    y = rn2(ROWNO);
1207 	} while (++count < 100 && levl[x][y].typ != CLOUD);
1208 
1209 	if(count < 100) {
1210 	    dirx = rn2(3) - 1;
1211 	    diry = rn2(3) - 1;
1212 	    if(dirx != 0 || diry != 0)
1213 		buzz(-15, /* "monster" LIGHTNING spell */
1214 		     8, x, y, dirx, diry);
1215 	}
1216     }
1217 
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) {
1222 	    stop_occupation();
1223 	    nomul(-3);
1224 	}
1225     } else
1226 	You_hear("a rumbling noise.");
1227 }
1228 #endif /* OVL1 */
1229 
1230 
1231 #ifdef OVL0
1232 /* ------------------------------------------------------------------------- */
1233 /*
1234  * Generic Timeout Functions.
1235  *
1236  * Interface:
1237  *
1238  * General:
1239  *	boolean start_timer(long timeout,short kind,short func_index,
1240  *							genericptr_t arg)
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
1246  *		timer count.
1247  *
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.
1253  *
1254  *	void run_timers(void)
1255  *		Call timers that have timed out.
1256  *
1257  *
1258  * Save/Restore:
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.
1264  *
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.
1269  *
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.
1273  *
1274  * Object Specific:
1275  *	void obj_move_timers(struct obj *src, struct obj *dest)
1276  *		Reassign all timers from src to dest.
1277  *
1278  *	void obj_split_timers(struct obj *src, struct obj *dest)
1279  *		Duplicate all timers assigned to src and attach them to dest.
1280  *
1281  *	void obj_stop_timers(struct obj *obj)
1282  *		Stop all timers attached to obj.
1283  */
1284 
1285 #ifdef WIZARD
1286 STATIC_DCL const char *FDECL(kind_name, (SHORT_P));
1287 STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
1288 #endif
1289 STATIC_DCL void FDECL(insert_timer, (timer_element *));
1290 STATIC_DCL timer_element *FDECL(remove_timer, (timer_element **, SHORT_P,
1291 								genericptr_t));
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));
1296 
1297 /* ordered timer list */
1298 static timer_element *timer_base;		/* "active" */
1299 static unsigned long timer_id = 1;
1300 
1301 /* If defined, then include names when printing out the timer queue */
1302 #define VERBOSE_TIMER
1303 
1304 typedef struct {
1305     timeout_proc f, cleanup;
1306 #ifdef VERBOSE_TIMER
1307     const char *name;
1308 # define TTAB(a, b, c) {a,b,c}
1309 #else
1310 # define TTAB(a, b, c) {a,b}
1311 #endif
1312 } ttable;
1313 
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")
1322 };
1323 #undef TTAB
1324 
1325 
1326 #if defined(WIZARD)
1327 
1328 STATIC_OVL const char *
kind_name(kind)1329 kind_name(kind)
1330     short kind;
1331 {
1332     switch (kind) {
1333 	case TIMER_LEVEL: return "level";
1334 	case TIMER_GLOBAL: return "global";
1335 	case TIMER_OBJECT: return "object";
1336 	case TIMER_MONSTER: return "monster";
1337     }
1338     return "unknown";
1339 }
1340 
1341 STATIC_OVL void
print_queue(win,base)1342 print_queue(win, base)
1343     winid win;
1344     timer_element *base;
1345 {
1346     timer_element *curr;
1347     char buf[BUFSZ], arg_address[20];
1348 
1349     if (!base) {
1350 	putstr(win, 0, "<empty>");
1351     } else {
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));
1359 #else
1360 	    Sprintf(buf, " %4ld   %4ld  %-6s #%d(%s)",
1361 		curr->timeout, curr->tid, kind_name(curr->kind),
1362 		curr->func_index,
1363 		fmt_ptr((genericptr_t)curr->arg, arg_address));
1364 #endif
1365 	    putstr(win, 0, buf);
1366 	}
1367     }
1368 }
1369 
1370 int
wiz_timeout_queue()1371 wiz_timeout_queue()
1372 {
1373     winid win;
1374     char buf[BUFSZ];
1375 
1376     win = create_nhwindow(NHW_MENU);	/* corner text window */
1377     if (win == WIN_ERR) return 0;
1378 
1379     Sprintf(buf, "Current time = %ld.", monstermoves);
1380     putstr(win, 0, buf);
1381     putstr(win, 0, "");
1382     putstr(win, 0, "Active timeout queue:");
1383     putstr(win, 0, "");
1384     print_queue(win, timer_base);
1385 
1386     display_nhwindow(win, FALSE);
1387     destroy_nhwindow(win);
1388 
1389     return 0;
1390 }
1391 
1392 void
timer_sanity_check()1393 timer_sanity_check()
1394 {
1395     timer_element *curr;
1396     char obj_address[20];
1397 
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);
1405 	    }
1406 	}
1407 }
1408 
1409 #endif /* WIZARD */
1410 
1411 
1412 /*
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.
1415  */
1416 void
run_timers()1417 run_timers()
1418 {
1419     timer_element *curr;
1420 
1421     /*
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
1424      * is in the future.
1425      */
1426     while (timer_base && timer_base->timeout <= monstermoves) {
1427 	curr = timer_base;
1428 	timer_base = curr->next;
1429 
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);
1433     }
1434 }
1435 
1436 
1437 /*
1438  * Start a timer.  Return TRUE if successful.
1439  */
1440 boolean
start_timer(when,kind,func_index,arg)1441 start_timer(when, kind, func_index, arg)
1442 long when;
1443 short kind;
1444 short func_index;
1445 genericptr_t arg;
1446 {
1447     timer_element *gnu;
1448 
1449     if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
1450 	panic("start_timer");
1451 
1452     gnu = (timer_element *) alloc(sizeof(timer_element));
1453     gnu->next = 0;
1454     gnu->tid = timer_id++;
1455     gnu->timeout = monstermoves + when;
1456     gnu->kind = kind;
1457     gnu->needs_fixup = 0;
1458     gnu->func_index = func_index;
1459     gnu->arg = arg;
1460     insert_timer(gnu);
1461 
1462     if (kind == TIMER_OBJECT)	/* increment object's timed count */
1463 	((struct obj *)arg)->timed++;
1464 
1465     /* should check for duplicates and fail if any */
1466     return TRUE;
1467 }
1468 
1469 
1470 /*
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.
1473  */
1474 long
stop_timer(func_index,arg)1475 stop_timer(func_index, arg)
1476 short func_index;
1477 genericptr_t arg;
1478 {
1479     timer_element *doomed;
1480     long timeout;
1481 
1482     doomed = remove_timer(&timer_base, func_index, arg);
1483 
1484     if (doomed) {
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);
1491 	return timeout;
1492     }
1493     return 0;
1494 }
1495 
1496 
1497 /*
1498  * Move all object timers from src to dest, leaving src untimed.
1499  */
1500 void
obj_move_timers(src,dest)1501 obj_move_timers(src, dest)
1502     struct obj *src, *dest;
1503 {
1504     int count;
1505     timer_element *curr;
1506 
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;
1510 	    dest->timed++;
1511 	    count++;
1512 	}
1513     if (count != src->timed)
1514 	panic("obj_move_timers");
1515     src->timed = 0;
1516 }
1517 
1518 
1519 /*
1520  * Find all object timers and duplicate them for the new object "dest".
1521  */
1522 void
obj_split_timers(src,dest)1523 obj_split_timers(src, dest)
1524     struct obj *src, *dest;
1525 {
1526     timer_element *curr, *next_timer=0;
1527 
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);
1533 	}
1534     }
1535 }
1536 
1537 
1538 /*
1539  * Stop all timers attached to this object.  We can get away with this because
1540  * all object pointers are unique.
1541  */
1542 void
obj_stop_timers(obj)1543 obj_stop_timers(obj)
1544     struct obj *obj;
1545 {
1546     timer_element *curr, *prev, *next_timer=0;
1547 
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) {
1551 	    if (prev)
1552 		prev->next = curr->next;
1553 	    else
1554 		timer_base = curr->next;
1555 	    if (timeout_funcs[curr->func_index].cleanup)
1556 		(*timeout_funcs[curr->func_index].cleanup)(curr->arg,
1557 			curr->timeout);
1558 	    free((genericptr_t) curr);
1559 	} else {
1560 	    prev = curr;
1561 	}
1562     }
1563     obj->timed = 0;
1564 }
1565 
1566 
1567 /* Insert timer into the global queue */
1568 STATIC_OVL void
insert_timer(gnu)1569 insert_timer(gnu)
1570     timer_element *gnu;
1571 {
1572     timer_element *curr, *prev;
1573 
1574     for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next)
1575 	if (curr->timeout >= gnu->timeout) break;
1576 
1577     gnu->next = curr;
1578     if (prev)
1579 	prev->next = gnu;
1580     else
1581 	timer_base = gnu;
1582 }
1583 
1584 
1585 STATIC_OVL timer_element *
remove_timer(base,func_index,arg)1586 remove_timer(base, func_index, arg)
1587 timer_element **base;
1588 short func_index;
1589 genericptr_t arg;
1590 {
1591     timer_element *prev, *curr;
1592 
1593     for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next)
1594 	if (curr->func_index == func_index && curr->arg == arg) break;
1595 
1596     if (curr) {
1597 	if (prev)
1598 	    prev->next = curr->next;
1599 	else
1600 	    *base = curr->next;
1601     }
1602 
1603     return curr;
1604 }
1605 
1606 
1607 STATIC_OVL void
write_timer(fd,timer)1608 write_timer(fd, timer)
1609     int fd;
1610     timer_element *timer;
1611 {
1612     genericptr_t arg_save;
1613 
1614     switch (timer->kind) {
1615 	case TIMER_GLOBAL:
1616 	case TIMER_LEVEL:
1617 	    /* assume no pointers in arg */
1618 	    bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
1619 	    break;
1620 
1621 	case TIMER_OBJECT:
1622 	    if (timer->needs_fixup)
1623 		bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1624 	    else {
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;
1632 	    }
1633 	    break;
1634 
1635 	case TIMER_MONSTER:
1636 	    if (timer->needs_fixup)
1637 		bwrite(fd, (genericptr_t)timer, sizeof(timer_element));
1638 	    else {
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;
1646 	    }
1647 	    break;
1648 
1649 	default:
1650 	    panic("write_timer");
1651 	    break;
1652     }
1653 }
1654 
1655 
1656 /*
1657  * Return TRUE if the object will stay on the level when the level is
1658  * saved.
1659  */
1660 boolean
obj_is_local(obj)1661 obj_is_local(obj)
1662     struct obj *obj;
1663 {
1664     switch (obj->where) {
1665 	case OBJ_INVENT:
1666 	case OBJ_MIGRATING:	return FALSE;
1667 	case OBJ_FLOOR:
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);
1671     }
1672     panic("obj_is_local");
1673     return FALSE;
1674 }
1675 
1676 
1677 /*
1678  * Return TRUE if the given monster will stay on the level when the
1679  * level is saved.
1680  */
1681 STATIC_OVL boolean
mon_is_local(mon)1682 mon_is_local(mon)
1683 struct monst *mon;
1684 {
1685     struct monst *curr;
1686 
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;
1692     return TRUE;
1693 }
1694 
1695 
1696 /*
1697  * Return TRUE if the timer is attached to something that will stay on the
1698  * level when the level is saved.
1699  */
1700 STATIC_OVL boolean
timer_is_local(timer)1701 timer_is_local(timer)
1702     timer_element *timer;
1703 {
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);
1709     }
1710     panic("timer_is_local");
1711     return FALSE;
1712 }
1713 
1714 
1715 /*
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.
1718  */
1719 STATIC_OVL int
maybe_write_timer(fd,range,write_it)1720 maybe_write_timer(fd, range, write_it)
1721     int fd, range;
1722     boolean write_it;
1723 {
1724     int count = 0;
1725     timer_element *curr;
1726 
1727     for (curr = timer_base; curr; curr = curr->next) {
1728 	if (range == RANGE_GLOBAL) {
1729 	    /* global timers */
1730 
1731 	    if (!timer_is_local(curr)) {
1732 		count++;
1733 		if (write_it) write_timer(fd, curr);
1734 	    }
1735 
1736 	} else {
1737 	    /* local timers */
1738 
1739 	    if (timer_is_local(curr)) {
1740 		count++;
1741 		if (write_it) write_timer(fd, curr);
1742 	    }
1743 
1744 	}
1745     }
1746 
1747     return count;
1748 }
1749 
1750 
1751 /*
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
1754  * timers.
1755  *
1756  * Global range:
1757  *		+ timeouts that follow the hero (global)
1758  *		+ timeouts that follow obj & monst that are migrating
1759  *
1760  * Level range:
1761  *		+ timeouts that are level specific (e.g. storms)
1762  *		+ timeouts that stay with the level (obj & monst)
1763  */
1764 void
save_timers(fd,mode,range)1765 save_timers(fd, mode, range)
1766     int fd, mode, range;
1767 {
1768     timer_element *curr, *prev, *next_timer=0;
1769     int count;
1770 
1771     if (perform_bwrite(mode)) {
1772 	if (range == RANGE_GLOBAL)
1773 	    bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id));
1774 
1775 	count = maybe_write_timer(fd, range, FALSE);
1776 	bwrite(fd, (genericptr_t) &count, sizeof count);
1777 	(void) maybe_write_timer(fd, range, TRUE);
1778     }
1779 
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 */
1783 
1784 	    if ( !(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr)) ) {
1785 		if (prev)
1786 		    prev->next = curr->next;
1787 		else
1788 		    timer_base = curr->next;
1789 		free((genericptr_t) curr);
1790 		/* prev stays the same */
1791 	    } else {
1792 		prev = curr;
1793 	    }
1794 	}
1795     }
1796 }
1797 
1798 
1799 /*
1800  * Pull in the structures from disk, but don't recalculate the object and
1801  * monster pointers.
1802  */
1803 void
restore_timers(fd,range,ghostly,adjust)1804 restore_timers(fd, range, ghostly, adjust)
1805     int fd, range;
1806     boolean ghostly;	/* restoring from a ghost level */
1807     long adjust;	/* how much to adjust timeout */
1808 {
1809     int count;
1810     timer_element *curr;
1811 
1812     if (range == RANGE_GLOBAL)
1813 	mread(fd, (genericptr_t) &timer_id, sizeof timer_id);
1814 
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));
1820 	if (ghostly)
1821 	    curr->timeout += adjust;
1822 	insert_timer(curr);
1823     }
1824 }
1825 
1826 
1827 /* reset all timers that are marked for reseting */
1828 void
relink_timers(ghostly)1829 relink_timers(ghostly)
1830     boolean ghostly;
1831 {
1832     timer_element *curr;
1833     unsigned nid;
1834 
1835     for (curr = timer_base; curr; curr = curr->next) {
1836 	if (curr->needs_fixup) {
1837 	    if (curr->kind == TIMER_OBJECT) {
1838 		if (ghostly) {
1839 		    if (!lookup_id_mapping((unsigned)curr->arg, &nid))
1840 			panic("relink_timers 1");
1841 		} else
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");
1848 	    } else
1849 		panic("relink_timers 2");
1850 	}
1851     }
1852 }
1853 
1854 #endif /* OVL0 */
1855 
1856 /*timeout.c*/
1857