1    | /*	SCCS Id: @(#)music.c	3.3	1999/08/19	*/
2    | /*	Copyright (c) 1989 by Jean-Christophe Collet */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | /*
6    |  * This file contains the different functions designed to manipulate the
7    |  * musical instruments and their various effects.
8    |  *
9    |  * Actually the list of instruments / effects is :
10   |  *
11   |  * (wooden) flute	may calm snakes if player has enough dexterity
12   |  * magic flute		may put monsters to sleep:  area of effect depends
13   |  *			on player level.
14   |  * (tooled) horn	Will awaken monsters:  area of effect depends on player
15   |  *			level.  May also scare monsters.
16   |  * fire horn		Acts like a wand of fire.
17   |  * frost horn		Acts like a wand of cold.
18   |  * bugle		Will awaken soldiers (if any):  area of effect depends
19   |  *			on player level.
20   |  * (wooden) harp	May calm nymph if player has enough dexterity.
21   |  * magic harp		Charm monsters:  area of effect depends on player
22   |  *			level.
23   |  * (leather) drum	Will awaken monsters like the horn.
24   |  * drum of earthquake	Will initiate an earthquake whose intensity depends
25   |  *			on player level.  That is, it creates random pits
26   |  *			called here chasms.
27   |  */
28   | 
29   | #include "hack.h"
30   | 
31   | STATIC_DCL void FDECL(awaken_monsters,(int));
32   | STATIC_DCL void FDECL(put_monsters_to_sleep,(int));
33   | STATIC_DCL void FDECL(charm_snakes,(int));
34   | STATIC_DCL void FDECL(calm_nymphs,(int));
35   | STATIC_DCL void FDECL(charm_monsters,(int));
36   | STATIC_DCL void FDECL(do_earthquake,(int));
37   | STATIC_DCL int FDECL(do_improvisation,(struct obj *));
38   | 
39   | #ifdef UNIX386MUSIC
40   | STATIC_DCL int NDECL(atconsole);
41   | STATIC_DCL void FDECL(speaker,(struct obj *,char *));
42   | #endif
43   | #ifdef VPIX_MUSIC
44   | extern int sco_flag_console;	/* will need changing if not _M_UNIX */
45   | STATIC_DCL void NDECL(playinit);
46   | STATIC_DCL void FDECL(playstring, (char *,size_t));
47   | STATIC_DCL void FDECL(speaker,(struct obj *,char *));
48   | #endif
49   | #ifdef PCMUSIC
50   | void FDECL( pc_speaker, ( struct obj *, char * ) );
51   | #endif
52   | #ifdef AMIGA
53   | void FDECL( amii_speaker, ( struct obj *, char *, int ) );
54   | #endif
55   | 
56   | /*
57   |  * Wake every monster in range...
58   |  */
59   | 
60   | STATIC_OVL void
61   | awaken_monsters(distance)
62   | int distance;
63   | {
64   | 	register struct monst *mtmp = fmon;
65   | 	register int distm;
66   | 
67   | 	while(mtmp) {
68   | 	    if (!DEADMONSTER(mtmp)) {
69   | 		distm = distu(mtmp->mx, mtmp->my);
70   | 		if (distm < distance) {
71   | 		    mtmp->msleeping = 0;
72   | 		    mtmp->mcanmove = 1;
73   | 		    mtmp->mfrozen = 0;
74   | 		    /* May scare some monsters */
75   | 		    if (distm < distance/3 &&
76   | 			    !resist(mtmp, SCROLL_CLASS, 0, NOTELL))
77   | 			mtmp->mflee = 1;
78   | 		}
79   | 	    }
80   | 	    mtmp = mtmp->nmon;
81   | 	}
82   | }
83   | 
84   | /*
85   |  * Make monsters fall asleep.  Note that they may resist the spell.
86   |  */
87   | 
88   | STATIC_OVL void
89   | put_monsters_to_sleep(distance)
90   | int distance;
91   | {
92   | 	register struct monst *mtmp = fmon;
93   | 
94   | 	while(mtmp) {
95   | 		if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance &&
96   | 			sleep_monst(mtmp, d(10,10), WAND_CLASS)) {
97   | 		    mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */
98   | 		    slept_monst(mtmp);
99   | 		}
100  | 		mtmp = mtmp->nmon;
101  | 	}
102  | }
103  | 
104  | /*
105  |  * Charm snakes in range.  Note that the snakes are NOT tamed.
106  |  */
107  | 
108  | STATIC_OVL void
109  | charm_snakes(distance)
110  | int distance;
111  | {
112  | 	register struct monst *mtmp = fmon;
113  | 	int could_see_mon, was_peaceful;
114  | 
115  | 	while (mtmp) {
116  | 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove &&
117  | 		    distu(mtmp->mx, mtmp->my) < distance) {
118  | 		was_peaceful = mtmp->mpeaceful;
119  | 		mtmp->mpeaceful = 1;
120  | 		could_see_mon = canseemon(mtmp);
121  | 		mtmp->mundetected = 0;
122  | 		newsym(mtmp->mx, mtmp->my);
123  | 		if (canseemon(mtmp)) {
124  | 		    if (!could_see_mon)
125  | 			You("notice %s, swaying with the music.",
126  | 			    a_monnam(mtmp));
127  | 		    else
128  | 			pline("%s freezes, then sways with the music%s.",
129  | 			      Monnam(mtmp),
130  | 			      was_peaceful ? "" : ", and now seems quieter");
131  | 		}
132  | 	    }
133  | 	    mtmp = mtmp->nmon;
134  | 	}
135  | }
136  | 
137  | /*
138  |  * Calm nymphs in range.
139  |  */
140  | 
141  | STATIC_OVL void
142  | calm_nymphs(distance)
143  | int distance;
144  | {
145  | 	register struct monst *mtmp = fmon;
146  | 
147  | 	while (mtmp) {
148  | 	    if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove &&
149  | 		    distu(mtmp->mx, mtmp->my) < distance) {
150  | 		mtmp->msleeping = 0;
151  | 		mtmp->mpeaceful = 1;
152  | 		if (canseemon(mtmp))
153  | 		    pline(
154  | 		     "%s listens cheerfully to the music, then seems quieter.",
155  | 			  Monnam(mtmp));
156  | 	    }
157  | 	    mtmp = mtmp->nmon;
158  | 	}
159  | }
160  | 
161  | /* Awake only soldiers of the level. */
162  | 
163  | void
164  | awaken_soldiers()
165  | {
166  | 	register struct monst *mtmp = fmon;
167  | 
168  | 	while(mtmp) {
169  | 	    if (!DEADMONSTER(mtmp) &&
170  | 			is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) {
171  | 		mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0;
172  | 		mtmp->mcanmove = 1;
173  | 		if (canseemon(mtmp))
174  | 		    pline("%s is now ready for battle!", Monnam(mtmp));
175  | 		else
176  | 		    Norep("You hear the rattle of battle gear being readied.");
177  | 	    }
178  | 	    mtmp = mtmp->nmon;
179  | 	}
180  | }
181  | 
182  | /* Charm monsters in range.  Note that they may resist the spell. */
183  | 
184  | STATIC_OVL void
185  | charm_monsters(distance)
186  | int distance;
187  | {
188  | 	register struct monst *mtmp = fmon, *mtmp2;
189  | 
190  | 	while(mtmp) {
191  | 		mtmp2 = mtmp->nmon;
192  | 		if (!DEADMONSTER(mtmp)) {
193  | 			if (distu(mtmp->mx, mtmp->my) <= distance)
194  | 			    if(!resist(mtmp, SCROLL_CLASS, 0, NOTELL))
195  | 				(void) tamedog(mtmp, (struct obj *) 0);
196  | 		}
197  | 		mtmp = mtmp2;
198  | 	}
199  | 
200  | }
201  | 
202  | /* Generate earthquake :-) of desired force.
203  |  * That is:  create random chasms (pits).
204  |  */
205  | 
206  | STATIC_OVL void
207  | do_earthquake(force)
208  | int force;
209  | {
210  | 	register int x,y;
211  | 	struct monst *mtmp;
212  | 	struct obj *otmp;
213  | 	struct trap *chasm;
214  | 	int start_x, start_y, end_x, end_y;
215  | 
216  | 	start_x = u.ux - (force * 2);
217  | 	start_y = u.uy - (force * 2);
218  | 	end_x = u.ux + (force * 2);
219  | 	end_y = u.uy + (force * 2);
220  | 	if (start_x < 1) start_x = 1;
221  | 	if (start_y < 1) start_y = 1;
222  | 	if (end_x >= COLNO) end_x = COLNO - 1;
223  | 	if (end_y >= ROWNO) end_y = ROWNO - 1;
224  | 	for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) {
225  | 	    if ((mtmp = m_at(x,y)) != 0) {
226  | 		wakeup(mtmp);	/* peaceful monster will become hostile */
227  | 		if (mtmp->mundetected && is_hider(mtmp->data)) {
228  | 		    mtmp->mundetected = 0;
229  | 		    if (cansee(x,y))
230  | 			pline("%s is shaken loose from the ceiling!",
231  | 							    Amonnam(mtmp));
232  | 		    else
233  | 			You_hear("a thumping sound.");
234  | 		    if (x==u.ux && y==u.uy)
235  | 			You("easily dodge the falling %s.",
236  | 							    mon_nam(mtmp));
237  | 		    newsym(x,y);
238  | 		}
239  | 	    }
240  | 	    if (!rn2(14 - force)) switch (levl[x][y].typ) {
241  | 		  case FOUNTAIN : /* Make the fountain disappear */
242  | 			if (cansee(x,y))
243  | 				pline_The("fountain falls into a chasm.");
244  | 			goto do_pit;
245  | #ifdef SINKS
246  | 		  case SINK :
247  | 			if (cansee(x,y))
248  | 				pline_The("kitchen sink falls into a chasm.");
249  | 			goto do_pit;
250  | #endif
251  | 		  case ALTAR :
252  | 			if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break;
253  | 
254  | 			if (cansee(x,y))
255  | 				pline_The("altar falls into a chasm.");
256  | 			goto do_pit;
257  | 		  case GRAVE :
258  | 			if (cansee(x,y))
259  | 				pline_The("headstone topples into a chasm.");
260  | 			goto do_pit;
261  | 		  case THRONE :
262  | 			if (cansee(x,y))
263  | 				pline_The("throne falls into a chasm.");
264  | 			/* Falls into next case */
265  | 		  case ROOM :
266  | 		  case CORR : /* Try to make a pit */
267  | do_pit:		    chasm = maketrap(x,y,PIT);
268  | 		    if (!chasm) break;	/* no pit if portal at that location */
269  | 		    chasm->tseen = 1;
270  | 
271  | 		    levl[x][y].doormask = 0;
272  | 
273  | 		    mtmp = m_at(x,y);
274  | 
275  | 		    if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
276  | 			if (cansee(x, y))
277  | 			   pline("KADOOM! The boulder falls into a chasm%s!",
278  | 			      ((x == u.ux) && (y == u.uy)) ? " below you" : "");
279  | 			if (mtmp)
280  | 				mtmp->mtrapped = 0;
281  | 			obj_extract_self(otmp);
282  | 			(void) flooreffects(otmp, x, y, "");
283  | 			break;
284  | 		    }
285  | 
286  | 		    /* We have to check whether monsters or player
287  | 		       falls in a chasm... */
288  | 
289  | 		    if (mtmp) {
290  | 			if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) {
291  | 			    mtmp->mtrapped = 1;
292  | 			    if(cansee(x,y))
293  | 				pline("%s falls into a chasm!", Monnam(mtmp));
294  | 			    else if (flags.soundok && humanoid(mtmp->data))
295  | 				You_hear("a scream!");
296  | 			    mselftouch(mtmp, "Falling, ", TRUE);
297  | 			    if (mtmp->mhp > 0)
298  | 				if ((mtmp->mhp -= rnd(6)) <= 0) {
299  | 				    if(!cansee(x,y))
300  | 					pline("It is destroyed!");
301  | 				    else {
302  | 					You("destroy %s!", mtmp->mtame ?
303  | 					    x_monnam(mtmp, ARTICLE_THE, "poor",
304  | 				mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE):
305  | 					    mon_nam(mtmp));
306  | 				    }
307  | 				    xkilled(mtmp,0);
308  | 				}
309  | 			}
310  | 		    } else if (x == u.ux && y == u.uy) {
311  | 			    if (Levitation || Flying ||
312  | 						is_clinger(youmonst.data)) {
313  | 				    pline("A chasm opens up under you!");
314  | 				    You("don't fall in!");
315  | 			    } else {
316  | 				    You("fall into a chasm!");
317  | 				    u.utrap = rn1(6,2);
318  | 				    u.utraptype = TT_PIT;
319  | 				    losehp(rnd(6),"fell into a chasm",
320  | 					NO_KILLER_PREFIX);
321  | 				    selftouch("Falling, you");
322  | 			    }
323  | 		    } else newsym(x,y);
324  | 		    break;
325  | 		  case DOOR : /* Make the door collapse */
326  | 		    if (levl[x][y].doormask == D_NODOOR) goto do_pit;
327  | 		    if (cansee(x,y))
328  | 			pline_The("door collapses.");
329  | 		    if (*in_rooms(x, y, SHOPBASE))
330  | 			add_damage(x, y, 0L);
331  | 		    levl[x][y].doormask = D_NODOOR;
332  | 		    newsym(x,y);
333  | 		    break;
334  | 	    }
335  | 	}
336  | }
337  | 
338  | /*
339  |  * The player is trying to extract something from his/her instrument.
340  |  */
341  | 
342  | STATIC_OVL int
343  | do_improvisation(instr)
344  | struct obj *instr;
345  | {
346  | 	int damage, do_spec = !Confusion;
347  | #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined (PCMUSIC)
348  | 	struct obj itmp;
349  | 
350  | 	itmp = *instr;
351  | 	/* if won't yield special effect, make sound of mundane counterpart */
352  | 	if (!do_spec || instr->spe <= 0)
353  | 	    while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1;
354  | # ifdef MAC
355  | 	mac_speaker(&itmp, "C");
356  | # endif
357  | # ifdef AMIGA
358  | 	amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME);
359  | # endif
360  | # ifdef VPIX_MUSIC
361  | 	if (sco_flag_console)
362  | 	    speaker(&itmp, "C");
363  | # endif
364  | #ifdef PCMUSIC
365  | 	  pc_speaker ( &itmp, "C");
366  | #endif
367  | #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */
368  | 
369  | 	if (!do_spec)
370  | 	    pline("What you produce is quite far from music...");
371  | 	else
372  | 	    You("start playing %s.", the(xname(instr)));
373  | 
374  | 	switch (instr->otyp) {
375  | 	case MAGIC_FLUTE:		/* Make monster fall asleep */
376  | 	    if (do_spec && instr->spe > 0) {
377  | 		check_unpaid(instr);
378  | 		instr->spe--;
379  | 		You("produce soft music.");
380  | 		put_monsters_to_sleep(u.ulevel * 5);
381  | 		exercise(A_DEX, TRUE);
382  | 		break;
383  | 	    } /* else FALLTHRU */
384  | 	case WOODEN_FLUTE:		/* May charm snakes */
385  | 	    do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
386  | 	    pline("%s %s.", The(xname(instr)),
387  | 		  do_spec ? "trills" : "toots");
388  | 	    if (do_spec) charm_snakes(u.ulevel * 3);
389  | 	    exercise(A_DEX, TRUE);
390  | 	    break;
391  | 	case FROST_HORN:		/* Idem wand of cold */
392  | 	case FIRE_HORN:			/* Idem wand of fire */
393  | 	    if (do_spec && instr->spe > 0) {
394  | 		check_unpaid(instr);
395  | 		instr->spe--;
396  | 		if (!getdir((char *)0)) {
397  | 		    pline("%s vibrates.", The(xname(instr)));
398  | 		    break;
399  | 		} else if (!u.dx && !u.dy && !u.dz) {
400  | 		    if ((damage = zapyourself(instr, TRUE)) != 0)
401  | 			losehp(damage,
402  | 			       self_pronoun("using a magical horn on %sself",
403  | 					    "him"),
404  | 			       NO_KILLER_PREFIX);
405  | 		} else {
406  | 		    buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1,
407  | 			 rn1(6,6), u.ux, u.uy, u.dx, u.dy);
408  | 		}
409  | 		makeknown(instr->otyp);
410  | 		break;
411  | 	    } /* else FALLTHRU */
412  | 	case TOOLED_HORN:		/* Awaken or scare monsters */
413  | 	    You("produce a frightful, grave sound.");
414  | 	    awaken_monsters(u.ulevel * 30);
415  | 	    exercise(A_WIS, FALSE);
416  | 	    break;
417  | 	case BUGLE:			/* Awaken & attract soldiers */
418  | 	    You("extract a loud noise from %s.", the(xname(instr)));
419  | 	    awaken_soldiers();
420  | 	    exercise(A_WIS, FALSE);
421  | 	    break;
422  | 	case MAGIC_HARP:		/* Charm monsters */
423  | 	    if (do_spec && instr->spe > 0) {
424  | 		check_unpaid(instr);
425  | 		instr->spe--;
426  | 		pline("%s produces very attractive music.",
427  | 		      The(xname(instr)));
428  | 		charm_monsters((u.ulevel - 1) / 3 + 1);
429  | 		exercise(A_DEX, TRUE);
430  | 		break;
431  | 	    } /* else FALLTHRU */
432  | 	case WOODEN_HARP:		/* May calm Nymph */
433  | 	    do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25);
434  | 	    pline("%s %s.", The(xname(instr)),
435  | 		  do_spec ? "produces a lilting melody" : "twangs");
436  | 	    if (do_spec) calm_nymphs(u.ulevel * 3);
437  | 	    exercise(A_DEX, TRUE);
438  | 	    break;
439  | 	case DRUM_OF_EARTHQUAKE:	/* create several pits */
440  | 	    if (do_spec && instr->spe > 0) {
441  | 		check_unpaid(instr);
442  | 		instr->spe--;
443  | 		You("produce a heavy, thunderous rolling!");
444  | 		pline_The("entire dungeon is shaking around you!");
445  | 		do_earthquake((u.ulevel - 1) / 3 + 1);
446  | 		/* shake up monsters in a much larger radius... */
447  | 		awaken_monsters(ROWNO * COLNO);
448  | 		makeknown(DRUM_OF_EARTHQUAKE);
449  | 		break;
450  | 	    } /* else FALLTHRU */
451  | 	case LEATHER_DRUM:		/* Awaken monsters */
452  | 	    You("beat a deafening row!");
453  | 	    awaken_monsters(u.ulevel * 40);
454  | 	    exercise(A_WIS, FALSE);
455  | 	    break;
456  | 	default:
457  | 	    impossible("What a weird instrument (%d)!", instr->otyp);
458  | 	    break;
459  | 	}
460  | 	return 2;		/* That takes time */
461  | }
462  | 
463  | /*
464  |  * So you want music...
465  |  */
466  | 
467  | int
468  | do_play_instrument(instr)
469  | struct obj *instr;
470  | {
471  |     char buf[BUFSZ], c = 'y';
472  | #ifndef	AMIGA
473  | 	char *s;
474  | #endif
475  |     int x,y;
476  |     boolean ok;
477  | 
478  |     if (Underwater) {
479  | 	You_cant("play music underwater!");
480  | 	return(0);
481  |     }
482  |     if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) {
483  | 	c = yn("Improvise?");
484  |     }
485  |     if (c == 'n') {
486  | 	if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y')
487  | 		Strcpy(buf, tune);
488  | 	else
489  | 		getlin("What tune are you playing? [what 5 notes]", buf);
490  | #ifndef	AMIGA
491  | 	/* The AMIGA supports two octaves of notes */
492  | 	for (s=buf; *s; s++) *s = highc(*s);
493  | #endif
494  | 	You("extract a strange sound from %s!", the(xname(instr)));
495  | #ifdef UNIX386MUSIC
496  | 	/* if user is at the console, play through the console speaker */
497  | 	if (atconsole())
498  | 	    speaker(instr, buf);
499  | #endif
500  | #ifdef VPIX_MUSIC
501  | 	if (sco_flag_console)
502  | 	    speaker(instr, buf);
503  | #endif
504  | #ifdef MAC
505  | 	mac_speaker ( instr , buf ) ;
506  | #endif
507  | #ifdef PCMUSIC
508  | 	pc_speaker ( instr, buf );
509  | #endif
510  | #ifdef AMIGA
511  | 	{
512  | 		char nbuf[ 20 ];
513  | 		int i;
514  | 		for( i = 0; buf[i] && i < 5; ++i )
515  | 		{
516  | 			nbuf[ i*2 ] = buf[ i ];
517  | 			nbuf[ (i*2)+1 ] = 'h';
518  | 		}
519  | 		nbuf[ i*2 ] = 0;
520  | 		amii_speaker ( instr , nbuf, AMII_OKAY_VOLUME ) ;
521  | 	}
522  | #endif
523  | 	/* Check if there was the Stronghold drawbridge near
524  | 	 * and if the tune conforms to what we're waiting for.
525  | 	 */
526  | 	if(Is_stronghold(&u.uz)) {
527  | 	    exercise(A_WIS, TRUE);		/* just for trying */
528  | 	    if(!strcmp(buf,tune)) {
529  | 		/* Search for the drawbridge */
530  | 		for(y=u.uy-1; y<=u.uy+1; y++)
531  | 		    for(x=u.ux-1;x<=u.ux+1;x++)
532  | 			if(isok(x,y))
533  | 			if(find_drawbridge(&x,&y)) {
534  | 			    u.uevent.uheard_tune = 2; /* tune now fully known */
535  | 			    if(levl[x][y].typ == DRAWBRIDGE_DOWN)
536  | 				close_drawbridge(x,y);
537  | 			    else
538  | 				open_drawbridge(x,y);
539  | 			    return 0;
540  | 			}
541  | 	    } else if(flags.soundok) {
542  | 		if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1;
543  | 		/* Okay, it wasn't the right tune, but perhaps
544  | 		 * we can give the player some hints like in the
545  | 		 * Mastermind game */
546  | 		ok = FALSE;
547  | 		for(y = u.uy-1; y <= u.uy+1 && !ok; y++)
548  | 		    for(x = u.ux-1; x <= u.ux+1 && !ok; x++)
549  | 			if(isok(x,y))
550  | 			if(IS_DRAWBRIDGE(levl[x][y].typ) ||
551  | 			   is_drawbridge_wall(x,y) >= 0)
552  | 				ok = TRUE;
553  | 		if(ok) { /* There is a drawbridge near */
554  | 		    int tumblers, gears;
555  | 		    boolean matched[5];
556  | 
557  | 		    tumblers = gears = 0;
558  | 		    for(x=0; x < 5; x++)
559  | 			matched[x] = FALSE;
560  | 
561  | 		    for(x=0; x < (int)strlen(buf); x++)
562  | 			if(x < 5) {
563  | 			    if(buf[x] == tune[x]) {
564  | 				gears++;
565  | 				matched[x] = TRUE;
566  | 			    } else
567  | 				for(y=0; y < 5; y++)
568  | 				    if(!matched[y] &&
569  | 				       buf[x] == tune[y] &&
570  | 				       buf[y] != tune[y]) {
571  | 					tumblers++;
572  | 					matched[y] = TRUE;
573  | 					break;
574  | 				    }
575  | 			}
576  | 		    if(tumblers)
577  | 			if(gears)
578  | 			    You_hear("%d tumbler%s click and %d gear%s turn.",
579  | 				tumblers, plur(tumblers), gears, plur(gears));
580  | 			else
581  | 			    You_hear("%d tumbler%s click.",
582  | 				tumblers, plur(tumblers));
583  | 		    else if(gears) {
584  | 			You_hear("%d gear%s turn.", gears, plur(gears));
585  | 			/* could only get `gears == 5' by playing five
586  | 			   correct notes followed by excess; otherwise,
587  | 			   tune would have matched above */
588  | 			if (gears == 5) u.uevent.uheard_tune = 2;
589  | 		    }
590  | 		}
591  | 	    }
592  | 	  }
593  | 	return 1;
594  |     } else
595  | 	    return do_improvisation(instr);
596  | }
597  | 
598  | #ifdef UNIX386MUSIC
599  | /*
600  |  * Play audible music on the machine's speaker if appropriate.
601  |  */
602  | 
603  | STATIC_OVL int
604  | atconsole()
605  | {
606  |     /*
607  |      * Kluge alert: This code assumes that your [34]86 has no X terminals
608  |      * attached and that the console tty type is AT386 (this is always true
609  |      * under AT&T UNIX for these boxen). The theory here is that your remote
610  |      * ttys will have terminal type `ansi' or something else other than
611  |      * `AT386' or `xterm'. We'd like to do better than this, but testing
612  |      * to see if we're running on the console physical terminal is quite
613  |      * difficult given the presence of virtual consoles and other modern
614  |      * UNIX impedimenta...
615  |      */
616  |     char	*termtype = nh_getenv("TERM");
617  | 
618  |      return(!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm"));
619  | }
620  | 
621  | STATIC_OVL void
622  | speaker(instr, buf)
623  | struct obj *instr;
624  | char	*buf;
625  | {
626  |     /*
627  |      * For this to work, you need to have installed the PD speaker-control
628  |      * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com)
629  |      * posted to comp.sources.unix in Feb 1990.  A copy should be included
630  |      * with your nethack distribution.
631  |      */
632  |     int	fd;
633  | 
634  |     if ((fd = open("/dev/speaker", 1)) != -1)
635  |     {
636  | 	/* send a prefix to modify instrumental `timbre' */
637  | 	switch (instr->otyp)
638  | 	{
639  | 	case WOODEN_FLUTE:
640  | 	case MAGIC_FLUTE:
641  | 	    (void) write(fd, ">ol", 1); /* up one octave & lock */
642  | 	    break;
643  | 	case TOOLED_HORN:
644  | 	case FROST_HORN:
645  | 	case FIRE_HORN:
646  | 	    (void) write(fd, "<<ol", 2); /* drop two octaves & lock */
647  | 	    break;
648  | 	case BUGLE:
649  | 	    (void) write(fd, "ol", 2); /* octave lock */
650  | 	    break;
651  | 	case WOODEN_HARP:
652  | 	case MAGIC_HARP:
653  | 	    (void) write(fd, "l8mlol", 4); /* fast, legato, octave lock */
654  | 	    break;
655  | 	}
656  | 	(void) write(fd, buf, strlen(buf));
657  | 	(void) close(fd);
658  |     }
659  | }
660  | #endif /* UNIX386MUSIC */
661  | 
662  | #ifdef VPIX_MUSIC
663  | 
664  | # if 0
665  | #include <sys/types.h>
666  | #include <sys/console.h>
667  | #include <sys/vtkd.h>
668  | # else
669  | #define KIOC ('K' << 8)
670  | #define KDMKTONE (KIOC | 8)
671  | # endif
672  | 
673  | #define noDEBUG
674  | 
675  | STATIC_OVL void tone(hz, ticks)
676  | /* emit tone of frequency hz for given number of ticks */
677  | unsigned int hz, ticks;
678  | {
679  |     ioctl(0,KDMKTONE,hz|((ticks*10)<<16));
680  | # ifdef DEBUG
681  |     printf("TONE: %6d %6d\n",hz,ticks * 10);
682  | # endif
683  |     nap(ticks * 10);
684  | }
685  | 
686  | STATIC_OVL void rest(ticks)
687  | /* rest for given number of ticks */
688  | int	ticks;
689  | {
690  |     nap(ticks * 10);
691  | # ifdef DEBUG
692  |     printf("REST:        %6d\n",ticks * 10);
693  | # endif
694  | }
695  | 
696  | 
697  | #include "interp.c"	/* from snd86unx.shr */
698  | 
699  | 
700  | STATIC_OVL void
701  | speaker(instr, buf)
702  | struct obj *instr;
703  | char	*buf;
704  | {
705  |     /* emit a prefix to modify instrumental `timbre' */
706  |     playinit();
707  |     switch (instr->otyp)
708  |     {
709  | 	case WOODEN_FLUTE:
710  | 	case MAGIC_FLUTE:
711  | 	    playstring(">ol", 1); /* up one octave & lock */
712  | 	    break;
713  | 	case TOOLED_HORN:
714  | 	case FROST_HORN:
715  | 	case FIRE_HORN:
716  | 	    playstring("<<ol", 2); /* drop two octaves & lock */
717  | 	    break;
718  | 	case BUGLE:
719  | 	    playstring("ol", 2); /* octave lock */
720  | 	    break;
721  | 	case WOODEN_HARP:
722  | 	case MAGIC_HARP:
723  | 	    playstring("l8mlol", 4); /* fast, legato, octave lock */
724  | 	    break;
725  |     }
726  |     playstring( buf, strlen(buf));
727  | }
728  | 
729  | # ifdef DEBUG
730  | main(argc,argv)
731  | char *argv[];
732  | {
733  |     if (argc == 2) {
734  | 	playinit();
735  | 	playstring(argv[1], strlen(argv[1]));
736  |     }
737  | }
738  | # endif
739  | #endif	/* VPIX_MUSIC */
740  | 
741  | /*music.c*/